From d7b1799f949c5d85596b7659331dea94f49a4726 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien <567105+nstepien@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:38:05 +0000 Subject: [PATCH] Tweak tests (#3948) --- README.md | 4 +- test/browser/TreeDataGrid.test.tsx | 14 ++--- test/browser/column/colSpan.test.ts | 30 ++++----- test/browser/column/headerCellClass.test.ts | 8 +-- test/browser/column/renderCell.test.tsx | 56 ++++++++--------- test/browser/column/renderEditCell.test.tsx | 28 ++++----- test/browser/column/renderHeaderCell.test.tsx | 4 +- .../browser/column/renderSummaryCell.test.tsx | 16 ++--- test/browser/column/resizable.test.tsx | 18 +++--- test/browser/column/summaryCellClass.test.ts | 16 ++--- test/browser/dragFill.test.tsx | 2 +- test/browser/keyboardNavigation.test.tsx | 5 +- test/browser/utils.tsx | 2 +- test/globals.d.ts | 4 ++ test/visual/basicGrid.test.tsx | 2 +- test/visual/treeGrid.test.tsx | 2 +- vite.config.ts | 62 ++++++++++++------- 17 files changed, 145 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 3f83246b67..b0a3051f5f 100644 --- a/README.md +++ b/README.md @@ -760,8 +760,8 @@ function MyGrid() { } test('grid', async () => { - await render(); - const grid = screen.getByRole('grid', { name: 'my-grid' }); + await page.render(); + const grid = page.getByRole('grid', { name: 'my-grid' }); }); ``` diff --git a/test/browser/TreeDataGrid.test.tsx b/test/browser/TreeDataGrid.test.tsx index 9150e7f56b..2afc7bbef6 100644 --- a/test/browser/TreeDataGrid.test.tsx +++ b/test/browser/TreeDataGrid.test.tsx @@ -322,7 +322,7 @@ test('cell navigation in a treegrid', async () => { // expand group const groupCell1 = getCell('USA'); - expect(document.body).toHaveFocus(); + await expect.element(document.body).toHaveFocus(); await expect.element(focusSink).toHaveAttribute('tabIndex', '-1'); await userEvent.click(groupCell1); await expect.element(focusSink).toHaveFocus(); @@ -351,23 +351,23 @@ test('cell navigation in a treegrid', async () => { // select cell await userEvent.click(getCellsAtRowIndex(5)[1]); - expect(getCellsAtRowIndex(5)[1]).toHaveAttribute('aria-selected', 'true'); + await expect.element(getCellsAtRowIndex(5)[1]).toHaveAttribute('aria-selected', 'true'); await expect.element(focusSink).toHaveAttribute('tabIndex', '-1'); // select the previous cell await userEvent.keyboard('{arrowleft}'); - expect(getCellsAtRowIndex(5)[1]).toHaveAttribute('aria-selected', 'false'); - expect(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'true'); + await expect.element(getCellsAtRowIndex(5)[1]).toHaveAttribute('aria-selected', 'false'); + await expect.element(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'true'); // if the first cell is selected then arrowleft should select the row await userEvent.keyboard('{arrowleft}'); - expect(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'false'); + await expect.element(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'false'); await expect.element(getRows()[4]).toHaveClass(rowSelectedClassname); await expect.element(focusSink).toHaveFocus(); // if the row is selected then arrowright should select the first cell on the same row await userEvent.keyboard('{arrowright}'); - expect(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'true'); + await expect.element(getCellsAtRowIndex(5)[0]).toHaveAttribute('aria-selected', 'true'); await userEvent.keyboard('{arrowleft}{arrowup}'); @@ -390,7 +390,7 @@ test('cell navigation in a treegrid', async () => { await expect.element(getRows()[5]).toHaveClass(rowSelectedClassname); await userEvent.keyboard('{home}'); - await expect.element(page.getByRole('row').all()[0]).toHaveClass(rowSelectedClassname); + await expect.element(page.getByRole('row').nth(0)).toHaveClass(rowSelectedClassname); // collpase parent group await userEvent.keyboard('{arrowdown}{arrowdown}{arrowleft}'); diff --git a/test/browser/column/colSpan.test.ts b/test/browser/column/colSpan.test.ts index 4b93ca1889..8eb4447f9a 100644 --- a/test/browser/column/colSpan.test.ts +++ b/test/browser/column/colSpan.test.ts @@ -46,9 +46,9 @@ describe('colSpan', () => { const topSummarryRow1 = getCellsAtRowIndex(0); expect(topSummarryRow1).toHaveLength(14); // 7th-8th cells are merged - expect(topSummarryRow1[7]).toHaveAttribute('aria-colindex', '8'); - expect(topSummarryRow1[7]).toHaveAttribute('aria-colspan', '2'); - expect(topSummarryRow1[7]).toHaveStyle({ + await expect.element(topSummarryRow1[7]).toHaveAttribute('aria-colindex', '8'); + await expect.element(topSummarryRow1[7]).toHaveAttribute('aria-colspan', '2'); + await expect.element(topSummarryRow1[7]).toHaveStyle({ gridColumnStart: '8', gridColumnEnd: '10' }); @@ -58,31 +58,31 @@ describe('colSpan', () => { const row1 = getCellsAtRowIndex(3); expect(row1).toHaveLength(14); // 7th-8th cells are merged - expect(row1[6]).toHaveAttribute('aria-colindex', '7'); - expect(row1[6]).toHaveAttribute('aria-colspan', '2'); - expect(row1[6]).toHaveStyle({ + await expect.element(row1[6]).toHaveAttribute('aria-colindex', '7'); + await expect.element(row1[6]).toHaveAttribute('aria-colspan', '2'); + await expect.element(row1[6]).toHaveStyle({ gridTemplateColumns: '7', gridColumnEnd: '9' }); - expect(row1[7]).toHaveAttribute('aria-colindex', '9'); - expect(row1[7]).not.toHaveAttribute('aria-colspan'); + await expect.element(row1[7]).toHaveAttribute('aria-colindex', '9'); + await expect.element(row1[7]).not.toHaveAttribute('aria-colspan'); // 3rd-5th, 7th-8th cells are merged const row2 = getCellsAtRowIndex(4); expect(row2).toHaveLength(12); - expect(row2[2]).toHaveAttribute('aria-colindex', '3'); - expect(row2[2]).toHaveStyle({ + await expect.element(row2[2]).toHaveAttribute('aria-colindex', '3'); + await expect.element(row2[2]).toHaveStyle({ gridColumnStart: '3', gridColumnEnd: '6' }); - expect(row2[2]).toHaveAttribute('aria-colspan', '3'); - expect(row2[3]).toHaveAttribute('aria-colindex', '6'); - expect(row2[4]).toHaveAttribute('aria-colindex', '7'); - expect(row2[4]).toHaveStyle({ + await expect.element(row2[2]).toHaveAttribute('aria-colspan', '3'); + await expect.element(row2[3]).toHaveAttribute('aria-colindex', '6'); + await expect.element(row2[4]).toHaveAttribute('aria-colindex', '7'); + await expect.element(row2[4]).toHaveStyle({ gridColumnStart: '7', gridColumnEnd: '9' }); - expect(row2[5]).toHaveAttribute('aria-colindex', '9'); + await expect.element(row2[5]).toHaveAttribute('aria-colindex', '9'); expect(getCellsAtRowIndex(6)).toHaveLength(14); // colSpan 6 won't work as there are 5 frozen columns expect(getCellsAtRowIndex(7)).toHaveLength(10); diff --git a/test/browser/column/headerCellClass.test.ts b/test/browser/column/headerCellClass.test.ts index b31f00c4df..205208902a 100644 --- a/test/browser/column/headerCellClass.test.ts +++ b/test/browser/column/headerCellClass.test.ts @@ -17,8 +17,8 @@ test('headerCellClass is either nullish or a string', async () => { await setup({ columns, rows: [] }); const [cell1, cell2] = getHeaderCells(); - expect(cell1).toHaveClass(cellClassname, { exact: true }); - expect(cell2).toHaveClass(`${cellClassname} my-header`, { exact: true }); + await expect.element(cell1).toHaveClass(cellClassname, { exact: true }); + await expect.element(cell2).toHaveClass(`${cellClassname} my-header`, { exact: true }); }); test('columnGroup.headerCellClass is either nullish or a string', async () => { @@ -36,6 +36,6 @@ test('columnGroup.headerCellClass is either nullish or a string', async () => { await setup({ columns, rows: [] }); const [cell1, cell2] = getHeaderCells(); - expect(cell1).toHaveClass(cellClassname, { exact: true }); - expect(cell2).toHaveClass(`${cellClassname} my-header`, { exact: true }); + await expect.element(cell1).toHaveClass(cellClassname, { exact: true }); + await expect.element(cell2).toHaveClass(`${cellClassname} my-header`, { exact: true }); }); diff --git a/test/browser/column/renderCell.test.tsx b/test/browser/column/renderCell.test.tsx index e62903ce20..90ae4af3e2 100644 --- a/test/browser/column/renderCell.test.tsx +++ b/test/browser/column/renderCell.test.tsx @@ -21,15 +21,15 @@ describe('renderValue', () => { it('should be used by default', async () => { await setup({ columns, rows }); const [cell1, cell2] = getCells(); - expect(cell1).toHaveTextContent('101'); - expect(cell2).toBeEmptyDOMElement(); + await expect.element(cell1).toHaveTextContent('101'); + await expect.element(cell2).toBeEmptyDOMElement(); }); it('should handle non-object values', async () => { await setup({ columns, rows: [null] }); const [cell1, cell2] = getCells(); - expect(cell1).toBeEmptyDOMElement(); - expect(cell2).toBeEmptyDOMElement(); + await expect.element(cell1).toBeEmptyDOMElement(); + await expect.element(cell2).toBeEmptyDOMElement(); }); }); @@ -52,8 +52,8 @@ describe('Custom cell renderer', () => { it('should replace the default cell renderer', async () => { await setup({ columns, rows }); const [cell1, cell2] = getCells(); - expect(cell1).toHaveTextContent('#101'); - expect(cell2).toHaveTextContent('No name'); + await expect.element(cell1).toHaveTextContent('#101'); + await expect.element(cell2).toHaveTextContent('No name'); }); it('can update rows', async () => { @@ -93,9 +93,9 @@ describe('Custom cell renderer', () => { await page.render(); const [cell] = getCells(); - expect(cell).toHaveTextContent('value: 1'); + await expect.element(cell).toHaveTextContent('value: 1'); await userEvent.click(page.getByRole('button')); - expect(cell).toHaveTextContent('value: 2'); + await expect.element(cell).toHaveTextContent('value: 2'); expect(onChange).toHaveBeenCalledExactlyOnceWith([{ id: 2 }], { column: { ...column, @@ -140,29 +140,29 @@ test('Focus child if it sets tabIndex', async () => { const button1 = page.getByRole('button', { name: 'Button 1' }); const button2 = page.getByRole('button', { name: 'Button 2' }); const cell = page.getByRole('gridcell', { name: 'Button 1 Text Button 2' }); - expect(button1).toHaveAttribute('tabindex', '-1'); - expect(cell).toHaveAttribute('tabindex', '-1'); + await expect.element(button1).toHaveAttribute('tabindex', '-1'); + await expect.element(cell).toHaveAttribute('tabindex', '-1'); await userEvent.click(page.getByText('Text')); - expect(button1).toHaveFocus(); - expect(button1).toHaveAttribute('tabindex', '0'); + await expect.element(button1).toHaveFocus(); + await expect.element(button1).toHaveAttribute('tabindex', '0'); await userEvent.tab({ shift: true }); - expect(button1).not.toHaveFocus(); - expect(button1).toHaveAttribute('tabindex', '-1'); - expect(cell).toHaveAttribute('tabindex', '-1'); + await expect.element(button1).not.toHaveFocus(); + await expect.element(button1).toHaveAttribute('tabindex', '-1'); + await expect.element(cell).toHaveAttribute('tabindex', '-1'); await userEvent.click(button1); - expect(button1).toHaveFocus(); - expect(button1).toHaveAttribute('tabindex', '0'); - expect(cell).toHaveAttribute('tabindex', '-1'); + await expect.element(button1).toHaveFocus(); + await expect.element(button1).toHaveAttribute('tabindex', '0'); + await expect.element(cell).toHaveAttribute('tabindex', '-1'); await userEvent.tab({ shift: true }); await userEvent.click(button2); - expect(button2).toHaveFocus(); + await expect.element(button2).toHaveFocus(); // It is user's responsibilty to set the tabIndex on button2 - expect(button1).toHaveAttribute('tabindex', '0'); - expect(cell).toHaveAttribute('tabindex', '-1'); + await expect.element(button1).toHaveAttribute('tabindex', '0'); + await expect.element(cell).toHaveAttribute('tabindex', '-1'); await userEvent.click(button1); - expect(button1).toHaveFocus(); - expect(button1).toHaveAttribute('tabindex', '0'); - expect(cell).toHaveAttribute('tabindex', '-1'); + await expect.element(button1).toHaveFocus(); + await expect.element(button1).toHaveAttribute('tabindex', '0'); + await expect.element(cell).toHaveAttribute('tabindex', '-1'); }); test('Cell should not steal focus when the focus is outside the grid and cell is recreated', async () => { @@ -193,11 +193,11 @@ test('Cell should not steal focus when the focus is outside the grid and cell is await page.render(); await userEvent.click(getCellsAtRowIndex(0)[0]); - expect(getCellsAtRowIndex(0)[0]).toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveFocus(); const button = page.getByRole('button', { name: 'Test' }).element(); - expect(button).not.toHaveFocus(); + await expect.element(button).not.toHaveFocus(); await userEvent.click(button); - expect(getCellsAtRowIndex(0)[0]).not.toHaveFocus(); - expect(button).toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[0]).not.toHaveFocus(); + await expect.element(button).toHaveFocus(); }); diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index 10570bb904..01b12d6f0c 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -22,7 +22,7 @@ describe('Editor', () => { await userEvent.keyboard('2'); await userEvent.tab(); await expect.element(editor).not.toBeInTheDocument(); - expect(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^12$/); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^12$/); }); it('should open and commit changes on enter', async () => { @@ -33,8 +33,8 @@ describe('Editor', () => { await userEvent.keyboard('{enter}'); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('3{enter}'); - expect(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^13$/); - expect(getCellsAtRowIndex(0)[0]).toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^13$/); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveFocus(); await expect.element(editor).not.toBeInTheDocument(); }); @@ -43,7 +43,7 @@ describe('Editor', () => { await userEvent.click(getCellsAtRowIndex(0)[0]); // TODO: await userEvent.keyboard('123{enter}'); fails in FF await userEvent.keyboard('{enter}123{enter}'); - expect(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^1123$/); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^1123$/); }); it('should close editor and discard changes on escape', async () => { @@ -53,8 +53,8 @@ describe('Editor', () => { await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222{escape}'); await expect.element(editor).not.toBeInTheDocument(); - expect(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^1$/); - expect(getCellsAtRowIndex(0)[0]).toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^1$/); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveFocus(); }); it('should commit changes and close editor when clicked outside', async () => { @@ -65,7 +65,7 @@ describe('Editor', () => { await userEvent.keyboard('2222'); await userEvent.click(page.getByText('outside')); await expect.element(editor).not.toBeInTheDocument(); - expect(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^12222$/); + await expect.element(getCellsAtRowIndex(0)[0]).toHaveTextContent(/^12222$/); }); it('should commit quickly enough on outside clicks so click event handlers access the latest rows state', async () => { @@ -115,7 +115,7 @@ describe('Editor', () => { it('should be editable if an editor is specified and editable is undefined/null', async () => { await page.render(); const cell = getCellsAtRowIndex(0)[1]; - expect(cell).not.toHaveAttribute('aria-readonly'); + await expect.element(cell).not.toHaveAttribute('aria-readonly'); await userEvent.dblClick(cell); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); }); @@ -129,7 +129,7 @@ describe('Editor', () => { it('should not be editable if editable is false', async () => { await page.render(); const cell = getCellsAtRowIndex(0)[1]; - expect(cell).toHaveAttribute('aria-readonly', 'true'); + await expect.element(cell).toHaveAttribute('aria-readonly', 'true'); await userEvent.dblClick(cell); await expect @@ -158,19 +158,19 @@ describe('Editor', () => { await expect.element(editor1).toHaveValue('a1'); await userEvent.keyboard('23'); // The cell value should update as the editor value is changed - expect(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a123$/); + await expect.element(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a123$/); // clicking in a portal does not count as an outside click await userEvent.click(editor1); await expect.element(editor1).toBeInTheDocument(); // true outside clicks are still detected await userEvent.click(page.getByText('outside')); await expect.element(editor1).not.toBeInTheDocument(); - expect(getCellsAtRowIndex(0)[1]).not.toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[1]).not.toHaveFocus(); await userEvent.dblClick(getCellsAtRowIndex(0)[1]); await userEvent.click(page.getByRole('textbox', { name: 'col2-editor' })); await userEvent.keyboard('{enter}'); - expect(getCellsAtRowIndex(0)[1]).toHaveFocus(); + await expect.element(getCellsAtRowIndex(0)[1]).toHaveFocus(); }); it('should not commit on outside click if commitOnOutsideClick is false', async () => { @@ -204,7 +204,7 @@ describe('Editor', () => { await userEvent.click(getCellsAtRowIndex(0)[1]); // TODO: await userEvent.keyboard('yz{enter}'); fails in FF await userEvent.keyboard('{enter}yz{enter}'); - expect(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a1yz$/); + await expect.element(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a1yz$/); await userEvent.keyboard('x'); await expect .element(page.getByRole('textbox', { name: 'col2-editor' })) @@ -224,7 +224,7 @@ describe('Editor', () => { ); await userEvent.dblClick(getCellsAtRowIndex(0)[1]); await userEvent.keyboard('a{arrowleft}b{arrowright}c{arrowdown}'); // should commit changes on arrowdown - expect(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a1bac$/); + await expect.element(getCellsAtRowIndex(0)[1]).toHaveTextContent(/^a1bac$/); }); it('should close the editor when closeOnExternalRowChange is true or undefined and row is changed from outside', async () => { diff --git a/test/browser/column/renderHeaderCell.test.tsx b/test/browser/column/renderHeaderCell.test.tsx index e7ad327e99..91ffe3d080 100644 --- a/test/browser/column/renderHeaderCell.test.tsx +++ b/test/browser/column/renderHeaderCell.test.tsx @@ -16,6 +16,6 @@ test('renderHeaderCell is either undefined or a component', async () => { await setup({ columns, rows: [] }); const [cell1, cell2] = getHeaderCells(); - expect(cell1).toHaveTextContent('ID'); - expect(cell2).toHaveTextContent('Fancy! Name'); + await expect.element(cell1).toHaveTextContent('ID'); + await expect.element(cell2).toHaveTextContent('Fancy! Name'); }); diff --git a/test/browser/column/renderSummaryCell.test.tsx b/test/browser/column/renderSummaryCell.test.tsx index ed40ce23bd..b6a374747e 100644 --- a/test/browser/column/renderSummaryCell.test.tsx +++ b/test/browser/column/renderSummaryCell.test.tsx @@ -37,13 +37,13 @@ test('renderSummaryCell', async () => { const cells = getCells(); expect(cells).toHaveLength(8); - expect(cells[0]).toHaveTextContent('Summary: 1'); - expect(cells[2]).toHaveTextContent('Summary: 2'); - expect(cells[4]).toHaveTextContent('Summary: 3'); - expect(cells[6]).toHaveTextContent('Summary: 4'); + await expect.element(cells[0]).toHaveTextContent('Summary: 1'); + await expect.element(cells[2]).toHaveTextContent('Summary: 2'); + await expect.element(cells[4]).toHaveTextContent('Summary: 3'); + await expect.element(cells[6]).toHaveTextContent('Summary: 4'); // nothing is rendered when renderSummaryCell is not defined - expect(cells[1]).toBeEmptyDOMElement(); - expect(cells[3]).toBeEmptyDOMElement(); - expect(cells[5]).toBeEmptyDOMElement(); - expect(cells[7]).toBeEmptyDOMElement(); + await expect.element(cells[1]).toBeEmptyDOMElement(); + await expect.element(cells[3]).toBeEmptyDOMElement(); + await expect.element(cells[5]).toBeEmptyDOMElement(); + await expect.element(cells[7]).toBeEmptyDOMElement(); }); diff --git a/test/browser/column/resizable.test.tsx b/test/browser/column/resizable.test.tsx index 9a2f0ad385..914e8be388 100644 --- a/test/browser/column/resizable.test.tsx +++ b/test/browser/column/resizable.test.tsx @@ -323,14 +323,12 @@ test('should use columnWidths and onColumnWidthsChange props when provided', asy async function testGridTemplateColumns(chrome: string, firefox: string, firefoxCI = firefox) { const grid = getGrid(); - if (navigator.userAgent.includes('Chrome')) { - await expect.element(grid).toHaveStyle({ gridTemplateColumns: chrome }); - } else { - await vi.waitFor(() => { - expect((grid.element() as HTMLDivElement).style.gridTemplateColumns).toBeOneOf([ - firefox, - firefoxCI - ]); - }); - } + + const gridTemplateColumns = navigator.userAgent.includes('Chrome') + ? chrome + : __IS_CI__ + ? firefoxCI + : firefox; + + await expect.element(grid).toHaveStyle({ gridTemplateColumns }); } diff --git a/test/browser/column/summaryCellClass.test.ts b/test/browser/column/summaryCellClass.test.ts index cab3d9e7cb..45d433b679 100644 --- a/test/browser/column/summaryCellClass.test.ts +++ b/test/browser/column/summaryCellClass.test.ts @@ -20,8 +20,8 @@ test('summaryCellClass is undefined', async () => { ]; await setup({ columns, topSummaryRows, bottomSummaryRows, rows: [] }); const [cell1, cell2] = getCells(); - expect(cell1).toHaveClass(cellClassname, { exact: true }); - expect(cell2).toHaveClass(cellClassname, { exact: true }); + await expect.element(cell1).toHaveClass(cellClassname, { exact: true }); + await expect.element(cell2).toHaveClass(cellClassname, { exact: true }); }); test('summaryCellClass is a string', async () => { @@ -35,7 +35,7 @@ test('summaryCellClass is a string', async () => { await setup({ columns, topSummaryRows, bottomSummaryRows, rows: [] }); const cells = getCells(); for (const cell of cells) { - expect(cell).toHaveClass(`${cellClassname} my-cell`, { exact: true }); + await expect.element(cell).toHaveClass(`${cellClassname} my-cell`, { exact: true }); } }); @@ -49,10 +49,10 @@ test('summaryCellClass returns a string', async () => { ]; await setup({ columns, topSummaryRows, bottomSummaryRows, rows: [] }); const [cell1, cell2, cell3, cell4] = getCells(); - expect(cell1).toHaveClass(`${cellClassname} my-cell-0`, { exact: true }); - expect(cell2).toHaveClass(`${cellClassname} my-cell-1`, { exact: true }); - expect(cell3).toHaveClass(`${cellClassname} my-cell-2`, { exact: true }); - expect(cell4).toHaveClass(`${cellClassname} my-cell-3`, { exact: true }); + await expect.element(cell1).toHaveClass(`${cellClassname} my-cell-0`, { exact: true }); + await expect.element(cell2).toHaveClass(`${cellClassname} my-cell-1`, { exact: true }); + await expect.element(cell3).toHaveClass(`${cellClassname} my-cell-2`, { exact: true }); + await expect.element(cell4).toHaveClass(`${cellClassname} my-cell-3`, { exact: true }); }); test('summaryCellClass returns undefined', async () => { @@ -66,6 +66,6 @@ test('summaryCellClass returns undefined', async () => { await setup({ columns, topSummaryRows, bottomSummaryRows, rows: [] }); const cells = getCells(); for (const cell of cells) { - expect(cell).toHaveClass(cellClassname, { exact: true }); + await expect.element(cell).toHaveClass(cellClassname, { exact: true }); } }); diff --git a/test/browser/dragFill.test.tsx b/test/browser/dragFill.test.tsx index 6562d2a430..20bc601816 100644 --- a/test/browser/dragFill.test.tsx +++ b/test/browser/dragFill.test.tsx @@ -92,7 +92,7 @@ test('should focus the cell when drag handle is clicked', async () => { await setup(); await userEvent.click(getCellsAtRowIndex(0)[0]); await userEvent.click(document.body); - expect(document.body).toHaveFocus(); + await expect.element(document.body).toHaveFocus(); await userEvent.click(getDragHandle()!); await expect.element(getCellsAtRowIndex(0)[0]).toHaveFocus(); }); diff --git a/test/browser/keyboardNavigation.test.tsx b/test/browser/keyboardNavigation.test.tsx index 777bb0e280..437d3327fa 100644 --- a/test/browser/keyboardNavigation.test.tsx +++ b/test/browser/keyboardNavigation.test.tsx @@ -255,13 +255,12 @@ test('navigation when selected cell not in the viewport', async () => { await userEvent.keyboard('{Control>}{end}{/Control}{arrowup}{arrowup}'); await validateCellPosition(99, 100); - // TODO: replace with `toHaveLength` when migrating to v4 - await expect.poll(() => selectedRowCells.elements().length).not.toBe(1); + await expect.element(selectedRowCells).not.toHaveLength(1); await commands.scrollGrid({ scrollTop: 0 }); await testCount(selectedRowCells, 1); await userEvent.keyboard('{arrowup}'); await validateCellPosition(99, 99); - await expect.poll(() => selectedRowCells.elements().length).not.toBe(1); + await expect.element(selectedRowCells).not.toHaveLength(1); await commands.scrollGrid({ scrollLeft: 0 }); await userEvent.keyboard('{arrowdown}'); diff --git a/test/browser/utils.tsx b/test/browser/utils.tsx index 46e5dd7aa3..a2ce698997 100644 --- a/test/browser/utils.tsx +++ b/test/browser/utils.tsx @@ -132,7 +132,7 @@ export async function tabIntoGrid() { } export function testCount(locator: Locator, expectedCount: number) { - return expect.poll(() => locator.elements()).toHaveLength(expectedCount); + return expect.element(locator).toHaveLength(expectedCount); } export function testRowCount(expectedLength: number) { diff --git a/test/globals.d.ts b/test/globals.d.ts index cd36ff8344..7094f4cec4 100644 --- a/test/globals.d.ts +++ b/test/globals.d.ts @@ -1,3 +1,7 @@ +declare global { + const __IS_CI__: boolean; +} + declare module 'vitest/browser' { interface BrowserCommands { dragFill: (from: string, to: string) => Promise; diff --git a/test/visual/basicGrid.test.tsx b/test/visual/basicGrid.test.tsx index efba45aca8..5ecedcf1bf 100644 --- a/test/visual/basicGrid.test.tsx +++ b/test/visual/basicGrid.test.tsx @@ -50,5 +50,5 @@ test('basic grid', async () => { /> ); - await expect(getGrid()).toMatchScreenshot('basic-grid'); + await expect.element(getGrid()).toMatchScreenshot('basic-grid'); }); diff --git a/test/visual/treeGrid.test.tsx b/test/visual/treeGrid.test.tsx index 6b9c67840d..3b59b5893c 100644 --- a/test/visual/treeGrid.test.tsx +++ b/test/visual/treeGrid.test.tsx @@ -75,7 +75,7 @@ test('tree grid', async () => { /> ); - await expect(getTreeGrid()).toMatchScreenshot('tree-grid'); + await expect.element(getTreeGrid()).toMatchScreenshot('tree-grid'); }); function rowKeyGetter(row: Row) { diff --git a/vite.config.ts b/vite.config.ts index 5b68f9c73f..d4652ff0fa 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,7 +3,7 @@ import react from '@vitejs/plugin-react'; import { playwright } from '@vitest/browser-playwright'; import { ecij } from 'ecij/plugin'; import { defineConfig, type ViteUserConfig } from 'vitest/config'; -import type { BrowserCommand } from 'vitest/node'; +import type { BrowserCommand, BrowserInstanceOption } from 'vitest/node'; const isCI = process.env.CI === 'true'; const isTest = process.env.NODE_ENV === 'test'; @@ -63,6 +63,35 @@ const scrollGrid: BrowserCommand<[{ scrollLeft?: number; scrollTop?: number }]> const viewport = { width: 1920, height: 1080 } as const; +// vitest modifies the instance objects, so we cannot rely on static objects +function getInstances(): BrowserInstanceOption[] { + return [ + { + browser: 'chromium', + provider: playwright({ + actionTimeout: 1000, + contextOptions: { + viewport + }, + launchOptions: { + channel: 'chromium' + } + }) + }, + { + browser: 'firefox', + provider: playwright({ + actionTimeout: 1000, + contextOptions: { + viewport + } + }), + // TODO: remove when FF tests are stable + fileParallelism: false + } + ]; +} + export default defineConfig( ({ isPreview }): ViteUserConfig => ({ base: '/react-data-grid/', @@ -93,6 +122,7 @@ export default defineConfig( open: true }, test: { + dir: 'test', globals: true, coverage: { provider: 'istanbul', @@ -108,28 +138,19 @@ export default defineConfig( projects: [ { extends: true, + define: { + __IS_CI__: JSON.stringify(isCI) + }, test: { name: 'browser', - include: ['test/browser/**/*.test.*'], + include: ['browser/**/*.test.*'], browser: { ui: false, enabled: true, - provider: playwright({ - contextOptions: { - viewport - } - }), trace: { mode: isCI ? 'off' : 'retain-on-failure' }, - instances: [ - { browser: 'chromium' }, - { - browser: 'firefox', - // TODO: remove when FF tests are stable - fileParallelism: false - } - ], + instances: getInstances(), commands: { resizeColumn, dragFill, scrollGrid }, viewport, headless: true, @@ -142,15 +163,10 @@ export default defineConfig( extends: true, test: { name: 'visual', - include: ['test/visual/*.test.*'], + include: ['visual/*.test.*'], browser: { enabled: true, - provider: playwright({ - contextOptions: { - viewport - } - }), - instances: [{ browser: 'chromium' }, { browser: 'firefox' }], + instances: getInstances(), viewport, headless: true, screenshotFailures: false @@ -162,7 +178,7 @@ export default defineConfig( extends: true, test: { name: 'node', - include: ['test/node/**/*.test.*'], + include: ['node/**/*.test.*'], environment: 'node' } }