Files
2026-10-08 22:38:34 +08:00

132 lines
5.3 KiB
TypeScript
Raw Permalink 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'
/**
* Drawer 四个方向的几何回归。
*
* 漏测教训:之前只验了默认的 `right`,导致「上下方向的抽屉宽度不是 100%」一直没被发现。
* 根因是容器用 flex 的 justify-content / align-items 做吸附 —— 两条轴各管一个方向,
* 上下面板在主轴(水平)方向没有约束,宽度缩到了内容宽。
* 现在改为按方向定边(上下 `left/right: 0`、左右 `top/bottom: 0`),与 fms 一致。
*
* 断言以 `.g3-drawer__wrap`(定位容器)为参照,而不是写死视口尺寸:
* 视口高度受 `devices['Desktop Chrome']` 与滚动条影响,写死会得到假失败。
* 这类断言必须放 E2E:真实布局结果在 happy-dom 里量不出来。
*/
/** 打开指定方向的抽屉,返回面板与定位容器的几何 */
async function openDrawer(page: import('@playwright/test').Page, testId: string) {
await page.getByTestId(testId).click()
const drawer = page.locator('.g3-drawer')
await expect(drawer).toBeVisible()
// 等入场动画结束(transform 归零),否则量到的是滑入途中的位置
await page.waitForTimeout(450)
const panel = (await drawer.boundingBox())!
const wrap = (await page.locator('.g3-drawer__wrap').boundingBox())!
return { drawer, panel, wrap }
}
test.describe('Drawer 方向与尺寸', () => {
test('右侧:贴右边缘、纵向撑满,宽度取 width', async ({ page }) => {
await page.goto('/')
const { panel, wrap } = await openDrawer(page, 'open-drawer')
expect(Math.round(panel.x + panel.width)).toBeCloseTo(Math.round(wrap.x + wrap.width), 0)
expect(Math.round(panel.height)).toBeCloseTo(Math.round(wrap.height), 0)
expect(Math.round(panel.width)).toBe(378)
})
test('左侧:贴左边缘、纵向撑满', async ({ page }) => {
await page.goto('/')
const { panel, wrap } = await openDrawer(page, 'open-drawer-left')
expect(Math.round(panel.x)).toBeCloseTo(Math.round(wrap.x), 0)
expect(Math.round(panel.height)).toBeCloseTo(Math.round(wrap.height), 0)
expect(Math.round(panel.width)).toBe(378)
})
test('上方:贴顶、横向撑满(回归:宽度曾是内容宽)', async ({ page }) => {
await page.goto('/')
const { panel, wrap } = await openDrawer(page, 'open-drawer-top')
expect(Math.round(panel.y)).toBeCloseTo(Math.round(wrap.y), 0)
expect(Math.round(panel.width)).toBeCloseTo(Math.round(wrap.width), 0)
expect(Math.round(panel.height)).toBe(378)
})
test('下方:贴底、横向撑满(回归:宽度曾是内容宽)', async ({ page }) => {
await page.goto('/')
const { panel, wrap } = await openDrawer(page, 'open-drawer-bottom')
expect(Math.round(panel.y + panel.height)).toBeCloseTo(Math.round(wrap.y + wrap.height), 0)
expect(Math.round(panel.width)).toBeCloseTo(Math.round(wrap.width), 0)
expect(Math.round(panel.height)).toBe(378)
})
test('四个方向都能撑满对应轴,且面板不被自身遮罩压住', async ({ page }) => {
await page.goto('/')
for (const [testId, name, axis] of [
['open-drawer', '右', 'height'],
['open-drawer-left', '左', 'height'],
['open-drawer-top', '上', 'width'],
['open-drawer-bottom', '下', 'width'],
] as const) {
const { drawer, panel, wrap } = await openDrawer(page, testId)
if (axis === 'height') {
expect(Math.round(panel.height), `${name}侧抽屉未撑满高度`).toBeCloseTo(
Math.round(wrap.height),
0,
)
} else {
expect(Math.round(panel.width), `${name}侧抽屉未撑满宽度`).toBeCloseTo(
Math.round(wrap.width),
0,
)
}
const hit = await page.evaluate(
([x, y]) => {
const el = document.elementFromPoint(x as number, y as number)
return el ? String(el.className || el.tagName) : null
},
[panel.x + panel.width / 2, panel.y + Math.min(20, panel.height / 2)],
)
expect(hit, `${name}侧抽屉面板被遮挡`).toContain('g3-drawer')
await page.keyboard.press('Escape')
await expect(drawer).toBeHidden()
}
})
test('面板尺寸由组件自己决定,不受宿主页面全局样式污染', async ({ page }) => {
await page.goto('/')
// 模拟用户页面的「全局元素选择器」:面板本体是 <section>,header / footer 同理
await page.addStyleTag({
content: `
section { margin: 16px; padding: 24px; border: 2px solid red; }
header { margin: 12px; padding: 20px; }
footer { margin: 12px; padding: 20px; }
`,
})
const { panel, wrap } = await openDrawer(page, 'open-drawer')
const styles = await page.$eval('.g3-drawer', (el) => {
const cs = getComputedStyle(el)
return {
margin: [cs.marginTop, cs.marginRight, cs.marginBottom, cs.marginLeft],
padding: [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft],
borderWidth: cs.borderTopWidth,
}
})
expect(styles.margin).toEqual(['0px', '0px', '0px', '0px'])
expect(styles.padding).toEqual(['0px', '0px', '0px', '0px'])
expect(styles.borderWidth).toBe('0px')
// 仍然撑满:宿主 margin 不该从高度里扣掉 16px
expect(Math.round(panel.height)).toBeCloseTo(Math.round(wrap.height), 0)
})
})