|
- import { captureScreenshot, expect, test } from './fixtures'
- import type { Page, Route } from '@playwright/test'
-
- const navigationModes = [
- { label: '顶部一级 + 左侧二级', value: 'top-side' },
- { label: '左侧分组菜单', value: 'side' },
- { label: '顶部下拉菜单', value: 'top' },
- ] as const
-
- const waitForDashboard = async (page: import('@playwright/test').Page) => {
- await expect(page.locator('.platform-shell')).toBeVisible()
- }
-
- const envelope = (data: unknown) => JSON.stringify({
- code: 200,
- message: '成功',
- data,
- timestamp: '2026-08-30T10:00:00+08:00',
- requestId: 'ute2e-preferences',
- })
-
- const fulfillJson = (route: Route, data: unknown) => route.fulfill({
- status: 200,
- contentType: 'application/json',
- body: envelope(data),
- })
-
- const installMockedSession = async (page: Page) => {
- await page.addInitScript(() => {
- sessionStorage.setItem('unreal-tran:web:access-token:v1', 'ute2e-preferences-token')
- })
- await page.route('**/api/auth/v1/**', (route) => {
- const path = new URL(route.request().url()).pathname
- if (path === '/api/auth/v1/system-config/public') {
- return fulfillJson(route, {
- systemName: '装备维修实训数字车间',
- loginDescription: '统一承载内容制作、虚实训练、训练考核与资源管理。',
- defaultTheme: 'military',
- logoConfigured: false,
- faviconConfigured: false,
- loginLogoConfigured: false,
- })
- }
- if (path === '/api/auth/v1/auth/me') {
- return fulfillJson(route, {
- user: {
- id: '1', username: 'admin', displayName: '系统管理员', departmentId: '10',
- departmentName: '信息中心', mustChangePassword: false, version: 1,
- },
- activeRoleId: '100',
- roles: [{
- id: '100', code: 'admin', name: '管理员', shortName: '管', status: 1,
- builtIn: 1, isSuperAdmin: 1, dataScopeCode: 'ALL',
- }],
- permissions: ['dashboard.view'],
- authorizationMode: 'SINGLE_ACTIVE',
- loginTime: 1788064800,
- })
- }
- if (path === '/api/auth/v1/menus/navigation') return fulfillJson(route, [])
- return fulfillJson(route, {})
- })
- await page.route('**/api/tran/v1/**', (route) => fulfillJson(route, {}))
- await page.goto('/dashboard')
- await waitForDashboard(page)
- }
-
- const contrastRatio = (foreground: string, background: string) => {
- const channels = (value: string) => (value.match(/[\d.]+/g) ?? []).slice(0, 3).map(Number)
- const luminance = (value: string) => channels(value).reduce((sum, channel, index) => {
- const normalized = channel / 255
- const linear = normalized <= .03928 ? normalized / 12.92 : ((normalized + .055) / 1.055) ** 2.4
- return sum + linear * [.2126, .7152, .0722][index]!
- }, 0)
- const [lighter, darker] = [luminance(foreground), luminance(background)].sort((left, right) => right - left)
- return (lighter! + .05) / (darker! + .05)
- }
-
- test('三种导航模式与四种主题可以持久化', async ({ page }, testInfo) => {
- await page.emulateMedia({ colorScheme: 'dark' })
- await installMockedSession(page)
- await expect(page.locator('.platform-shell')).toHaveAttribute('data-navigation-mode', 'top-side')
- await expect(page.locator('html')).toHaveAttribute('data-theme', 'light')
- await expect(page.locator('html')).toHaveAttribute('data-color-theme', 'military')
- expect(await page.locator('html').evaluate((element) => getComputedStyle(element).getPropertyValue('--primary').trim())).toBe('#168a72')
- await expect(page.getByText('本地服务正常', { exact: true })).toHaveCount(0)
- await expect(page.getByText('平台服务正常', { exact: true })).toHaveCount(0)
-
- for (const mode of navigationModes) {
- await test.step(`导航模式:${mode.label}`, async () => {
- await page.getByRole('button', { name: '界面与导航设置' }).click()
- const drawer = page.locator('.el-drawer:visible')
- await drawer.getByRole('button', { name: new RegExp(mode.label.replace('+', '\\+')) }).click()
- await expect(page.locator('.platform-shell')).toHaveAttribute('data-navigation-mode', mode.value)
- await page.keyboard.press('Escape')
- await page.reload()
- await expect(page.locator('.platform-shell')).toHaveAttribute('data-navigation-mode', mode.value)
- await waitForDashboard(page)
- await captureScreenshot(page, testInfo, `navigation-${mode.value}`)
- })
- }
-
- await test.step('桌面侧栏收起、刷新持久化与展开恢复', async () => {
- await page.getByRole('button', { name: '界面与导航设置' }).click()
- const drawer = page.locator('.el-drawer:visible')
- await drawer.getByRole('button', { name: /顶部一级 \+ 左侧二级/ }).click()
- await page.keyboard.press('Escape')
- await expect(drawer).toBeHidden()
-
- const shell = page.locator('.platform-shell')
- await expect(shell).toHaveAttribute('data-navigation-mode', 'top-side')
- const collapseButton = page.getByRole('button', { name: '收起左侧导航' })
- await expect(collapseButton).toBeVisible()
- await collapseButton.click()
- await expect(shell).toHaveClass(/sidebar-collapsed/)
- await expect(page.getByRole('button', { name: '展开左侧导航' })).toBeVisible()
- await captureScreenshot(page, testInfo, 'sidebar-collapsed')
-
- await page.reload()
- await waitForDashboard(page)
- await expect(shell).toHaveClass(/sidebar-collapsed/)
- const expandButton = page.getByRole('button', { name: '展开左侧导航' })
- await expect(expandButton).toBeVisible()
- await expandButton.click()
- await expect(shell).not.toHaveClass(/sidebar-collapsed/)
- await expect(page.getByRole('button', { name: '收起左侧导航' })).toBeVisible()
- await captureScreenshot(page, testInfo, 'sidebar-expanded')
-
- await page.reload()
- await waitForDashboard(page)
- await expect(shell).not.toHaveClass(/sidebar-collapsed/)
- })
-
- const themes = [
- { label: '军工绿', value: 'military', expected: 'light', primary: '#168a72' },
- { label: '科技蓝', value: 'technology', expected: 'light', primary: '#197fc8' },
- { label: '深空灰', value: 'graphite', expected: 'light', primary: '#4f8995' },
- { label: '暗色', value: 'dark', expected: 'dark', primary: '#55d0bd' },
- ] as const
-
- for (const theme of themes) {
- await test.step(`主题模式:${theme.label}`, async () => {
- await page.getByRole('button', { name: '界面与导航设置' }).click()
- const drawer = page.locator('.el-drawer:visible')
- await drawer.getByRole('button', { name: new RegExp(theme.label) }).click()
- await expect(page.locator('html')).toHaveAttribute('data-theme', theme.expected)
- await expect(page.locator('html')).toHaveAttribute('data-color-theme', theme.value)
- await page.keyboard.press('Escape')
- await page.reload()
- await expect(page.locator('html')).toHaveAttribute('data-theme', theme.expected)
- await expect(page.locator('html')).toHaveAttribute('data-color-theme', theme.value)
- await waitForDashboard(page)
- expect(await page.locator('html').evaluate((element) => getComputedStyle(element).getPropertyValue('--primary').trim())).toBe(theme.primary)
- if (theme.expected === 'dark') {
- const colors = await page.locator('html').evaluate(() => {
- const probe = document.createElement('div')
- probe.style.color = 'var(--text-primary)'
- probe.style.backgroundColor = 'var(--surface)'
- document.body.appendChild(probe)
- const result = {
- foreground: getComputedStyle(probe).color,
- background: getComputedStyle(probe).backgroundColor,
- }
- probe.remove()
- return result
- })
- expect(contrastRatio(colors.foreground, colors.background)).toBeGreaterThanOrEqual(4.5)
- }
- await captureScreenshot(page, testInfo, `theme-${theme.value}`)
- })
- }
-
- // 保持默认值,避免 headed 模式下人工继续检查时继承最后一次设置。
- await page.getByRole('button', { name: '界面与导航设置' }).click()
- const drawer = page.locator('.el-drawer:visible')
- await drawer.getByRole('button', { name: /军工绿/ }).click()
- await drawer.getByRole('button', { name: /顶部一级 \+ 左侧二级/ }).click()
- })
|