Files
lexgo/learner/e2e/overlay.ts
T
ila c22f9c3f06 fix: 导入 Element Plus 对话框与确认框样式,弹窗不再是文档流块 (#37)
- main.ts 补上 dialog 与 message-box 的样式导入:自 #10 起 ElDialog/ElMessageBox 一直
  缺少样式,退化成列表后面的普通块(用户报告「编辑区显示在章节列表下面」)
- 新增 e2e/overlay.ts:expectModalOverlay / expectMessageBoxOverlay 断言弹窗位于
  .el-overlay(position: fixed)、在视口内且横向不溢出
- attachments.spec.ts(章节编辑对话框、插图弹窗)与 edit.spec.ts(书名对话框、删除确认)
  都改用该断言,堵住「只看可见性、不看是否浮层」的验证盲区
- 真实链路确认:对话框遮罩为 rgba(0,0,0,0.5)、居中于视口;确认框同样为固定浮层
- 文档:Local-Development 记录缺陷、根因、修复与新增回归断言
2026-09-15 22:22:50 +08:00

43 lines
2.1 KiB
TypeScript

import { expect, type Locator, type Page } from '@playwright/test'
/**
* Asserts that a dialog is a modal overlay rather than a block in the document flow.
*
* A missing Element Plus stylesheet is invisible to `toBeVisible()` and to the unit tests, but it
* turns every dialog into content appended after the list it was opened from — which is exactly how
* a reader reported it. These checks need a real browser with the real stylesheets.
*/
export async function expectModalOverlay(page: Page, dialog: Locator): Promise<void> {
await expect(dialog).toBeVisible()
const layout = await dialog.evaluate(element => {
const box = element.getBoundingClientRect()
const overlay = element.closest('.el-overlay')
return {
overlay: overlay ? getComputedStyle(overlay).position : 'none',
position: getComputedStyle(element).position,
top: Math.round(box.top),
left: Math.round(box.left),
width: Math.round(box.width),
viewportHeight: window.innerHeight,
viewportWidth: window.innerWidth,
}
})
expect(layout.overlay, 'the dialog must render inside a fixed overlay').toBe('fixed')
expect(layout.position, 'the dialog itself is positioned by the overlay').not.toBe('static')
// It is laid out over the viewport, not below the page content that opened it.
expect(layout.top, 'the dialog must start inside the viewport').toBeGreaterThanOrEqual(0)
expect(layout.top, 'the dialog must not be pushed below the viewport').toBeLessThan(layout.viewportHeight)
expect(layout.viewportWidth - (layout.left + layout.width), 'the dialog must fit horizontally').toBeGreaterThanOrEqual(-2)
}
/** Asserts that a message box is a modal overlay as well. */
export async function expectMessageBoxOverlay(page: Page): Promise<void> {
const box = page.locator('.el-message-box')
await expect(box).toBeVisible()
const overlay = await box.evaluate(element => {
const wrapper = element.closest('.el-overlay')
return wrapper ? getComputedStyle(wrapper).position : 'none'
})
expect(overlay, 'the confirmation must render inside a fixed overlay').toBe('fixed')
}