132 lines
5.3 KiB
TypeScript
132 lines
5.3 KiB
TypeScript
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)
|
||
})
|
||
})
|