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('周') }) })