diff --git a/src/data-table/__tests__/data-table-batch-action.e2e.ts b/src/data-table/__tests__/data-table-batch-action.e2e.ts index 839b01a11d..c8429c15db 100644 --- a/src/data-table/__tests__/data-table-batch-action.e2e.ts +++ b/src/data-table/__tests__/data-table-batch-action.e2e.ts @@ -7,30 +7,10 @@ LICENSE file in the root directory of this source tree. import { expect, test } from '@playwright/test'; import { mount, analyzeAccessibility } from '../../test/integration'; -import { getTable, getCellContentsAtColumnIndex, matchArrayElements } from './utilities'; +import { getTableLocator, getCellContentsAtColumnIndex } from './utilities'; const COLUMN_COUNT = 2; -function getCheckboxes(parent) { - return parent.$$('label[data-baseweb="checkbox"]'); -} - -async function clickCheckboxAtRowIndex(parent, index) { - const checkboxes = await getCheckboxes(parent); - await checkboxes[index].click(); -} - -function wait(ms) { - return new Promise((res) => setTimeout(res, ms)); -} - -async function getCheckboxValues(element) { - await wait(50); // briefly wait to give table state chance to update - return element.$$eval('label[data-baseweb="checkbox"] input', (elements) => - elements.map((el) => String(el.checked)) - ); -} - test.describe('data-table batch-actions', () => { test('passes basic a11y tests', async ({ page }) => { await mount(page, 'data-table--columns'); @@ -43,122 +23,155 @@ test.describe('data-table batch-actions', () => { test('renders checkboxes if batch actions are provided', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - const checkboxes = await getCheckboxes(table); - expect(checkboxes.length).toBe(6); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + expect(checkboxes).toHaveCount(6); }); test('checks row on selection', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); - const actual = await getCheckboxValues(table); - const expected = ['true', 'true', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(actual, expected)).toBe(true); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); + await expect(checkboxes.nth(0)).toBeChecked(); + await expect(checkboxes.nth(1)).toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); }); test('unchecks row on second selection', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); - await clickCheckboxAtRowIndex(table, 1); - const actual = await getCheckboxValues(table); - const expected = ['false', 'false', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(actual, expected)).toBe(true); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); + await checkboxes.nth(1).click(); + await expect(checkboxes.nth(0)).not.toBeChecked(); + await expect(checkboxes.nth(1)).not.toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); }); test('checks all rows on header selection', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 0); - const actual = await getCheckboxValues(table); - const expected = ['true', 'true', 'true', 'true', 'true', 'true']; - expect(matchArrayElements(actual, expected)).toBe(true); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(0).click(); + await expect(checkboxes.nth(0)).toBeChecked(); + await expect(checkboxes.nth(1)).toBeChecked(); + await expect(checkboxes.nth(2)).toBeChecked(); + await expect(checkboxes.nth(3)).toBeChecked(); + await expect(checkboxes.nth(4)).toBeChecked(); + await expect(checkboxes.nth(5)).toBeChecked(); }); test('unchecks all rows on second header selection', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 0); - await clickCheckboxAtRowIndex(table, 0); - const actual = await getCheckboxValues(table); - const expected = ['false', 'false', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(actual, expected)).toBe(true); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(0).click(); + await checkboxes.nth(0).click(); + await expect(checkboxes.nth(0)).not.toBeChecked(); + await expect(checkboxes.nth(1)).not.toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); }); test('unchecks all after row select, then header selection', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); - await clickCheckboxAtRowIndex(table, 0); - const actual = await getCheckboxValues(table); - const expected = ['false', 'false', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(actual, expected)).toBe(true); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); + await checkboxes.nth(0).click(); + await expect(checkboxes.nth(0)).not.toBeChecked(); + await expect(checkboxes.nth(1)).not.toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); }); test('does not check header if no rows in table', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 0); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(0).click(); - const button = await page.$('button[aria-label="Approve"]'); + const button = page.locator('button[aria-label="Approve"]'); await button.click(); - const actual = await getCheckboxValues(table); - const expected = ['false']; - expect(matchArrayElements(actual, expected)).toBe(true); + await expect(checkboxes).toHaveCount(1); + await expect(checkboxes.nth(0)).not.toBeChecked(); }); test('calls onSelectionChange on selection changes', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); - await clickCheckboxAtRowIndex(table, 2); - await clickCheckboxAtRowIndex(table, 3); - const count = await page.$eval('#selection-change-count', (el) => el.textContent); - expect(count).toBe('selection change count: 3'); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); + await checkboxes.nth(2).click(); + await checkboxes.nth(3).click(); + const count = page.locator('#selection-change-count'); + await expect(count).toHaveText('selection change count: 3'); }); test('avoids sort on header check', async ({ page }) => { const index = 0; await mount(page, 'data-table--batch-action'); - const table = await getTable(page); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); const before = await getCellContentsAtColumnIndex(page, COLUMN_COUNT, index); - expect(matchArrayElements(before, ['1', '2', '3', '4', '5'])).toBe(true); + expect(before).toEqual(['1', '2', '3', '4', '5']); - await clickCheckboxAtRowIndex(table, 0); + await checkboxes.nth(0).click(); const after = await getCellContentsAtColumnIndex(page, COLUMN_COUNT, index); - expect(matchArrayElements(after, ['1', '2', '3', '4', '5'])).toBe(true); + expect(after).toEqual(['1', '2', '3', '4', '5']); }); test('calls batch action onClick with selected rows', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); - const button = await page.$('button[aria-label="Approve"]'); + const button = page.locator('button[aria-label="Approve"]'); await button.click(); - const actual = await getCheckboxValues(table); - const expected = ['false', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(actual, expected)).toBe(true); + expect(checkboxes).toHaveCount(5); + await expect(checkboxes.nth(0)).not.toBeChecked(); + await expect(checkboxes.nth(1)).not.toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); }); test('batch action clearSelection clears selected rows', async ({ page }) => { await mount(page, 'data-table--batch-action'); - const table = await getTable(page); - await clickCheckboxAtRowIndex(table, 1); - - const beforeActual = await getCheckboxValues(table); - const beforeExpected = ['true', 'true', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(beforeActual, beforeExpected)).toBe(true); - - const button = await page.$('button[aria-label="Flag"]'); + const table = await getTableLocator(page); + const checkboxes = table.locator('label[data-baseweb="checkbox"]'); + await checkboxes.nth(1).click(); + + await expect(checkboxes.nth(0)).toBeChecked(); + await expect(checkboxes.nth(1)).toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); + + const button = page.locator('button[aria-label="Flag"]'); await button.click(); - const afterActual = await getCheckboxValues(table); - const afterExpected = ['false', 'false', 'false', 'false', 'false', 'false']; - expect(matchArrayElements(afterActual, afterExpected)).toBe(true); + await expect(checkboxes.nth(0)).not.toBeChecked(); + await expect(checkboxes.nth(1)).not.toBeChecked(); + await expect(checkboxes.nth(2)).not.toBeChecked(); + await expect(checkboxes.nth(3)).not.toBeChecked(); + await expect(checkboxes.nth(4)).not.toBeChecked(); + await expect(checkboxes.nth(5)).not.toBeChecked(); }); }); diff --git a/src/data-table/__tests__/data-table-imperative-clear-selection.e2e.ts b/src/data-table/__tests__/data-table-imperative-clear-selection.e2e.ts new file mode 100644 index 0000000000..3b36cd5563 --- /dev/null +++ b/src/data-table/__tests__/data-table-imperative-clear-selection.e2e.ts @@ -0,0 +1,39 @@ +/* +Copyright (c) Uber Technologies, Inc. + +This source code is licensed under the MIT license found in the +LICENSE file in the root directory of this source tree. +*/ + +import { expect, test } from '@playwright/test'; +import { mount } from '../../test/integration'; +import { getCellContentsAtColumnIndex } from './utilities'; + +const COLUMN_COUNT = 2; + +test.describe('data-table imperative clear selection', () => { + test('clears selection outside of batch action', async ({ page }) => { + await mount(page, 'data-table--imperative-clear-selection'); + const batchActionRemoveButton = page.locator('text=Remove selected rows'); + const rowActionRemoveButton = page.locator('button[title="Remove row"]'); + const firstRowCheckbox = page.locator('[data-baseweb="checkbox"]').nth(1); + + await expect(batchActionRemoveButton).toBeHidden(); + await expect(rowActionRemoveButton).toBeHidden(); + const initialActual = await getCellContentsAtColumnIndex(page, COLUMN_COUNT, 0); + const initialExpected = ['1', '2', '3', '4', '5']; + expect(initialActual).toEqual(initialExpected); + + await firstRowCheckbox.click(); + await batchActionRemoveButton.click(); + await expect(batchActionRemoveButton).toBeHidden(); + const batchActual = await getCellContentsAtColumnIndex(page, COLUMN_COUNT, 0); + expect(batchActual.slice(0, 4)).toEqual(initialExpected.slice(1)); + + await firstRowCheckbox.click(); + await expect(batchActionRemoveButton).toBeVisible(); + await rowActionRemoveButton.click(); + const rowActual = await getCellContentsAtColumnIndex(page, COLUMN_COUNT, 0); + expect(rowActual.slice(0, 3)).toEqual(initialExpected.slice(2)); + }); +}); diff --git a/src/data-table/__tests__/data-table-imperative-clear-selection.scenario.tsx b/src/data-table/__tests__/data-table-imperative-clear-selection.scenario.tsx new file mode 100644 index 0000000000..ac7eb82038 --- /dev/null +++ b/src/data-table/__tests__/data-table-imperative-clear-selection.scenario.tsx @@ -0,0 +1,82 @@ +/* +Copyright (c) Uber Technologies, Inc. + +This source code is licensed under the MIT license found in the +LICENSE file in the root directory of this source tree. +*/ +import * as React from 'react'; + +import Check from '../../icon/check'; + +import NumericalColumn from '../column-numerical'; +import { StatefulDataTable } from '../stateful-data-table'; + +type RowData = number; + +const columns = [ + NumericalColumn({ + title: 'row-id', + mapDataToValue: (data: RowData) => data, + }), + + NumericalColumn({ + title: 'filler', + mapDataToValue: (data: RowData) => data, + }), +]; + +export function Scenario() { + const controlRef = React.useRef(null); + const [rows, setRows] = React.useState([ + { id: 1, data: 1 }, + { id: 2, data: 2 }, + { id: 3, data: 3 }, + { id: 4, data: 4 }, + { id: 5, data: 5 }, + ]); + + function removeRows(ids) { + const nextRows = rows.filter((row) => !ids.includes(row.id)); + setRows(nextRows); + } + + const batchActions = [ + { + label: 'Remove selected rows', + onClick: ({ selection, clearSelection }) => { + removeRows(selection.map((r) => r.id)); + clearSelection(); + }, + }, + ]; + + const rowActions = [ + { + label: 'Remove row', + onClick: ({ row }) => { + removeRows([row.id]); + if (controlRef.current) { + console.log('here'); + controlRef.current.clearSelection(); + } + }, + renderIcon: function RenderCheck({ size }) { + return ; + }, + }, + ]; + + return ( +
+
+ +
+
+ ); +} diff --git a/src/data-table/__tests__/data-table-row-actions-dynamic.e2e.ts b/src/data-table/__tests__/data-table-row-actions-dynamic.e2e.ts index 3510cff832..7e56c47d0d 100644 --- a/src/data-table/__tests__/data-table-row-actions-dynamic.e2e.ts +++ b/src/data-table/__tests__/data-table-row-actions-dynamic.e2e.ts @@ -7,28 +7,23 @@ LICENSE file in the root directory of this source tree. import { expect, test } from '@playwright/test'; import { mount } from '../../test/integration'; -import { getActionButtonByLabel } from './utilities'; test.describe('data-table-row-actions-dynamic', () => { test('renders provided row action buttons', async ({ page }) => { await mount(page, 'data-table--row-actions-dynamic'); - // hover first row - await page.mouse.move(150, 175); + const stable = page.locator('button[title="stable-action-icon"]'); + const dynamic = page.locator('button[title="dynamic-action-icon"]'); - const a = await getActionButtonByLabel(page, 'stable-action-icon'); - expect(a).toBeTruthy(); + expect(stable).toBeHidden(); + expect(dynamic).toBeHidden(); - const b = await getActionButtonByLabel(page, 'dynamic-action-icon'); - expect(b).toBeFalsy(); + await page.locator('text=1').first().hover(); + expect(stable).toBeVisible(); + expect(dynamic).toBeHidden(); - // hover second row - await page.mouse.move(150, 215); - - const c = await getActionButtonByLabel(page, 'stable-action-icon'); - expect(c).toBeTruthy(); - - const d = await getActionButtonByLabel(page, 'dynamic-action-icon'); - expect(d).toBeTruthy(); + await page.locator('text=2').first().hover(); + expect(stable).toBeVisible(); + expect(dynamic).toBeVisible(); }); }); diff --git a/src/data-table/__tests__/data-table-row-actions.e2e.ts b/src/data-table/__tests__/data-table-row-actions.e2e.ts index b42636fc06..616dcc641f 100644 --- a/src/data-table/__tests__/data-table-row-actions.e2e.ts +++ b/src/data-table/__tests__/data-table-row-actions.e2e.ts @@ -7,41 +7,48 @@ LICENSE file in the root directory of this source tree. import { expect, test } from '@playwright/test'; import { mount } from '../../test/integration'; -import { sortColumnAtIndex, getActionButtonByLabel } from './utilities'; +import { sortColumnAtIndex, TABLE_ROOT } from './utilities'; test.describe('data-table-row-actions', () => { test('renders provided row action buttons', async ({ page }) => { await mount(page, 'data-table--row-actions'); - await page.mouse.move(150, 327); - const actionButtonOne = await getActionButtonByLabel(page, 'row-action-label-one'); - expect(actionButtonOne).toBeTruthy(); + const cell1x1 = page.locator(`${TABLE_ROOT} > div:nth-child(2)`); + await cell1x1.hover(); - const actionButtonTwo = await getActionButtonByLabel(page, 'row-action-label-two'); - expect(actionButtonTwo).toBeTruthy(); + await expect(page.locator('button[title="row-action-label-one"]')).toBeVisible(); + await expect(page.locator('button[title="row-action-label-two"]')).toBeVisible(); }); test('calls provided onclick function when clicked', async ({ browserName, page }) => { - test.fixme(browserName === 'firefox', 'this feature fails in firefox'); + test.fixme(browserName === 'firefox', 'this test is unreliable in firefox'); await mount(page, 'data-table--row-actions'); - await page.mouse.move(150, 327); - const actionButton = await getActionButtonByLabel(page, 'row-action-label-one'); + const cell1x1 = page.locator(`${TABLE_ROOT} > div:nth-child(2)`); + await cell1x1.hover(); + + const actionButton = page.locator('button[title="row-action-label-one"]'); await actionButton.click({ force: true }); const listItems = page.locator('li'); await expect(listItems).toHaveCount(1); - await expect(listItems.first()).toHaveText('Finding Nemo'); + await expect(listItems.first()).toHaveText('Avatar'); }); test('calls onclick with correct row after sorting', async ({ browserName, page }) => { - test.fixme(browserName === 'firefox', 'this feature fails in firefox'); + test.fixme(browserName === 'firefox', 'this test is unreliable in firefox'); await mount(page, 'data-table--row-actions'); + await page.waitForSelector(TABLE_ROOT); + + // click twice to sort z - a await sortColumnAtIndex(page, 0); + await sortColumnAtIndex(page, 0); + + const cell1x1 = page.locator(`${TABLE_ROOT} > div:nth-child(2)`); + await cell1x1.hover(); - await page.mouse.move(150, 327); - const actionButton = await getActionButtonByLabel(page, 'row-action-label-one'); + const actionButton = page.locator('button[title="row-action-label-one"]'); await actionButton.click({ force: true }); - await expect(page.locator('li').first()).toHaveText('Iron Man 3'); + await expect(page.locator('li').first()).toHaveText('Zookeeper'); }); }); diff --git a/src/data-table/__tests__/data-table-rtl.e2e.ts b/src/data-table/__tests__/data-table-rtl.e2e.ts index 38f4ee5c9d..55c3a3558a 100644 --- a/src/data-table/__tests__/data-table-rtl.e2e.ts +++ b/src/data-table/__tests__/data-table-rtl.e2e.ts @@ -7,24 +7,20 @@ LICENSE file in the root directory of this source tree. import { expect, test } from '@playwright/test'; import { mount } from '../../test/integration'; +import { TABLE_ROOT } from './utilities'; test.describe('data-table-rtl', () => { test('renders column cells in RTL order', async ({ page }) => { await mount(page, 'data-table--test-rtl', 'light', true); - // Row 1, cell1 should be rendered to the right - const cell1x1 = await page.$('[data-baseweb="data-table"] > div:nth-child(2)'); - expect(await cell1x1.evaluate((node) => node.style.right)).toBe('0px'); + const cell1x1 = page.locator(`${TABLE_ROOT} > div:nth-child(2)`); + await expect(cell1x1).toHaveCSS('right', '0px'); }); test('action row in RTL order', async ({ page }) => { await mount(page, 'data-table--test-rtl', 'light', true); - // Row 1, cell1 - const cell1x1 = await page.$('[data-baseweb="data-table"] > div:nth-child(2)'); - // Hover on Cell1x1 + const cell1x1 = page.locator(`${TABLE_ROOT} > div:nth-child(2)`); await cell1x1.hover(); - const actionRow = await page.$('[data-baseweb="data-table"] > div:last-child'); - //Action row should be in RTL order - expect(await actionRow.evaluate((node) => node.style.right)).toBe('initial'); - expect(await actionRow.evaluate((node) => node.style.left)).toBe('0px'); + const actionRow = page.locator(`${TABLE_ROOT} > div:last-child`); + await expect(actionRow).toHaveCSS('left', '0px'); }); }); diff --git a/src/data-table/__tests__/data-table.stories.tsx b/src/data-table/__tests__/data-table.stories.tsx index ca96fda2aa..7057776333 100644 --- a/src/data-table/__tests__/data-table.stories.tsx +++ b/src/data-table/__tests__/data-table.stories.tsx @@ -18,6 +18,8 @@ import { Scenario as DataTableEmpty } from './data-table-empty.scenario'; import { Scenario as DataTableExtractedFilters } from './data-table-extracted-filters.scenario'; import { Scenario as DataTableExtractedHighlight } from './data-table-extracted-highlight.scenario'; import { Scenario as DataTableFullWindow } from './data-table-full-window.scenario'; +import { Scenario as DataTableGetRows } from './data-table-get-rows.scenario'; +import { Scenario as DataTableImperativeClearSelection } from './data-table-imperative-clear-selection.scenario'; import { Scenario as DataTableIncludedRowsChange } from './data-table-included-rows-change.scenario'; import { Scenario as DataTableInitialFilters } from './data-table-initial-filters.scenario'; import { Scenario as DataTableInitialSelectedRows } from './data-table-initial-selected-rows.scenario'; @@ -35,7 +37,6 @@ import { Scenario as DataTableTextSearch } from './data-table-text-search.scenar import { Scenario as DataTableDefault } from './data-table.scenario'; import { Scenario as DataTableRtl } from './data-table-rtl.scenario'; import { Scenario as DataTableLargeData } from './data-table-large-column-data.scenario'; -import { Scenario as DataTableGetRows } from './data-table-get-rows.scenario'; export const AddRemoveColumns = () => ; export const BatchAction = () => ; @@ -50,6 +51,8 @@ export const Empty = () => ; export const ExtractedFilters = () => ; export const ExtractedHighlight = () => ; export const FullWindow = () => ; +export const GetRows = () => ; +export const ImperativeClearSelection = () => ; export const IncludedRowsChange = () => ; export const InitialFilters = () => ; export const InitialSelectedRows = () => ; @@ -67,4 +70,3 @@ export const TextSearch = () => ; export const DataTable = () => ; export const TestRtl = () => ; export const LargeData = () => ; -export const GetRows = () => ; diff --git a/src/data-table/__tests__/utilities.ts b/src/data-table/__tests__/utilities.ts index 2a441afa26..80ecda4579 100644 --- a/src/data-table/__tests__/utilities.ts +++ b/src/data-table/__tests__/utilities.ts @@ -13,11 +13,8 @@ export function getTable(page: Page) { return page.$('div[data-baseweb="data-table"]'); } -export function getHeaderCellAtIndex(page: Page, index: number) { - return page.$( - // plus one to convert to one indexed item - `${TABLE_ROOT} > div > div:nth-child(${index + 1})` - ); +export function getTableLocator(page: Page) { + return page.locator('div[data-baseweb="data-table"]'); } export function getCellsAtColumnIndex(page: Page, columnCount: number, index: number) { @@ -38,25 +35,15 @@ export function getCellsAtColumnIndex(page: Page, columnCount: number, index: nu export async function getCellContentsAtColumnIndex(page: Page, columnCount: number, index: number) { const elements = await getCellsAtColumnIndex(page, columnCount, index); - - function getTextContentFromElements(page, elements) { - return Promise.all( - elements.map((element) => { - return page.evaluate((e) => e.textContent, element); - }) - ); - } - - return getTextContentFromElements(page, elements.filter(Boolean)); -} - -export function getActionButtonByLabel(parent: Page, label: string) { - return parent.$(`button[alt="${label}"]`); + return Promise.all(elements.filter(Boolean).map((element) => element.textContent())); } export async function sortColumnAtIndex(page: Page, index: number) { - const headerCell = await getHeaderCellAtIndex(page, index); - const sortButton = await headerCell.$('div[role="button"]'); + const headerCell = page.locator( + // plus one to convert to one indexed item + `${TABLE_ROOT} > div > div:nth-child(${index + 1})` + ); + const sortButton = headerCell.locator('div[role="button"]'); return sortButton.click(); } diff --git a/src/data-table/data-table.js.flow b/src/data-table/data-table.js.flow index 2df6c24ba3..ff86a4cd1e 100644 --- a/src/data-table/data-table.js.flow +++ b/src/data-table/data-table.js.flow @@ -810,8 +810,6 @@ export function DataTable({ return result; }, [sortedIndices, filteredIndices, onIncludedRowsChange, allRows]); - React.useImperativeHandle(controlRef, () => ({ getRows: () => rows }), [rows]); - const [browserScrollbarWidth, setBrowserScrollbarWidth] = React.useState(0); const normalizedWidths = React.useMemo(() => { const resizedWidths = measuredWidths.map((w, i) => Math.floor(w) + Math.floor(resizeDeltas[i])); @@ -902,6 +900,8 @@ export function DataTable({ [onSort] ); + React.useImperativeHandle(controlRef, () => ({ getRows: () => rows, clearSelection: handleSelectNone }), [handleSelectNone, rows]); + const [columnHighlightIndex, setColumnHighlightIndex] = React.useState(-1); const [rowHighlightIndex, setRowHighlightIndex] = React.useState(-1); diff --git a/src/data-table/data-table.tsx b/src/data-table/data-table.tsx index 7873f5d8e2..3e6537835e 100644 --- a/src/data-table/data-table.tsx +++ b/src/data-table/data-table.tsx @@ -574,8 +574,6 @@ const InnerTableElement = React.forwardRef< const RowActionIcon = rowAction.renderIcon; return (