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

114 lines
4.5 KiB
TypeScript

import { expect, test } from '@playwright/test'
/**
* 表单类组件的真实布局回归。
*
* 曾经踩过的坑:
* - textarea 的 footer(计数 + 拖拽手柄)在文档流里,被挤到框外;
* - 日期时间面板上下排列而不是「左日期 / 右时间」;
* - 日期面板宽度跟随输入框被拉伸,日历格子间距被撑散;
* - 非法日期(2026-02-30)被原生解析静默顺延成 3 月 2 日。
*/
test.describe('Input / textarea', () => {
test('拖拽手柄落在输入框内部右下角(不再被挤到框外)', async ({ page }) => {
await page.goto('/')
const root = page.locator('[data-testid="textarea-count"]')
const box = (await root.boundingBox())!
const handle = (await root.locator('.g3-input__resize-handle').boundingBox())!
expect(handle.x + handle.width).toBeLessThanOrEqual(box.x + box.width + 1)
expect(handle.y + handle.height).toBeLessThanOrEqual(box.y + box.height + 1)
expect(handle.y).toBeGreaterThan(box.y + box.height / 2)
})
test('字数统计与手柄同处一行,且有可访问语义', async ({ page }) => {
await page.goto('/')
const root = page.locator('[data-testid="textarea-count"]')
await expect(root.locator('.g3-input__count')).toHaveText(/\d+ \/ 100/)
await expect(root.locator('.g3-input__resize-handle')).toHaveAttribute('role', 'slider')
await expect(root.locator('.g3-input__resize-handle')).toHaveAttribute('aria-orientation', 'vertical')
})
test('number 输入实时净化,只保留一个小数点', async ({ page }) => {
await page.goto('/')
const input = page.locator('[data-testid="input-number"] input')
await input.fill('12.3.4')
await expect(input).toHaveValue('12.34')
})
test('password 可切换明文', async ({ page }) => {
await page.goto('/')
const root = page.locator('[data-testid="input-password"]')
await expect(root.locator('input')).toHaveAttribute('type', 'password')
await root.locator('.g3-input__password-toggle').click()
await expect(root.locator('input')).toHaveAttribute('type', 'text')
})
})
test.describe('DatePicker', () => {
test('日期时间面板呈「左日历 / 右时间」,且日历定宽不被拉伸', async ({ page }) => {
await page.goto('/')
const trigger = page.locator('[data-testid="date-picker"] .g3-date-picker__trigger')
const triggerWidth = (await trigger.boundingBox())!.width
await trigger.click()
const panel = page.locator('.g3-date-picker__panel')
await expect(panel).toBeVisible()
const calendar = panel.locator('.g3-calendar__main')
const time = panel.locator('.g3-calendar__time')
await expect(calendar).toBeVisible()
await expect(time).toBeVisible()
const calendarBox = (await calendar.boundingBox())!
const timeBox = (await time.boundingBox())!
// 日历在左、时间列在右,同一行(纵向重叠)
expect(timeBox.x).toBeGreaterThan(calendarBox.x + calendarBox.width - 1)
expect(timeBox.y).toBeLessThan(calendarBox.y + calendarBox.height)
// 日历定宽,面板不跟随输入框拉宽
expect(calendarBox.width).toBeLessThan(260)
const panelBox = (await panel.boundingBox())!
expect(panelBox.width).toBeLessThan(triggerWidth)
})
test('面板内的确定按钮只有点选后才能用', async ({ page }) => {
await page.goto('/')
await page.locator('[data-testid="date-picker"] .g3-date-picker__trigger').click()
const confirm = page.locator('.g3-calendar__footer button')
await expect(confirm).toBeEnabled()
})
test('非法日期不会被接受(不再静默顺延)', async ({ page }) => {
await page.goto('/')
const input = page.locator('[data-testid="date-picker"] .g3-date-picker__input')
await input.click()
await input.fill('2026-02-30')
await input.press('Enter')
// 回退到原值,不能变成 2026-03-02
await expect(input).not.toHaveValue('2026-03-02')
await expect(page.locator('[data-testid="date-picker"]')).toHaveClass(/is-invalid/)
})
})
test.describe('RangePicker', () => {
test('区间面板打开且两端都有值', async ({ page }) => {
await page.goto('/')
const root = page.locator('[data-testid="range-picker"]')
await expect(root.locator('input').first()).toHaveValue('2026-10-01')
await expect(root.locator('input').nth(1)).toHaveValue('2026-10-08')
await root.locator('.g3-range-picker__trigger').click()
await expect(page.locator('.g3-range-picker__panel')).toBeVisible()
})
})