This commit is contained in:
oneao committed 2026-10-08 22:38:34 +08:00
1 parent f572dce2f6
commit e99a9fb274
356 files changed
+28877 -1055

No files matched your search

@@ -0,0 +1,171 @@
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('周')
})
})