From 10b852559c9a1ae7aa12c760315ac4dda752598d Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 7 Mar 2026 00:01:39 +0000 Subject: [PATCH 1/5] Extend locators and expect further --- test/browser/column/renderEditCell.test.tsx | 8 ++-- test/browser/dragFill.test.tsx | 2 +- test/browser/keyboardNavigation.test.tsx | 16 +++----- test/browser/rowHeight.test.ts | 2 +- test/browser/utils.tsx | 10 +---- test/browser/virtualization.test.ts | 39 +++++++++--------- test/setupBrowser.ts | 45 +++++++++++++++++++++ 7 files changed, 77 insertions(+), 45 deletions(-) diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index d4aec74b95..e12ce76ef2 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -4,7 +4,7 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../../src'; import type { Column, DataGridProps } from '../../../src'; -import { getCellsAtRowIndex, getRowWithCell, safeTab, scrollGrid, testCount } from '../utils'; +import { getCellsAtRowIndex, getRowWithCell, safeTab, testCount } from '../utils'; const grid = page.getGrid(); @@ -98,7 +98,7 @@ describe('Editor', () => { await userEvent.click(getCellsAtRowIndex(0).nth(0)); const activeRowCells = getRowWithCell(page.getActiveCell()).getCell(); await testCount(activeRowCells, 2); - await scrollGrid({ top: 2001 }); + await grid.scroll({ top: 2001 }); await testCount(activeRowCells, 1); const editor = grid.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).not.toBeInTheDocument(); @@ -271,10 +271,10 @@ describe('Editor', () => { await userEvent.dblClick(page.getCell({ name: 'name0' })); await userEvent.keyboard('abc'); - await scrollGrid({ top: 1500 }); + await grid.scroll({ top: 1500 }); await userEvent.click(page.getCell({ name: 'name43' })); await expect.element(page.getActiveCell()).toHaveTextContent(/^name43$/); - await scrollGrid({ top: 0 }); + await grid.scroll({ top: 0 }); await expect.element(page.getCell({ name: 'name0abc' })).toBeVisible(); }); diff --git a/test/browser/dragFill.test.tsx b/test/browser/dragFill.test.tsx index 16b125b353..c60c370128 100644 --- a/test/browser/dragFill.test.tsx +++ b/test/browser/dragFill.test.tsx @@ -93,7 +93,7 @@ test('should focus the cell when drag handle is clicked', async () => { await userEvent.click(cell); await expect.element(cell).toHaveFocus(); - cell.element().blur(); + cell.blur(); await expect.element(cell).not.toHaveFocus(); await userEvent.click(dragHandle); diff --git a/test/browser/keyboardNavigation.test.tsx b/test/browser/keyboardNavigation.test.tsx index 46806e1f4d..8624303ea4 100644 --- a/test/browser/keyboardNavigation.test.tsx +++ b/test/browser/keyboardNavigation.test.tsx @@ -2,15 +2,9 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid, SelectColumn } from '../../src'; import type { Column } from '../../src'; -import { - getRowWithCell, - safeTab, - scrollGrid, - setup, - testCount, - validateCellPosition -} from './utils'; +import { getRowWithCell, safeTab, setup, testCount, validateCellPosition } from './utils'; +const grid = page.getGrid(); const activeCell = page.getActiveCell(); const activeSelectAllCheckbox = activeCell.getSelectAllCheckbox(); const activeSelectCheckbox = activeCell.getByRole('checkbox', { name: 'Select', exact: true }); @@ -279,13 +273,13 @@ test('navigation when active cell not in the viewport', async () => { await userEvent.keyboard('{Control>}{end}{/Control}{arrowup}{arrowup}'); await validateCellPosition(99, 100); await expect.element(activeRowCells).not.toHaveLength(1); - await scrollGrid({ top: 0 }); + await grid.scroll({ top: 0 }); await testCount(activeRowCells, 1); await userEvent.keyboard('{arrowup}'); await validateCellPosition(99, 99); await expect.element(activeRowCells).not.toHaveLength(1); - await scrollGrid({ left: 0 }); + await grid.scroll({ left: 0 }); await userEvent.keyboard('{arrowdown}'); await validateCellPosition(99, 100); @@ -293,7 +287,7 @@ test('navigation when active cell not in the viewport', async () => { '{home}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}' ); await validateCellPosition(7, 100); - await scrollGrid({ left: 2000 }); + await grid.scroll({ left: 2000 }); await userEvent.keyboard('{arrowleft}'); await validateCellPosition(6, 100); }); diff --git a/test/browser/rowHeight.test.ts b/test/browser/rowHeight.test.ts index 5ed9647509..700bc5371a 100644 --- a/test/browser/rowHeight.test.ts +++ b/test/browser/rowHeight.test.ts @@ -35,7 +35,7 @@ test('rowHeight is number', async () => { gridTemplateRows: '40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px' }); - await testRowCount(30); + await expect.element(grid).toHaveRowsCount(30); await safeTab(); await expect.element(grid).toHaveProperty('scrollTop', 0); await userEvent.keyboard('{Control>}{end}'); diff --git a/test/browser/utils.tsx b/test/browser/utils.tsx index 0b4558ef72..26717ea26c 100644 --- a/test/browser/utils.tsx +++ b/test/browser/utils.tsx @@ -8,7 +8,7 @@ export function setup(props: DataGridPro } export function getRowWithCell(cell: Locator) { - return page.getRow().filter({ has: cell }); + return page.getRow({ has: cell }); } export function getCellsAtRowIndex(rowIdx: number) { @@ -25,14 +25,6 @@ export async function validateCellPosition(columnIdx: number, rowIdx: number) { await expect.element(row).toHaveAttribute('aria-rowindex', `${rowIdx + 1}`); } -export async function scrollGrid(options: ScrollToOptions) { - await new Promise((resolve) => { - const gridElement = page.getGrid().element() as HTMLElement; - gridElement.addEventListener('scrollend', resolve, { once: true }); - gridElement.scroll(options); - }); -} - export function testCount(locator: Locator, expectedCount: number) { return expect.element(locator).toHaveLength(expectedCount); } diff --git a/test/browser/virtualization.test.ts b/test/browser/virtualization.test.ts index 70529a94c4..bf2db89edf 100644 --- a/test/browser/virtualization.test.ts +++ b/test/browser/virtualization.test.ts @@ -1,8 +1,9 @@ import { page, type Locator } from 'vitest/browser'; import type { Column } from '../../src'; -import { getCellsAtRowIndex, scrollGrid, setup } from './utils'; +import { getCellsAtRowIndex, setup } from './utils'; +const grid = page.getGrid(); const headerCells = page.getHeaderCell(); const rows = page.getRow(); const cells = page.getCell(); @@ -102,50 +103,50 @@ test('virtualization is enabled', async () => { await assertHeaderCells(18, 0, 17); await assertRows(34, 0, 33); await assertCells(0, 18, 0, 17); - await scrollGrid({ top: 244 }); + await grid.scroll({ top: 244 }); await assertRows(39, 2, 40); - await scrollGrid({ top: 245 }); + await grid.scroll({ top: 245 }); await assertRows(38, 3, 40); - await scrollGrid({ top: 419 }); + await grid.scroll({ top: 419 }); await assertRows(39, 7, 45); - await scrollGrid({ top: 420 }); + await grid.scroll({ top: 420 }); await assertRows(38, 8, 45); - await scrollGrid({ top: 524 }); + await grid.scroll({ top: 524 }); await assertRows(39, 10, 48); - await scrollGrid({ top: 525 }); + await grid.scroll({ top: 525 }); await assertRows(38, 11, 48); - await scrollGrid({ top: 1000 }); + await grid.scroll({ top: 1000 }); await assertRows(39, 24, 62); // scroll height = header height + row height * row count // max top = scroll height - grid height - await scrollGrid({ top: rowHeight + rowHeight * 100 - 1080 }); + await grid.scroll({ top: rowHeight + rowHeight * 100 - 1080 }); await assertRows(34, 66, 99); - await scrollGrid({ left: 92 }); + await grid.scroll({ left: 92 }); await assertHeaderCells(18, 0, 17); await assertCells(66, 18, 0, 17); - await scrollGrid({ left: 93 }); + await grid.scroll({ left: 93 }); await assertHeaderCells(19, 0, 18); await assertCells(66, 19, 0, 18); - await scrollGrid({ left: 209 }); + await grid.scroll({ left: 209 }); await assertHeaderCells(19, 0, 18); await assertCells(66, 19, 0, 18); - await scrollGrid({ left: 210 }); + await grid.scroll({ left: 210 }); await assertHeaderCells(18, 1, 18); await assertCells(66, 18, 1, 18); // max left = row width - grid width - await scrollGrid({ left: 3600 - 1920 }); + await grid.scroll({ left: 3600 - 1920 }); await assertHeaderCells(17, 13, 29); await assertCells(66, 17, 13, 29); }); @@ -157,13 +158,13 @@ test('virtualization is enabled with 4 frozen columns', async () => { await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); - await scrollGrid({ left: 1000 }); + await grid.scroll({ left: 1000 }); indexes = [0, 1, 2, 3, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]; await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); // max left = row width - grid width - await scrollGrid({ left: 3600 - 1920 }); + await grid.scroll({ left: 3600 - 1920 }); indexes = [0, 1, 2, 3, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]; await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); @@ -179,12 +180,12 @@ test('virtualization is enabled with all columns frozen', async () => { await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); - await scrollGrid({ left: 1000 }); + await grid.scroll({ left: 1000 }); await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); // max left = row width - grid width - await scrollGrid({ left: 3600 - 1920 }); + await grid.scroll({ left: 3600 - 1920 }); await assertHeaderCellIndexes(indexes); await assertCellIndexes(0, indexes); }); @@ -197,7 +198,7 @@ test('virtualization is enabled with 2 summary rows', async () => { 26, 27, 28, 29, 30, 31, 102, 103 ]); - await scrollGrid({ top: 1000 }); + await grid.scroll({ top: 1000 }); await assertRowIndexes([ 0, 1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 102, 103 diff --git a/test/setupBrowser.ts b/test/setupBrowser.ts index f02b875252..f9c985b27d 100644 --- a/test/setupBrowser.ts +++ b/test/setupBrowser.ts @@ -21,6 +21,8 @@ declare module 'vitest/browser' { getActiveCell: () => Locator; getDragHandle: () => Locator; getBySelector: (selector: string) => Locator; + scroll: (this: Locator, options: ScrollToOptions) => Promise; + blur: (this: Locator) => void; } } @@ -65,6 +67,18 @@ locators.extend({ getBySelector(selector: string) { return selector; + }, + + async scroll(options: ScrollToOptions) { + await new Promise((resolve) => { + const element = (this as Locator).element(); + element.addEventListener('scrollend', resolve, { once: true }); + element.scroll(options); + }); + }, + + blur() { + (this as Locator).element().blur(); } }); @@ -81,6 +95,37 @@ function defaultToExactOpts( return opts; } +interface CustomMatchers { + toHaveRowsCount: (rowsCount: number) => R; +} + +declare module 'vitest' { + // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-explicit-any + interface Matchers extends CustomMatchers {} +} + +expect.extend({ + toHaveRowsCount(grid: HTMLElement, expected) { + if (!grid.matches('.rdg')) { + return { + pass: false, + message: () => 'expected element to be a grid' + }; + } + + const allRowsCount = Number(grid.getAttribute('aria-rowcount')); + const otherRowsCount = grid.querySelectorAll( + ':scope > :is(.rdg-header-row, .rdg-summary-row)' + ).length; + const count = allRowsCount - otherRowsCount; + + return { + pass: count === expected, + message: () => `expected ${count} to have row count ${expected}` + }; + } +}); + beforeEach(async () => { // 1. reset cursor position to avoid hover issues // 2. force focus to be on the page From 0eb8de006d60b8c8a3f1cce4afe319dd7d0961ec Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 7 Mar 2026 02:41:32 +0000 Subject: [PATCH 2/5] Move test utilities to custom locators and matchers - Add custom locators: getSummaryRow, getRowWithCell, getCellsAtRowIndex - Add custom matcher: toHaveCellPosition - Replace validateCellPosition, getCellsAtRowIndex, getRowWithCell, testCount utility functions with locators/matchers across all test files - Keep testRowCount in utils for virtualized grid tests Co-Authored-By: Claude Opus 4.6 --- test/browser/TreeDataGrid.test.tsx | 81 +++++++------- test/browser/column/colSpan.test.ts | 100 ++++++++--------- test/browser/column/grouping.test.ts | 88 +++++++-------- test/browser/column/renderCell.test.tsx | 4 +- test/browser/column/renderEditCell.test.tsx | 78 ++++++------- test/browser/columnOrder.test.tsx | 3 +- test/browser/copyPaste.test.tsx | 12 +- test/browser/dragFill.test.tsx | 35 +++--- test/browser/keyboardNavigation.test.tsx | 118 ++++++++++---------- test/browser/renderers.test.tsx | 30 ++--- test/browser/utils.tsx | 26 +---- test/browser/virtualization.test.ts | 6 +- test/setupBrowser.ts | 32 ++++++ 13 files changed, 311 insertions(+), 302 deletions(-) diff --git a/test/browser/TreeDataGrid.test.tsx b/test/browser/TreeDataGrid.test.tsx index 8588f7c0c6..9a0a901f41 100644 --- a/test/browser/TreeDataGrid.test.tsx +++ b/test/browser/TreeDataGrid.test.tsx @@ -4,7 +4,6 @@ import { page, userEvent } from 'vitest/browser'; import type { Column } from '../../src'; import { renderTextEditor, SelectColumn, TreeDataGrid } from '../../src'; import { rowActiveClassname } from '../../src/style/row'; -import { getCellsAtRowIndex, getRowWithCell, testCount, testRowCount } from './utils'; const treeGrid = page.getTreeGrid(); const headerRow = treeGrid.getHeaderRow(); @@ -132,7 +131,7 @@ function setup(groupBy: string[], groupIdGetter?: (groupKey: string, parentId?: } async function testHeaderCellsContent(expected: readonly string[]) { - await testCount(headerCells, expected.length); + await expect.element(headerCells).toHaveLength(expected.length); for (const [n, text] of expected.entries()) { await expect.element(headerCells.nth(n)).toHaveTextContent(text); @@ -143,27 +142,27 @@ test('should not group if groupBy is empty', async () => { await setup([]); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '7'); await testHeaderCellsContent(['', 'Sport', 'Country', 'Year', 'Id']); - await testRowCount(6); + await expect.element(rows).toHaveLength(6); }); test('should not group if column does not exist', async () => { await setup(['abc']); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '7'); - await testRowCount(6); + await expect.element(rows).toHaveLength(6); }); test('should group by single column', async () => { await setup(['country']); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '9'); await testHeaderCellsContent(['', 'Country', 'Sport', 'Year', 'Id']); - await testRowCount(4); + await expect.element(rows).toHaveLength(4); }); test('should group by multiple columns', async () => { await setup(['country', 'year']); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '13'); await testHeaderCellsContent(['', 'Country', 'Year', 'Sport', 'Id']); - await testRowCount(4); + await expect.element(rows).toHaveLength(4); }); test('should use groupIdGetter when provided', async () => { @@ -174,60 +173,60 @@ test('should use groupIdGetter when provided', async () => { expect(groupIdGetter).toHaveBeenCalled(); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '13'); await testHeaderCellsContent(['', 'Country', 'Year', 'Sport', 'Id']); - await testRowCount(4); + await expect.element(rows).toHaveLength(4); groupIdGetter.mockClear(); await userEvent.click(page.getCell({ name: 'USA' })); - await testRowCount(6); + await expect.element(rows).toHaveLength(6); expect(groupIdGetter).toHaveBeenCalled(); await userEvent.click(page.getCell({ name: 'Canada' })); - await testRowCount(8); + await expect.element(rows).toHaveLength(8); await userEvent.click(page.getCell({ name: '2020' })); - await testRowCount(9); + await expect.element(rows).toHaveLength(9); }); test('should ignore duplicate groupBy columns', async () => { await setup(['year', 'year', 'year']); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '10'); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); }); test('should use groupBy order while grouping', async () => { await setup(['year', 'country']); await expect.element(treeGrid).toHaveAttribute('aria-rowcount', '14'); await testHeaderCellsContent(['', 'Year', 'Country', 'Sport', 'Id']); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); }); test('should toggle group when group cell is clicked', async () => { await setup(['year']); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); const groupCell = page.getCell({ name: '2021' }); await userEvent.click(groupCell); - await testRowCount(7); + await expect.element(rows).toHaveLength(7); await userEvent.click(groupCell); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); }); test('should toggle group using keyboard', async () => { await setup(['year']); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); const groupCell = page.getCell({ name: '2021' }); await userEvent.click(groupCell); - await testRowCount(7); + await expect.element(rows).toHaveLength(7); // clicking on the group cell focuses the row await expect.element(activeCell).not.toBeInTheDocument(); - await expect.element(getRowWithCell(groupCell)).toHaveClass(rowActiveClassname); + await expect.element(page.getRowWithCell(groupCell)).toHaveClass(rowActiveClassname); await userEvent.keyboard('{arrowright}{arrowright}{enter}'); - await testRowCount(5); + await expect.element(rows).toHaveLength(5); await userEvent.keyboard('{enter}'); - await testRowCount(7); + await expect.element(rows).toHaveLength(7); }); test('should set aria-attributes', async () => { await setup(['year', 'country']); const groupCell1 = page.getCell({ name: '2020' }); - const groupRow1 = getRowWithCell(groupCell1); + const groupRow1 = page.getRowWithCell(groupCell1); await expect.element(groupRow1).toHaveAttribute('aria-level', '1'); await expect.element(groupRow1).toHaveAttribute('aria-setsize', '3'); await expect.element(groupRow1).toHaveAttribute('aria-posinset', '1'); @@ -235,7 +234,7 @@ test('should set aria-attributes', async () => { await expect.element(groupRow1).toHaveAttribute('aria-expanded', 'false'); const groupCell2 = page.getCell({ name: '2021' }); - const groupRow2 = getRowWithCell(groupCell2); + const groupRow2 = page.getRowWithCell(groupCell2); await expect.element(groupRow2).toHaveAttribute('aria-level', '1'); await expect.element(groupRow2).toHaveAttribute('aria-setsize', '3'); await expect.element(groupRow2).toHaveAttribute('aria-posinset', '2'); @@ -246,7 +245,7 @@ test('should set aria-attributes', async () => { await expect.element(groupRow2).toHaveAttribute('aria-expanded', 'true'); const groupCell3 = page.getCell({ name: 'Canada' }); - const groupRow3 = getRowWithCell(groupCell3); + const groupRow3 = page.getRowWithCell(groupCell3); await expect.element(groupRow3).toHaveAttribute('aria-level', '2'); await expect.element(groupRow3).toHaveAttribute('aria-setsize', '2'); await expect.element(groupRow3).toHaveAttribute('aria-posinset', '2'); @@ -269,11 +268,11 @@ test('should select rows in a group', async () => { await userEvent.click(groupCell2); const selectedRows = page.getRow({ selected: true }); - await testCount(selectedRows, 0); + await expect.element(selectedRows).toHaveLength(0); // select parent row - await userEvent.click(getRowWithCell(groupCell1).getByRole('checkbox', { name: 'Select Group' })); - await testCount(selectedRows, 4); + await userEvent.click(page.getRowWithCell(groupCell1).getByRole('checkbox', { name: 'Select Group' })); + await expect.element(selectedRows).toHaveLength(4); await expect.element(selectedRows.nth(0)).toHaveAttribute('aria-rowindex', '6'); await expect.element(selectedRows.nth(1)).toHaveAttribute('aria-rowindex', '7'); await expect.element(selectedRows.nth(2)).toHaveAttribute('aria-rowindex', '9'); @@ -281,36 +280,36 @@ test('should select rows in a group', async () => { // unselecting child should unselect the parent row await userEvent.click(selectedRows.nth(3).getByRole('checkbox', { name: 'Select' })); - await testCount(selectedRows, 1); + await expect.element(selectedRows).toHaveLength(1); await expect.element(selectedRows.nth(0)).toHaveAttribute('aria-rowindex', '7'); // select child group - const checkbox = getRowWithCell(groupCell2).getByRole('checkbox', { + const checkbox = page.getRowWithCell(groupCell2).getByRole('checkbox', { name: 'Select Group' }); await userEvent.click(checkbox); - await testCount(selectedRows, 4); + await expect.element(selectedRows).toHaveLength(4); // unselect child group await userEvent.click(checkbox); - await testCount(selectedRows, 1); + await expect.element(selectedRows).toHaveLength(1); await userEvent.click(page.getCell({ name: '2020' })); await userEvent.click(page.getCell({ name: '2022' })); await userEvent.click(headerCheckbox); - await testCount(selectedRows, 0); + await expect.element(selectedRows).toHaveLength(0); await userEvent.click(headerCheckbox); - await testCount(selectedRows, 8); + await expect.element(selectedRows).toHaveLength(8); await userEvent.click(headerCheckbox); - await testCount(selectedRows, 0); + await expect.element(selectedRows).toHaveLength(0); }); test('cell navigation in a treegrid', async () => { await setup(['country', 'year']); - await testRowCount(4); + await expect.element(rows).toHaveLength(4); const topSummaryRow = rows.nth(0); const row1 = rows.nth(1); @@ -361,7 +360,7 @@ test('cell navigation in a treegrid', async () => { await expect.element(row3).toHaveAttribute('tabIndex', '0'); // focus cell - const cells = getCellsAtRowIndex(5); + const cells = page.getCellsAtRowIndex(5); await userEvent.click(cells.nth(1)); await expect.element(cells.nth(1)).toHaveAttribute('aria-selected', 'true'); await expect.element(cells.nth(1)).toHaveFocus(); @@ -384,15 +383,15 @@ test('cell navigation in a treegrid', async () => { await userEvent.keyboard('{arrowleft}{arrowup}'); - await testRowCount(7); + await expect.element(rows).toHaveLength(7); // left arrow should collapse the group await userEvent.keyboard('{arrowleft}'); - await testRowCount(6); + await expect.element(rows).toHaveLength(6); // right arrow should expand the group await userEvent.keyboard('{arrowright}'); - await testRowCount(7); + await expect.element(rows).toHaveLength(7); // left arrow on a collapsed group should focus the parent group await expect.element(rows.nth(1)).not.toHaveClass(rowActiveClassname); @@ -410,7 +409,7 @@ test('cell navigation in a treegrid', async () => { // collapse parent group await userEvent.keyboard('{arrowdown}{arrowdown}{arrowleft}{arrowleft}'); await expect.element(page.getCell({ name: '2021' })).not.toBeInTheDocument(); - await testRowCount(4); + await expect.element(rows).toHaveLength(4); }); test('copy/paste when grouping is enabled', async () => { @@ -462,6 +461,6 @@ test('custom renderGroupCell', async () => { await setup(['country']); const usaCell = page.getCell({ name: 'USA' }); const canadaCell = page.getCell({ name: 'Canada' }); - await expect.element(getRowWithCell(usaCell).getCell().nth(4)).toHaveTextContent('1'); - await expect.element(getRowWithCell(canadaCell).getCell().nth(4)).toHaveTextContent('3'); + await expect.element(page.getRowWithCell(usaCell).getCell().nth(4)).toHaveTextContent('1'); + await expect.element(page.getRowWithCell(canadaCell).getCell().nth(4)).toHaveTextContent('3'); }); diff --git a/test/browser/column/colSpan.test.ts b/test/browser/column/colSpan.test.ts index 758722742f..82b0251cc8 100644 --- a/test/browser/column/colSpan.test.ts +++ b/test/browser/column/colSpan.test.ts @@ -1,7 +1,7 @@ import { page, userEvent } from 'vitest/browser'; import type { Column } from '../../../src'; -import { getCellsAtRowIndex, safeTab, setup, validateCellPosition } from '../utils'; +import { safeTab, setup } from '../utils'; const headerCells = page.getHeaderCell(); @@ -45,7 +45,7 @@ describe('colSpan', () => { await expect.element(headerCells).toHaveLength(13); // top summary rows - const topSummarryRow1 = getCellsAtRowIndex(0); + const topSummarryRow1 = page.getCellsAtRowIndex(0); await expect.element(topSummarryRow1).toHaveLength(14); // 7th-8th cells are merged await expect.element(topSummarryRow1.nth(7)).toHaveAttribute('aria-colindex', '8'); @@ -54,10 +54,10 @@ describe('colSpan', () => { gridColumnStart: '8', gridColumnEnd: '10' }); - await expect.element(getCellsAtRowIndex(1)).toHaveLength(15); + await expect.element(page.getCellsAtRowIndex(1)).toHaveLength(15); // rows - const row1 = getCellsAtRowIndex(3); + const row1 = page.getCellsAtRowIndex(3); await expect.element(row1).toHaveLength(14); // 7th-8th cells are merged await expect.element(row1.nth(6)).toHaveAttribute('aria-colindex', '7'); @@ -70,7 +70,7 @@ describe('colSpan', () => { await expect.element(row1.nth(7)).not.toHaveAttribute('aria-colspan'); // 3rd-5th, 7th-8th cells are merged - const row2 = getCellsAtRowIndex(4); + const row2 = page.getCellsAtRowIndex(4); await expect.element(row2).toHaveLength(12); await expect.element(row2.nth(2)).toHaveAttribute('aria-colindex', '3'); await expect.element(row2.nth(2)).toHaveStyle({ @@ -86,95 +86,95 @@ describe('colSpan', () => { }); await expect.element(row2.nth(5)).toHaveAttribute('aria-colindex', '9'); - await expect.element(getCellsAtRowIndex(6)).toHaveLength(14); // colSpan 6 won't work as there are 5 frozen columns - await expect.element(getCellsAtRowIndex(7)).toHaveLength(10); + await expect.element(page.getCellsAtRowIndex(6)).toHaveLength(14); // colSpan 6 won't work as there are 5 frozen columns + await expect.element(page.getCellsAtRowIndex(7)).toHaveLength(10); // bottom summary row - await expect.element(getCellsAtRowIndex(12)).toHaveLength(14); - await expect.element(getCellsAtRowIndex(13)).toHaveLength(15); + await expect.element(page.getCellsAtRowIndex(12)).toHaveLength(14); + await expect.element(page.getCellsAtRowIndex(13)).toHaveLength(15); }); it('should navigate between merged cells', async () => { await setupColSpan(); // header row await userEvent.click(headerCells.nth(7)); - await validateCellPosition(7, 0); + await expect.element(page.getActiveCell()).toHaveCellPosition(7, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(8, 0); + await expect.element(page.getActiveCell()).toHaveCellPosition(8, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(11, 0); + await expect.element(page.getActiveCell()).toHaveCellPosition(11, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(12, 0); + await expect.element(page.getActiveCell()).toHaveCellPosition(12, 0); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await validateCellPosition(7, 0); + await expect.element(page.getActiveCell()).toHaveCellPosition(7, 0); // top summary rows - await userEvent.click(getCellsAtRowIndex(0).nth(6)); - await validateCellPosition(6, 1); + await userEvent.click(page.getCellsAtRowIndex(0).nth(6)); + await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(7, 1); + await expect.element(page.getActiveCell()).toHaveCellPosition(7, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(9, 1); + await expect.element(page.getActiveCell()).toHaveCellPosition(9, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(10, 1); + await expect.element(page.getActiveCell()).toHaveCellPosition(10, 1); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await validateCellPosition(6, 1); + await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); // viewport rows - await userEvent.click(getCellsAtRowIndex(3).nth(1)); - await validateCellPosition(1, 4); + await userEvent.click(page.getCellsAtRowIndex(3).nth(1)); + await expect.element(page.getActiveCell()).toHaveCellPosition(1, 4); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(2, 4); + await expect.element(page.getActiveCell()).toHaveCellPosition(2, 4); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(3, 4); + await expect.element(page.getActiveCell()).toHaveCellPosition(3, 4); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(2, 5); + await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(1, 5); + await expect.element(page.getActiveCell()).toHaveCellPosition(1, 5); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(2, 5); + await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(5, 5); + await expect.element(page.getActiveCell()).toHaveCellPosition(5, 5); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(2, 5); + await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(2, 6); + await expect.element(page.getActiveCell()).toHaveCellPosition(2, 6); await userEvent.keyboard('{arrowdown}{arrowdown}'); - await validateCellPosition(0, 8); + await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); await userEvent.keyboard('{arrowLeft}'); - await validateCellPosition(0, 8); + await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(5, 8); + await expect.element(page.getActiveCell()).toHaveCellPosition(5, 8); await safeTab(true); await safeTab(true); - await validateCellPosition(14, 7); + await expect.element(page.getActiveCell()).toHaveCellPosition(14, 7); await safeTab(); - await validateCellPosition(0, 8); - await userEvent.click(getCellsAtRowIndex(10).nth(11)); - await validateCellPosition(11, 11); + await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); + await userEvent.click(page.getCellsAtRowIndex(10).nth(11)); + await expect.element(page.getActiveCell()).toHaveCellPosition(11, 11); await safeTab(); - await validateCellPosition(12, 11); + await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); await safeTab(); - await validateCellPosition(0, 12); + await expect.element(page.getActiveCell()).toHaveCellPosition(0, 12); await safeTab(true); - await validateCellPosition(12, 11); + await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); // bottom summary rows - await userEvent.click(getCellsAtRowIndex(12).nth(6)); - await validateCellPosition(6, 13); + await userEvent.click(page.getCellsAtRowIndex(12).nth(6)); + await expect.element(page.getActiveCell()).toHaveCellPosition(6, 13); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(7, 13); + await expect.element(page.getActiveCell()).toHaveCellPosition(7, 13); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(9, 13); + await expect.element(page.getActiveCell()).toHaveCellPosition(9, 13); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(10, 13); + await expect.element(page.getActiveCell()).toHaveCellPosition(10, 13); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await validateCellPosition(6, 13); + await expect.element(page.getActiveCell()).toHaveCellPosition(6, 13); }); it('should scroll to the merged cell when selected', async () => { await setupColSpan(30); - await userEvent.click(getCellsAtRowIndex(10).nth(23)); // last visible cell (1920/80) + await userEvent.click(page.getCellsAtRowIndex(10).nth(23)); // last visible cell (1920/80) const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView'); const testScrollIntoView = () => { expect(spy).toHaveBeenCalled(); @@ -184,13 +184,13 @@ describe('colSpan', () => { testScrollIntoView(); await navigate(1); testScrollIntoView(); // should bring the merged cell into view - await validateCellPosition(27, 11); + await expect.element(page.getActiveCell()).toHaveCellPosition(27, 11); await navigate(7); testScrollIntoView(); - await validateCellPosition(6, 12); // should navigate to the next row + await expect.element(page.getActiveCell()).toHaveCellPosition(6, 12); // should navigate to the next row await navigate(7, true); testScrollIntoView(); - await validateCellPosition(27, 11); // should navigate to the previous row + await expect.element(page.getActiveCell()).toHaveCellPosition(27, 11); // should navigate to the previous row await navigate(27); testScrollIntoView(); await navigate(1); diff --git a/test/browser/column/grouping.test.ts b/test/browser/column/grouping.test.ts index e86b552666..bb1468a384 100644 --- a/test/browser/column/grouping.test.ts +++ b/test/browser/column/grouping.test.ts @@ -1,7 +1,7 @@ import { page, userEvent } from 'vitest/browser'; import type { ColumnOrColumnGroup } from '../../../src'; -import { safeTab, setup, testCount, validateCellPosition } from '../utils'; +import { safeTab, setup } from '../utils'; const grid = page.getGrid(); const headerRows = grid.getHeaderRow(); @@ -97,19 +97,19 @@ test('grouping', async () => { await expect.element(grid).toHaveAttribute('aria-colcount', '12'); await expect.element(grid).toHaveAttribute('aria-rowcount', '5'); - await testCount(headerRows, 4); + await expect.element(headerRows).toHaveLength(4); await expect.element(headerRows.nth(0)).toHaveAttribute('aria-rowindex', '1'); await expect.element(headerRows.nth(1)).toHaveAttribute('aria-rowindex', '2'); await expect.element(headerRows.nth(2)).toHaveAttribute('aria-rowindex', '3'); await expect.element(headerRows.nth(3)).toHaveAttribute('aria-rowindex', '4'); - await testCount(headerRows.nth(0).getHeaderCell(), 2); - await testCount(headerRows.nth(1).getHeaderCell(), 2); - await testCount(headerRows.nth(2).getHeaderCell(), 4); - await testCount(headerRows.nth(3).getHeaderCell(), 12); + await expect.element(headerRows.nth(0).getHeaderCell()).toHaveLength(2); + await expect.element(headerRows.nth(1).getHeaderCell()).toHaveLength(2); + await expect.element(headerRows.nth(2).getHeaderCell()).toHaveLength(4); + await expect.element(headerRows.nth(3).getHeaderCell()).toHaveLength(12); - await testCount(headerCells, 20); + await expect.element(headerCells).toHaveLength(20); const expected = [ { @@ -234,7 +234,7 @@ test('grouping', async () => { } ] as const; - await testCount(headerCells, expected.length); + await expect.element(headerCells).toHaveLength(expected.length); for (const [n, item] of expected.entries()) { const cell = headerCells.nth(n); @@ -258,86 +258,86 @@ test('keyboard navigation', async () => { await expect.element(grid.getActiveCell()).not.toBeInTheDocument(); await safeTab(); - await validateCellPosition(0, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(0, 3); // arrow navigation await userEvent.keyboard('{arrowup}'); - await validateCellPosition(0, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(0, 3); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(1, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(1, 3); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(1, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(1, 2); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(1, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(1, 2); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(0, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(0, 3); await userEvent.keyboard('{arrowright}{arrowright}'); - await validateCellPosition(2, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(2, 3); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(1, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(1, 2); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(1, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(1, 3); await userEvent.keyboard('{arrowright}{arrowright}'); - await validateCellPosition(3, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(3, 3); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(4, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 3); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(4, 4); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 4); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 3); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 2); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 1); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 1); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 0); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(4, 1); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(5, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(5, 3); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(4, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 3); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 2); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(5, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(5, 3); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(6, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(6, 3); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(7, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(7, 3); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(7, 2); + await expect.element(grid.getActiveCell()).toHaveCellPosition(7, 2); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(4, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(8, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(8, 0); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(4, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 0); // home/end navigation await userEvent.keyboard('{home}'); - await validateCellPosition(0, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(0, 3); await userEvent.keyboard('{end}'); - await validateCellPosition(11, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(11, 3); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(10, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(10, 3); // tab navigation await safeTab(); - await validateCellPosition(11, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(11, 3); await safeTab(true); await safeTab(true); await safeTab(true); - await validateCellPosition(8, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(8, 3); await userEvent.keyboard('{arrowup}'); await safeTab(true); - await validateCellPosition(4, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(4, 0); await safeTab(); - await validateCellPosition(8, 0); + await expect.element(grid.getActiveCell()).toHaveCellPosition(8, 0); await userEvent.keyboard('{home}{end}'); await safeTab(); - await validateCellPosition(0, 4); + await expect.element(grid.getActiveCell()).toHaveCellPosition(0, 4); await safeTab(true); - await validateCellPosition(11, 3); + await expect.element(grid.getActiveCell()).toHaveCellPosition(11, 3); }); diff --git a/test/browser/column/renderCell.test.tsx b/test/browser/column/renderCell.test.tsx index d0bdaf7ff1..02972da49e 100644 --- a/test/browser/column/renderCell.test.tsx +++ b/test/browser/column/renderCell.test.tsx @@ -4,7 +4,7 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../../src'; import type { Column } from '../../../src'; import defaultRenderHeaderCell from '../../../src/renderHeaderCell'; -import { getCellsAtRowIndex, safeTab, setup } from '../utils'; +import { safeTab, setup } from '../utils'; const cells = page.getCell(); @@ -191,7 +191,7 @@ test('Cell should not steal focus when the focus is outside the grid and cell is await page.render(); - const cell = getCellsAtRowIndex(0).nth(0); + const cell = page.getCellsAtRowIndex(0).nth(0); await userEvent.click(cell); await expect.element(cell).toHaveFocus(); diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index e12ce76ef2..5bb81d707a 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -4,7 +4,7 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../../src'; import type { Column, DataGridProps } from '../../../src'; -import { getCellsAtRowIndex, getRowWithCell, safeTab, testCount } from '../utils'; +import { safeTab } from '../utils'; const grid = page.getGrid(); @@ -17,63 +17,63 @@ describe('Editor', () => { it('should open editor on double click', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); await expect.element(editor).not.toBeInTheDocument(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2'); await safeTab(); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12$/); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12$/); }); it('should open and commit changes on enter', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); await expect.element(editor).not.toBeInTheDocument(); await userEvent.keyboard('{enter}'); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('3{enter}'); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^13$/); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^13$/); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); await expect.element(editor).not.toBeInTheDocument(); }); it('should open editor when user types', async () => { await page.render(); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); // TODO: await userEvent.keyboard('123{enter}'); fails in FF await userEvent.keyboard('{enter}123{enter}'); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1123$/); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1123$/); }); it('should close editor and discard changes on escape', async () => { await page.render(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222{escape}'); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1$/); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1$/); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); }); it('should commit changes and close editor when clicked outside', async () => { await page.render(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222'); await userEvent.click(page.getByText('outside')); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12222$/); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12222$/); }); it('should commit quickly enough on outside clicks so click event handlers access the latest rows state', async () => { const onSave = vi.fn(); await page.render(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); await userEvent.keyboard('234'); expect(onSave).not.toHaveBeenCalled(); const saveButton = page.getByRole('button', { name: 'save' }); @@ -95,17 +95,17 @@ describe('Editor', () => { } await page.render(); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); - const activeRowCells = getRowWithCell(page.getActiveCell()).getCell(); - await testCount(activeRowCells, 2); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + const activeRowCells = page.getRowWithCell(page.getActiveCell()).getCell(); + await expect.element(activeRowCells).toHaveLength(2); await grid.scroll({ top: 2001 }); - await testCount(activeRowCells, 1); + await expect.element(activeRowCells).toHaveLength(1); const editor = grid.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).not.toBeInTheDocument(); await expect.element(grid).toHaveProperty('scrollTop', 2001); // TODO: await userEvent.keyboard('123'); fails in FF await userEvent.keyboard('{enter}123'); - await testCount(activeRowCells, 2); + await expect.element(activeRowCells).toHaveLength(2); await expect.element(editor).toHaveValue(123); await expect.element(grid).toHaveProperty('scrollTop', 0); }); @@ -113,7 +113,7 @@ describe('Editor', () => { describe('editable', () => { it('should be editable if an editor is specified and editable is undefined/null', async () => { await page.render(); - const cell = getCellsAtRowIndex(0).nth(1); + const cell = page.getCellsAtRowIndex(0).nth(1); await expect.element(cell).not.toHaveAttribute('aria-readonly'); await userEvent.dblClick(cell); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); @@ -121,13 +121,13 @@ describe('Editor', () => { it('should be editable if an editor is specified and editable is set to true', async () => { await page.render(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); }); it('should not be editable if editable is false', async () => { await page.render(); - const cell = getCellsAtRowIndex(0).nth(1); + const cell = page.getCellsAtRowIndex(0).nth(1); await expect.element(cell).toHaveAttribute('aria-readonly', 'true'); await userEvent.dblClick(cell); @@ -138,11 +138,11 @@ describe('Editor', () => { it('should not be editable if editable function returns false', async () => { await page.render( row.col1 === 2} />); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).not.toBeInTheDocument(); - await userEvent.dblClick(getCellsAtRowIndex(1).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(1).nth(1)); await expect.element(editor).toBeInTheDocument(); }); }); @@ -152,24 +152,24 @@ describe('Editor', () => { await page.render( ); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const editor1 = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor1).toHaveValue('a1'); await userEvent.keyboard('23'); // The cell value should update as the editor value is changed - await expect.element(getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a123$/); + await expect.element(page.getCellsAtRowIndex(0).nth(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(); - await expect.element(getCellsAtRowIndex(0).nth(1)).not.toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(0).nth(1)).not.toHaveFocus(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); await userEvent.click(page.getByRole('textbox', { name: 'col2-editor' })); await userEvent.keyboard('{enter}'); - await expect.element(getCellsAtRowIndex(0).nth(1)).toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveFocus(); }); it('should not commit on outside click if commitOnOutsideClick is false', async () => { @@ -180,7 +180,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByText('outside')); @@ -200,10 +200,10 @@ describe('Editor', () => { }} /> ); - await userEvent.click(getCellsAtRowIndex(0).nth(1)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(1)); // TODO: await userEvent.keyboard('yz{enter}'); fails in FF await userEvent.keyboard('{enter}yz{enter}'); - await expect.element(getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1yz$/); + await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1yz$/); await userEvent.keyboard('x'); await expect .element(page.getByRole('textbox', { name: 'col2-editor' })) @@ -221,9 +221,9 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); await userEvent.keyboard('a{arrowleft}b{arrowright}c{arrowdown}'); // should commit changes on arrowdown - await expect.element(getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1bac$/); + await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1bac$/); }); it('should close the editor when closeOnExternalRowChange is true or undefined and row is changed from outside', async () => { @@ -235,7 +235,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -251,7 +251,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -317,7 +317,7 @@ describe('Editor', () => { ); const outerInput = page.getByRole('textbox', { name: 'outer-input' }); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); const col1Input = page.getByRole('textbox', { name: 'col1-input' }); await expect.element(col1Input).toHaveFocus(); await userEvent.click(outerInput); @@ -325,7 +325,7 @@ describe('Editor', () => { await expect.element(col1Input).not.toBeInTheDocument(); await expect.element(outerInput).toHaveFocus(); - await userEvent.dblClick(getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); const col2Input = page.getByRole('textbox', { name: 'col2-input' }); await expect.element(col2Input).toHaveFocus(); await userEvent.click(outerInput); diff --git a/test/browser/columnOrder.test.tsx b/test/browser/columnOrder.test.tsx index 345e93c96d..c1d4e7588f 100644 --- a/test/browser/columnOrder.test.tsx +++ b/test/browser/columnOrder.test.tsx @@ -2,7 +2,6 @@ import { page } from 'vitest/browser'; import { DataGrid, SelectColumn, TreeDataGrid } from '../../src'; import type { Column } from '../../src'; -import { testCount } from './utils'; const headerCells = page.getHeaderCell(); @@ -48,7 +47,7 @@ test('column order', async () => { )); } - await testCount(headerCells, expected.length); + await expect.element(headerCells).toHaveLength(expected.length); for (const [n, text] of expected.entries()) { await expect.element(headerCells.nth(n)).toHaveTextContent(text); } diff --git a/test/browser/copyPaste.test.tsx b/test/browser/copyPaste.test.tsx index a063235dc1..aad8028778 100644 --- a/test/browser/copyPaste.test.tsx +++ b/test/browser/copyPaste.test.tsx @@ -3,7 +3,7 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../src'; import type { CellPasteArgs, Column } from '../../src'; -import { getCellsAtRowIndex, safeTab } from './utils'; +import { safeTab } from './utils'; interface Row { col: string; @@ -70,7 +70,7 @@ function setup() { test('should call onCellCopy on cell copy', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); await userEvent.copy(); expect(onCellCopySpy).toHaveBeenCalledExactlyOnceWith( { @@ -83,7 +83,7 @@ test('should call onCellCopy on cell copy', async () => { test('should call onCellPaste on cell paste', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); await userEvent.paste(); expect(onCellPasteSpy).toHaveBeenCalledExactlyOnceWith( { @@ -96,14 +96,14 @@ test('should call onCellPaste on cell paste', async () => { test('should not allow paste on readonly cells', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(2).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(2).nth(0)); await userEvent.paste(); expect(onCellPasteSpy).not.toHaveBeenCalled(); }); test('should allow copying a readonly cell', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(2).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(2).nth(0)); await userEvent.copy(); expect(onCellCopySpy).toHaveBeenCalledExactlyOnceWith( { @@ -131,7 +131,7 @@ test('should not allow copy/paste on header or summary cells', async () => { test('should not start editing when pressing ctrl+', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(1).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(1).nth(0)); await userEvent.keyboard('{Control>}b'); await expect.element(page.getActiveCell()).not.toHaveClass('rdg-editor-container'); }); diff --git a/test/browser/dragFill.test.tsx b/test/browser/dragFill.test.tsx index c60c370128..c15313d549 100644 --- a/test/browser/dragFill.test.tsx +++ b/test/browser/dragFill.test.tsx @@ -3,7 +3,6 @@ import { commands, page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../src'; import type { Column, FillEvent } from '../../src'; -import { getCellsAtRowIndex } from './utils'; const dragHandle = page.getDragHandle(); @@ -47,48 +46,48 @@ function DragFillTest({ allowDragFill = true }: { allowDragFill?: boolean }) { test('should not allow dragFill if onFill is undefined', async () => { await setup(false); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); await expect.element(dragHandle).not.toBeInTheDocument(); }); test('should allow dragFill if onFill is specified', async () => { await setup(); - await userEvent.click(getCellsAtRowIndex(0).nth(0)); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); await userEvent.dblClick(dragHandle); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus(); - await expect.element(getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); - await expect.element(getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); + await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); + await expect.element(page.getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell }); test('should update single row using mouse', async () => { await setup(); await commands.dragFill('a1', 'a2'); - await expect.element(getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a3'); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); + await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a3'); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); }); test('should update multiple rows using mouse', async () => { await setup(); await commands.dragFill('a1', 'a4'); - await expect.element(getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); - await expect.element(getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell + await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); + await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); + await expect.element(page.getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell }); test('should allow drag up using mouse', async () => { await setup(); await commands.dragFill('a4', 'a1'); - await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveTextContent('a4'); - await expect.element(getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a4'); - await expect.element(getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a4'); + await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent('a4'); + await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a4'); + await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a4'); }); test('should focus the cell when drag handle is clicked', async () => { await setup(); - const cell = getCellsAtRowIndex(0).nth(0); + const cell = page.getCellsAtRowIndex(0).nth(0); await userEvent.click(cell); await expect.element(cell).toHaveFocus(); diff --git a/test/browser/keyboardNavigation.test.tsx b/test/browser/keyboardNavigation.test.tsx index 8624303ea4..0625ff1574 100644 --- a/test/browser/keyboardNavigation.test.tsx +++ b/test/browser/keyboardNavigation.test.tsx @@ -2,7 +2,7 @@ import { page, userEvent } from 'vitest/browser'; import { DataGrid, SelectColumn } from '../../src'; import type { Column } from '../../src'; -import { getRowWithCell, safeTab, setup, testCount, validateCellPosition } from './utils'; +import { safeTab, setup } from './utils'; const grid = page.getGrid(); const activeCell = page.getActiveCell(); @@ -33,72 +33,72 @@ test('keyboard navigation', async () => { // tab into the grid await safeTab(); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); // tab to the next cell await safeTab(); - await validateCellPosition(1, 0); + await expect.element(activeCell).toHaveCellPosition(1, 0); // tab back to the previous cell await safeTab(true); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); // arrow navigation await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(1, 1); + await expect.element(activeCell).toHaveCellPosition(1, 1); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(1, 2); + await expect.element(activeCell).toHaveCellPosition(1, 2); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(0, 2); + await expect.element(activeCell).toHaveCellPosition(0, 2); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); // page {up,down} await userEvent.keyboard('{PageDown}'); - await validateCellPosition(0, 26); + await expect.element(activeCell).toHaveCellPosition(0, 26); await userEvent.keyboard('{PageDown}'); - await validateCellPosition(0, 52); + await expect.element(activeCell).toHaveCellPosition(0, 52); await userEvent.keyboard('{PageUp}'); - await validateCellPosition(0, 26); + await expect.element(activeCell).toHaveCellPosition(0, 26); // home/end navigation await userEvent.keyboard('{end}'); - await validateCellPosition(6, 26); + await expect.element(activeCell).toHaveCellPosition(6, 26); await userEvent.keyboard('{home}'); - await validateCellPosition(0, 26); + await expect.element(activeCell).toHaveCellPosition(0, 26); await userEvent.keyboard('{Control>}{end}{/Control}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{end}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{Control>}{end}{/Control}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{PageDown}'); - await validateCellPosition(6, 103); + await expect.element(activeCell).toHaveCellPosition(6, 103); await userEvent.keyboard('{Control>}{home}{/Control}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{home}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{Control>}{home}{/Control}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{PageUp}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); // tab at the end of a row focuses the first cell on the next row await userEvent.keyboard('{end}'); await safeTab(); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); // shift tab should focus the last cell of the previous row await safeTab(true); - await validateCellPosition(6, 0); + await expect.element(activeCell).toHaveCellPosition(6, 0); }); test('arrow and tab navigation', async () => { @@ -107,23 +107,23 @@ test('arrow and tab navigation', async () => { // pressing arrowleft on the leftmost cell does nothing await safeTab(); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); // pressing arrowright on the rightmost cell does nothing await userEvent.keyboard('{end}'); - await validateCellPosition(6, 1); + await expect.element(activeCell).toHaveCellPosition(6, 1); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(6, 1); + await expect.element(activeCell).toHaveCellPosition(6, 1); // pressing tab on the rightmost cell navigates to the leftmost cell on the next row await safeTab(); - await validateCellPosition(0, 2); + await expect.element(activeCell).toHaveCellPosition(0, 2); // pressing shift+tab on the leftmost cell navigates to the rightmost cell on the previous row await safeTab(true); - await validateCellPosition(6, 1); + await expect.element(activeCell).toHaveCellPosition(6, 1); }); test('grid enter/exit', async () => { @@ -148,7 +148,7 @@ test('grid enter/exit', async () => { // tab into the grid await safeTab(); await safeTab(); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await expect.element(activeSelectAllCheckbox).toHaveFocus(); // shift+tab tabs out of the grid if we are at the first cell @@ -156,11 +156,11 @@ test('grid enter/exit', async () => { await expect.element(beforeButton).toHaveFocus(); await safeTab(); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await expect.element(activeSelectAllCheckbox).toHaveFocus(); await userEvent.keyboard('{arrowdown}{arrowdown}'); - await validateCellPosition(0, 2); + await expect.element(activeCell).toHaveCellPosition(0, 2); await expect.element(activeSelectCheckbox).toHaveFocus(); // tab should focus the last active cell @@ -168,14 +168,14 @@ test('grid enter/exit', async () => { await userEvent.click(beforeButton); await safeTab(); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(0, 3); + await expect.element(activeCell).toHaveCellPosition(0, 3); await expect.element(activeSelectCheckbox).toHaveFocus(); // shift+tab should focus the last active cell // click outside the grid await userEvent.click(afterButton); await safeTab(true); - await validateCellPosition(0, 3); + await expect.element(activeCell).toHaveCellPosition(0, 3); await expect.element(activeSelectCheckbox).toHaveFocus(); // tab tabs out of the grid if we are at the last cell @@ -188,7 +188,7 @@ test('navigation with focusable cell renderer', async () => { await setup({ columns, rows: Array.from({ length: 1 }), bottomSummaryRows }); await safeTab(); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); // cell should not set tabIndex to 0 if it contains a focusable cell renderer await expect.element(activeCell).toHaveAttribute('tabIndex', '-1'); @@ -196,7 +196,7 @@ test('navigation with focusable cell renderer', async () => { await expect.element(activeSelectCheckbox).toHaveAttribute('tabIndex', '0'); await safeTab(); - await validateCellPosition(1, 1); + await expect.element(activeCell).toHaveCellPosition(1, 1); // cell should set tabIndex to 0 if it does not have focusable cell renderer await expect.element(activeCell).toHaveAttribute('tabIndex', '0'); }); @@ -235,7 +235,7 @@ test('navigation when header and summary rows have focusable elements', async () await expect.element(page.getByTestId('header-filter2')).toHaveFocus(); await safeTab(); - await validateCellPosition(0, 1); + await expect.element(activeCell).toHaveCellPosition(0, 1); await safeTab(true); await expect.element(page.getByTestId('header-filter2')).toHaveFocus(); @@ -246,7 +246,7 @@ test('navigation when header and summary rows have focusable elements', async () await safeTab(); await safeTab(); await userEvent.keyboard('{Control>}{end}{/Control}{arrowup}{arrowup}'); - await validateCellPosition(1, 2); + await expect.element(activeCell).toHaveCellPosition(1, 2); await safeTab(); await expect.element(page.getByTestId('summary-col2-1')).toHaveFocus(); @@ -256,40 +256,40 @@ test('navigation when header and summary rows have focusable elements', async () await safeTab(true); await safeTab(true); - await validateCellPosition(1, 2); + await expect.element(activeCell).toHaveCellPosition(1, 2); await expect.element(activeCell).toHaveFocus(); }); test('navigation when active cell not in the viewport', async () => { const columns: Column[] = [SelectColumn]; - const activeRowCells = getRowWithCell(activeCell).getCell(); + const activeRowCells = page.getRowWithCell(activeCell).getCell(); for (let i = 0; i < 99; i++) { columns.push({ key: `col${i}`, name: `col${i}`, frozen: i < 5 }); } await setup({ columns, rows, bottomSummaryRows }); await safeTab(); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{Control>}{end}{/Control}{arrowup}{arrowup}'); - await validateCellPosition(99, 100); + await expect.element(activeCell).toHaveCellPosition(99, 100); await expect.element(activeRowCells).not.toHaveLength(1); await grid.scroll({ top: 0 }); - await testCount(activeRowCells, 1); + await expect.element(activeRowCells).toHaveLength(1); await userEvent.keyboard('{arrowup}'); - await validateCellPosition(99, 99); + await expect.element(activeCell).toHaveCellPosition(99, 99); await expect.element(activeRowCells).not.toHaveLength(1); await grid.scroll({ left: 0 }); await userEvent.keyboard('{arrowdown}'); - await validateCellPosition(99, 100); + await expect.element(activeCell).toHaveCellPosition(99, 100); await userEvent.keyboard( '{home}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}' ); - await validateCellPosition(7, 100); + await expect.element(activeCell).toHaveCellPosition(7, 100); await grid.scroll({ left: 2000 }); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(6, 100); + await expect.element(activeCell).toHaveCellPosition(6, 100); }); test('reset active cell when column is removed', async () => { @@ -307,7 +307,7 @@ test('reset active cell when column is removed', async () => { await safeTab(); await userEvent.keyboard('{arrowdown}{arrowright}'); - await validateCellPosition(1, 1); + await expect.element(activeCell).toHaveCellPosition(1, 1); await rerender(); @@ -329,7 +329,7 @@ test('reset active cell when row is removed', async () => { await safeTab(); await userEvent.keyboard('{arrowdown}{arrowdown}{arrowright}'); - await validateCellPosition(1, 2); + await expect.element(activeCell).toHaveCellPosition(1, 2); await rerender(); @@ -339,15 +339,15 @@ test('reset active cell when row is removed', async () => { test('should not change the left and right arrow behavior for right to left languages', async () => { await setup({ columns, rows, direction: 'rtl' }); await safeTab(); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await safeTab(); - await validateCellPosition(1, 0); + await expect.element(activeCell).toHaveCellPosition(1, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{arrowright}'); - await validateCellPosition(0, 0); + await expect.element(activeCell).toHaveCellPosition(0, 0); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(1, 0); + await expect.element(activeCell).toHaveCellPosition(1, 0); await userEvent.keyboard('{arrowleft}'); - await validateCellPosition(2, 0); + await expect.element(activeCell).toHaveCellPosition(2, 0); }); diff --git a/test/browser/renderers.test.tsx b/test/browser/renderers.test.tsx index 54059ee126..13e4207c7f 100644 --- a/test/browser/renderers.test.tsx +++ b/test/browser/renderers.test.tsx @@ -17,7 +17,9 @@ import type { RenderSortStatusProps, SortColumn } from '../../src'; -import { getRowWithCell, setup, testCount, testRowCount } from './utils'; +import { setup } from './utils'; + +const grid = page.getGrid(); interface Row { id: number; @@ -116,21 +118,21 @@ function setupContext(props: DataGridProps test('fallback defined using renderers prop with no rows', async () => { await setup({ columns, rows: noRows, renderers: { noRowsFallback: } }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Local no rows fallback')).toBeInTheDocument(); }); test('fallback defined using context with no rows', async () => { await setupContext({ columns, rows: noRows }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Global no rows fallback')).toBeInTheDocument(); }); test('fallback defined using both context and renderers with no rows', async () => { await setupContext({ columns, rows: noRows, renderers: { noRowsFallback: } }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Local no rows fallback')).toBeInTheDocument(); }); @@ -141,14 +143,14 @@ test('fallback defined using renderers prop with a row', async () => { renderers: { noRowsFallback: } }); - await testRowCount(1); + await expect.element(grid).toHaveRowsCount(1); await expect.element(page.getByText('Local no rows fallback')).not.toBeInTheDocument(); }); test('fallback defined using context with a row', async () => { await setupContext({ columns, rows: [{ id: 1, col1: 'value 1', col2: 'value 2' }] }); - await testRowCount(1); + await expect.element(grid).toHaveRowsCount(1); await expect.element(page.getByText('Global no rows fallback')).not.toBeInTheDocument(); }); @@ -159,7 +161,7 @@ test('fallback defined using both context and renderers with a row', async () => renderers: { noRowsFallback: } }); - await testRowCount(1); + await expect.element(grid).toHaveRowsCount(1); await expect.element(page.getByText('Global no rows fallback')).not.toBeInTheDocument(); await expect.element(page.getByText('Local no rows fallback')).not.toBeInTheDocument(); }); @@ -167,21 +169,21 @@ test('fallback defined using both context and renderers with a row', async () => test('checkbox defined using renderers prop', async () => { await setup({ columns, rows: noRows, renderers: { renderCheckbox: renderLocalCheckbox } }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Local checkbox')).toBeInTheDocument(); }); test('checkbox defined using context', async () => { await setupContext({ columns, rows: noRows }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Global checkbox')).toBeInTheDocument(); }); test('checkbox defined using both context and renderers', async () => { await setupContext({ columns, rows: noRows, renderers: { renderCheckbox: renderLocalCheckbox } }); - await testRowCount(0); + await expect.element(grid).toHaveRowsCount(0); await expect.element(page.getByText('Local checkbox')).toBeInTheDocument(); await expect.element(page.getByText('Global checkbox')).not.toBeInTheDocument(); }); @@ -196,7 +198,7 @@ test('sortPriority defined using both contexts', async () => { await userEvent.click(column2); const p = page.getByTestId('global-sort-priority'); - await testCount(p, 2); + await expect.element(p).toHaveLength(2); await expect.element(p.nth(0)).toHaveTextContent('1'); await expect.element(p.nth(1)).toHaveTextContent('2'); @@ -217,7 +219,7 @@ test('sortPriority defined using both contexts and renderers', async () => { await userEvent.click(column1); const p = page.getByTestId('local-sort-priority'); - await testCount(p, 2); + await expect.element(p).toHaveLength(2); await expect.element(p.nth(0)).toHaveTextContent('2'); await expect.element(p.nth(1)).toHaveTextContent('1'); @@ -259,7 +261,7 @@ test('renderCell defined using both contexts and renderers', async () => { test('renderRow defined using context', async () => { await setupContext({ columns, rows: [{ id: 1, col1: 'value 1', col2: 'value 2' }] }); - const row = getRowWithCell(page.getCell({ name: 'value 1' })); + const row = page.getRowWithCell(page.getCell({ name: 'value 1' })); await expect.element(row).toHaveClass('global'); await expect.element(row).not.toHaveClass('local'); }); @@ -271,7 +273,7 @@ test('renderRow defined using both contexts and renderers', async () => { renderers: { renderRow: renderLocalRow } }); - const row = getRowWithCell(page.getCell({ name: 'value 1' })); + const row = page.getRowWithCell(page.getCell({ name: 'value 1' })); await expect.element(row).toHaveClass('local'); await expect.element(row).not.toHaveClass('global'); }); diff --git a/test/browser/utils.tsx b/test/browser/utils.tsx index 26717ea26c..d2b89de7d0 100644 --- a/test/browser/utils.tsx +++ b/test/browser/utils.tsx @@ -1,4 +1,4 @@ -import { page, userEvent, type Locator } from 'vitest/browser'; +import { page, userEvent } from 'vitest/browser'; import { DataGrid } from '../../src'; import type { DataGridProps } from '../../src'; @@ -7,30 +7,8 @@ export function setup(props: DataGridPro return page.render(); } -export function getRowWithCell(cell: Locator) { - return page.getRow({ has: cell }); -} - -export function getCellsAtRowIndex(rowIdx: number) { - return page - .getRow() - .and(page.getBySelector(`[aria-rowindex="${rowIdx + 2}"]`)) - .getCell(); -} - -export async function validateCellPosition(columnIdx: number, rowIdx: number) { - const cell = page.getActiveCell(); - const row = page.getRow().or(page.getHeaderRow()).filter({ has: cell }); - await expect.element(cell).toHaveAttribute('aria-colindex', `${columnIdx + 1}`); - await expect.element(row).toHaveAttribute('aria-rowindex', `${rowIdx + 1}`); -} - -export function testCount(locator: Locator, expectedCount: number) { - return expect.element(locator).toHaveLength(expectedCount); -} - export function testRowCount(expectedCount: number) { - return testCount(page.getRow(), expectedCount); + return expect.element(page.getRow()).toHaveLength(expectedCount); } /** diff --git a/test/browser/virtualization.test.ts b/test/browser/virtualization.test.ts index bf2db89edf..4c3c3fc35c 100644 --- a/test/browser/virtualization.test.ts +++ b/test/browser/virtualization.test.ts @@ -1,7 +1,7 @@ import { page, type Locator } from 'vitest/browser'; import type { Column } from '../../src'; -import { getCellsAtRowIndex, setup } from './utils'; +import { setup } from './utils'; const grid = page.getGrid(); const headerCells = page.getHeaderCell(); @@ -85,7 +85,7 @@ async function assertRowIndexes(indexes: number[]) { async function assertCells(rowIdx: number, count: number, startIdx: number, endIdx: number) { await assertElements( - getCellsAtRowIndex(rowIdx), + page.getCellsAtRowIndex(rowIdx), 'aria-colindex', count, startIdx + 1, @@ -94,7 +94,7 @@ async function assertCells(rowIdx: number, count: number, startIdx: number, endI } async function assertCellIndexes(rowIdx: number, indexes: number[]) { - await assertIndexes(getCellsAtRowIndex(rowIdx), indexes, 'aria-colindex', 1); + await assertIndexes(page.getCellsAtRowIndex(rowIdx), indexes, 'aria-colindex', 1); } test('virtualization is enabled', async () => { diff --git a/test/setupBrowser.ts b/test/setupBrowser.ts index f9c985b27d..6d001a35f3 100644 --- a/test/setupBrowser.ts +++ b/test/setupBrowser.ts @@ -16,10 +16,13 @@ declare module 'vitest/browser' { getHeaderRow: (opts?: LocatorByRoleOptions) => Locator; getHeaderCell: (opts?: LocatorByRoleOptions) => Locator; getRow: (opts?: LocatorByRoleOptions) => Locator; + getSummaryRow: (opts?: LocatorByRoleOptions) => Locator; getCell: (opts?: LocatorByRoleOptions) => Locator; getSelectAllCheckbox: () => Locator; getActiveCell: () => Locator; getDragHandle: () => Locator; + getRowWithCell: (cell: Locator) => Locator; + getCellsAtRowIndex: (rowIdx: number) => Locator; getBySelector: (selector: string) => Locator; scroll: (this: Locator, options: ScrollToOptions) => Promise; blur: (this: Locator) => void; @@ -53,6 +56,12 @@ locators.extend({ return this.getByRole('gridcell', defaultToExactOpts(opts)); }, + getSummaryRow(opts?: LocatorByRoleOptions) { + return this.getByRole('row', defaultToExactOpts(opts)).and( + this.getBySelector('.rdg-summary-row') + ); + }, + getSelectAllCheckbox() { return this.getByRole('checkbox', { name: 'Select All' }); }, @@ -65,6 +74,14 @@ locators.extend({ return '.rdg-cell-drag-handle'; }, + getRowWithCell(cell: Locator) { + return this.getRow().filter({ has: cell }); + }, + + getCellsAtRowIndex(rowIdx: number) { + return this.getRow().and(this.getBySelector(`[aria-rowindex="${rowIdx + 2}"]`)).getCell(); + }, + getBySelector(selector: string) { return selector; }, @@ -97,6 +114,7 @@ function defaultToExactOpts( interface CustomMatchers { toHaveRowsCount: (rowsCount: number) => R; + toHaveCellPosition: (columnIdx: number, rowIdx: number) => R; } declare module 'vitest' { @@ -123,6 +141,20 @@ expect.extend({ pass: count === expected, message: () => `expected ${count} to have row count ${expected}` }; + }, + + toHaveCellPosition(cell: HTMLElement, columnIdx: number, rowIdx: number) { + const actualColIndex = cell.getAttribute('aria-colindex'); + const row = cell.closest('.rdg-row, .rdg-header-row, .rdg-summary-row'); + const actualRowIndex = row?.getAttribute('aria-rowindex'); + const expectedColIndex = String(columnIdx + 1); + const expectedRowIndex = String(rowIdx + 1); + + return { + pass: actualColIndex === expectedColIndex && actualRowIndex === expectedRowIndex, + message: () => + `expected cell position (${columnIdx}, ${rowIdx}) but got (${Number(actualColIndex) - 1}, ${Number(actualRowIndex) - 1})` + }; } }); From ba9b0d0d56c423d4525481b56c754f125ced1e8f Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 7 Mar 2026 03:06:42 +0000 Subject: [PATCH 3/5] Replace getCellsAtRowIndex with getRow/getCell index support Add 0-based `index` option to `getRow()` and `getCell()` locators. `getRow({ index })` matches the `rows` prop by dynamically computing `aria-rowindex` from the grid's header and top summary row count. `getCell({ index })` filters by `aria-colindex` for column index. Co-Authored-By: Claude Opus 4.6 --- AGENTS.md | 2 +- test/browser/TreeDataGrid.test.tsx | 2 +- test/browser/column/colSpan.test.ts | 38 ++++++------ test/browser/column/renderCell.test.tsx | 2 +- test/browser/column/renderEditCell.test.tsx | 68 ++++++++++----------- test/browser/copyPaste.test.tsx | 10 +-- test/browser/dragFill.test.tsx | 34 +++++------ test/browser/virtualization.test.ts | 4 +- test/setupBrowser.ts | 29 +++++---- 9 files changed, 99 insertions(+), 90 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e6775ffa51..ba453eee99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,7 +53,7 @@ website/ # demo site (Vite + TanStack Router) ## Testing - Browser tests use `vitest/browser` + Playwright. `test/setupBrowser.ts` configures `page.render()` via `vitest-browser-react` and registers custom locators via `locators.extend()` — prefer `page.getGrid()`, `page.getCell({ name })`, `page.getRow()`, `page.getHeaderCell()`, `page.getSelectedCell()`, etc. over raw `page.getByRole()`. -- Test helpers in `test/browser/utils.tsx`: `setup()`, `getRowWithCell()`, `getCellsAtRowIndex()`, `validateCellPosition()`, `scrollGrid()`, `tabIntoGrid()`, `testCount()`, `testRowCount()`. +- Test helpers in `test/browser/utils.tsx`: `setup()`, `getRowWithCell()`, `validateCellPosition()`, `scrollGrid()`, `tabIntoGrid()`, `testCount()`, `testRowCount()`. - `test/failOnConsole.ts` fails tests on unexpected console warnings/errors. - **Never run visual regression tests locally** — screenshots are CI-only and environment-dependent. diff --git a/test/browser/TreeDataGrid.test.tsx b/test/browser/TreeDataGrid.test.tsx index 9a0a901f41..2e4de753a2 100644 --- a/test/browser/TreeDataGrid.test.tsx +++ b/test/browser/TreeDataGrid.test.tsx @@ -360,7 +360,7 @@ test('cell navigation in a treegrid', async () => { await expect.element(row3).toHaveAttribute('tabIndex', '0'); // focus cell - const cells = page.getCellsAtRowIndex(5); + const cells = page.getRow({ index: 4 }).getCell(); await userEvent.click(cells.nth(1)); await expect.element(cells.nth(1)).toHaveAttribute('aria-selected', 'true'); await expect.element(cells.nth(1)).toHaveFocus(); diff --git a/test/browser/column/colSpan.test.ts b/test/browser/column/colSpan.test.ts index 82b0251cc8..b1a0c20d25 100644 --- a/test/browser/column/colSpan.test.ts +++ b/test/browser/column/colSpan.test.ts @@ -4,6 +4,8 @@ import type { Column } from '../../../src'; import { safeTab, setup } from '../utils'; const headerCells = page.getHeaderCell(); +const topSummaryRows = page.getSummaryRow().and(page.getBySelector('.rdg-top-summary-row')); +const bottomSummaryRows = page.getSummaryRow().and(page.getBySelector('.rdg-bottom-summary-row')); describe('colSpan', () => { function setupColSpan(colCount = 15) { @@ -45,19 +47,19 @@ describe('colSpan', () => { await expect.element(headerCells).toHaveLength(13); // top summary rows - const topSummarryRow1 = page.getCellsAtRowIndex(0); - await expect.element(topSummarryRow1).toHaveLength(14); + const topSummaryRow1Cells = topSummaryRows.nth(0).getCell(); + await expect.element(topSummaryRow1Cells).toHaveLength(14); // 7th-8th cells are merged - await expect.element(topSummarryRow1.nth(7)).toHaveAttribute('aria-colindex', '8'); - await expect.element(topSummarryRow1.nth(7)).toHaveAttribute('aria-colspan', '2'); - await expect.element(topSummarryRow1.nth(7)).toHaveStyle({ + await expect.element(topSummaryRow1Cells.nth(7)).toHaveAttribute('aria-colindex', '8'); + await expect.element(topSummaryRow1Cells.nth(7)).toHaveAttribute('aria-colspan', '2'); + await expect.element(topSummaryRow1Cells.nth(7)).toHaveStyle({ gridColumnStart: '8', gridColumnEnd: '10' }); - await expect.element(page.getCellsAtRowIndex(1)).toHaveLength(15); + await expect.element(topSummaryRows.nth(1).getCell()).toHaveLength(15); // rows - const row1 = page.getCellsAtRowIndex(3); + const row1 = page.getRow({ index: 1 }).getCell(); await expect.element(row1).toHaveLength(14); // 7th-8th cells are merged await expect.element(row1.nth(6)).toHaveAttribute('aria-colindex', '7'); @@ -70,7 +72,7 @@ describe('colSpan', () => { await expect.element(row1.nth(7)).not.toHaveAttribute('aria-colspan'); // 3rd-5th, 7th-8th cells are merged - const row2 = page.getCellsAtRowIndex(4); + const row2 = page.getRow({ index: 2 }).getCell(); await expect.element(row2).toHaveLength(12); await expect.element(row2.nth(2)).toHaveAttribute('aria-colindex', '3'); await expect.element(row2.nth(2)).toHaveStyle({ @@ -86,12 +88,12 @@ describe('colSpan', () => { }); await expect.element(row2.nth(5)).toHaveAttribute('aria-colindex', '9'); - await expect.element(page.getCellsAtRowIndex(6)).toHaveLength(14); // colSpan 6 won't work as there are 5 frozen columns - await expect.element(page.getCellsAtRowIndex(7)).toHaveLength(10); + await expect.element(page.getRow({ index: 4 }).getCell()).toHaveLength(14); // colSpan 6 won't work as there are 5 frozen columns + await expect.element(page.getRow({ index: 5 }).getCell()).toHaveLength(10); - // bottom summary row - await expect.element(page.getCellsAtRowIndex(12)).toHaveLength(14); - await expect.element(page.getCellsAtRowIndex(13)).toHaveLength(15); + // bottom summary rows + await expect.element(bottomSummaryRows.nth(0).getCell()).toHaveLength(14); + await expect.element(bottomSummaryRows.nth(1).getCell()).toHaveLength(15); }); it('should navigate between merged cells', async () => { @@ -109,7 +111,7 @@ describe('colSpan', () => { await expect.element(page.getActiveCell()).toHaveCellPosition(7, 0); // top summary rows - await userEvent.click(page.getCellsAtRowIndex(0).nth(6)); + await userEvent.click(topSummaryRows.nth(0).getCell({ index: 6 })); await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); await userEvent.keyboard('{arrowright}'); await expect.element(page.getActiveCell()).toHaveCellPosition(7, 1); @@ -121,7 +123,7 @@ describe('colSpan', () => { await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); // viewport rows - await userEvent.click(page.getCellsAtRowIndex(3).nth(1)); + await userEvent.click(page.getRow({ index: 1 }).getCell({ index: 1 })); await expect.element(page.getActiveCell()).toHaveCellPosition(1, 4); await userEvent.keyboard('{arrowright}'); await expect.element(page.getActiveCell()).toHaveCellPosition(2, 4); @@ -150,7 +152,7 @@ describe('colSpan', () => { await expect.element(page.getActiveCell()).toHaveCellPosition(14, 7); await safeTab(); await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); - await userEvent.click(page.getCellsAtRowIndex(10).nth(11)); + await userEvent.click(page.getRow({ index: 8 }).getCell({ index: 11 })); await expect.element(page.getActiveCell()).toHaveCellPosition(11, 11); await safeTab(); await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); @@ -160,7 +162,7 @@ describe('colSpan', () => { await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); // bottom summary rows - await userEvent.click(page.getCellsAtRowIndex(12).nth(6)); + await userEvent.click(bottomSummaryRows.nth(0).getCell({ index: 6 })); await expect.element(page.getActiveCell()).toHaveCellPosition(6, 13); await userEvent.keyboard('{arrowright}'); await expect.element(page.getActiveCell()).toHaveCellPosition(7, 13); @@ -174,7 +176,7 @@ describe('colSpan', () => { it('should scroll to the merged cell when selected', async () => { await setupColSpan(30); - await userEvent.click(page.getCellsAtRowIndex(10).nth(23)); // last visible cell (1920/80) + await userEvent.click(page.getRow({ index: 8 }).getCell({ index: 23 })); // last visible cell (1920/80) const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView'); const testScrollIntoView = () => { expect(spy).toHaveBeenCalled(); diff --git a/test/browser/column/renderCell.test.tsx b/test/browser/column/renderCell.test.tsx index 02972da49e..6bb1683474 100644 --- a/test/browser/column/renderCell.test.tsx +++ b/test/browser/column/renderCell.test.tsx @@ -191,7 +191,7 @@ test('Cell should not steal focus when the focus is outside the grid and cell is await page.render(); - const cell = page.getCellsAtRowIndex(0).nth(0); + const cell = page.getRow({ index: 0 }).getCell({ index: 0 }); await userEvent.click(cell); await expect.element(cell).toHaveFocus(); diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index 5bb81d707a..2c167851d2 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -17,63 +17,63 @@ describe('Editor', () => { it('should open editor on double click', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); await expect.element(editor).not.toBeInTheDocument(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2'); await safeTab(); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^12$/); }); it('should open and commit changes on enter', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); await expect.element(editor).not.toBeInTheDocument(); await userEvent.keyboard('{enter}'); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('3{enter}'); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^13$/); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^13$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); await expect.element(editor).not.toBeInTheDocument(); }); it('should open editor when user types', async () => { await page.render(); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); // TODO: await userEvent.keyboard('123{enter}'); fails in FF await userEvent.keyboard('{enter}123{enter}'); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1123$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^1123$/); }); it('should close editor and discard changes on escape', async () => { await page.render(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222{escape}'); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^1$/); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^1$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); }); it('should commit changes and close editor when clicked outside', async () => { await page.render(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222'); await userEvent.click(page.getByText('outside')); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent(/^12222$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^12222$/); }); it('should commit quickly enough on outside clicks so click event handlers access the latest rows state', async () => { const onSave = vi.fn(); await page.render(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); await userEvent.keyboard('234'); expect(onSave).not.toHaveBeenCalled(); const saveButton = page.getByRole('button', { name: 'save' }); @@ -95,7 +95,7 @@ describe('Editor', () => { } await page.render(); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); const activeRowCells = page.getRowWithCell(page.getActiveCell()).getCell(); await expect.element(activeRowCells).toHaveLength(2); await grid.scroll({ top: 2001 }); @@ -113,7 +113,7 @@ describe('Editor', () => { describe('editable', () => { it('should be editable if an editor is specified and editable is undefined/null', async () => { await page.render(); - const cell = page.getCellsAtRowIndex(0).nth(1); + const cell = page.getRow({ index: 0 }).getCell({ index: 1 }); await expect.element(cell).not.toHaveAttribute('aria-readonly'); await userEvent.dblClick(cell); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); @@ -121,13 +121,13 @@ describe('Editor', () => { it('should be editable if an editor is specified and editable is set to true', async () => { await page.render(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); }); it('should not be editable if editable is false', async () => { await page.render(); - const cell = page.getCellsAtRowIndex(0).nth(1); + const cell = page.getRow({ index: 0 }).getCell({ index: 1 }); await expect.element(cell).toHaveAttribute('aria-readonly', 'true'); await userEvent.dblClick(cell); @@ -138,11 +138,11 @@ describe('Editor', () => { it('should not be editable if editable function returns false', async () => { await page.render( row.col1 === 2} />); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).not.toBeInTheDocument(); - await userEvent.dblClick(page.getCellsAtRowIndex(1).nth(1)); + await userEvent.dblClick(page.getRow({ index: 1 }).getCell({ index: 1 })); await expect.element(editor).toBeInTheDocument(); }); }); @@ -152,24 +152,24 @@ describe('Editor', () => { await page.render( ); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const editor1 = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor1).toHaveValue('a1'); await userEvent.keyboard('23'); // The cell value should update as the editor value is changed - await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a123$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 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(); - await expect.element(page.getCellsAtRowIndex(0).nth(1)).not.toHaveFocus(); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).not.toHaveFocus(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); await userEvent.click(page.getByRole('textbox', { name: 'col2-editor' })); await userEvent.keyboard('{enter}'); - await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveFocus(); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveFocus(); }); it('should not commit on outside click if commitOnOutsideClick is false', async () => { @@ -180,7 +180,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByText('outside')); @@ -200,10 +200,10 @@ describe('Editor', () => { }} /> ); - await userEvent.click(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 1 })); // TODO: await userEvent.keyboard('yz{enter}'); fails in FF await userEvent.keyboard('{enter}yz{enter}'); - await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1yz$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveTextContent(/^a1yz$/); await userEvent.keyboard('x'); await expect .element(page.getByRole('textbox', { name: 'col2-editor' })) @@ -221,9 +221,9 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); await userEvent.keyboard('a{arrowleft}b{arrowright}c{arrowdown}'); // should commit changes on arrowdown - await expect.element(page.getCellsAtRowIndex(0).nth(1)).toHaveTextContent(/^a1bac$/); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveTextContent(/^a1bac$/); }); it('should close the editor when closeOnExternalRowChange is true or undefined and row is changed from outside', async () => { @@ -235,7 +235,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -251,7 +251,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -317,7 +317,7 @@ describe('Editor', () => { ); const outerInput = page.getByRole('textbox', { name: 'outer-input' }); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); const col1Input = page.getByRole('textbox', { name: 'col1-input' }); await expect.element(col1Input).toHaveFocus(); await userEvent.click(outerInput); @@ -325,7 +325,7 @@ describe('Editor', () => { await expect.element(col1Input).not.toBeInTheDocument(); await expect.element(outerInput).toHaveFocus(); - await userEvent.dblClick(page.getCellsAtRowIndex(0).nth(1)); + await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); const col2Input = page.getByRole('textbox', { name: 'col2-input' }); await expect.element(col2Input).toHaveFocus(); await userEvent.click(outerInput); diff --git a/test/browser/copyPaste.test.tsx b/test/browser/copyPaste.test.tsx index aad8028778..4a6509caac 100644 --- a/test/browser/copyPaste.test.tsx +++ b/test/browser/copyPaste.test.tsx @@ -70,7 +70,7 @@ function setup() { test('should call onCellCopy on cell copy', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); await userEvent.copy(); expect(onCellCopySpy).toHaveBeenCalledExactlyOnceWith( { @@ -83,7 +83,7 @@ test('should call onCellCopy on cell copy', async () => { test('should call onCellPaste on cell paste', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); await userEvent.paste(); expect(onCellPasteSpy).toHaveBeenCalledExactlyOnceWith( { @@ -96,14 +96,14 @@ test('should call onCellPaste on cell paste', async () => { test('should not allow paste on readonly cells', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(2).nth(0)); + await userEvent.click(page.getRow({ index: 2 }).getCell({ index: 0 })); await userEvent.paste(); expect(onCellPasteSpy).not.toHaveBeenCalled(); }); test('should allow copying a readonly cell', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(2).nth(0)); + await userEvent.click(page.getRow({ index: 2 }).getCell({ index: 0 })); await userEvent.copy(); expect(onCellCopySpy).toHaveBeenCalledExactlyOnceWith( { @@ -131,7 +131,7 @@ test('should not allow copy/paste on header or summary cells', async () => { test('should not start editing when pressing ctrl+', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(1).nth(0)); + await userEvent.click(page.getRow({ index: 1 }).getCell({ index: 0 })); await userEvent.keyboard('{Control>}b'); await expect.element(page.getActiveCell()).not.toHaveClass('rdg-editor-container'); }); diff --git a/test/browser/dragFill.test.tsx b/test/browser/dragFill.test.tsx index c15313d549..5e3048ae0d 100644 --- a/test/browser/dragFill.test.tsx +++ b/test/browser/dragFill.test.tsx @@ -46,48 +46,48 @@ function DragFillTest({ allowDragFill = true }: { allowDragFill?: boolean }) { test('should not allow dragFill if onFill is undefined', async () => { await setup(false); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); await expect.element(dragHandle).not.toBeInTheDocument(); }); test('should allow dragFill if onFill is specified', async () => { await setup(); - await userEvent.click(page.getCellsAtRowIndex(0).nth(0)); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); await userEvent.dblClick(dragHandle); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); - await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); - await expect.element(page.getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); + await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); + await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a1'); + await expect.element(page.getRow({ index: 3 }).getCell({ index: 0 })).toHaveTextContent('a4'); // readonly cell }); test('should update single row using mouse', async () => { await setup(); await commands.dragFill('a1', 'a2'); - await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a3'); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveFocus(); + await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); + await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a3'); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); }); test('should update multiple rows using mouse', async () => { await setup(); await commands.dragFill('a1', 'a4'); - await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a1'); - await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a1'); - await expect.element(page.getCellsAtRowIndex(3).nth(0)).toHaveTextContent('a4'); // readonly cell + await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); + await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a1'); + await expect.element(page.getRow({ index: 3 }).getCell({ index: 0 })).toHaveTextContent('a4'); // readonly cell }); test('should allow drag up using mouse', async () => { await setup(); await commands.dragFill('a4', 'a1'); - await expect.element(page.getCellsAtRowIndex(0).nth(0)).toHaveTextContent('a4'); - await expect.element(page.getCellsAtRowIndex(1).nth(0)).toHaveTextContent('a4'); - await expect.element(page.getCellsAtRowIndex(2).nth(0)).toHaveTextContent('a4'); + await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent('a4'); + await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a4'); + await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a4'); }); test('should focus the cell when drag handle is clicked', async () => { await setup(); - const cell = page.getCellsAtRowIndex(0).nth(0); + const cell = page.getRow({ index: 0 }).getCell({ index: 0 }); await userEvent.click(cell); await expect.element(cell).toHaveFocus(); diff --git a/test/browser/virtualization.test.ts b/test/browser/virtualization.test.ts index 4c3c3fc35c..826814fa3c 100644 --- a/test/browser/virtualization.test.ts +++ b/test/browser/virtualization.test.ts @@ -85,7 +85,7 @@ async function assertRowIndexes(indexes: number[]) { async function assertCells(rowIdx: number, count: number, startIdx: number, endIdx: number) { await assertElements( - page.getCellsAtRowIndex(rowIdx), + page.getRow({ index: rowIdx }).getCell(), 'aria-colindex', count, startIdx + 1, @@ -94,7 +94,7 @@ async function assertCells(rowIdx: number, count: number, startIdx: number, endI } async function assertCellIndexes(rowIdx: number, indexes: number[]) { - await assertIndexes(page.getCellsAtRowIndex(rowIdx), indexes, 'aria-colindex', 1); + await assertIndexes(page.getRow({ index: rowIdx }).getCell(), indexes, 'aria-colindex', 1); } test('virtualization is enabled', async () => { diff --git a/test/setupBrowser.ts b/test/setupBrowser.ts index 6d001a35f3..ede104f4a4 100644 --- a/test/setupBrowser.ts +++ b/test/setupBrowser.ts @@ -15,14 +15,13 @@ declare module 'vitest/browser' { getTreeGrid: () => Locator; getHeaderRow: (opts?: LocatorByRoleOptions) => Locator; getHeaderCell: (opts?: LocatorByRoleOptions) => Locator; - getRow: (opts?: LocatorByRoleOptions) => Locator; + getRow: (opts?: LocatorByRoleOptions & { index?: number }) => Locator; getSummaryRow: (opts?: LocatorByRoleOptions) => Locator; - getCell: (opts?: LocatorByRoleOptions) => Locator; + getCell: (opts?: LocatorByRoleOptions & { index?: number }) => Locator; getSelectAllCheckbox: () => Locator; getActiveCell: () => Locator; getDragHandle: () => Locator; getRowWithCell: (cell: Locator) => Locator; - getCellsAtRowIndex: (rowIdx: number) => Locator; getBySelector: (selector: string) => Locator; scroll: (this: Locator, options: ScrollToOptions) => Promise; blur: (this: Locator) => void; @@ -48,12 +47,24 @@ locators.extend({ return this.getByRole('columnheader', defaultToExactOpts(opts)); }, - getRow(opts?: LocatorByRoleOptions) { - return this.getByRole('row', defaultToExactOpts(opts)).and(this.getBySelector('.rdg-row')); + getRow(opts?: LocatorByRoleOptions & { index?: number }) { + const row = this.getByRole('row', defaultToExactOpts(opts)).and(this.getBySelector('.rdg-row')); + if (opts?.index != null) { + const grid = document.querySelector('.rdg')!; + const headerRowsCount = grid.querySelectorAll(':scope > .rdg-header-row').length; + const topSummaryRowsCount = grid.querySelectorAll(':scope > .rdg-top-summary-row').length; + const ariaRowIndex = headerRowsCount + topSummaryRowsCount + opts.index + 1; + return row.and(this.getBySelector(`[aria-rowindex="${ariaRowIndex}"]`)); + } + return row; }, - getCell(opts?: LocatorByRoleOptions) { - return this.getByRole('gridcell', defaultToExactOpts(opts)); + getCell(opts?: LocatorByRoleOptions & { index?: number }) { + const cell = this.getByRole('gridcell', defaultToExactOpts(opts)); + if (opts?.index != null) { + return cell.and(this.getBySelector(`[aria-colindex="${opts.index + 1}"]`)); + } + return cell; }, getSummaryRow(opts?: LocatorByRoleOptions) { @@ -78,10 +89,6 @@ locators.extend({ return this.getRow().filter({ has: cell }); }, - getCellsAtRowIndex(rowIdx: number) { - return this.getRow().and(this.getBySelector(`[aria-rowindex="${rowIdx + 2}"]`)).getCell(); - }, - getBySelector(selector: string) { return selector; }, From f11b24c75601a230bd41944b53231180b4139a24 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 7 Mar 2026 03:10:21 +0000 Subject: [PATCH 4/5] Format code Co-Authored-By: Claude Opus 4.6 --- test/browser/TreeDataGrid.test.tsx | 4 +++- test/browser/column/renderEditCell.test.tsx | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/browser/TreeDataGrid.test.tsx b/test/browser/TreeDataGrid.test.tsx index 2e4de753a2..f3e95f0cfa 100644 --- a/test/browser/TreeDataGrid.test.tsx +++ b/test/browser/TreeDataGrid.test.tsx @@ -271,7 +271,9 @@ test('should select rows in a group', async () => { await expect.element(selectedRows).toHaveLength(0); // select parent row - await userEvent.click(page.getRowWithCell(groupCell1).getByRole('checkbox', { name: 'Select Group' })); + await userEvent.click( + page.getRowWithCell(groupCell1).getByRole('checkbox', { name: 'Select Group' }) + ); await expect.element(selectedRows).toHaveLength(4); await expect.element(selectedRows.nth(0)).toHaveAttribute('aria-rowindex', '6'); await expect.element(selectedRows.nth(1)).toHaveAttribute('aria-rowindex', '7'); diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index 2c167851d2..cd2a07486e 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -45,7 +45,9 @@ describe('Editor', () => { await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); // TODO: await userEvent.keyboard('123{enter}'); fails in FF await userEvent.keyboard('{enter}123{enter}'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^1123$/); + await expect + .element(page.getRow({ index: 0 }).getCell({ index: 0 })) + .toHaveTextContent(/^1123$/); }); it('should close editor and discard changes on escape', async () => { @@ -67,7 +69,9 @@ describe('Editor', () => { await userEvent.keyboard('2222'); await userEvent.click(page.getByText('outside')); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^12222$/); + await expect + .element(page.getRow({ index: 0 }).getCell({ index: 0 })) + .toHaveTextContent(/^12222$/); }); it('should commit quickly enough on outside clicks so click event handlers access the latest rows state', async () => { @@ -157,7 +161,9 @@ describe('Editor', () => { await expect.element(editor1).toHaveValue('a1'); await userEvent.keyboard('23'); // The cell value should update as the editor value is changed - await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveTextContent(/^a123$/); + await expect + .element(page.getRow({ index: 0 }).getCell({ index: 1 })) + .toHaveTextContent(/^a123$/); // clicking in a portal does not count as an outside click await userEvent.click(editor1); await expect.element(editor1).toBeInTheDocument(); @@ -203,7 +209,9 @@ describe('Editor', () => { await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 1 })); // TODO: await userEvent.keyboard('yz{enter}'); fails in FF await userEvent.keyboard('{enter}yz{enter}'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveTextContent(/^a1yz$/); + await expect + .element(page.getRow({ index: 0 }).getCell({ index: 1 })) + .toHaveTextContent(/^a1yz$/); await userEvent.keyboard('x'); await expect .element(page.getByRole('textbox', { name: 'col2-editor' })) @@ -223,7 +231,9 @@ describe('Editor', () => { ); await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); await userEvent.keyboard('a{arrowleft}b{arrowright}c{arrowdown}'); // should commit changes on arrowdown - await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveTextContent(/^a1bac$/); + await expect + .element(page.getRow({ index: 0 }).getCell({ index: 1 })) + .toHaveTextContent(/^a1bac$/); }); it('should close the editor when closeOnExternalRowChange is true or undefined and row is changed from outside', async () => { From 111d5314f85716e004f5c7fbcaaa164b251dde93 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 7 Mar 2026 03:25:23 +0000 Subject: [PATCH 5/5] Deduplicate repeated locator calls in tests Co-Authored-By: Claude Opus 4.6 --- test/browser/column/colSpan.test.ts | 73 +++++++++---------- test/browser/column/renderEditCell.test.tsx | 79 ++++++++++----------- test/browser/dragFill.test.tsx | 47 ++++++------ 3 files changed, 98 insertions(+), 101 deletions(-) diff --git a/test/browser/column/colSpan.test.ts b/test/browser/column/colSpan.test.ts index b1a0c20d25..0a6339bd54 100644 --- a/test/browser/column/colSpan.test.ts +++ b/test/browser/column/colSpan.test.ts @@ -6,6 +6,7 @@ import { safeTab, setup } from '../utils'; const headerCells = page.getHeaderCell(); const topSummaryRows = page.getSummaryRow().and(page.getBySelector('.rdg-top-summary-row')); const bottomSummaryRows = page.getSummaryRow().and(page.getBySelector('.rdg-bottom-summary-row')); +const activeCell = page.getActiveCell(); describe('colSpan', () => { function setupColSpan(colCount = 15) { @@ -100,78 +101,78 @@ describe('colSpan', () => { await setupColSpan(); // header row await userEvent.click(headerCells.nth(7)); - await expect.element(page.getActiveCell()).toHaveCellPosition(7, 0); + await expect.element(activeCell).toHaveCellPosition(7, 0); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(8, 0); + await expect.element(activeCell).toHaveCellPosition(8, 0); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(11, 0); + await expect.element(activeCell).toHaveCellPosition(11, 0); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(12, 0); + await expect.element(activeCell).toHaveCellPosition(12, 0); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(7, 0); + await expect.element(activeCell).toHaveCellPosition(7, 0); // top summary rows await userEvent.click(topSummaryRows.nth(0).getCell({ index: 6 })); - await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); + await expect.element(activeCell).toHaveCellPosition(6, 1); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(7, 1); + await expect.element(activeCell).toHaveCellPosition(7, 1); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(9, 1); + await expect.element(activeCell).toHaveCellPosition(9, 1); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(10, 1); + await expect.element(activeCell).toHaveCellPosition(10, 1); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(6, 1); + await expect.element(activeCell).toHaveCellPosition(6, 1); // viewport rows await userEvent.click(page.getRow({ index: 1 }).getCell({ index: 1 })); - await expect.element(page.getActiveCell()).toHaveCellPosition(1, 4); + await expect.element(activeCell).toHaveCellPosition(1, 4); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(2, 4); + await expect.element(activeCell).toHaveCellPosition(2, 4); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(3, 4); + await expect.element(activeCell).toHaveCellPosition(3, 4); await userEvent.keyboard('{arrowdown}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); + await expect.element(activeCell).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowleft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(1, 5); + await expect.element(activeCell).toHaveCellPosition(1, 5); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); + await expect.element(activeCell).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(5, 5); + await expect.element(activeCell).toHaveCellPosition(5, 5); await userEvent.keyboard('{arrowleft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(2, 5); + await expect.element(activeCell).toHaveCellPosition(2, 5); await userEvent.keyboard('{arrowdown}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(2, 6); + await expect.element(activeCell).toHaveCellPosition(2, 6); await userEvent.keyboard('{arrowdown}{arrowdown}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); + await expect.element(activeCell).toHaveCellPosition(0, 8); await userEvent.keyboard('{arrowLeft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); + await expect.element(activeCell).toHaveCellPosition(0, 8); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(5, 8); + await expect.element(activeCell).toHaveCellPosition(5, 8); await safeTab(true); await safeTab(true); - await expect.element(page.getActiveCell()).toHaveCellPosition(14, 7); + await expect.element(activeCell).toHaveCellPosition(14, 7); await safeTab(); - await expect.element(page.getActiveCell()).toHaveCellPosition(0, 8); + await expect.element(activeCell).toHaveCellPosition(0, 8); await userEvent.click(page.getRow({ index: 8 }).getCell({ index: 11 })); - await expect.element(page.getActiveCell()).toHaveCellPosition(11, 11); + await expect.element(activeCell).toHaveCellPosition(11, 11); await safeTab(); - await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); + await expect.element(activeCell).toHaveCellPosition(12, 11); await safeTab(); - await expect.element(page.getActiveCell()).toHaveCellPosition(0, 12); + await expect.element(activeCell).toHaveCellPosition(0, 12); await safeTab(true); - await expect.element(page.getActiveCell()).toHaveCellPosition(12, 11); + await expect.element(activeCell).toHaveCellPosition(12, 11); // bottom summary rows await userEvent.click(bottomSummaryRows.nth(0).getCell({ index: 6 })); - await expect.element(page.getActiveCell()).toHaveCellPosition(6, 13); + await expect.element(activeCell).toHaveCellPosition(6, 13); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(7, 13); + await expect.element(activeCell).toHaveCellPosition(7, 13); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(9, 13); + await expect.element(activeCell).toHaveCellPosition(9, 13); await userEvent.keyboard('{arrowright}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(10, 13); + await expect.element(activeCell).toHaveCellPosition(10, 13); await userEvent.keyboard('{arrowleft}{arrowleft}{arrowleft}'); - await expect.element(page.getActiveCell()).toHaveCellPosition(6, 13); + await expect.element(activeCell).toHaveCellPosition(6, 13); }); it('should scroll to the merged cell when selected', async () => { @@ -186,13 +187,13 @@ describe('colSpan', () => { testScrollIntoView(); await navigate(1); testScrollIntoView(); // should bring the merged cell into view - await expect.element(page.getActiveCell()).toHaveCellPosition(27, 11); + await expect.element(activeCell).toHaveCellPosition(27, 11); await navigate(7); testScrollIntoView(); - await expect.element(page.getActiveCell()).toHaveCellPosition(6, 12); // should navigate to the next row + await expect.element(activeCell).toHaveCellPosition(6, 12); // should navigate to the next row await navigate(7, true); testScrollIntoView(); - await expect.element(page.getActiveCell()).toHaveCellPosition(27, 11); // should navigate to the previous row + await expect.element(activeCell).toHaveCellPosition(27, 11); // should navigate to the previous row await navigate(27); testScrollIntoView(); await navigate(1); diff --git a/test/browser/column/renderEditCell.test.tsx b/test/browser/column/renderEditCell.test.tsx index cd2a07486e..4af276bf00 100644 --- a/test/browser/column/renderEditCell.test.tsx +++ b/test/browser/column/renderEditCell.test.tsx @@ -14,70 +14,69 @@ interface Row { } describe('Editor', () => { + const col1Cell = page.getRow({ index: 0 }).getCell({ index: 0 }); + const col2Cell = page.getRow({ index: 0 }).getCell({ index: 1 }); + it('should open editor on double click', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.click(col1Cell); await expect.element(editor).not.toBeInTheDocument(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.dblClick(col1Cell); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2'); await safeTab(); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^12$/); + await expect.element(col1Cell).toHaveTextContent(/^12$/); }); it('should open and commit changes on enter', async () => { await page.render(); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.click(col1Cell); await expect.element(editor).not.toBeInTheDocument(); await userEvent.keyboard('{enter}'); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('3{enter}'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^13$/); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); + await expect.element(col1Cell).toHaveTextContent(/^13$/); + await expect.element(col1Cell).toHaveFocus(); await expect.element(editor).not.toBeInTheDocument(); }); it('should open editor when user types', async () => { await page.render(); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.click(col1Cell); // TODO: await userEvent.keyboard('123{enter}'); fails in FF await userEvent.keyboard('{enter}123{enter}'); - await expect - .element(page.getRow({ index: 0 }).getCell({ index: 0 })) - .toHaveTextContent(/^1123$/); + await expect.element(col1Cell).toHaveTextContent(/^1123$/); }); it('should close editor and discard changes on escape', async () => { await page.render(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.dblClick(col1Cell); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222{escape}'); await expect.element(editor).not.toBeInTheDocument(); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent(/^1$/); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); + await expect.element(col1Cell).toHaveTextContent(/^1$/); + await expect.element(col1Cell).toHaveFocus(); }); it('should commit changes and close editor when clicked outside', async () => { await page.render(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.dblClick(col1Cell); const editor = page.getByRole('spinbutton', { name: 'col1-editor' }); await expect.element(editor).toHaveValue(1); await userEvent.keyboard('2222'); await userEvent.click(page.getByText('outside')); await expect.element(editor).not.toBeInTheDocument(); - await expect - .element(page.getRow({ index: 0 }).getCell({ index: 0 })) - .toHaveTextContent(/^12222$/); + await expect.element(col1Cell).toHaveTextContent(/^12222$/); }); it('should commit quickly enough on outside clicks so click event handlers access the latest rows state', async () => { const onSave = vi.fn(); await page.render(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.dblClick(col1Cell); await userEvent.keyboard('234'); expect(onSave).not.toHaveBeenCalled(); const saveButton = page.getByRole('button', { name: 'save' }); @@ -99,7 +98,7 @@ describe('Editor', () => { } await page.render(); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.click(col1Cell); const activeRowCells = page.getRowWithCell(page.getActiveCell()).getCell(); await expect.element(activeRowCells).toHaveLength(2); await grid.scroll({ top: 2001 }); @@ -117,7 +116,7 @@ describe('Editor', () => { describe('editable', () => { it('should be editable if an editor is specified and editable is undefined/null', async () => { await page.render(); - const cell = page.getRow({ index: 0 }).getCell({ index: 1 }); + const cell = col2Cell; await expect.element(cell).not.toHaveAttribute('aria-readonly'); await userEvent.dblClick(cell); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); @@ -125,13 +124,13 @@ describe('Editor', () => { it('should be editable if an editor is specified and editable is set to true', async () => { await page.render(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); await expect.element(page.getByRole('textbox', { name: 'col2-editor' })).toBeInTheDocument(); }); it('should not be editable if editable is false', async () => { await page.render(); - const cell = page.getRow({ index: 0 }).getCell({ index: 1 }); + const cell = col2Cell; await expect.element(cell).toHaveAttribute('aria-readonly', 'true'); await userEvent.dblClick(cell); @@ -142,7 +141,7 @@ describe('Editor', () => { it('should not be editable if editable function returns false', async () => { await page.render( row.col1 === 2} />); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).not.toBeInTheDocument(); @@ -156,26 +155,24 @@ describe('Editor', () => { await page.render( ); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const editor1 = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor1).toHaveValue('a1'); await userEvent.keyboard('23'); // The cell value should update as the editor value is changed - await expect - .element(page.getRow({ index: 0 }).getCell({ index: 1 })) - .toHaveTextContent(/^a123$/); + await expect.element(col2Cell).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(); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).not.toHaveFocus(); + await expect.element(col2Cell).not.toHaveFocus(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); await userEvent.click(page.getByRole('textbox', { name: 'col2-editor' })); await userEvent.keyboard('{enter}'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 1 })).toHaveFocus(); + await expect.element(col2Cell).toHaveFocus(); }); it('should not commit on outside click if commitOnOutsideClick is false', async () => { @@ -186,7 +183,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByText('outside')); @@ -206,12 +203,10 @@ describe('Editor', () => { }} /> ); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.click(col2Cell); // TODO: await userEvent.keyboard('yz{enter}'); fails in FF await userEvent.keyboard('{enter}yz{enter}'); - await expect - .element(page.getRow({ index: 0 }).getCell({ index: 1 })) - .toHaveTextContent(/^a1yz$/); + await expect.element(col2Cell).toHaveTextContent(/^a1yz$/); await userEvent.keyboard('x'); await expect .element(page.getByRole('textbox', { name: 'col2-editor' })) @@ -229,11 +224,9 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); await userEvent.keyboard('a{arrowleft}b{arrowright}c{arrowdown}'); // should commit changes on arrowdown - await expect - .element(page.getRow({ index: 0 }).getCell({ index: 1 })) - .toHaveTextContent(/^a1bac$/); + await expect.element(col2Cell).toHaveTextContent(/^a1bac$/); }); it('should close the editor when closeOnExternalRowChange is true or undefined and row is changed from outside', async () => { @@ -245,7 +238,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -261,7 +254,7 @@ describe('Editor', () => { }} /> ); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const editor = page.getByRole('textbox', { name: 'col2-editor' }); await expect.element(editor).toBeInTheDocument(); await userEvent.click(page.getByRole('button', { name: 'update' })); @@ -327,7 +320,7 @@ describe('Editor', () => { ); const outerInput = page.getByRole('textbox', { name: 'outer-input' }); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.dblClick(col1Cell); const col1Input = page.getByRole('textbox', { name: 'col1-input' }); await expect.element(col1Input).toHaveFocus(); await userEvent.click(outerInput); @@ -335,7 +328,7 @@ describe('Editor', () => { await expect.element(col1Input).not.toBeInTheDocument(); await expect.element(outerInput).toHaveFocus(); - await userEvent.dblClick(page.getRow({ index: 0 }).getCell({ index: 1 })); + await userEvent.dblClick(col2Cell); const col2Input = page.getByRole('textbox', { name: 'col2-input' }); await expect.element(col2Input).toHaveFocus(); await userEvent.click(outerInput); diff --git a/test/browser/dragFill.test.tsx b/test/browser/dragFill.test.tsx index 5e3048ae0d..d56693d76e 100644 --- a/test/browser/dragFill.test.tsx +++ b/test/browser/dragFill.test.tsx @@ -5,6 +5,10 @@ import { DataGrid } from '../../src'; import type { Column, FillEvent } from '../../src'; const dragHandle = page.getDragHandle(); +const cell0 = page.getRow({ index: 0 }).getCell({ index: 0 }); +const cell1 = page.getRow({ index: 1 }).getCell({ index: 0 }); +const cell2 = page.getRow({ index: 2 }).getCell({ index: 0 }); +const cell3 = page.getRow({ index: 3 }).getCell({ index: 0 }); interface Row { col: string; @@ -46,55 +50,54 @@ function DragFillTest({ allowDragFill = true }: { allowDragFill?: boolean }) { test('should not allow dragFill if onFill is undefined', async () => { await setup(false); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); + await userEvent.click(cell0); await expect.element(dragHandle).not.toBeInTheDocument(); }); test('should allow dragFill if onFill is specified', async () => { await setup(); - await userEvent.click(page.getRow({ index: 0 }).getCell({ index: 0 })); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); + await userEvent.click(cell0); + await expect.element(cell0).toHaveFocus(); await userEvent.dblClick(dragHandle); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); - await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); - await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a1'); - await expect.element(page.getRow({ index: 3 }).getCell({ index: 0 })).toHaveTextContent('a4'); // readonly cell + await expect.element(cell0).toHaveFocus(); + await expect.element(cell1).toHaveTextContent('a1'); + await expect.element(cell2).toHaveTextContent('a1'); + await expect.element(cell3).toHaveTextContent('a4'); // readonly cell }); test('should update single row using mouse', async () => { await setup(); await commands.dragFill('a1', 'a2'); - await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); - await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a3'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveFocus(); + await expect.element(cell1).toHaveTextContent('a1'); + await expect.element(cell2).toHaveTextContent('a3'); + await expect.element(cell0).toHaveFocus(); }); test('should update multiple rows using mouse', async () => { await setup(); await commands.dragFill('a1', 'a4'); - await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a1'); - await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a1'); - await expect.element(page.getRow({ index: 3 }).getCell({ index: 0 })).toHaveTextContent('a4'); // readonly cell + await expect.element(cell1).toHaveTextContent('a1'); + await expect.element(cell2).toHaveTextContent('a1'); + await expect.element(cell3).toHaveTextContent('a4'); // readonly cell }); test('should allow drag up using mouse', async () => { await setup(); await commands.dragFill('a4', 'a1'); - await expect.element(page.getRow({ index: 0 }).getCell({ index: 0 })).toHaveTextContent('a4'); - await expect.element(page.getRow({ index: 1 }).getCell({ index: 0 })).toHaveTextContent('a4'); - await expect.element(page.getRow({ index: 2 }).getCell({ index: 0 })).toHaveTextContent('a4'); + await expect.element(cell0).toHaveTextContent('a4'); + await expect.element(cell1).toHaveTextContent('a4'); + await expect.element(cell2).toHaveTextContent('a4'); }); test('should focus the cell when drag handle is clicked', async () => { await setup(); - const cell = page.getRow({ index: 0 }).getCell({ index: 0 }); - await userEvent.click(cell); - await expect.element(cell).toHaveFocus(); + await userEvent.click(cell0); + await expect.element(cell0).toHaveFocus(); - cell.blur(); - await expect.element(cell).not.toHaveFocus(); + cell0.blur(); + await expect.element(cell0).not.toHaveFocus(); await userEvent.click(dragHandle); - await expect.element(cell).toHaveFocus(); + await expect.element(cell0).toHaveFocus(); });