diff --git a/packages/react/__tests__/src/components/Table/index.js b/packages/react/__tests__/src/components/Table/index.js
deleted file mode 100644
index 233cf0a85..000000000
--- a/packages/react/__tests__/src/components/Table/index.js
+++ /dev/null
@@ -1,278 +0,0 @@
-import React from 'react';
-import { shallow, mount } from 'enzyme';
-import { spy } from 'sinon';
-import Table, {
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
- TableFooter
-} from '../../../../src/components/Table';
-import axe from '../../../axe';
-
-const renderDefaultTable = () =>
- mount(
-
-
-
-
- A
-
-
- B
-
-
-
-
-
-
- 1
-
- 2
-
-
-
-
-
- foo
-
- bar
-
-
-
- );
-
-describe('Table components', () => {
- test('render children', () => {
- const table = renderDefaultTable();
- const tableHead = table.find('TableHead');
- const tableRow = table.find('TableRow').at(0);
- const tableHeader = table.find('TableHeader').at(0);
- const tableBody = table.find('TableBody');
- const tableCell = table.find('TableCell').at(0);
- const tableFooter = table.find('TableFooter').at(0);
-
- const tableItems = [
- table,
- tableHead,
- tableRow,
- tableHeader,
- tableBody,
- tableCell,
- tableFooter
- ];
-
- tableItems.forEach(wrapper => {
- expect(!!wrapper.children().length).toBe(true);
- });
- });
-
- test('passes classNames through', () => {
- const table = renderDefaultTable();
- const tableHead = table.find('TableHead');
- const tableRow = table.find('TableRow').at(0);
- const tableHeader = table.find('TableHeader').at(0);
- const tableBody = table.find('TableBody');
- const tableCell = table.find('TableCell').at(0);
- const tableFooter = table.find('TableFooter').at(0);
-
- expect(table.is('.my-table')).toBe(true);
- expect(tableHead.is('.my-table-head')).toBe(true);
- expect(tableRow.is('.my-table-row')).toBe(true);
- expect(tableHeader.is('.my-table-header')).toBe(true);
- expect(tableBody.is('.my-table-body')).toBe(true);
- expect(tableCell.is('.my-table-cell')).toBe(true);
- expect(tableFooter.is('.my-table-footer')).toBe(true);
- });
-
- test('passes arbitrary props through', () => {
- const table = renderDefaultTable();
- const tableHead = table.find('TableHead');
- const tableRow = table.find('TableRow').at(0);
- const tableHeader = table.find('TableHeader').at(0);
- const tableBody = table.find('TableBody');
- const tableCell = table.find('TableCell').at(0);
- const tableFooter = table.find('TableFooter').at(0);
-
- const tableItems = [
- table,
- tableHead,
- tableRow,
- tableHeader,
- tableBody,
- tableCell,
- tableFooter
- ];
-
- tableItems.forEach(wrapper => {
- expect(wrapper.is('[data-foo="true"]')).toBe(true);
- });
-
- expect(tableHeader.is('[scope="col"]')).toBe(true);
- });
-
- test('renders the expected semantic HTML elements', () => {
- const table = shallow();
- const body = shallow(a);
- const cell = shallow(a);
- const head = shallow(a);
- const header = shallow(a);
- const row = shallow(a);
- const footer = shallow(a);
-
- expect(table.is('table')).toBe(true);
- expect(body.is('tbody')).toBe(true);
- expect(cell.is('td')).toBe(true);
- expect(head.is('thead')).toBe(true);
- expect(header.is('th')).toBe(true);
- expect(footer.is('tfoot')).toBe(true);
- expect(row.is('tr')).toBe(true);
- });
-
- test('renders border variant', () => {
- const wrapper = mount(
-
-
-
- Header
-
-
-
-
- Cell
-
-
-
- );
-
- expect(wrapper.find('.Table--border').exists()).toBe(true);
- });
-
- describe('Sortable Table', () => {
- test('renders sort button and icons when passing in sortDirection and onSort in TableHeader', () => {
- const wrapper = mount(
-
-
-
- null}>
- Sortable Header
-
-
-
-
- );
-
- expect(wrapper.find('button').exists()).toBe(true);
- expect(wrapper.find('.Icon--sort-triangle').exists()).toBe(true);
- expect(wrapper.find('Offscreen').text()).toBe('');
- });
-
- test('render className TableHeader--sorting when a TableHeader is actively sorting', () => {
- const wrapper = mount(
-
-
-
- null}>
- Sortable Header
-
-
-
-
- );
-
- expect(wrapper.find('.TableHeader--sort-ascending').exists()).toBe(true);
- });
-
- test('renders triangle up Icon and ascending message when sortDirection is ascending', () => {
- const wrapper = mount(
-
-
-
- null}
- >
- Sortable Header
-
-
-
-
- );
-
- expect(wrapper.find('Offscreen').text()).toBe('up and away');
- expect(wrapper.find('.Icon--table-sort-ascending').exists()).toBe(true);
- });
-
- test('renders triangle down Icon and descending message when sortDirection is descending', () => {
- const wrapper = mount(
-
-
-
- null}
- >
- Sortable Header
-
-
-
-
- );
-
- expect(wrapper.find('Offscreen').text()).toBe('down below');
- expect(wrapper.find('.Icon--table-sort-descending').exists()).toBe(true);
- });
-
- test('calls onSort when sort button is clicked', () => {
- const onSortSpy = spy();
- const wrapper = mount(
-
-
-
-
- Sortable Header
-
-
-
-
- );
-
- wrapper.find('button').simulate('click');
-
- expect(onSortSpy.calledOnce).toBe(true);
- });
-
- test('focus stays on the sort button after it is clicked', () => {
- const wrapper = mount(
-
-
-
- null}
- >
- Sortable Header
-
-
-
-
- );
-
- wrapper.find('button').simulate('click');
- wrapper.update();
-
- expect(document.activeElement.id).toBe(
- wrapper.find('button').getDOMNode().id
- );
- });
- });
-});
-
-test('returns 0 axe violations', async () => {
- const table = renderDefaultTable();
- expect(await axe(table.html())).toHaveNoViolations();
-});
diff --git a/packages/react/src/components/Table/index.test.tsx b/packages/react/src/components/Table/index.test.tsx
new file mode 100644
index 000000000..752a8c499
--- /dev/null
+++ b/packages/react/src/components/Table/index.test.tsx
@@ -0,0 +1,369 @@
+import React from 'react';
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import Table, {
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+ TableFooter
+} from './';
+import axe from '../../axe';
+
+const renderDefaultTable = () => {
+ return render(
+
+
+
+
+ A
+
+
+ B
+
+
+
+
+
+
+ 1
+
+ 2
+
+
+
+
+
+ foo
+
+ bar
+
+
+
+ );
+};
+
+test('should render table and its components correctly', () => {
+ renderDefaultTable();
+
+ const table = screen.getByRole('table');
+ const tableHead = screen.getByTestId('thead');
+ const tableBody = screen.getByTestId('tbody');
+ const tableRows = screen.getAllByRole('row');
+ const tableHeaders = screen.getAllByRole('columnheader');
+ const tableCells = screen.getAllByRole('cell');
+ const tableFooter = screen.getByTestId('tfoot');
+
+ // Accessing the first elements of each type for more detailed assertions
+ const firstTableRow = tableRows[0];
+ const firstTableHeader = tableHeaders[0];
+ const firstTableCell = tableCells[0];
+
+ // Assertions on the lengths of various table components
+ expect(tableRows).toHaveLength(3); // Assuming there are three rows
+ expect(tableHeaders).toHaveLength(2); // Assuming there are two column headers
+ expect(tableCells).toHaveLength(4); // Assuming there are four cells
+
+ const tableItems = [
+ table,
+ tableHead,
+ tableBody,
+ firstTableRow,
+ firstTableHeader,
+ firstTableCell,
+ tableFooter
+ ];
+
+ tableItems.forEach((element) => {
+ expect(element).toBeInTheDocument();
+ });
+});
+
+test('should pass classNames through', () => {
+ renderDefaultTable();
+
+ const table = screen.getByRole('table');
+ const tableHead = screen.getByTestId('thead');
+ const tableBody = screen.getByTestId('tbody');
+ const tableRows = screen.getAllByRole('row');
+ const tableHeaders = screen.getAllByRole('columnheader');
+ const tableCells = screen.getAllByRole('cell');
+ const tableFooter = screen.getByTestId('tfoot');
+
+ const firstTableRow = tableRows[0];
+ const firstTableHeader = tableHeaders[0];
+ const firstTableCell = tableCells[0];
+
+ expect(table).toHaveClass('Table', 'my-table');
+ expect(tableHead).toHaveClass('TableHead', 'my-table-head');
+ expect(tableBody).toHaveClass('TableBody', 'my-table-body');
+ expect(firstTableRow).toHaveClass('TableRow', 'my-table-row');
+ expect(firstTableHeader).toHaveClass('TableHeader', 'my-table-header');
+ expect(firstTableCell).toHaveClass('TableCell', 'my-table-cell');
+ expect(tableFooter).toHaveClass('TableFooter', 'my-table-footer');
+});
+
+test('should pass arbitrary props through', () => {
+ renderDefaultTable();
+
+ const table = screen.getByRole('table');
+ const tableHead = screen.getByTestId('thead');
+ const tableBody = screen.getByTestId('tbody');
+ const tableRows = screen.getAllByRole('row');
+ const tableHeaders = screen.getAllByRole('columnheader');
+ const tableCells = screen.getAllByRole('cell');
+ const tableFooter = screen.getByTestId('tfoot');
+
+ const firstTableRow = tableRows[0];
+ const firstTableHeader = tableHeaders[0];
+ const firstTableCell = tableCells[0];
+
+ const tableItems = [
+ table,
+ tableHead,
+ tableBody,
+ firstTableRow,
+ firstTableHeader,
+ firstTableCell,
+ tableFooter
+ ];
+
+ tableItems.forEach((element) => {
+ expect(element).toHaveAttribute('data-foo', 'true');
+ });
+
+ expect(firstTableHeader).toHaveAttribute('scope', 'col');
+});
+
+test('should render the expected semantic HTML elements', () => {
+ renderDefaultTable();
+
+ const table = screen.getByRole('table');
+ const tableHead = screen.getByTestId('thead');
+ const tableBody = screen.getByTestId('tbody');
+ const tableRows = screen.getAllByRole('row');
+ const tableHeaders = screen.getAllByRole('columnheader');
+ const tableCells = screen.getAllByRole('cell');
+ const tableFooter = screen.getByTestId('tfoot');
+
+ const firstTableRow = tableRows[0];
+ const firstTableHeader = tableHeaders[0];
+ const firstTableCell = tableCells[0];
+
+ expect(table.tagName).toBe('TABLE');
+ expect(tableHead.tagName).toBe('THEAD');
+ expect(tableBody.tagName).toBe('TBODY');
+ expect(firstTableRow.tagName).toBe('TR');
+ expect(firstTableHeader.tagName).toBe('TH');
+ expect(firstTableCell.tagName).toBe('TD');
+ expect(tableFooter.tagName).toBe('TFOOT');
+});
+
+test('should render with border variant', () => {
+ render(
+
+
+
+ Header
+
+
+
+
+ Cell
+
+
+
+ );
+
+ expect(screen.getByRole('table')).toHaveClass('Table', 'Table--border');
+});
+
+test('should render sort button and icons with sortDirection and onSort in Table', () => {
+ render(
+
+
+
+ null}>
+ Sortable Header
+
+
+
+
+ );
+
+ expect(screen.getByRole('button')).toBeInTheDocument();
+ expect(screen.getByRole('status').closest('.Icon--sort-triangle'));
+ expect(screen.getByRole('status')).toHaveTextContent('');
+});
+
+test('should render className "TableHeader--sorting" when actively sorting', () => {
+ render(
+
+
+
+ null}>
+ Sortable Header
+
+
+
+
+ );
+
+ expect(screen.getByRole('columnheader')).toHaveAttribute(
+ 'aria-sort',
+ 'ascending'
+ );
+ expect(screen.getByRole('columnheader')).toHaveClass(
+ 'TableHeader',
+ 'TableHeader--sort-ascending'
+ );
+});
+
+test('should render triangle up Icon and ascending message when sortDirection is ascending', () => {
+ render(
+
+
+
+ null}
+ >
+ Sortable Header
+
+
+
+
+ );
+
+ expect(screen.getByRole('status')).toHaveTextContent('up and away');
+ expect(screen.getByRole('status').closest('.Icon--table-sort-ascending'));
+});
+
+test('should render triangle down Icon and descending message when sortDirection is descending', () => {
+ render(
+
+
+
+ null}
+ >
+ Sortable Header
+
+
+
+
+ );
+
+ expect(screen.getByRole('status')).toHaveTextContent('down below');
+ expect(screen.getByRole('status').closest('.Icon--table-sort-descending'));
+});
+
+test('should call onSort when sort button is clicked', async () => {
+ const onSortMock = jest.fn();
+
+ render(
+
+
+
+
+ Sortable Header
+
+
+
+
+ );
+
+ const button = screen.getByRole('button');
+
+ await userEvent.click(button);
+ await waitFor(() => {
+ expect(onSortMock).toHaveBeenCalledTimes(1);
+ });
+});
+
+test('should maintain focus on the sort button after it is clicked', async () => {
+ render(
+
+
+
+ null}
+ >
+ Sortable Header
+
+
+
+
+ );
+
+ const button = screen.getByRole('button');
+
+ await userEvent.click(button);
+ await waitFor(() => {
+ expect(button).toHaveFocus();
+ });
+});
+
+test('returns 0 axe violations', async () => {
+ const { container } = renderDefaultTable();
+ const results = await axe(container);
+ expect(results).toHaveNoViolations();
+});
+
+test('returns 0 axe violations without any sorting', async () => {
+ const { container } = render(
+
+
+
+ null}>
+ Sortable Header
+
+
+
+
+ );
+ const results = await axe(container);
+ expect(results).toHaveNoViolations();
+});
+
+test('returns 0 axe violations with ascending sorting', async () => {
+ const { container } = render(
+
+
+
+ null}>
+ Sortable Header
+
+
+
+
+ );
+ const results = await axe(container);
+ expect(results).toHaveNoViolations();
+});
+
+test('returns 0 axe violations with descending sorting', async () => {
+ const { container } = render(
+
+
+
+ null}>
+ Sortable Header
+
+
+
+
+ );
+ const results = await axe(container);
+ expect(results).toHaveNoViolations();
+});