diff --git a/test/browser/TextEditor.test.tsx b/test/browser/TextEditor.test.tsx
index a18f40e461..2afa699dc0 100644
--- a/test/browser/TextEditor.test.tsx
+++ b/test/browser/TextEditor.test.tsx
@@ -3,7 +3,6 @@ import { page, userEvent } from '@vitest/browser/context';
import { DataGrid, textEditor } from '../../src';
import type { Column } from '../../src';
-import { getCells } from './utils';
interface Row {
readonly name: string;
@@ -29,27 +28,27 @@ function Test() {
test('TextEditor', async () => {
page.render();
-
- await userEvent.dblClick(getCells()[0]);
- let input = page.getByRole('textbox').element() as HTMLInputElement;
- expect(input).toHaveClass('rdg-text-editor');
+ const cell = page.getByRole('gridcell');
+ await expect.element(cell).toHaveTextContent(/^Tacitus Kilgore$/);
+ await userEvent.dblClick(cell);
+ const input = page.getByRole('textbox');
+ await expect.element(input).toHaveClass('rdg-text-editor');
// input value is row[column.key]
- expect(input).toHaveValue(initialRows[0].name);
+ await expect.element(input).toHaveValue(initialRows[0].name);
// input is focused
- expect(input).toHaveFocus();
+ await expect.element(input).toHaveFocus();
// input value is fully selected
- expect(input).toHaveSelection(initialRows[0].name);
+ await expect.element(input).toHaveSelection(initialRows[0].name);
// pressing escape closes the editor without committing
await userEvent.keyboard('Test{escape}');
- expect(input).not.toBeInTheDocument();
- await expect.element(getCells()[0]).toHaveTextContent(/^Tacitus Kilgore$/);
+ await expect.element(input).not.toBeInTheDocument();
+ await expect.element(cell).toHaveTextContent(/^Tacitus Kilgore$/);
// blurring the input closes and commits the editor
- await userEvent.dblClick(getCells()[0]);
- input = page.getByRole('textbox').element() as HTMLInputElement;
+ await userEvent.dblClick(cell);
await userEvent.fill(input, 'Jim Milton');
await userEvent.tab();
- expect(input).not.toBeInTheDocument();
- await expect.element(getCells()[0]).toHaveTextContent(/^Jim Milton$/);
+ await expect.element(input).not.toBeInTheDocument();
+ await expect.element(cell).toHaveTextContent(/^Jim Milton$/);
});
diff --git a/test/browser/column/cellClass.test.ts b/test/browser/column/cellClass.test.ts
index 8d6f4c7afe..d86d3c98ca 100644
--- a/test/browser/column/cellClass.test.ts
+++ b/test/browser/column/cellClass.test.ts
@@ -1,6 +1,6 @@
import type { Column } from '../../../src';
import { cellClassname } from '../../../src/style/cell';
-import { getCells, setup } from '../utils';
+import { getCellsNew, setup } from '../utils';
interface Row {
id: number;
@@ -8,7 +8,7 @@ interface Row {
const rows: readonly Row[] = [{ id: 0 }, { id: 1 }];
-test('cellClass is undefined', () => {
+test('cellClass is undefined', async () => {
const columns: readonly Column[] = [
{
key: 'id',
@@ -16,12 +16,12 @@ test('cellClass is undefined', () => {
}
];
setup({ columns, rows });
- const [cell1, cell2] = getCells();
- expect(cell1).toHaveClass(cellClassname, { exact: true });
- expect(cell2).toHaveClass(cellClassname, { exact: true });
+ const [cell1, cell2] = getCellsNew('0', '1');
+ await expect.element(cell1).toHaveClass(cellClassname, { exact: true });
+ await expect.element(cell2).toHaveClass(cellClassname, { exact: true });
});
-test('cellClass is a string', () => {
+test('cellClass is a string', async () => {
const columns: readonly Column[] = [
{
key: 'id',
@@ -30,12 +30,12 @@ test('cellClass is a string', () => {
}
];
setup({ columns, rows });
- const [cell1, cell2] = getCells();
- expect(cell1).toHaveClass(`${cellClassname} my-cell`, { exact: true });
- expect(cell2).toHaveClass(`${cellClassname} my-cell`, { exact: true });
+ const [cell1, cell2] = getCellsNew('0', '1');
+ await expect.element(cell1).toHaveClass(`${cellClassname} my-cell`, { exact: true });
+ await expect.element(cell2).toHaveClass(`${cellClassname} my-cell`, { exact: true });
});
-test('cellClass returns a string', () => {
+test('cellClass returns a string', async () => {
const columns: readonly Column[] = [
{
key: 'id',
@@ -44,12 +44,12 @@ test('cellClass returns a string', () => {
}
];
setup({ columns, rows });
- const [cell1, cell2] = getCells();
- expect(cell1).toHaveClass(`${cellClassname} my-cell-0`, { exact: true });
- expect(cell2).toHaveClass(`${cellClassname} my-cell-1`, { exact: true });
+ const [cell1, cell2] = getCellsNew('0', '1');
+ await expect.element(cell1).toHaveClass(`${cellClassname} my-cell-0`, { exact: true });
+ await expect.element(cell2).toHaveClass(`${cellClassname} my-cell-1`, { exact: true });
});
-test('cellClass returns undefined', () => {
+test('cellClass returns undefined', async () => {
const columns: readonly Column[] = [
{
key: 'id',
@@ -58,7 +58,7 @@ test('cellClass returns undefined', () => {
}
];
setup({ columns, rows });
- const [cell1, cell2] = getCells();
- expect(cell1).toHaveClass(cellClassname, { exact: true });
- expect(cell2).toHaveClass(cellClassname, { exact: true });
+ const [cell1, cell2] = getCellsNew('0', '1');
+ await expect.element(cell1).toHaveClass(cellClassname, { exact: true });
+ await expect.element(cell2).toHaveClass(cellClassname, { exact: true });
});
diff --git a/test/browser/column/draggable.test.ts b/test/browser/column/draggable.test.ts
index 14efe0bf41..e32e0a9e23 100644
--- a/test/browser/column/draggable.test.ts
+++ b/test/browser/column/draggable.test.ts
@@ -1,7 +1,7 @@
import { userEvent } from '@vitest/browser/context';
import type { Column } from '../../../src';
-import { getHeaderCells, setup } from '../utils';
+import { getHeaderCellsNew, setup } from '../utils';
const columns: readonly Column[] = [
{
@@ -28,12 +28,12 @@ const columns: readonly Column[] = [
test('draggable columns', async () => {
const onColumnsReorder = vi.fn();
setup({ columns, rows: [], onColumnsReorder });
- const [cell1, cell2, cell3, cell4] = getHeaderCells();
+ const [cell1, cell2, cell3, cell4] = getHeaderCellsNew('col1', 'col2', 'col3', 'col4');
- expect(cell1).not.toHaveAttribute('draggable');
- expect(cell2).toHaveAttribute('draggable');
- expect(cell3).toHaveAttribute('draggable');
- expect(cell4).toHaveAttribute('draggable');
+ await expect.element(cell1).not.toHaveAttribute('draggable');
+ await expect.element(cell2).toHaveAttribute('draggable');
+ await expect.element(cell3).toHaveAttribute('draggable');
+ await expect.element(cell4).toHaveAttribute('draggable');
expect(onColumnsReorder).not.toHaveBeenCalled();
diff --git a/test/browser/column/frozen.test.ts b/test/browser/column/frozen.test.ts
index 9075f446ce..4223a06a4e 100644
--- a/test/browser/column/frozen.test.ts
+++ b/test/browser/column/frozen.test.ts
@@ -1,8 +1,10 @@
+import { page } from '@vitest/browser/context';
+
import type { Column } from '../../../src';
import { cellClassname, cellFrozenClassname } from '../../../src/style/cell';
-import { getHeaderCells, setup } from '../utils';
+import { getHeaderCellsNew, setup } from '../utils';
-test('frozen column have a specific class, and are stable-sorted before non-frozen columns', () => {
+test('frozen column have a specific class, and are stable-sorted before non-frozen columns', async () => {
const columns: readonly Column[] = [
{
key: 'col1',
@@ -26,15 +28,15 @@ test('frozen column have a specific class, and are stable-sorted before non-froz
];
setup({ columns, rows: [] });
- const [cell1, cell2, cell3, cell4] = getHeaderCells();
-
- expect(cell1).toHaveClass(`${cellClassname} ${cellFrozenClassname}`, { exact: true });
- expect(cell2).toHaveClass(`${cellClassname} ${cellFrozenClassname}`, { exact: true });
- expect(cell3).toHaveClass(cellClassname, { exact: true });
- expect(cell4).toHaveClass(cellClassname, { exact: true });
+ await expect.element(page.getByRole('row')).toHaveTextContent('col1col3col2col4');
+ const [cell1, cell2, cell3, cell4] = getHeaderCellsNew('col1', 'col2', 'col3', 'col4');
- expect(cell1).toHaveTextContent('col1');
- expect(cell2).toHaveTextContent('col3');
- expect(cell3).toHaveTextContent('col2');
- expect(cell4).toHaveTextContent('col4');
+ await expect
+ .element(cell1)
+ .toHaveClass(`${cellClassname} ${cellFrozenClassname}`, { exact: true });
+ await expect
+ .element(cell3)
+ .toHaveClass(`${cellClassname} ${cellFrozenClassname}`, { exact: true });
+ await expect.element(cell2).toHaveClass(cellClassname, { exact: true });
+ await expect.element(cell4).toHaveClass(cellClassname, { exact: true });
});
diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx
index deaab7b840..c4b9a77d7b 100644
--- a/test/browser/column/renderEditCell.test.tsx
+++ b/test/browser/column/renderEditCell.test.tsx
@@ -1,10 +1,10 @@
import { useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
-import { page, userEvent } from '@vitest/browser/context';
+import { commands, page, userEvent } from '@vitest/browser/context';
import { DataGrid } from '../../../src';
import type { Column, DataGridProps } from '../../../src';
-import { getCellsAtRowIndex, getGrid, getSelectedCell, scrollGrid } from '../utils';
+import { getCell, getCellsAtRowIndex, getGrid, getSelectedCell, scrollGrid } from '../utils';
interface Row {
col1: number;
@@ -258,20 +258,19 @@ describe('Editor', () => {
it('should not steal focus back to the cell if the editor is not in the viewport and another cell is clicked', async () => {
const rows: Row[] = [];
for (let i = 0; i < 99; i++) {
- rows.push({ col1: i, col2: `${i}` });
+ rows.push({ col1: i, col2: `name${i}` });
}
page.render();
- await userEvent.dblClick(getCellsAtRowIndex(0)[1]);
+ await userEvent.dblClick(getCell('name0'));
await userEvent.keyboard('abc');
- await scrollGrid({ scrollTop: 1500 });
- expect(getCellsAtRowIndex(40)[1]).toHaveTextContent(/^40$/);
- await userEvent.click(getCellsAtRowIndex(40)[1]);
- await expect.element(getSelectedCell()).toHaveTextContent(/^40$/);
- await scrollGrid({ scrollTop: 0 });
- expect(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^0abc$/);
+ await commands.scrollGrid({ scrollTop: 1500 });
+ await userEvent.click(getCell('name43'));
+ await expect.element(getSelectedCell()).toHaveTextContent(/^name43$/);
+ await commands.scrollGrid({ scrollTop: 0 });
+ await expect.element(getCell('name0abc')).toBeVisible();
});
it('should not steal focus back to the cell after being closed by clicking outside the grid', async () => {
diff --git a/test/browser/headerRowClass.test.ts b/test/browser/headerRowClass.test.ts
index 0b16cbc3a4..10d1e816c9 100644
--- a/test/browser/headerRowClass.test.ts
+++ b/test/browser/headerRowClass.test.ts
@@ -9,24 +9,24 @@ interface Row {
}
const columns: readonly Column[] = [{ key: 'id', name: 'ID' }];
-const rows: readonly Row[] = [{ id: 0 }];
+const rows: readonly Row[] = [];
-test('headerRowClass is undefined', () => {
+test('headerRowClass is undefined', async () => {
setup({
columns,
rows,
- rowClass: undefined
+ headerRowClass: undefined
});
- const header = page.getByRole('row').first();
- expect(header).toHaveClass(headerRowClassname, { exact: true });
+ const header = page.getByRole('row');
+ await expect.element(header).toHaveClass(headerRowClassname, { exact: true });
});
-test('headerRowClass is a string', () => {
+test('headerRowClass is a string', async () => {
setup({
columns,
rows,
headerRowClass: 'my-header-row'
});
- const header = page.getByRole('row').first();
- expect(header).toHaveClass(`${headerRowClassname} my-header-row`, { exact: true });
+ const header = page.getByRole('row');
+ await expect.element(header).toHaveClass(`${headerRowClassname} my-header-row`, { exact: true });
});
diff --git a/test/browser/label.test.ts b/test/browser/label.test.ts
index 7a10790111..aa077c0715 100644
--- a/test/browser/label.test.ts
+++ b/test/browser/label.test.ts
@@ -1,6 +1,6 @@
import { getGrid, setup } from './utils';
-test('should set label and description', () => {
+test('should set label and description', async () => {
setup({
rows: [],
columns: [],
@@ -12,11 +12,11 @@ test('should set label and description', () => {
'data-cy': 'cy'
});
- const grid = getGrid().element();
- expect(grid).toHaveAttribute('aria-label', 'label');
- expect(grid).toHaveAttribute('aria-labelledby', 'labelledby');
- expect(grid).toHaveAttribute('aria-description', 'description');
- expect(grid).toHaveAttribute('aria-describedby', 'describedby');
- expect(grid).toHaveAttribute('data-testid', 'testid');
- expect(grid).toHaveAttribute('data-cy', 'cy');
+ const grid = getGrid();
+ await expect.element(grid).toHaveAttribute('aria-label', 'label');
+ await expect.element(grid).toHaveAttribute('aria-labelledby', 'labelledby');
+ await expect.element(grid).toHaveAttribute('aria-description', 'description');
+ await expect.element(grid).toHaveAttribute('aria-describedby', 'describedby');
+ await expect.element(grid).toHaveAttribute('data-testid', 'testid');
+ await expect.element(grid).toHaveAttribute('data-cy', 'cy');
});
diff --git a/test/browser/rowClass.test.ts b/test/browser/rowClass.test.ts
index be50467c12..ad4a41d704 100644
--- a/test/browser/rowClass.test.ts
+++ b/test/browser/rowClass.test.ts
@@ -1,6 +1,6 @@
import type { Column } from '../../src';
import { rowClassname } from '../../src/style/row';
-import { getRows, setup } from './utils';
+import { getRowsNew, setup } from './utils';
interface Row {
id: number;
@@ -9,38 +9,38 @@ interface Row {
const columns: readonly Column[] = [{ key: 'id', name: 'ID' }];
const rows: readonly Row[] = [{ id: 0 }, { id: 1 }, { id: 2 }];
-test('rowClass is undefined', () => {
+test('rowClass is undefined', async () => {
setup({
columns,
rows,
rowClass: undefined
});
- const [row1, row2, row3] = getRows();
- expect(row1).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
- expect(row2).toHaveClass(`${rowClassname} rdg-row-odd`, { exact: true });
- expect(row3).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
+ const [row1, row2, row3] = getRowsNew('0', '1', '2');
+ await expect.element(row1).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
+ await expect.element(row2).toHaveClass(`${rowClassname} rdg-row-odd`, { exact: true });
+ await expect.element(row3).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
});
-test('rowClass returns a string', () => {
+test('rowClass returns a string', async () => {
setup({
columns,
rows,
rowClass: (row) => `my-row-${row.id}`
});
- const [row1, row2, row3] = getRows();
- expect(row1).toHaveClass(`${rowClassname} rdg-row-even my-row-0`, { exact: true });
- expect(row2).toHaveClass(`${rowClassname} rdg-row-odd my-row-1`, { exact: true });
- expect(row3).toHaveClass(`${rowClassname} rdg-row-even my-row-2`, { exact: true });
+ const [row1, row2, row3] = getRowsNew('0', '1', '2');
+ await expect.element(row1).toHaveClass(`${rowClassname} rdg-row-even my-row-0`, { exact: true });
+ await expect.element(row2).toHaveClass(`${rowClassname} rdg-row-odd my-row-1`, { exact: true });
+ await expect.element(row3).toHaveClass(`${rowClassname} rdg-row-even my-row-2`, { exact: true });
});
-test('rowClass returns undefined', () => {
+test('rowClass returns undefined', async () => {
setup({
columns,
rows,
rowClass: () => undefined
});
- const [row1, row2, row3] = getRows();
- expect(row1).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
- expect(row2).toHaveClass(`${rowClassname} rdg-row-odd`, { exact: true });
- expect(row3).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
+ const [row1, row2, row3] = getRowsNew('0', '1', '2');
+ await expect.element(row1).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
+ await expect.element(row2).toHaveClass(`${rowClassname} rdg-row-odd`, { exact: true });
+ await expect.element(row3).toHaveClass(`${rowClassname} rdg-row-even`, { exact: true });
});
diff --git a/test/browser/rowSelection.test.tsx b/test/browser/rowSelection.test.tsx
index a37c375a91..d0f6be5684 100644
--- a/test/browser/rowSelection.test.tsx
+++ b/test/browser/rowSelection.test.tsx
@@ -3,7 +3,7 @@ import { page, userEvent } from '@vitest/browser/context';
import { DataGrid, SelectColumn } from '../../src';
import type { Column } from '../../src';
-import { getCellsAtRowIndex, getRows } from './utils';
+import { getCell, getRow, getSelectAllCheckbox } from './utils';
interface Row {
id: number;
@@ -12,8 +12,8 @@ interface Row {
const columns: readonly Column[] = [
SelectColumn,
{
- key: 'name',
- name: 'Name'
+ key: 'id',
+ name: 'ID'
}
];
@@ -49,75 +49,77 @@ function setup(initialRows = defaultRows) {
}
function testSelection(rowIdx: number, isSelected: boolean) {
- expect(getRows()[rowIdx]).toHaveAttribute('aria-selected', isSelected ? 'true' : 'false');
+ return expect
+ .element(getRow(String(rowIdx + 1)))
+ .toHaveAttribute('aria-selected', isSelected ? 'true' : 'false');
}
-async function toggleSelection(rowIdx: number, shift = false) {
- const element = page.getByRole('row').all()[rowIdx + 1].getByRole('checkbox', { name: 'Select' });
+async function toggleSelection(rowIdx: number, shift = false, force = false) {
+ const checkbox = getRow(String(rowIdx + 1)).getByRole('checkbox', { name: 'Select' });
if (shift) await userEvent.keyboard('{Shift>}');
- await userEvent.click(element, { force: true });
+ await userEvent.click(checkbox, { force });
if (shift) await userEvent.keyboard('{/Shift}');
}
test('toggle selection when checkbox is clicked', async () => {
setup();
await toggleSelection(0);
- testSelection(0, true);
+ await testSelection(0, true);
await toggleSelection(1);
- testSelection(1, true);
+ await testSelection(1, true);
await toggleSelection(0);
- testSelection(0, false);
+ await testSelection(0, false);
await toggleSelection(1);
- testSelection(1, false);
+ await testSelection(1, false);
});
test('toggle selection using keyboard', async () => {
setup();
- testSelection(0, false);
- await userEvent.click(getCellsAtRowIndex(0)[0]);
- testSelection(0, true);
+ await testSelection(0, false);
+ await userEvent.click(getRow('1').getByRole('checkbox', { name: 'Select' }));
+ await testSelection(0, true);
await userEvent.keyboard(' ');
- testSelection(0, false);
+ await testSelection(0, false);
await userEvent.keyboard(' ');
- testSelection(0, true);
+ await testSelection(0, true);
await userEvent.keyboard('{arrowdown} ');
- testSelection(1, true);
+ await testSelection(1, true);
await userEvent.keyboard('{arrowup} ');
- testSelection(0, false);
+ await testSelection(0, false);
});
test('should partially select header checkbox', async () => {
setup();
- const headerCheckbox = page.getByRole('checkbox', { name: 'Select All' }).element();
- expect(headerCheckbox).not.toBeChecked();
- expect(headerCheckbox).not.toBePartiallyChecked();
+ const headerCheckbox = getSelectAllCheckbox();
+ await expect.element(headerCheckbox).not.toBeChecked();
+ await expect.element(headerCheckbox).not.toBePartiallyChecked();
await toggleSelection(0);
- expect(headerCheckbox).not.toBeChecked();
- expect(headerCheckbox).toBePartiallyChecked();
+ await expect.element(headerCheckbox).not.toBeChecked();
+ await expect.element(headerCheckbox).toBePartiallyChecked();
await toggleSelection(1);
- expect(headerCheckbox).not.toBeChecked();
- expect(headerCheckbox).toBePartiallyChecked();
+ await expect.element(headerCheckbox).not.toBeChecked();
+ await expect.element(headerCheckbox).toBePartiallyChecked();
await toggleSelection(2);
- expect(headerCheckbox).toBeChecked();
- expect(headerCheckbox).not.toBePartiallyChecked();
+ await expect.element(headerCheckbox).toBeChecked();
+ await expect.element(headerCheckbox).not.toBePartiallyChecked();
await toggleSelection(0);
- expect(headerCheckbox).not.toBeChecked();
- expect(headerCheckbox).toBePartiallyChecked();
+ await expect.element(headerCheckbox).not.toBeChecked();
+ await expect.element(headerCheckbox).toBePartiallyChecked();
await userEvent.click(headerCheckbox);
- testSelection(0, false);
- testSelection(1, false);
- testSelection(2, false);
+ await testSelection(0, false);
+ await testSelection(1, false);
+ await testSelection(2, false);
await userEvent.click(headerCheckbox);
- testSelection(0, true);
- testSelection(1, true);
- testSelection(2, true);
+ await testSelection(0, true);
+ await testSelection(1, true);
+ await testSelection(2, true);
});
test('should not select row when isRowSelectionDisabled returns true', async () => {
@@ -125,44 +127,44 @@ test('should not select row when isRowSelectionDisabled returns true', async ()
row.id === 2} />
);
await toggleSelection(0);
- testSelection(0, true);
- await toggleSelection(1);
- testSelection(1, false);
+ await testSelection(0, true);
+ await toggleSelection(1, false, true); // force click even if disabled
+ await testSelection(1, false);
await toggleSelection(2);
- testSelection(2, true);
+ await testSelection(2, true);
- await userEvent.click(page.getByRole('checkbox', { name: 'Select All' }));
+ await userEvent.click(getSelectAllCheckbox());
await toggleSelection(0);
await toggleSelection(2, true);
- testSelection(0, true);
- testSelection(1, false);
- testSelection(2, true);
+ await testSelection(0, true);
+ await testSelection(1, false);
+ await testSelection(2, true);
});
test('select/deselect all rows when header checkbox is clicked', async () => {
setup();
- const headerCheckbox = page.getByRole('checkbox', { name: 'Select All' }).element();
- expect(headerCheckbox).not.toBeChecked();
+ const headerCheckbox = getSelectAllCheckbox();
+ await expect.element(headerCheckbox).not.toBeChecked();
await userEvent.click(headerCheckbox);
- testSelection(0, true);
- testSelection(1, true);
- testSelection(2, true);
+ await testSelection(0, true);
+ await testSelection(1, true);
+ await testSelection(2, true);
// deselecting a row should toggle header
await toggleSelection(0);
- expect(headerCheckbox).not.toBeChecked();
+ await expect.element(headerCheckbox).not.toBeChecked();
await toggleSelection(0);
- expect(headerCheckbox).toBeChecked();
+ await expect.element(headerCheckbox).toBeChecked();
await userEvent.click(headerCheckbox);
- testSelection(0, false);
- testSelection(1, false);
- testSelection(2, false);
+ await testSelection(0, false);
+ await testSelection(1, false);
+ await testSelection(2, false);
});
test('header checkbox is not checked when there are no rows', async () => {
setup([]);
- await expect.element(page.getByRole('checkbox', { name: 'Select All' })).not.toBeChecked();
+ await expect.element(getSelectAllCheckbox()).not.toBeChecked();
});
test('header checkbox is not necessarily checked when selectedRows.size === rows.length', async () => {
@@ -175,7 +177,7 @@ test('header checkbox is not necessarily checked when selectedRows.size === rows
/>
);
- await expect.element(page.getByRole('checkbox', { name: 'Select All' })).not.toBeChecked();
+ await expect.element(getSelectAllCheckbox()).not.toBeChecked();
});
test('header checkbox is not necessarily checked when selectedRows.size > rows.length', async () => {
@@ -188,7 +190,7 @@ test('header checkbox is not necessarily checked when selectedRows.size > rows.l
/>
);
- await expect.element(page.getByRole('checkbox', { name: 'Select All' })).not.toBeChecked();
+ await expect.element(getSelectAllCheckbox()).not.toBeChecked();
});
test('extra keys are preserved when updating the selectedRows Set', async () => {
@@ -216,7 +218,7 @@ test('extra keys are preserved when updating the selectedRows Set', async () =>
page.render();
- const headerCheckbox = page.getByRole('checkbox', { name: 'Select All' }).element();
+ const headerCheckbox = getSelectAllCheckbox();
await toggleSelection(1);
expect(set).toStrictEqual(new Set([...initialSet, 2]));
@@ -241,23 +243,23 @@ test('select/deselect rows using shift click', async () => {
setup();
await toggleSelection(0);
await toggleSelection(2, true);
- testSelection(0, true);
- testSelection(1, true);
- testSelection(2, true);
+ await testSelection(0, true);
+ await testSelection(1, true);
+ await testSelection(2, true);
await toggleSelection(0);
await toggleSelection(2, true);
- testSelection(0, false);
- testSelection(1, false);
- testSelection(2, false);
+ await testSelection(0, false);
+ await testSelection(1, false);
+ await testSelection(2, false);
});
test('select rows using shift space', async () => {
setup();
- await userEvent.click(getCellsAtRowIndex(0)[1]);
+ await userEvent.click(getCell('1'));
await userEvent.keyboard('{Shift>} {/Shift}');
- testSelection(0, true);
+ await testSelection(0, true);
await userEvent.keyboard(' ');
- testSelection(0, true);
+ await testSelection(0, true);
await userEvent.keyboard('{Shift>} {/Shift}');
- testSelection(0, false);
+ await testSelection(0, false);
});
diff --git a/test/browser/scrollToCell.test.tsx b/test/browser/scrollToCell.test.tsx
index ba843a39c3..3a58c416c5 100644
--- a/test/browser/scrollToCell.test.tsx
+++ b/test/browser/scrollToCell.test.tsx
@@ -4,21 +4,23 @@ import { page, userEvent } from '@vitest/browser/context';
import { DataGrid } from '../../src';
import type { Column, DataGridHandle } from '../../src';
import type { PartialPosition } from '../../src/ScrollToCell';
-import { getGrid } from './utils';
-type Row = undefined;
-
-const rows: readonly Row[] = new Array(50);
-const summaryRows: readonly Row[] = [undefined, undefined];
-
-const columns: Column[] = [];
+const rows: readonly number[] = Array.from({ length: 50 }, (_, i) => i);
+const summaryRows: readonly number[] = Array.from({ length: 2 }, (_, i) => i + 50);
+const columns: Column[] = [];
for (let i = 0; i < 50; i++) {
const key = String(i);
columns.push({
key,
name: key,
- frozen: i < 5
+ frozen: i < 5,
+ renderCell(props) {
+ return `${props.column.key}×${props.row}`;
+ },
+ renderSummaryCell(props) {
+ return `${props.column.key}×${props.row}`;
+ }
});
}
@@ -54,43 +56,57 @@ async function testScroll(p: PartialPosition) {
test('scrollToCell', async () => {
page.render();
- const grid = getGrid().element();
- validateScrollPosition(0, 0);
+ await validateCellVisibility('0×0', true);
+ await validateCellVisibility('40×30', false);
+ await validateCellVisibility('0×51', true);
// should scroll to a cell when a valid position is specified
await testScroll({ idx: 40, rowIdx: 30 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('0×0', false);
+ await validateCellVisibility('40×30', true);
// should scroll to a column when a valid idx is specified
await testScroll({ idx: 6 });
- validateScrollPosition(1572, 50);
+ await validateCellVisibility('6×30', true);
+ await validateCellVisibility('40×30', false);
await testScroll({ idx: 40 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('6×30', false);
+ await validateCellVisibility('40×30', true);
// should scroll to a row when a valid rowIdx is specified
await testScroll({ rowIdx: 1 });
- validateScrollPosition(0, 132);
+ await validateCellVisibility('40×1', true);
+ await validateCellVisibility('40×30', false);
await testScroll({ rowIdx: 30 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('40×1', false);
+ await validateCellVisibility('40×30', true);
// should not scroll if scroll to column is frozen
await testScroll({ idx: 2 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('40×30', true);
// should not scroll if rowIdx is header row
await testScroll({ idx: -1 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('40×30', true);
// should not scroll if rowIdx is summary row
await testScroll({ idx: 50 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('40×30', true);
// should not scroll if position is out of bound
await testScroll({ idx: 60, rowIdx: 60 });
- validateScrollPosition(1572, 132);
+ await validateCellVisibility('40×30', true);
- function validateScrollPosition(scrollTop: number, scrollLeft: number) {
- expect(grid.scrollTop).toBe(scrollTop);
- expect(grid.scrollLeft).toBe(scrollLeft);
- }
+ // should not scroll vertically when scrolling to summary row
+ await testScroll({ idx: 49, rowIdx: 51 });
+ await validateCellVisibility('49×30', true);
});
+
+function validateCellVisibility(name: string, isVisible: boolean) {
+ const cell = page.getByRole('gridcell', { name, exact: true });
+ if (isVisible) {
+ return expect.element(cell).toBeVisible();
+ }
+
+ return expect.element(cell).not.toBeInTheDocument();
+}
diff --git a/test/browser/sorting.test.tsx b/test/browser/sorting.test.tsx
index 8f1e829766..5bb6ba1b8e 100644
--- a/test/browser/sorting.test.tsx
+++ b/test/browser/sorting.test.tsx
@@ -3,7 +3,7 @@ import { page, userEvent } from '@vitest/browser/context';
import { DataGrid } from '../../src';
import type { Column, SortColumn } from '../../src/types';
-import { getHeaderCells } from './utils';
+import { getHeaderCell, getHeaderCellsNew } from './utils';
const columns: readonly Column[] = [
{ key: 'colA', name: 'colA' },
@@ -41,43 +41,45 @@ function testSortColumns(expectedValue: readonly SortColumn[]) {
test('should not sort if sortable is false', async () => {
setup();
- const headerCell = getHeaderCells()[3];
+ const headerCell = getHeaderCell('colD');
await userEvent.click(headerCell);
- expect(headerCell).not.toHaveAttribute('aria-sort');
+ await expect.element(headerCell).not.toHaveAttribute('aria-sort');
await testSortColumns([]);
});
test('single column sort', async () => {
setup();
- const headerCell = getHeaderCells()[0];
+ const headerCell = getHeaderCell('colA');
await userEvent.click(headerCell);
- expect(headerCell).toHaveAttribute('aria-sort', 'ascending');
+ await expect.element(headerCell).toHaveAttribute('aria-sort', 'ascending');
// priority is not shown for single sort
- expect(headerCell).not.toHaveTextContent('1');
+ await expect.element(headerCell).not.toHaveTextContent('1');
await testSortColumns([{ columnKey: 'colA', direction: 'ASC' }]);
await userEvent.click(headerCell);
- expect(headerCell).toHaveAttribute('aria-sort', 'descending');
+ await expect.element(headerCell).toHaveAttribute('aria-sort', 'descending');
await testSortColumns([{ columnKey: 'colA', direction: 'DESC' }]);
await userEvent.click(headerCell);
- expect(headerCell).not.toHaveAttribute('aria-sort');
+ await expect.element(headerCell).not.toHaveAttribute('aria-sort');
await testSortColumns([]);
});
test('multi column sort', async () => {
setup();
- const [headerCell1, headerCell2, headerCell3] = getHeaderCells();
+ const headerCell1 = getHeaderCell('colA', false);
+ const headerCell2 = getHeaderCell('colB', false);
+ const headerCell3 = getHeaderCell('colC', false);
await userEvent.click(headerCell1);
await userEvent.keyboard('{Control>}');
await userEvent.click(headerCell2);
await userEvent.click(headerCell3);
// aria-sort is only added for single sort
- expect(headerCell1).not.toHaveAttribute('aria-sort');
- expect(headerCell1).toHaveTextContent('1'); // priority
- expect(headerCell2).not.toHaveAttribute('aria-sort');
- expect(headerCell2).toHaveTextContent('2');
- expect(headerCell3).not.toHaveAttribute('aria-sort');
- expect(headerCell3).toHaveTextContent('3');
+ await expect.element(headerCell1).not.toHaveAttribute('aria-sort');
+ await expect.element(headerCell1).toHaveTextContent('1'); // priority
+ await expect.element(headerCell2).not.toHaveAttribute('aria-sort');
+ await expect.element(headerCell2).toHaveTextContent('2');
+ await expect.element(headerCell3).not.toHaveAttribute('aria-sort');
+ await expect.element(headerCell3).toHaveTextContent('3');
await testSortColumns([
{ columnKey: 'colA', direction: 'ASC' },
{ columnKey: 'colB', direction: 'DESC' },
@@ -95,19 +97,19 @@ test('multi column sort', async () => {
{ columnKey: 'colA', direction: 'ASC' },
{ columnKey: 'colC', direction: 'ASC' }
]);
- expect(headerCell3).toHaveTextContent('2');
+ await expect.element(headerCell3).toHaveTextContent('2');
// clicking on a column without ctrlKey should remove multisort
await userEvent.keyboard('{/Control}');
await userEvent.click(headerCell2);
await testSortColumns([{ columnKey: 'colB', direction: 'DESC' }]);
- expect(headerCell2).toHaveAttribute('aria-sort');
- expect(headerCell2).not.toHaveTextContent('2');
+ await expect.element(headerCell2).toHaveAttribute('aria-sort');
+ await expect.element(headerCell2).not.toHaveTextContent('2');
});
test('multi column sort with metakey', async () => {
setup();
- const [headerCell1, headerCell2] = getHeaderCells();
+ const [headerCell1, headerCell2] = getHeaderCellsNew('colA', 'colB');
await userEvent.click(headerCell1);
await userEvent.keyboard('{Meta>}');
await userEvent.click(headerCell2);
@@ -119,7 +121,7 @@ test('multi column sort with metakey', async () => {
test('multi column sort with keyboard', async () => {
setup();
- const [headerCell1] = getHeaderCells();
+ const headerCell1 = getHeaderCell('colA');
await userEvent.click(headerCell1);
await userEvent.keyboard(' {arrowright}{Control>}{enter}');
await testSortColumns([
diff --git a/test/browser/utils.tsx b/test/browser/utils.tsx
index 9f01850cb2..00b0b589b7 100644
--- a/test/browser/utils.tsx
+++ b/test/browser/utils.tsx
@@ -40,6 +40,34 @@ export function getTreeGrid() {
return page.getByRole('treegrid');
}
+export function getHeaderCell(name: string, exact = true) {
+ return page.getByRole('columnheader', { name, exact });
+}
+
+export function getHeaderCellsNew(...names: readonly string[]) {
+ return names.map((name) => getHeaderCell(name));
+}
+
+export function getRow(name: string) {
+ return page.getByRole('row', { name });
+}
+
+export function getRowsNew(...names: readonly string[]) {
+ return names.map(getRow);
+}
+
+export function getCell(name: string) {
+ return page.getByRole('gridcell', { name, exact: true });
+}
+
+export function getCellsNew(...names: readonly string[]) {
+ return names.map(getCell);
+}
+
+export function getSelectAllCheckbox() {
+ return page.getByRole('checkbox', { name: 'Select All' });
+}
+
export function getRows() {
return page.getByRole('row').elements().slice(1);
}
diff --git a/test/globals.d.ts b/test/globals.d.ts
index fad484533a..6ccaf2509e 100644
--- a/test/globals.d.ts
+++ b/test/globals.d.ts
@@ -1,7 +1,8 @@
declare module '@vitest/browser/context' {
interface BrowserCommands {
- resizeColumn: (resizeBy: number | readonly number[]) => Promise;
dragFill: (from: string, to: string) => Promise;
+ resizeColumn: (resizeBy: number | readonly number[]) => Promise;
+ scrollGrid: (position: { scrollLeft?: number; scrollTop?: number }) => Promise;
}
}
diff --git a/tsconfig.vite.json b/tsconfig.vite.json
index 55ce01b576..57d8db9414 100644
--- a/tsconfig.vite.json
+++ b/tsconfig.vite.json
@@ -2,6 +2,7 @@
"extends": "./tsconfig.base.json",
"compilerOptions": {
"skipLibCheck": true,
+ "lib": ["ESNext", "DOM"],
"types": ["@vitest/browser/providers/playwright"]
},
"include": ["package.json", "rolldown.config.ts", "vite.config.ts"]
diff --git a/vite.config.ts b/vite.config.ts
index c2aefbaec4..dabe74be47 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -41,6 +41,24 @@ const dragFill: BrowserCommand<[from: string, to: string]> = async (context, fro
await page.mouse.up();
};
+const scrollGrid: BrowserCommand<[{ scrollLeft?: number; scrollTop?: number }]> = async (
+ context,
+ { scrollLeft, scrollTop }
+) => {
+ const frame = await context.frame();
+ await frame.getByRole('grid').evaluate(
+ (grid: HTMLDivElement, { scrollLeft, scrollTop }) => {
+ if (scrollLeft !== undefined) {
+ grid.scrollLeft = scrollLeft;
+ }
+ if (scrollTop !== undefined) {
+ grid.scrollTop = scrollTop;
+ }
+ },
+ { scrollLeft, scrollTop }
+ );
+};
+
const viewport = { width: 1920, height: 1080 } as const;
export default defineConfig(({ command, isPreview }) => ({
@@ -108,7 +126,7 @@ export default defineConfig(({ command, isPreview }) => ({
context: { viewport }
}
],
- commands: { resizeColumn, dragFill },
+ commands: { resizeColumn, dragFill, scrollGrid },
viewport,
headless: true,
screenshotFailures: !isCI