Files
workspace/code/g3soft-libs/packages/ui/e2e/feedback.spec.ts
T
2026-10-08 22:38:34 +08:00

139 lines
4.9 KiB
TypeScript

import { expect, test } from '@playwright/test'
/**
* 反馈类组件回归。
*
* 曾经踩过的坑:
* - Message 的方位类名手写成 `g3-message-list--*`(样式表是 `g3-message__list--*`),
* 9 个方位全部失效、消息一律堆在左上角;
* - Modal 面板不是弹性布局,缩放后内容溢出面板而不是内部滚动。
*/
test.describe('Message 方位', () => {
test('默认方位是顶部居中', async ({ page }) => {
await page.goto('/')
await page.getByTestId('toast-default').click()
const message = page.locator('.g3-message').first()
await expect(message).toBeVisible()
const messageBox = (await message.boundingBox())!
const viewport = page.viewportSize()!
const center = messageBox.x + messageBox.width / 2
expect(Math.abs(center - viewport.width / 2)).toBeLessThan(2)
expect(messageBox.y).toBeLessThan(viewport.height * 0.25)
})
test('指定方位生效:左上 / 右下', async ({ page }) => {
await page.goto('/')
const viewport = page.viewportSize()!
await page.getByTestId('toast-top-left').click()
const topLeft = (await page.locator('.g3-message').first().boundingBox())!
expect(topLeft.x).toBeLessThan(48)
expect(topLeft.y).toBeLessThan(viewport.height * 0.25)
await page.waitForTimeout(3200)
await page.getByTestId('toast-bottom-right').click()
const bottomRight = (await page.locator('.g3-message').first().boundingBox())!
expect(bottomRight.x + bottomRight.width).toBeGreaterThan(viewport.width - 48)
expect(bottomRight.y).toBeGreaterThan(viewport.height * 0.6)
})
})
test.describe('Notification', () => {
test('默认出现在右上角', async ({ page }) => {
await page.goto('/')
const viewport = page.viewportSize()!
await page.getByTestId('notify').click()
const notification = page.locator('.g3-notification').first()
await expect(notification).toBeVisible()
const box = (await notification.boundingBox())!
expect(box.x + box.width).toBeGreaterThan(viewport.width - 48)
expect(box.y).toBeLessThan(viewport.height * 0.3)
})
})
test.describe('Modal', () => {
test('缩放变矮后内容区内部滚动,而不是溢出面板', async ({ page }) => {
await page.goto('/')
await page.getByTestId('open-modal').click()
const modal = page.locator('.g3-modal')
await expect(modal).toBeVisible()
// 把南侧手柄往上拖,压缩面板高度
const handle = (await page.locator('.g3-modal__resizer-s').boundingBox())!
const startX = handle.x + handle.width / 2
await page.mouse.move(startX, handle.y + handle.height / 2)
await page.mouse.down()
await page.mouse.move(startX, handle.y - 400, { steps: 8 })
await page.mouse.up()
const panel = (await modal.boundingBox())!
const body = await page.evaluate(() => {
const el = document.querySelector('.g3-modal__body') as HTMLElement
return { client: el.clientHeight, scroll: el.scrollHeight }
})
// 面板被压矮,内容比可视区高 → 必须内部滚动
expect(panel.height).toBeLessThan(700)
expect(body.scroll).toBeGreaterThan(body.client)
})
test('Esc 关闭,遮罩点击可关闭', async ({ page }) => {
await page.goto('/')
await page.getByTestId('open-modal').click()
await expect(page.locator('.g3-modal')).toBeVisible()
await page.keyboard.press('Escape')
await expect(page.locator('.g3-modal')).toBeHidden()
await page.getByTestId('open-modal').click()
await page.mouse.click(60, 400)
await expect(page.locator('.g3-modal')).toBeHidden()
})
test('焦点被限制在面板内(Tab 循环)', async ({ page }) => {
await page.goto('/')
await page.getByTestId('open-modal').click()
await expect(page.locator('.g3-modal')).toBeVisible()
for (let index = 0; index < 8; index += 1) {
await page.keyboard.press('Tab')
}
const inside = await page.evaluate(() => {
const panel = document.querySelector('.g3-modal')
return panel ? panel.contains(document.activeElement) : false
})
expect(inside).toBe(true)
})
})
test.describe('Modal.confirm(命令式)', () => {
test('点确定后按钮进入 loading,完成后自动关闭', async ({ page }) => {
await page.goto('/')
await page.getByTestId('open-confirm').click()
const modal = page.locator('.g3-modal')
await expect(modal).toBeVisible()
await expect(modal.locator('.g3-modal__title')).toHaveText('删除确认')
const confirmButton = modal.locator('.g3-modal__footer button').last()
await expect(confirmButton).toHaveText('确定')
await confirmButton.click()
// loading 期间按钮禁用且带 aria-busy
await expect(confirmButton).toBeDisabled()
await expect(confirmButton).toHaveAttribute('aria-busy', 'true')
// onConfirm 的 Promise resolve 后自动关闭
await expect(modal).toBeHidden({ timeout: 5000 })
})
})