u
This commit is contained in:
1 parent
78eb811ff7
commit
97fe2ff306
83 files changed
+10083
-3662
No files matched your search
@@ -0,0 +1,162 @@
|
||||
import { expect, test } from '@playwright/test'
|
||||
|
||||
/**
|
||||
* G3Table 的几何 / 命中类断言 —— happy-dom 没有布局引擎,这些只能在真浏览器里量。
|
||||
*
|
||||
* 用例只按 data-testid 找元素(不依赖文案与结构),宿主页在 playground/main.ts。
|
||||
*/
|
||||
|
||||
test.describe('G3Table 表格', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await page.locator('[data-testid="table"]').scrollIntoViewIfNeeded()
|
||||
})
|
||||
|
||||
test('基础渲染:表头与数据行都在,且序号列存在', async ({ page }) => {
|
||||
const table = page.locator('[data-testid="table-wrap"]')
|
||||
await expect(table.locator('.stk-table')).toBeVisible()
|
||||
// 表头至少有我们的业务列文案
|
||||
await expect(table.locator('th', { hasText: '名称' })).toBeVisible()
|
||||
await expect(table.locator('th', { hasText: '金额' })).toBeVisible()
|
||||
// 数据行渲染出来了
|
||||
const rows = table.locator('.stk-tbody-main tr')
|
||||
await expect(rows).toHaveCount(3)
|
||||
})
|
||||
|
||||
test('小数据量(3 行):纵向虚拟滚动关闭,DOM 里是真实 3 行', async ({ page }) => {
|
||||
const table = page.locator('[data-testid="table-wrap"]')
|
||||
// 库开启虚拟滚动时会给根加 .virtual 类;门控生效时不应有
|
||||
await expect(table.locator('.stk-table')).not.toHaveClass(/virtual/)
|
||||
})
|
||||
|
||||
test('大数据量(5000 行):纵向虚拟滚动开启,DOM 行数远少于数据量', async ({ page }) => {
|
||||
const big = page.locator('[data-testid="table-big-wrap"]')
|
||||
await big.scrollIntoViewIfNeeded()
|
||||
await expect(big.locator('.stk-table')).toHaveClass(/virtual/)
|
||||
|
||||
// 虚拟滚动的意义:只渲染视口内若干行,DOM 行数应当是个位数/几十,而不是 5000
|
||||
const rendered = await big.locator('.stk-tbody-main tr').count()
|
||||
expect(rendered).toBeGreaterThan(0)
|
||||
expect(rendered).toBeLessThan(200)
|
||||
})
|
||||
|
||||
test('大数据量:滚动后仍只渲染视口内行(虚拟窗口跟随)', async ({ page }) => {
|
||||
const big = page.locator('[data-testid="table-big-wrap"]')
|
||||
await big.scrollIntoViewIfNeeded()
|
||||
|
||||
const scroller = big.locator('.stk-table-scroll-container, .stk-table-main').first()
|
||||
await scroller.evaluate((el) => {
|
||||
el.scrollTop = 3000
|
||||
})
|
||||
await page.waitForTimeout(150)
|
||||
|
||||
const rendered = await big.locator('.stk-tbody-main tr').count()
|
||||
expect(rendered).toBeGreaterThan(0)
|
||||
expect(rendered).toBeLessThan(200)
|
||||
})
|
||||
|
||||
test('高度约束:容器限高时表格不溢出', async ({ page }) => {
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
const wrapBox = await wrap.boundingBox()
|
||||
const inner = wrap.locator('.stk-table').first()
|
||||
const innerBox = await inner.boundingBox()
|
||||
expect(wrapBox).not.toBeNull()
|
||||
expect(innerBox).not.toBeNull()
|
||||
// 表格不应高于它的容器(留 2px 容差:边框/亚像素)
|
||||
expect(innerBox!.height).toBeLessThanOrEqual(wrapBox!.height + 2)
|
||||
})
|
||||
|
||||
test('外框圆角:bordered 时容器有圆角与描边', async ({ page }) => {
|
||||
// 注意:data-testid 透传给了内层 StkTable(组件 inheritAttrs: false),
|
||||
// 外框与圆角在我们自己的根节点 .g3-table 上,所以要按类名定位。
|
||||
const root = page.locator('[data-testid="table-wrap"] .g3-table').first()
|
||||
await expect(root).toHaveClass(/is-bordered/)
|
||||
const radius = await root.evaluate((el) => getComputedStyle(el).borderRadius)
|
||||
expect(radius).not.toBe('0px')
|
||||
const borderWidth = await root.evaluate((el) => getComputedStyle(el).borderTopWidth)
|
||||
expect(borderWidth).toBe('1px')
|
||||
})
|
||||
|
||||
test('表头显示序号列(seq 默认开启)', async ({ page }) => {
|
||||
const table = page.locator('[data-testid="table-wrap"]')
|
||||
await expect(table.locator('th', { hasText: '序号' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('窄容器下不横向溢出容器宽度', async ({ page }) => {
|
||||
const wrap = page.locator('[data-testid="table-narrow-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
const wrapBox = await wrap.boundingBox()
|
||||
const rootBox = await wrap.locator('[data-testid="table-narrow"]').boundingBox()
|
||||
expect(rootBox!.width).toBeLessThanOrEqual(wrapBox!.width + 2)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('G3Table 选择列(真浏览器命中)', () => {
|
||||
test('点击行复选框:勾选态可见地变化', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
|
||||
const firstRowCheckbox = wrap.locator('.g3-table__checkbox').first()
|
||||
await firstRowCheckbox.scrollIntoViewIfNeeded()
|
||||
await expect(firstRowCheckbox).not.toHaveClass(/is-checked/)
|
||||
|
||||
await firstRowCheckbox.click()
|
||||
await expect(firstRowCheckbox).toHaveClass(/is-checked/)
|
||||
})
|
||||
|
||||
test('每行复选框数 = 选择列 + checkbox 编辑器列(演示数据定义了两列)', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
|
||||
// 演示数据的 tableColumns 里有两个复选框列:选择列(注入)+ 启用列(editor: checkbox)。
|
||||
// 所以每行 2 个是预期值——这正是为什么不能靠「数复选框个数」判断是否有重复渲染。
|
||||
const bodyRows = wrap.locator('.stk-tbody-main tr')
|
||||
await expect(bodyRows).toHaveCount(3)
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
await expect(bodyRows.nth(i).locator('.g3-table__checkbox')).toHaveCount(2)
|
||||
}
|
||||
})
|
||||
|
||||
test('无重复渲染:每行 td 数等于表头列数', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
|
||||
// 单元格数必须与表头列数一致;固定列若被双份渲染,这里会多出来。
|
||||
const headerCount = await wrap.locator('thead th').count()
|
||||
const firstRowTd = await wrap.locator('.stk-tbody-main tr').first().locator('td').count()
|
||||
expect(firstRowTd).toBe(headerCount)
|
||||
})
|
||||
|
||||
test('表头全选:点击后表头与所有数据行的选择列都被勾选', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
|
||||
const headerCheckbox = wrap.locator('th .g3-table__checkbox').first()
|
||||
await headerCheckbox.scrollIntoViewIfNeeded()
|
||||
await headerCheckbox.click()
|
||||
|
||||
// 表头 choice 项 + 3 行选择列 = 4 个处于勾选态的选择框
|
||||
// (「启用」列的 checkbox 是数据值,初始为 1 的那两行也会是勾选态,
|
||||
// 所以这里按选择列的固定类名限定范围)
|
||||
await expect(wrap.locator('th .g3-table__checkbox.is-checked')).toHaveCount(1)
|
||||
await expect(wrap.locator('.stk-tbody-main td:first-child .g3-table__checkbox.is-checked')).toHaveCount(3)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('G3Table RTL 镜像', () => {
|
||||
test('RTL 下固定列与表格布局不塌陷', async ({ page }) => {
|
||||
await page.goto('/?dir=rtl')
|
||||
const wrap = page.locator('[data-testid="table-wrap"]')
|
||||
await wrap.scrollIntoViewIfNeeded()
|
||||
|
||||
const wrapBox = await wrap.boundingBox()
|
||||
const tableBox = await wrap.locator('.stk-table').first().boundingBox()
|
||||
expect(tableBox).not.toBeNull()
|
||||
// 表格仍应占据容器的整宽(镜像不该把宽度算丢)
|
||||
expect(tableBox!.width).toBeGreaterThan(wrapBox!.width * 0.9)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user