diff --git a/.yarn/cache/@playwright-test-npm-1.28.0-20a17c7d04-5b90a4fd7a.zip b/.yarn/cache/@playwright-test-npm-1.28.0-20a17c7d04-5b90a4fd7a.zip deleted file mode 100644 index f8eb2b9edc92..000000000000 Binary files a/.yarn/cache/@playwright-test-npm-1.28.0-20a17c7d04-5b90a4fd7a.zip and /dev/null differ diff --git a/.yarn/cache/@playwright-test-npm-1.36.2-0b5c09b329-659304e0bb.zip b/.yarn/cache/@playwright-test-npm-1.36.2-0b5c09b329-659304e0bb.zip new file mode 100644 index 000000000000..4e11584d1c55 Binary files /dev/null and b/.yarn/cache/@playwright-test-npm-1.36.2-0b5c09b329-659304e0bb.zip differ diff --git a/.yarn/cache/playwright-core-npm-1.28.0-9bd034478b-4bd13bf83b.zip b/.yarn/cache/playwright-core-npm-1.28.0-9bd034478b-4bd13bf83b.zip deleted file mode 100644 index c5f6a0c3fb33..000000000000 Binary files a/.yarn/cache/playwright-core-npm-1.28.0-9bd034478b-4bd13bf83b.zip and /dev/null differ diff --git a/.yarn/cache/playwright-core-npm-1.36.2-37b679cd9b-2193ce802e.zip b/.yarn/cache/playwright-core-npm-1.36.2-37b679cd9b-2193ce802e.zip new file mode 100644 index 000000000000..c538ca249d08 Binary files /dev/null and b/.yarn/cache/playwright-core-npm-1.36.2-37b679cd9b-2193ce802e.zip differ diff --git a/e2e/components/DataTable/DataTable-test.avt.e2e.js b/e2e/components/DataTable/DataTable-test.avt.e2e.js new file mode 100644 index 000000000000..7259c55644d2 --- /dev/null +++ b/e2e/components/DataTable/DataTable-test.avt.e2e.js @@ -0,0 +1,373 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { expect, test } = require('@playwright/test'); +const { visitStory } = require('../../test-utils/storybook'); + +test.describe('DataTable @avt', () => { + test.describe('basic', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-basic--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-basic--default' + ); + }); + test('xl with two lines has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-basic--xl-with-two-lines', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-basic--xl-with-two-lines' + ); + }); + }); + + test.describe('batch actions', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-batch-actions--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-batch-actions--default' + ); + }); + }); + + test.describe('dynamic', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-dynamic--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-dynamic--default' + ); + }); + + test('default keyboard navigation sequence', async ({ page }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-dynamic--default', + globals: { + theme: 'white', + }, + }); + + await expect(page).toHaveNoACViolations( + 'components-datatable-dynamic--default' + ); + + // Start off by manually focusing the search input + await page.getByRole('searchbox').focus(); + await expect(page.getByRole('searchbox')).toBeFocused(); + + // Navigate to the gear/settings button + await page.keyboard.press('Tab'); + await expect( + page.getByRole('button', { name: 'Settings' }) + ).toBeFocused(); + + // Navigate to the select all checkbox + await page.keyboard.press('Tab'); + await expect( + page.getByRole('checkbox', { name: 'Select all rows' }) + ).toBeFocused(); + + // Pressing enter on the select all checkbox shouldn't do anything + await page.keyboard.press('Enter'); + await expect( + page.getByRole('checkbox', { name: 'Select all rows' }) + ).not.toBeChecked(); + + // Pressing space should check the select all checkbox + await page.keyboard.press('Space'); + await expect( + page.getByRole('checkbox', { name: 'Select all rows' }) + ).toBeChecked(); + + // Every checkbox should be checked + for (const checkbox of await page.getByRole('checkbox').all()) { + await expect(checkbox).toBeChecked(); + } + + // Pressing space should uncheck the select all checkbox + await page.keyboard.press('Space'); + await expect( + page.getByRole('checkbox', { name: 'Select all rows' }) + ).not.toBeChecked(); + // Every checkbox should no longer be checked + for (const checkbox of await page.getByRole('checkbox').all()) { + await expect(checkbox).not.toBeChecked(); + } + + // Navigate to the first expansion button + await page.keyboard.press('Tab'); + await expect( + page.getByRole('button', { name: 'Expand current row' }).first() + ).toBeFocused(); + // Expand the first row + await page.keyboard.press('Space'); + await expect( + page.getByRole('heading', { name: 'Expandable row content' }).first() + ).toBeVisible(); + + // Navigate to the first row selection checkbox and check it + await page.keyboard.press('Tab'); + await page.keyboard.press('Space'); + await expect(page.getByText('1 item selected')).toBeVisible(); + + // Navigate backwards up into the batch action bar + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('Shift+Tab'); + + await page + .getByRole('heading', { name: 'Expandable row content' }) + .first() + .hover(); + await expect(page).toHaveNoACViolations( + 'components-datatable-dynamic--default---with-batch-actions-open-and-row-expanded' + ); + await expect(page.getByRole('button', { name: 'Delete' })).toBeFocused(); + + // Navigate forwards through the batch action buttons + await page.keyboard.press('Tab'); + await expect(page.getByRole('button', { name: 'Save' })).toBeFocused(); + await page.keyboard.press('Tab'); + await expect( + page.getByRole('button', { name: 'Download' }) + ).toBeFocused(); + await page.keyboard.press('Tab'); + await expect(page.getByRole('button', { name: 'Cancel' })).toBeFocused(); + // Invoke the cancel button + await page.keyboard.press('Space'); + await expect(page.getByText('1 item selected')).not.toBeVisible(); + // Every checkbox should no longer be checked + for (const checkbox of await page.getByRole('checkbox').all()) { + await expect(checkbox).not.toBeChecked(); + } + }); + }); + + test.describe('expansion', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-expansion--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-expansion--default' + ); + }); + test('batch expansion has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-expansion--batch-expansion', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-expansion--batch-expansion' + ); + }); + }); + + test.describe('filtering', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-filtering--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-filtering--default' + ); + }); + }); + + test.describe('selection', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-selection--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-selection--default' + ); + }); + test('with-radio-expansion has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-selection--with-radio-expansion', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-selection--with-radio-expansion' + ); + }); + test('with-selection-and-sorting has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-selection--with-selection-and-sorting', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-selection--with-selection-and-sorting' + ); + }); + }); + + test.describe('skeleton', () => { + test('skeleton has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-skeleton--skeleton', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-skeleton--skeleton' + ); + }); + }); + + test.describe('sorting', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-sorting--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-sorting--default' + ); + }); + }); + + test.describe('toolbar', () => { + test('default has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-toolbar--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-toolbar--default' + ); + }); + test('persistent-toolbar has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-toolbar--persistent-toolbar', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-toolbar--persistent-toolbar' + ); + }); + test('small-persistent-toolbar has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-toolbar--small-persistent-toolbar', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-toolbar--small-persistent-toolbar' + ); + }); + test('with-overflow-menu has no accessibility-checker violations', async ({ + page, + }) => { + await visitStory(page, { + component: 'DataTable', + id: 'components-datatable-toolbar--with-overflow-menu', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations( + 'components-datatable-toolbar--with-overflow-menu' + ); + }); + }); +}); diff --git a/e2e/components/DataTable/DataTable-test.e2e.js b/e2e/components/DataTable/DataTable-test.e2e.js index 0c20124d666d..2687d087996f 100644 --- a/e2e/components/DataTable/DataTable-test.e2e.js +++ b/e2e/components/DataTable/DataTable-test.e2e.js @@ -7,9 +7,9 @@ 'use strict'; -const { expect, test } = require('@playwright/test'); +const { test } = require('@playwright/test'); const { themes } = require('../../test-utils/env'); -const { snapshotStory, visitStory } = require('../../test-utils/storybook'); +const { snapshotStory } = require('../../test-utils/storybook'); test.describe('DataTable', () => { themes.forEach((theme) => { @@ -127,15 +127,4 @@ test.describe('DataTable', () => { }); }); }); - - test('accessibility-checker @avt', async ({ page }) => { - await visitStory(page, { - component: 'DataTable', - id: 'components-datatable-basic--default', - globals: { - theme: 'white', - }, - }); - await expect(page).toHaveNoACViolations('DataTable'); - }); }); diff --git a/package.json b/package.json index d1da3637b574..d38f331ea660 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@commitlint/config-conventional": "^17.0.0", "@percy/cli": "^1.1.0", "@percy/playwright": "^1.0.4", - "@playwright/test": "^1.28.0", + "@playwright/test": "^1.36.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", diff --git a/packages/react/src/components/DataTable/stories/DataTable-toolbar.stories.js b/packages/react/src/components/DataTable/stories/DataTable-toolbar.stories.js index c04d223dfaab..a26d66719fd4 100644 --- a/packages/react/src/components/DataTable/stories/DataTable-toolbar.stories.js +++ b/packages/react/src/components/DataTable/stories/DataTable-toolbar.stories.js @@ -261,7 +261,7 @@ export const WithOverflowMenu = () => ( {header.header} ))} - + diff --git a/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js b/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js index f5668b6bfed5..83185d03e76f 100644 --- a/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js +++ b/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js @@ -116,77 +116,89 @@ export const Default = () => { selectedRows, getTableProps, getTableContainerProps, - }) => ( - - - - - Delete - - - Save - - - Download - - - - - - - Add row - - - Add header - - - - - - - - - - {headers.map((header, i) => ( - - {header.header} - + }) => { + const batchActionProps = getBatchActionProps(); + return ( + + + + + Delete + + + Save + + + Download + + + + + + + Add row + + + Add header + + + + +
+ + + + + {headers.map((header, i) => ( + + {header.header} + + ))} + + + + {rows.map((row) => ( + + + + {row.cells.map((cell) => ( + {cell.value} + ))} + + +
Expandable row content
+
Description here
+
+
))} - - - - {rows.map((row) => ( - - - - {row.cells.map((cell) => ( - {cell.value} - ))} - - -
Expandable row content
-
Description here
-
-
- ))} -
-
-
- )} +
+ + + ); + }} /> ); } @@ -273,99 +285,111 @@ export const Playground = (args) => { selectedRows, getTableProps, getTableContainerProps, - }) => ( - - - - - Delete - - - Save - - - Download - - - - { - action('TableToolbarSearch - onChange')(evt); - onInputChange(evt); - }} - /> - - { - action('handleOnRowAdd')(evt); - this.handleOnRowAdd(); - }}> - Add row - - { - action('handleOnHeaderAdd')(evt); - this.handleOnHeaderAdd(); - }}> - Add header - - - - - - - - - {args.radio ? ( -
- ) : ( - - )} - {headers.map((header, i) => ( - - {header.header} - + }) => { + const batchActionProps = getBatchActionProps(); + return ( + + + + + Delete + + + Save + + + Download + + + + { + action('TableToolbarSearch - onChange')(evt); + onInputChange(evt); + }} + /> + + { + action('handleOnRowAdd')(evt); + this.handleOnRowAdd(); + }}> + Add row + + { + action('handleOnHeaderAdd')(evt); + this.handleOnHeaderAdd(); + }}> + Add header + + + + + + + + + {args.radio ? ( +
+ ) : ( + + )} + {headers.map((header, i) => ( + + {header.header} + + ))} + + + + {rows.map((row) => ( + + + + {row.cells.map((cell) => ( + {cell.value} + ))} + + +
Expandable row content
+
Description here
+
+
))} - - - - {rows.map((row) => ( - - - - {row.cells.map((cell) => ( - {cell.value} - ))} - - -
Expandable row content
-
Description here
-
-
- ))} -
-
-
- )} + +
+
+ ); + }} /> ); } diff --git a/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js b/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js index 4103741697b2..1f7fb6d0943d 100644 --- a/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js +++ b/packages/react/src/components/DataTable/stories/expansion/DataTable-expansion.stories.js @@ -62,7 +62,7 @@ export const Default = () => ( - + {headers.map((header, i) => ( {header.header} @@ -115,6 +115,7 @@ export const BatchExpansion = () => ( {headers.map((header, i) => ( diff --git a/packages/react/src/components/DataTableSkeleton/DataTableSkeleton.stories.js b/packages/react/src/components/DataTableSkeleton/DataTableSkeleton.stories.js index 239ded4f1fb9..b27a1ea3b37b 100644 --- a/packages/react/src/components/DataTableSkeleton/DataTableSkeleton.stories.js +++ b/packages/react/src/components/DataTableSkeleton/DataTableSkeleton.stories.js @@ -29,7 +29,11 @@ export const Skeleton = () => { const { ...rest } = props(); return (
- +
); @@ -38,7 +42,11 @@ export const Skeleton = () => { export const Playground = (args) => { return (
- +
); diff --git a/yarn.lock b/yarn.lock index dae9f5f78657..922d8cf350e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5041,15 +5041,19 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:^1.28.0": - version: 1.28.0 - resolution: "@playwright/test@npm:1.28.0" +"@playwright/test@npm:^1.36.2": + version: 1.36.2 + resolution: "@playwright/test@npm:1.36.2" dependencies: "@types/node": "*" - playwright-core: 1.28.0 + fsevents: 2.3.2 + playwright-core: 1.36.2 + dependenciesMeta: + fsevents: + optional: true bin: playwright: cli.js - checksum: 5b90a4fd7a30e989f0b7ff97201eb3ab91d56b93ac5cd020ca6e36cd90a0f9386770214375b6c50471def75cbe0e7219f77f2c126d5d31655c5228bd16ab4f1a + checksum: 659304e0bbbafb2fa36395fbd8bd2c5db2b7791bbb55fa62409946ec7ec726cf8fff89f2b8a1a74fe831bf50a8780a37a5322a1251a6f7db2a9220a57ac408f0 languageName: node linkType: hard @@ -10556,7 +10560,7 @@ __metadata: "@commitlint/config-conventional": ^17.0.0 "@percy/cli": ^1.1.0 "@percy/playwright": ^1.0.4 - "@playwright/test": ^1.28.0 + "@playwright/test": ^1.36.2 "@testing-library/jest-dom": ^5.16.5 "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.4.3 @@ -15809,7 +15813,7 @@ __metadata: languageName: node linkType: hard -"fsevents@^2.3.2, fsevents@~2.3.2": +"fsevents@^2.3.2, fsevents@npm:2.3.2, fsevents@~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -15819,7 +15823,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: @@ -24175,12 +24179,12 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.28.0": - version: 1.28.0 - resolution: "playwright-core@npm:1.28.0" +"playwright-core@npm:1.36.2": + version: 1.36.2 + resolution: "playwright-core@npm:1.36.2" bin: - playwright: cli.js - checksum: 4bd13bf83bca37f239f1573fcad7f3b559b3b5e28925f57fa66055446b2aef90c4403f9dbb4a9c34f6bd03a2461e61c97eb7fe5faed6b88f027c0bc3727cd096 + playwright-core: cli.js + checksum: 2193ce802ef93c28b9b5e11a0b1d7b60778c686015659978d1cbf0eb9cda2cdc85ec5575b887c1346e9d161cc2805bf27638d76a2f7f857dffeae968e6ceffcd languageName: node linkType: hard