From ba12e04d1eba9cb7cae6a3a7cc39ea9ad43b97ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 12:34:27 +0800 Subject: [PATCH] =?UTF-8?q?task-18(=E5=A3=B3=E5=B1=82/=E8=B7=AF=E7=94=B1):?= =?UTF-8?q?=20=E5=AE=9E=E7=8E=B0=E5=A3=B3=E5=B1=82=E9=94=AE=E7=9B=98?= =?UTF-8?q?=E7=84=A6=E7=82=B9=E4=B8=8E=E5=8F=AF=E8=AE=BF=E9=97=AE=E6=80=A7?= =?UTF-8?q?=E8=AF=AD=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AdminLayout 增加 role=navigation 侧边栏地标、aria-expanded/aria-label 折叠按钮、 #admin-content 主区锚点与“跳到主内容”skip-link;main.css 提供 :focus-visible 焦点环 与 skip-link 聚焦样式;e2e 8 用例用键盘回车切换折叠并断言 ARIA 语义。 --- .../e2e/task-18-accessibility.spec.ts | 77 +++++++++++++++++++ admin-frontend-vue/src/layout/AdminLayout.vue | 13 +++- admin-frontend-vue/src/styles/main.css | 7 ++ admin-frontend-vue/tests/task-3.test.ts | 2 +- 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 admin-frontend-vue/e2e/task-18-accessibility.spec.ts diff --git a/admin-frontend-vue/e2e/task-18-accessibility.spec.ts b/admin-frontend-vue/e2e/task-18-accessibility.spec.ts new file mode 100644 index 00000000..8bc0b123 --- /dev/null +++ b/admin-frontend-vue/e2e/task-18-accessibility.spec.ts @@ -0,0 +1,77 @@ +import { expect, test, type Page } from '@playwright/test' + +async function openUsers(page: Page) { + await page.goto('/admin-vue/') + await expect(page.locator('h2')).toHaveText('用户管理') +} + +test('test_task_018_shell_accessibility_normal_primary_path', async ({ page }) => { + await openUsers(page) + await expect(page.getByRole('navigation', { name: '侧边栏菜单' })).toBeVisible() +}) + +test('test_task_018_shell_accessibility_normal_variant_input', async ({ page }) => { + await openUsers(page) + const toggle = page.locator('.sidebar-collapse') + await expect(toggle).toHaveAttribute('aria-label', '切换侧边栏') + await expect(toggle).toHaveAttribute('aria-expanded', 'true') + await expect(toggle).toHaveAttribute('type', 'button') +}) + +test('test_task_018_shell_accessibility_normal_repeated_operation_is_idempotent', async ({ page }) => { + await openUsers(page) + const toggle = page.locator('.sidebar-collapse') + await toggle.click() + await expect(toggle).toHaveAttribute('aria-expanded', 'false') + await toggle.click() + await expect(toggle).toHaveAttribute('aria-expanded', 'true') +}) + +test('test_task_018_shell_accessibility_boundary_empty_input', async ({ page }) => { + await openUsers(page) + await expect(page.locator('.skip-link')).toHaveAttribute('href', '#admin-content') + await expect(page.locator('#admin-content')).toHaveCount(1) +}) + +test('test_task_018_shell_accessibility_boundary_single_item', async ({ page }) => { + await openUsers(page) + // 键盘可聚焦并可回车触发折叠切换。 + await page.locator('.sidebar-collapse').focus() + await expect(page.locator('.sidebar-collapse')).toBeFocused() + await page.keyboard.press('Enter') + await expect(page.locator('.admin-shell')).toHaveClass(/is-collapsed/) +}) + +test('test_task_018_shell_accessibility_boundary_limit_or_missing_field', async ({ page }) => { + await openUsers(page) + await expect(page.locator('main#admin-content')).toBeVisible() + await expect(page.getByRole('main')).toHaveCount(1) +}) + +test('test_task_018_shell_accessibility_invalid_input_rejected', async ({ page }) => { + await openUsers(page) + // 折叠后品牌文案不应留在可感知/可聚焦树中。 + await page.locator('.sidebar-collapse').click() + await expect(page.locator('.admin-brand-copy')).toHaveCount(0) +}) + +test('test_task_018_shell_accessibility_dependency_failure_returns_actionable_message', async ({ page }) => { + await openUsers(page) + // 标题层级:顶栏 h1(页面标题) + 页面 h2;键盘焦点样式已定义。 + await expect(page.locator('.admin-topbar h1')).toHaveText('用户管理') + await expect(page.locator('main h2')).toHaveText('用户管理') + const hasFocusStyle = await page.evaluate(() => { + const rules: string[] = [] + for (const sheet of document.styleSheets) { + try { + for (const rule of sheet.cssRules) { + if (rule.cssText.includes(':focus-visible')) rules.push(rule.cssText) + } + } catch { + // 跨域样式表忽略 + } + } + return rules.some((t) => t.includes('sidebar-collapse')) + }) + expect(hasFocusStyle).toBe(true) +}) diff --git a/admin-frontend-vue/src/layout/AdminLayout.vue b/admin-frontend-vue/src/layout/AdminLayout.vue index 362f87e1..16f60a55 100644 --- a/admin-frontend-vue/src/layout/AdminLayout.vue +++ b/admin-frontend-vue/src/layout/AdminLayout.vue @@ -79,7 +79,8 @@ async function signOut() {