|
- import type { Page, Route } from '@playwright/test'
-
- import { captureScreenshot, expect, test } from './fixtures'
-
- const DEFAULT_SYSTEM_NAME = '某类装备维修实训数字车间'
- const PNG_BYTES = Buffer.from(
- 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=',
- 'base64',
- )
-
- type BrandAsset = 'logo' | 'favicon'
-
- interface ConfigurationState {
- systemName: string
- systemNameConfigured: boolean
- systemNameDataVersion: number
- defaultTheme: 'military' | 'technology' | 'graphite' | 'dark'
- defaultThemeConfigured: boolean
- defaultThemeDataVersion: number
- digitalHumanWidgetConfigured: boolean
- digitalHumanWidget: {
- baseUrl: string
- agentSlug: string
- position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
- label: string
- } | null
- digitalHumanWidgetDataVersion: number
- logoConfigured: boolean
- logoUrl: string | null
- logoMediaType: string | null
- logoOriginalName: string | null
- logoSize: number | null
- logoSha256: string | null
- logoDataVersion: number
- faviconConfigured: boolean
- faviconUrl: string | null
- faviconMediaType: string | null
- faviconOriginalName: string | null
- faviconSize: number | null
- faviconSha256: string | null
- faviconDataVersion: number
- }
-
- const initialConfiguration = (): ConfigurationState => ({
- systemName: DEFAULT_SYSTEM_NAME,
- systemNameConfigured: false,
- systemNameDataVersion: 0,
- defaultTheme: 'military',
- defaultThemeConfigured: true,
- defaultThemeDataVersion: 1,
- digitalHumanWidgetConfigured: false,
- digitalHumanWidget: null,
- digitalHumanWidgetDataVersion: 0,
- logoConfigured: false,
- logoUrl: null,
- logoMediaType: null,
- logoOriginalName: null,
- logoSize: null,
- logoSha256: null,
- logoDataVersion: 0,
- faviconConfigured: false,
- faviconUrl: null,
- faviconMediaType: null,
- faviconOriginalName: null,
- faviconSize: null,
- faviconSha256: null,
- faviconDataVersion: 0,
- })
-
- const profile = (canUpdate: boolean) => ({
- user: {
- id: '1',
- username: 'admin',
- displayName: '系统管理员',
- departmentId: '10',
- departmentName: '信息中心',
- mustChangePassword: false,
- version: 1,
- },
- activeRoleId: '100',
- activeRole: { id: '100', code: 'admin', name: '管理员' },
- roles: [{
- id: '100', code: 'admin', name: '管理员', shortName: '管', status: 1,
- builtIn: 1, isSuperAdmin: 1, dataScopeCode: 'ALL',
- }],
- permissions: ['system.config', ...(canUpdate ? ['system.config.update'] : [])],
- authorizationMode: 'SINGLE_ACTIVE',
- loginTime: 1786387200,
- })
-
- const loginContext = {
- defaultRoleCode: 'admin',
- roles: [{ code: 'admin', label: '管理员', accountLabel: '登录账号', organizationMode: 'NONE', organizationLabels: [] }],
- departments: [],
- }
-
- const envelope = (data: unknown, message = '成功', code: number | string = 200) => JSON.stringify({
- code,
- message,
- data,
- timestamp: '2026-08-11T12:00:00+08:00',
- requestId: 'ute2e-system-config',
- })
-
- const fulfillJson = (route: Route, data: unknown, status = 200, message = '成功', code: number | string = status) => route.fulfill({
- status,
- contentType: 'application/json',
- body: envelope(data, message, code),
- })
-
- class SystemConfigurationMock {
- readonly state = initialConfiguration()
- readonly mutations: string[] = []
- readonly canUpdate: boolean
- conflictNextNameSave = false
- managementReadCount = 0
-
- constructor(canUpdate = true) {
- this.canUpdate = canUpdate
- }
-
- async install(page: Page, authenticated = true) {
- if (authenticated) {
- await page.addInitScript(() => {
- sessionStorage.setItem('unreal-tran:web:access-token:v1', 'ute2e-system-config-token')
- })
- }
- await page.route('**/api/auth/v1/**', (route) => this.handle(route))
- await page.route('https://human.example.test/**', (route) => route.fulfill({
- status: 200,
- headers: { 'Content-Type': 'text/html; charset=utf-8' },
- body: `<!doctype html><html><body style="margin:0;background:transparent">
- <button style="width:188px;height:56px">问数字教员</button>
- <script>
- addEventListener('message', function (event) {
- var data = event.data || {};
- if (data.source !== 'virtual-instructor-widget-host' || data.type !== 'theme') return;
- document.body.dataset.hostTheme = data.theme && data.theme.scheme;
- document.body.dataset.hostAccent = data.theme && data.theme.accent;
- });
- parent.postMessage({source:'virtual-instructor-widget',type:'ready',protocolVersion:2,capabilities:['resize','drag','theme']}, '*');
- parent.postMessage({source:'virtual-instructor-widget',type:'resize',width:208,height:92}, '*');
- </script>
- </body></html>`,
- }))
- }
-
- private publicState() {
- return {
- systemName: this.state.systemName,
- defaultTheme: this.state.defaultTheme,
- digitalHumanWidget: this.state.digitalHumanWidget,
- logoConfigured: this.state.logoConfigured,
- logoUrl: this.state.logoUrl,
- logoMediaType: this.state.logoMediaType,
- faviconConfigured: this.state.faviconConfigured,
- faviconUrl: this.state.faviconUrl,
- faviconMediaType: this.state.faviconMediaType,
- }
- }
-
- private configureAsset(asset: BrandAsset) {
- const nextVersion = this.state[`${asset}DataVersion`] + 1
- this.state[`${asset}Configured`] = true
- this.state[`${asset}Url`] = `/api/auth/v1/system-config/assets/${asset}?v=${nextVersion}`
- this.state[`${asset}MediaType`] = 'image/png'
- this.state[`${asset}OriginalName`] = asset === 'logo' ? 'brand-logo.png' : 'site-icon.png'
- this.state[`${asset}Size`] = PNG_BYTES.length
- this.state[`${asset}Sha256`] = `mock-${asset}-sha256`
- this.state[`${asset}DataVersion`] = nextVersion
- }
-
- private removeAsset(asset: BrandAsset) {
- this.state[`${asset}Configured`] = false
- this.state[`${asset}Url`] = null
- this.state[`${asset}MediaType`] = null
- this.state[`${asset}OriginalName`] = null
- this.state[`${asset}Size`] = null
- this.state[`${asset}Sha256`] = null
- this.state[`${asset}DataVersion`] += 1
- }
-
- private async handle(route: Route) {
- const request = route.request()
- const url = new URL(request.url())
- const path = url.pathname
- const method = request.method()
-
- if (method === 'GET' && path === '/api/auth/v1/system-config/public') {
- return fulfillJson(route, this.publicState())
- }
- if (method === 'GET' && path === '/api/auth/v1/auth/login-context') {
- return fulfillJson(route, loginContext)
- }
- if (method === 'GET' && path === '/api/auth/v1/auth/me') {
- return fulfillJson(route, profile(this.canUpdate))
- }
- if (method === 'GET' && path === '/api/auth/v1/menus/navigation') {
- return fulfillJson(route, [])
- }
- if (method === 'GET' && path === '/api/auth/v1/system-config') {
- this.managementReadCount += 1
- return fulfillJson(route, this.state)
- }
- if (method === 'PUT' && path === '/api/auth/v1/system-config/name') {
- this.mutations.push('name')
- if (this.conflictNextNameSave) {
- this.conflictNextNameSave = false
- this.state.systemName = '其他管理员刚保存的名称'
- this.state.systemNameConfigured = true
- this.state.systemNameDataVersion += 1
- return fulfillJson(route, null, 409, '系统名称版本冲突', 'CONFIG_VERSION_CONFLICT')
- }
- const body = request.postDataJSON() as { systemName?: string }
- const nextName = String(body.systemName ?? '').trim()
- this.state.systemName = nextName || DEFAULT_SYSTEM_NAME
- this.state.systemNameConfigured = Boolean(nextName)
- this.state.systemNameDataVersion += 1
- return fulfillJson(route, this.state)
- }
- if (method === 'PUT' && path === '/api/auth/v1/system-config/default-theme') {
- this.mutations.push('default-theme')
- const body = request.postDataJSON() as { defaultTheme?: ConfigurationState['defaultTheme'] }
- this.state.defaultTheme = body.defaultTheme ?? 'military'
- this.state.defaultThemeConfigured = true
- this.state.defaultThemeDataVersion += 1
- return fulfillJson(route, this.state)
- }
- if (method === 'POST' && path === '/api/auth/v1/system-config/digital-human-widget/parse') {
- const body = request.postDataJSON() as { embedCode?: string }
- const code = String(body.embedCode ?? '')
- if (!code.includes('/embed/') || !code.includes('virtual-instructor-widget')) {
- return fulfillJson(route, null, 400, '不是数字人系统生成的有效悬浮图标代码', 'VALIDATION_FAILED')
- }
- return fulfillJson(route, {
- baseUrl: 'https://human.example.test',
- agentSlug: 'dh-global-demo',
- position: 'bottom-right',
- label: '问数字教员',
- })
- }
- if (method === 'PUT' && path === '/api/auth/v1/system-config/digital-human-widget') {
- this.mutations.push('digital-human-widget')
- this.state.digitalHumanWidgetConfigured = true
- this.state.digitalHumanWidget = {
- baseUrl: 'https://human.example.test',
- agentSlug: 'dh-global-demo',
- position: 'bottom-right',
- label: '问数字教员',
- }
- this.state.digitalHumanWidgetDataVersion += 1
- return fulfillJson(route, this.state)
- }
- if (method === 'DELETE' && path === '/api/auth/v1/system-config/digital-human-widget') {
- this.mutations.push('remove-digital-human-widget')
- this.state.digitalHumanWidgetConfigured = false
- this.state.digitalHumanWidget = null
- this.state.digitalHumanWidgetDataVersion += 1
- return fulfillJson(route, this.state)
- }
- if (method === 'POST' && /^\/api\/auth\/v1\/system-config\/(logo|favicon)$/.test(path)) {
- const asset = path.endsWith('/logo') ? 'logo' : 'favicon'
- this.mutations.push(`upload-${asset}`)
- this.configureAsset(asset)
- return fulfillJson(route, this.state)
- }
- if (method === 'DELETE' && /^\/api\/auth\/v1\/system-config\/(logo|favicon)$/.test(path)) {
- const asset = path.endsWith('/logo') ? 'logo' : 'favicon'
- this.mutations.push(`remove-${asset}`)
- this.removeAsset(asset)
- return fulfillJson(route, this.state)
- }
- if (method === 'GET' && /^\/api\/auth\/v1\/system-config\/assets\/(logo|favicon)$/.test(path)) {
- return route.fulfill({
- status: 200,
- contentType: 'image/png',
- headers: { 'Cache-Control': 'public, max-age=31536000, immutable' },
- body: PNG_BYTES,
- })
- }
- return fulfillJson(route, {})
- }
- }
-
- const configuredBrandImage = (page: Page) => page.locator('.platform-brand .brand-mark.configured img')
- const faviconLink = (page: Page) => page.locator('link[rel~="icon"]')
-
- test.describe('系统配置(状态化 Mock,不访问真实 API/数据库)', () => {
- test('公开配置为空时登录页使用当前内置品牌', async ({ page }) => {
- const mock = new SystemConfigurationMock()
- await mock.install(page, false)
-
- await page.goto('/login')
-
- await expect(page.locator('.login-brand')).toContainText(DEFAULT_SYSTEM_NAME)
- await expect(page).toHaveTitle(`登录 - ${DEFAULT_SYSTEM_NAME}`)
- await expect(faviconLink(page)).toHaveAttribute('href', '/favicon.svg')
- await expect(faviconLink(page)).toHaveAttribute('type', 'image/svg+xml')
- expect(mock.mutations).toEqual([])
- })
-
- test('已配置的悬浮数字人只挂载到登录后的业务外壳', async ({ page }) => {
- const mock = new SystemConfigurationMock()
- mock.state.digitalHumanWidgetConfigured = true
- mock.state.digitalHumanWidget = {
- baseUrl: 'https://human.example.test',
- agentSlug: 'dh-global-demo',
- position: 'bottom-right',
- label: '问数字教员',
- }
- mock.state.digitalHumanWidgetDataVersion = 1
- await mock.install(page, false)
-
- await page.goto('/login')
-
- await expect(page.getByTestId('global-digital-human-widget')).toHaveCount(0)
- })
-
- test('已配置的平台 LOGO 保持透明且不显示边框', async ({ page }) => {
- const mock = new SystemConfigurationMock()
- Object.assign(mock.state, {
- logoConfigured: true,
- logoUrl: '/api/auth/v1/system-config/assets/logo?v=1',
- logoMediaType: 'image/png',
- logoOriginalName: 'brand-logo.png',
- logoSize: PNG_BYTES.length,
- logoSha256: 'mock-logo-sha256',
- logoDataVersion: 1,
- })
- await mock.install(page)
-
- await page.goto('/system/config')
- await expect(page.getByTestId('system-config-page')).toHaveAttribute('data-ready', 'true')
- const configuredBrandMark = configuredBrandImage(page).locator('..')
- await expect(configuredBrandMark).toHaveCSS('border-top-width', '0px')
- await expect(configuredBrandMark).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
- await expect(configuredBrandMark).toHaveCSS('box-shadow', 'none')
- })
-
- test('管理员可从菜单进入并保存、清空名称以及上传、移除 PNG 品牌资源', async ({ page }, testInfo) => {
- const mock = new SystemConfigurationMock()
- await mock.install(page)
- await page.setViewportSize({ width: 1920, height: 1080 })
-
- await page.goto('/system/config')
- await expect(page.getByTestId('system-config-page')).toHaveAttribute('data-ready', 'true')
- await expect(page).toHaveURL(/\/system\/config(?:\?|$)/)
- await expect(page.locator('.current-group-navigation')).toContainText('系统配置')
- await expect(page.getByRole('link', { name: '系统配置' })).toHaveClass(/active/)
- await expect(page.getByTestId('system-config-form')).toBeVisible()
- await expect(page.locator('.config-navigation')).toHaveCount(0)
- await expect(page.locator('.system-config-form-card')).toHaveCount(1)
- await expect(page.locator('.system-config-form-row')).toHaveCount(7)
- const pageBox = await page.getByTestId('system-config-page').boundingBox()
- const formBox = await page.getByTestId('system-config-form').boundingBox()
- expect(pageBox).not.toBeNull()
- expect(formBox).not.toBeNull()
- expect(formBox!.width / pageBox!.width).toBeGreaterThan(0.95)
-
- const nameInput = page.getByTestId('system-config-name')
- await nameInput.fill('装备维修教学测试平台')
- await page.getByTestId('system-config-save-name').click()
- await expect(page.locator('.platform-brand')).toContainText('装备维修教学测试平台')
- await expect(page).toHaveTitle('系统配置 - 装备维修教学测试平台')
-
- await page.getByTestId('system-config-clear-name').click()
- const restoreNameDialog = page.locator('.el-message-box:visible')
- await restoreNameDialog.getByRole('button', { name: '恢复默认' }).click()
- await expect(page.locator('.platform-brand')).toContainText(DEFAULT_SYSTEM_NAME)
- await expect(page).toHaveTitle(`系统配置 - ${DEFAULT_SYSTEM_NAME}`)
-
- await page.getByTestId('system-config-default-theme').getByRole('button', { name: /科技蓝/ }).click()
- await page.getByTestId('system-config-save-default-theme').click()
- await expect(page.locator('html')).toHaveAttribute('data-color-theme', 'technology')
- await expect(page.locator('.el-message')).toHaveCount(0, { timeout: 10_000 })
-
- await page.getByTestId('system-config-open-widget-drawer').click()
- await expect(page.getByTestId('system-config-widget-drawer')).toBeVisible()
- await page.getByTestId('system-config-widget-code').fill('这不是悬浮数字人代码')
- await page.getByTestId('system-config-parse-widget').click()
- await expect(page.getByText('不是数字人系统生成的有效悬浮图标代码', { exact: false })).toBeVisible()
-
- await page.getByTestId('system-config-widget-code').fill(`
- <script>
- (function () {
- var BASE = "https://human.example.test";
- var AGENT = "dh-global-demo";
- var POSITION = "bottom-right";
- var LABEL = "问数字教员";
- var frame = document.createElement('iframe');
- frame.id = 'virtual-instructor-widget';
- frame.src = BASE + '/embed/' + AGENT;
- window.__unsafePastedScriptWasExecuted = true;
- })();
- <\/script>
- `)
- await page.getByTestId('system-config-parse-widget').click()
- await expect(page.getByText('解析成功,请确认接入信息')).toBeVisible()
- const widgetPreviewFrame = page.getByTestId('system-config-widget-preview').locator('iframe')
- await expect(widgetPreviewFrame).toHaveAttribute('src', /human\.example\.test\/embed\/dh-global-demo\?.*open=1/)
- expect(await page.evaluate(() => (window as Window & { __unsafePastedScriptWasExecuted?: boolean }).__unsafePastedScriptWasExecuted)).toBeUndefined()
- await captureScreenshot(page, testInfo, 'system-config-widget-preview')
- await page.getByTestId('system-config-save-widget').click()
- await expect(page.getByTestId('system-config-widget-drawer')).toBeHidden()
- await expect(page.getByTestId('system-config-digital-human-widget-card')).toContainText('已接入数字教员')
- const globalWidget = page.getByTestId('global-digital-human-widget')
- await expect(globalWidget).toHaveAttribute('src', /human\.example\.test\/embed\/dh-global-demo/)
- const globalWidgetBody = page.frameLocator('[data-testid="global-digital-human-widget"]').locator('body')
- await expect(globalWidgetBody).toHaveAttribute('data-host-theme', 'light')
- await expect(globalWidgetBody).toHaveAttribute('data-host-accent', '#197fc8')
-
- const widgetBeforeDrag = await globalWidget.boundingBox()
- const widgetHandle = await globalWidget.elementHandle()
- const widgetContent = await widgetHandle?.contentFrame()
- expect(widgetBeforeDrag).not.toBeNull()
- expect(widgetContent).not.toBeNull()
- await widgetContent!.evaluate(() => {
- parent.postMessage({ source: 'virtual-instructor-widget', type: 'drag-start', handle: 'launcher' }, '*')
- parent.postMessage({ source: 'virtual-instructor-widget', type: 'drag-move', handle: 'launcher', deltaX: -180, deltaY: -120 }, '*')
- parent.postMessage({ source: 'virtual-instructor-widget', type: 'drag-end', handle: 'launcher' }, '*')
- })
- await expect.poll(async () => (await globalWidget.boundingBox())?.x).toBeLessThan(widgetBeforeDrag!.x - 100)
- const storedWidgetPosition = await page.evaluate(() => Object.entries(localStorage)
- .find(([key]) => key.startsWith('unreal-tran:web:digital-human-widget-position:v1:'))?.[1] ?? '')
- expect(storedWidgetPosition).toContain('offsetX')
-
- await page.getByTestId('system-config-remove-widget').click()
- await page.locator('.el-message-box:visible').getByRole('button', { name: '确认移除' }).click()
- await expect(page.getByTestId('global-digital-human-widget')).toHaveCount(0)
-
- const logoCard = page.getByTestId('system-config-logo-card')
- await logoCard.locator('input[type="file"]').setInputFiles({
- name: 'brand-logo.png',
- mimeType: 'image/png',
- buffer: PNG_BYTES,
- })
- const logoDialog = page.getByTestId('system-config-upload-dialog')
- await expect(logoDialog).toBeVisible()
- await logoDialog.getByRole('button', { name: '确认上传' }).click()
- await expect(logoCard).toContainText('brand-logo.png')
- await expect(configuredBrandImage(page)).toHaveAttribute('src', /\/api\/auth\/v1\/system-config\/assets\/logo\?v=1$/)
-
- await page.getByTestId('system-config-remove-logo').click()
- await page.locator('.el-message-box:visible').getByRole('button', { name: '确认移除' }).click()
- await expect(configuredBrandImage(page)).toHaveCount(0)
- await expect(logoCard).toContainText('使用系统内置 LOGO')
-
- const faviconCard = page.getByTestId('system-config-favicon-card')
- await faviconCard.locator('input[type="file"]').setInputFiles({
- name: 'site-icon.png',
- mimeType: 'image/png',
- buffer: PNG_BYTES,
- })
- const faviconDialog = page.getByTestId('system-config-upload-dialog')
- await faviconDialog.getByRole('button', { name: '确认上传' }).click()
- await expect(faviconCard).toContainText('site-icon.png')
- await expect(faviconLink(page)).toHaveAttribute('type', 'image/png')
- await expect(faviconLink(page)).toHaveAttribute('href', /\/api\/auth\/v1\/system-config\/assets\/favicon\?v=1$/)
-
- await page.getByTestId('system-config-remove-favicon').click()
- await page.locator('.el-message-box:visible').getByRole('button', { name: '确认移除' }).click()
- await expect(faviconLink(page)).toHaveAttribute('type', 'image/svg+xml')
- await expect(faviconLink(page)).toHaveAttribute('href', '/favicon.svg')
- await expect(faviconCard).toContainText('使用系统内置网站图标')
-
- expect(mock.mutations).toEqual([
- 'name', 'name', 'default-theme', 'digital-human-widget', 'remove-digital-human-widget',
- 'upload-logo', 'remove-logo', 'upload-favicon', 'remove-favicon',
- ])
- await expect(page.locator('.el-message')).toHaveCount(0, { timeout: 10_000 })
- await captureScreenshot(page, testInfo, 'system-config-defaults-restored')
- })
-
- test('保存遇到 409 时刷新服务端配置并提示重新确认', async ({ page }) => {
- const mock = new SystemConfigurationMock()
- mock.conflictNextNameSave = true
- await mock.install(page)
-
- await page.goto('/system/config')
- await expect(page.getByTestId('system-config-page')).toHaveAttribute('data-ready', 'true')
- const readsBeforeSave = mock.managementReadCount
- await page.getByTestId('system-config-name').fill('本次输入会冲突')
- await page.getByTestId('system-config-save-name').click()
-
- await expect(page.getByText('配置已被其他管理员修改,页面已刷新,请确认后重新操作', { exact: true })).toBeVisible()
- await expect(page.getByTestId('system-config-name')).toHaveValue('其他管理员刚保存的名称')
- await expect(page.locator('.platform-brand')).toContainText('其他管理员刚保存的名称')
- await expect(page).toHaveTitle('系统配置 - 其他管理员刚保存的名称')
- expect(mock.managementReadCount).toBeGreaterThan(readsBeforeSave)
- })
-
- test('只有查看权限时页面为只读且不暴露更新操作', async ({ page }, testInfo) => {
- const mock = new SystemConfigurationMock(false)
- await mock.install(page)
-
- await page.goto('/system/config')
- await expect(page.getByTestId('system-config-page')).toHaveAttribute('data-ready', 'true')
- await expect(page.getByRole('link', { name: '系统配置' })).toBeVisible()
- await expect(page.getByTestId('system-config-name')).toBeDisabled()
- await expect(page.getByTestId('system-config-save-name')).toHaveCount(0)
- await expect(page.getByTestId('system-config-clear-name')).toHaveCount(0)
- await expect(page.getByTestId('system-config-save-default-theme')).toHaveCount(0)
- await expect(page.getByTestId('system-config-open-widget-drawer')).toHaveCount(0)
- await expect(page.getByTestId('system-config-upload-logo')).toHaveCount(0)
- await expect(page.getByTestId('system-config-upload-favicon')).toHaveCount(0)
- expect(mock.mutations).toEqual([])
- await captureScreenshot(page, testInfo, 'system-config-read-only')
- })
-
- test('简化表单在移动端暗色模式下无横向溢出', async ({ page }, testInfo) => {
- const mock = new SystemConfigurationMock()
- await mock.install(page)
- await page.addInitScript(() => {
- localStorage.setItem('unreal-tran:web:preferences:v1', JSON.stringify({
- navigationMode: 'top-side',
- themeMode: 'dark',
- sidebarCollapsed: false,
- }))
- })
- await page.setViewportSize({ width: 375, height: 812 })
-
- await page.goto('/system/config')
- await expect(page.getByTestId('system-config-page')).toHaveAttribute('data-ready', 'true')
- await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
- await expect(page.getByTestId('system-config-form')).toBeVisible()
- await expect(page.locator('.config-navigation')).toHaveCount(0)
- expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true)
- await captureScreenshot(page, testInfo, 'system-config-mobile-dark')
- })
- })
|