기여 목록 / 8494771
[security] Migrate SecurityOriginView security state section to Lit
DevToolsrefactordevtools/devtools-frontendIn Review
SecurityOriginView의 security state section을 Lit으로 전환했습니다.
security details가 없는 secure·insecure·unknown 상태의 제목과 설명을 검증하는
테스트를 추가했습니다.
문제 설명
security details가 없는 경우 상태별 제목과 설명을 직접 DOM으로 생성하고 있었습니다.
세 분기의 공통 구조를 Lit template으로 옮기고, 상태별 표시를 테스트로 검증하도록 했습니다.
해결 내용
- 상태에 따라 제목과 설명을 선택하는
renderSecurityStateSection()을 추가했습니다. security-state-section에 Lit template을 렌더링하도록 변경했습니다.- 기존 제목의
role="heading"과aria-level="2"를 유지했습니다. - secure·insecure·unknown 세 상태의 제목·설명·heading 속성을 검증했습니다.
전체 코드 diff는 다음과 같습니다.
diff --git a/front_end/panels/security/SecurityPanel.test.ts b/front_end/panels/security/SecurityPanel.test.ts
index 889b29a..e92b134 100644
--- a/front_end/panels/security/SecurityPanel.test.ts
+++ b/front_end/panels/security/SecurityPanel.test.ts
@@ -76,6 +76,41 @@
row => [...row.cells].map(cell => cell.textContent ?? ''));
}
+ describe('security state section', () => {
+ const cases = [
+ {
+ securityState: Protocol.Security.SecurityState.Secure,
+ title: 'Secure',
+ description: 'This origin is a non-HTTPS secure origin.',
+ },
+ {
+ securityState: Protocol.Security.SecurityState.Insecure,
+ title: 'Not secure',
+ description: 'Your connection to this origin isn’t secure.',
+ },
+ {
+ securityState: Protocol.Security.SecurityState.Unknown,
+ title: 'No security information',
+ description: 'No security details are available for this origin.',
+ },
+ ];
+ for (const {securityState, title, description} of cases) {
+ it(`renders when securityState is ${securityState} without security details`, () => {
+ const view = new Security.SecurityPanel.SecurityOriginView(urlString`https://foo.bar`, {
+ securityState,
+ securityDetails: null,
+ loadedFromCache: false,
+ });
+ const section = querySelectorErrorOnMissing(view.element, '.security-state-section');
+ const heading = querySelectorErrorOnMissing(section, '.origin-view-section-title');
+ assert.strictEqual(heading.textContent, title);
+ assert.strictEqual(heading.getAttribute('role'), 'heading');
+ assert.strictEqual(heading.getAttribute('aria-level'), '2');
+ assert.include(section.textContent, description);
+ });
+ }
+ });
+
describe('connection section', () => {
function getConnectionDetailsRows(securityDetails: Partial<Protocol.Network.SecurityDetails> = {}): string[][] {
const view =
diff --git a/front_end/panels/security/SecurityPanel.ts b/front_end/panels/security/SecurityPanel.ts
index 8f2833b..930a900 100644
--- a/front_end/panels/security/SecurityPanel.ts
+++ b/front_end/panels/security/SecurityPanel.ts
@@ -1570,6 +1570,30 @@
// clang-format on
}
+function renderSecurityStateSection(securityState: Protocol.Security.SecurityState): TemplateResult {
+ let title;
+ let description;
+ if (securityState === Protocol.Security.SecurityState.Secure) {
+ // If the security state is secure but there are no security details,
+ // this means that the origin is a non-cryptographic secure origin, e.g.
+ // chrome:// or about:.
+ title = i18nString(UIStrings.secure);
+ description = i18nString(UIStrings.thisOriginIsANonhttpsSecure);
+ } else if (securityState !== Protocol.Security.SecurityState.Unknown) {
+ title = i18nString(UIStrings.notSecure);
+ description = i18nString(UIStrings.yourConnectionToThisOriginIsNot);
+ } else {
+ title = i18nString(UIStrings.noSecurityInformation);
+ description = i18nString(UIStrings.noSecurityDetailsAreAvailableFor);
+ }
+
+ // clang-format off
+ return html`
+ <div class="origin-view-section-title" role="heading" aria-level="2">${title}</div>
+ <div>${description}</div>`;
+ // clang-format on
+}
+
export class SecurityOriginView extends UI.Widget.VBox {
readonly #origin: Platform.DevToolsPath.UrlString;
readonly #titleSection: HTMLElement;
@@ -1601,27 +1625,10 @@
const noteSection = this.element.createChild('div', 'origin-view-section origin-view-notes');
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
render(renderNoteSection(originState.loadedFromCache), noteSection);
- } else if (originState.securityState === Protocol.Security.SecurityState.Secure) {
- // If the security state is secure but there are no security details,
- // this means that the origin is a non-cryptographic secure origin, e.g.
- // chrome:// or about:.
- const secureSection = this.element.createChild('div', 'origin-view-section');
- const secureDiv = secureSection.createChild('div', 'origin-view-section-title');
- secureDiv.textContent = i18nString(UIStrings.secure);
- UI.ARIAUtils.markAsHeading(secureDiv, 2);
- secureSection.createChild('div').textContent = i18nString(UIStrings.thisOriginIsANonhttpsSecure);
- } else if (originState.securityState !== Protocol.Security.SecurityState.Unknown) {
- const notSecureSection = this.element.createChild('div', 'origin-view-section');
- const notSecureDiv = notSecureSection.createChild('div', 'origin-view-section-title');
- notSecureDiv.textContent = i18nString(UIStrings.notSecure);
- UI.ARIAUtils.markAsHeading(notSecureDiv, 2);
- notSecureSection.createChild('div').textContent = i18nString(UIStrings.yourConnectionToThisOriginIsNot);
} else {
- const noInfoSection = this.element.createChild('div', 'origin-view-section');
- const noInfoDiv = noInfoSection.createChild('div', 'origin-view-section-title');
- noInfoDiv.textContent = i18nString(UIStrings.noSecurityInformation);
- UI.ARIAUtils.markAsHeading(noInfoDiv, 2);
- noInfoSection.createChild('div').textContent = i18nString(UIStrings.noSecurityDetailsAreAvailableFor);
+ const securityStateSection = this.element.createChild('div', 'origin-view-section security-state-section');
+ // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
+ render(renderSecurityStateSection(originState.securityState), securityStateSection);
}
}
테스트 방법
SecurityPanel.test.ts에 상태별 테스트 3개를 추가했습니다.
patchset 2의 CQ 실행에서는 다음 Chromium 웹 테스트 2개가 실패했습니다.
http/tests/devtools/security/origin-view-noncryptographic-secure-origin.jshttp/tests/devtools/security/origin-view-then-interstitial.js
해당 테스트의 기대값을 임시 조정하는 CL 8493052도 리뷰 중입니다. 2026년 10월 4일 확인 기준으로 이 CL의 CQ는 통과 상태가 아닙니다.
배운 점
Lit 전환에서는 표시 문구뿐 아니라 heading의 접근성 속성도 유지해야 합니다. DOM 출력을 비교하는 Chromium 웹 테스트의 결과도 함께 확인해야 합니다.