136 lines
5.2 KiB
TypeScript
136 lines
5.2 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
||
|
||
/**
|
||
* 双列菜单布局的头部区域回归 —— 针对 ERP 应用。
|
||
*
|
||
* 结构对照 vben(packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue):
|
||
* 第一列(layout-mixed-rail,width = mixedWidth):
|
||
* · 背景 bg-sidebar-deep(本项目按需求用白色)
|
||
* · <slot name="logo"> 在这一列(:410,高度 = headerHeight)
|
||
* 第二列(layout-mixed-column,extraWidth):
|
||
* · 背景 bg-sidebar
|
||
* · <slot name="extra-title"> 在这一列(:446,高度 = extraTitleHeight ?? headerHeight - 1)
|
||
*
|
||
* ⚠️ 注意区分:vben 的 `isMixedNav` = layout === 'mixed-nav'(顶栏混合),
|
||
* 与本布局 `sidebar-mixed-nav` 不是一回事。vben-layout.vue:619 的
|
||
* `isSideMode && !isMixedNav && sidebarLogoVisible` 对 sidebar-mixed-nav 成立,
|
||
* 所以 logo 渲染在第一列。
|
||
*
|
||
* 即:logo 在第一列,标题在第二列。
|
||
*/
|
||
|
||
const ERP_URL = process.env.ERP_URL ?? 'http://localhost:5090'
|
||
|
||
async function useMixedNavLayout(page: import('@playwright/test').Page) {
|
||
await page.goto(`${ERP_URL}/`)
|
||
await page.evaluate(() => {
|
||
const KEY = 'g3erp:preferences'
|
||
const raw = localStorage.getItem(KEY)
|
||
const pref: Record<string, Record<string, unknown>> = raw ? JSON.parse(raw) : {}
|
||
|
||
const app = pref.app || {}
|
||
app.layout = 'sidebar-mixed-nav'
|
||
pref.app = app
|
||
|
||
const sidebar = pref.sidebar || {}
|
||
sidebar.enable = true
|
||
sidebar.extraCollapse = false
|
||
pref.sidebar = sidebar
|
||
|
||
const logo = pref.logo || {}
|
||
logo.enable = true
|
||
logo.showText = true
|
||
pref.logo = logo
|
||
|
||
localStorage.setItem(KEY, JSON.stringify(pref))
|
||
|
||
for (const key of Object.keys(localStorage)) {
|
||
if (key.indexOf('g3erp:app') === 0) localStorage.removeItem(key)
|
||
}
|
||
})
|
||
await page.reload()
|
||
await page.waitForTimeout(400)
|
||
}
|
||
|
||
test.describe('ERP 双列菜单 - 头部结构', () => {
|
||
test('logo 在第一列(layout-mixed-rail)', async ({ page }) => {
|
||
await useMixedNavLayout(page)
|
||
await page.goto(`${ERP_URL}/ocean/booking`)
|
||
await page.waitForTimeout(400)
|
||
|
||
const rail = page.locator('.layout-mixed-rail')
|
||
await expect(rail).toBeVisible()
|
||
|
||
// 第一列顶部有 logo 方块
|
||
const mark = rail.locator('.layout-mixed-rail__logo-mark')
|
||
await expect(mark, '第一列应有 logo 方块').toBeVisible()
|
||
await expect(mark).toHaveText('G3')
|
||
|
||
// 有实际尺寸,不是被压成 0
|
||
const box = await mark.boundingBox()
|
||
expect(box, 'logo 方块应有实际尺寸').not.toBeNull()
|
||
expect(box!.width).toBeGreaterThan(10)
|
||
expect(box!.height).toBeGreaterThan(10)
|
||
|
||
// 第二列不应再出现 logo
|
||
await expect(page.locator('.layout-mixed-column__logo')).toHaveCount(0)
|
||
// 顶栏也不应出现 logo(双列布局下由第一列承载)
|
||
await expect(page.locator('.layout-header__logo')).toHaveCount(0)
|
||
})
|
||
|
||
test('标题行展示的是 logo 文字(不是分组名)', async ({ page }) => {
|
||
await useMixedNavLayout(page)
|
||
await page.goto(`${ERP_URL}/ocean/booking`)
|
||
await page.waitForTimeout(400)
|
||
|
||
const title = page.locator('.layout-mixed-column__title')
|
||
await expect(title, '第二列标题行应可见').toBeVisible()
|
||
|
||
// 应是 logo 文字(默认 G3Soft ERP),而不是当前分组名「海运」
|
||
const text = (await title.innerText()).trim()
|
||
expect(text, '标题行应是 logo 文字').not.toBe('海运')
|
||
expect(text.length, '标题行应有内容').toBeGreaterThan(0)
|
||
|
||
// 与单列侧栏/顶栏的 logo 文字取自同一偏好项
|
||
const logoText = await page.evaluate(() => {
|
||
const raw = localStorage.getItem('g3erp:preferences')
|
||
const pref = raw ? JSON.parse(raw) : {}
|
||
return pref.logo ? pref.logo.text : null
|
||
})
|
||
expect(logoText, '应能读到 logo.text 偏好').toBeTruthy()
|
||
expect(text, '标题行文本应等于 logo.text').toBe(logoText)
|
||
|
||
const box = await title.boundingBox()
|
||
expect(box).not.toBeNull()
|
||
expect(box!.height).toBeGreaterThan(20)
|
||
})
|
||
|
||
test('切换分组不影响标题行(它显示 logo 文字,与分组无关)', async ({ page }) => {
|
||
await useMixedNavLayout(page)
|
||
await page.goto(`${ERP_URL}/ocean/booking`)
|
||
await page.waitForTimeout(400)
|
||
|
||
const before = (await page.locator('.layout-mixed-column__title').innerText()).trim()
|
||
|
||
await page.locator('.layout-mixed-rail__item', { hasText: '财务' }).click()
|
||
await page.waitForTimeout(500)
|
||
|
||
const after = (await page.locator('.layout-mixed-column__title').innerText()).trim()
|
||
expect(after, '标题行是 logo 文字,切分组不应变化').toBe(before)
|
||
|
||
// 但列表内容确实换成了财务的子项
|
||
const columnText = await page.locator('.layout-mixed-column').innerText()
|
||
expect(columnText, '第二列列表应切换为财务子项').toContain('应收费用')
|
||
})
|
||
|
||
test('第一列背景为白色', async ({ page }) => {
|
||
await useMixedNavLayout(page)
|
||
await page.goto(`${ERP_URL}/ocean/booking`)
|
||
await page.waitForTimeout(400)
|
||
|
||
const rail = page.locator('.layout-mixed-rail')
|
||
const bg = await rail.evaluate((el) => getComputedStyle(el).backgroundColor)
|
||
expect(bg, `图标栏背景应为白色,实际 ${bg}`).toMatch(/^rgba?\(255,\s*255,\s*255(,\s*1)?\)$/)
|
||
})
|
||
})
|