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

172 lines
6.5 KiB
TypeScript
Raw 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'
/**
* 数据展示类组件的交互回归。
*
* 注意:用 page.mouse.* 之前必须先 scrollIntoViewIfNeeded ——
* mouse 事件按视口坐标派发,元素在视口外时事件会落到别的元素上
* (表现为「拖拽/点击完全没反应」,很容易被误判成组件 bug)。
*/
test.describe('Tabs', () => {
test('面板懒渲染,切换后保留旧面板(表单状态不丢)', async ({ page }) => {
await page.goto('/')
const tabs = page.getByTestId('tabs')
await expect(tabs.locator('.g3-tabs__pane')).toHaveCount(1)
await tabs.locator('.g3-tabs__tab').nth(1).click()
await expect(tabs.locator('.g3-tabs__pane')).toHaveCount(2)
await expect(tabs.locator('.g3-tabs__pane').first()).toBeHidden()
})
test('禁用标签不可点击(回归:空值布尔属性被 Boolean("") 判成 false)', async ({ page }) => {
await page.goto('/')
const tabs = page.getByTestId('tabs')
const disabled = tabs.locator('.g3-tabs__tab').nth(2)
await expect(disabled).toBeDisabled()
await expect(disabled).toHaveAttribute('aria-disabled', 'true')
await expect(tabs.locator('.g3-tabs__pane')).toHaveCount(1)
})
})
test.describe('Tree', () => {
test('勾选父节点后子节点全选(父子联动)', async ({ page }) => {
await page.goto('/')
const tree = page.getByTestId('tree')
const checkboxes = tree.locator('.g3-tree-node__checkbox .g3-checkbox')
await expect(checkboxes).toHaveCount(6)
await checkboxes.first().click()
const checkedCount = await tree.locator('.g3-tree-node__checkbox .g3-checkbox.is-checked').count()
// 「前端」及其 3 个子孙(Vue / 组合式 API / React)
expect(checkedCount).toBe(4)
})
test('收起父节点后其子孙不再渲染(后端仍展开,所以剩下 3 个)', async ({ page }) => {
await page.goto('/')
const tree = page.getByTestId('tree')
await expect(tree.locator('.g3-tree-node')).toHaveCount(6)
await tree.locator('.g3-tree-node__switcher').first().click()
await expect(tree.locator('.g3-tree-node')).toHaveCount(3)
})
})
test.describe('Pagination', () => {
test('省略号点击跳 5 页', async ({ page }) => {
await page.goto('/')
const pagination = page.getByTestId('pagination')
await expect(pagination.locator('[aria-current="page"]')).toHaveText('1')
await pagination.locator('.g3-pagination__ellipsis').click()
await expect(pagination.locator('[aria-current="page"]')).toHaveText('6')
})
test('显示总数与跳页控件', async ({ page }) => {
await page.goto('/')
const pagination = page.getByTestId('pagination')
await expect(pagination.locator('.g3-pagination__total')).toContainText('126')
await expect(pagination.locator('.g3-pagination__jumper')).toBeVisible()
})
})
test.describe('Splitter', () => {
test('拖拽分隔条同时改变分隔条位置与两侧尺寸', async ({ page }) => {
await page.goto('/')
const splitter = page.getByTestId('splitter')
await splitter.scrollIntoViewIfNeeded()
const panels = splitter.locator('.g3-splitter-panel')
const bar = splitter.locator('.g3-splitter__bar')
// 探针:区分「pointerdown 没落到分隔条上」与「落上了但逻辑没生效」
await page.evaluate(() => {
;(window as unknown as { __barDown: number }).__barDown = 0
document.querySelector('.g3-splitter__bar')?.addEventListener('pointerdown', () => {
;(window as unknown as { __barDown: number }).__barDown += 1
})
})
const before = (await panels.first().boundingBox())!.width
const box = (await bar.boundingBox())!
const centerX = box.x + box.width / 2
const centerY = box.y + box.height / 2
await page.mouse.move(centerX, centerY)
await page.mouse.down()
await page.mouse.move(centerX + 40, centerY, { steps: 3 })
await page.mouse.move(centerX + 80, centerY, { steps: 3 })
await page.mouse.up()
await page.waitForTimeout(150)
const barDown = await page.evaluate(() => (window as unknown as { __barDown: number }).__barDown)
expect(barDown).toBe(1)
expect((await panels.first().boundingBox())!.width).toBeGreaterThan(before + 20)
})
test('分隔条可键盘调整(方向键 ±10px)', async ({ page }) => {
await page.goto('/')
const splitter = page.getByTestId('splitter')
await splitter.scrollIntoViewIfNeeded()
const panels = splitter.locator('.g3-splitter-panel')
const before = (await panels.first().boundingBox())!.width
await splitter.locator('.g3-splitter__bar').focus()
await page.keyboard.press('ArrowRight')
await page.keyboard.press('ArrowRight')
expect((await panels.first().boundingBox())!.width).toBeGreaterThan(before + 10)
})
})
test.describe('Scrollbar', () => {
test('点击轨道跳转滚动(clickScroll 默认开启)', async ({ page }) => {
await page.goto('/')
const scrollbar = page.getByTestId('scrollbar')
await scrollbar.scrollIntoViewIfNeeded()
const view = scrollbar.locator('.g3-scrollbar__view')
expect(await view.evaluate((el) => el.scrollTop)).toBe(0)
const track = (await scrollbar.locator('.g3-scrollbar__track-v').boundingBox())!
await page.mouse.click(track.x + track.width / 2, track.y + track.height * 0.7)
await page.waitForTimeout(100)
expect(await view.evaluate((el) => el.scrollTop)).toBeGreaterThan(0)
})
test('拖动滑块同步滚动位置', async ({ page }) => {
await page.goto('/')
const scrollbar = page.getByTestId('scrollbar')
await scrollbar.scrollIntoViewIfNeeded()
const view = scrollbar.locator('.g3-scrollbar__view')
const box = (await scrollbar.locator('.g3-scrollbar__thumb-v').boundingBox())!
const centerX = box.x + box.width / 2
const centerY = box.y + box.height / 2
await page.mouse.move(centerX, centerY)
await page.mouse.down()
await page.mouse.move(centerX, centerY + 60, { steps: 5 })
await page.mouse.up()
await page.waitForTimeout(100)
expect(await view.evaluate((el) => el.scrollTop)).toBeGreaterThan(0)
})
})
test.describe('Segmented', () => {
test('点击选项切换选中态(滑块跟随)', async ({ page }) => {
await page.goto('/')
const segmented = page.getByTestId('segmented')
await expect(segmented.locator('.g3-segmented__item.is-selected')).toHaveText('日')
await segmented.locator('.g3-segmented__item').filter({ hasText: '周' }).click()
await expect(segmented.locator('.g3-segmented__item.is-selected')).toHaveText('周')
})
})