Files
workspace/code/g3soft-libs/packages/ui/e2e/erp-mixed-nav-fixes.spec.ts
T
2026-10-10 17:33:59 +08:00

136 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)?\)$/)
})
})