diff --git a/cypress/component/Table.cy.tsx b/cypress/component/Table.cy.tsx new file mode 100644 index 0000000000..9991e6ae99 --- /dev/null +++ b/cypress/component/Table.cy.tsx @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 - present Instructure, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React from 'react' +import '../support/component' +import 'cypress-real-events' + +import { Table } from '../../packages/ui' + +describe('', () => + it('can render table head as a combobox when in stacked layout', async () => { + const sortFoo = cy.stub() + cy.mount( +
+ + + + Foo + + + Bar + + + + + + + +
+ ) + + const input = cy.get('input[role="combobox"]') + + input.click() + + cy.get('[role="option"]').first().click() + + cy.wrap(sortFoo).should('have.been.calledOnce') + })) diff --git a/package-lock.json b/package-lock.json index f67d379cac..d61692c0fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10679,14 +10679,13 @@ } }, "node_modules/@vitest/expect": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.2.tgz", - "integrity": "sha512-nKAvxBYqcDugYZ4nJvnm5OR8eDJdgWjk4XM9owQKUjzW70q0icGV2HVnQOyYsp906xJaBDUXw0+9EHw2T8e0mQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.4.tgz", + "integrity": "sha512-39jr5EguIoanChvBqe34I8m1hJFI4+jxvdOpD7gslZrVQBKhh8H9eD7J/LJX4zakrw23W+dITQTDqdt43xVcJw==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/spy": "2.0.2", - "@vitest/utils": "2.0.2", + "@vitest/spy": "2.0.4", + "@vitest/utils": "2.0.4", "chai": "^5.1.1", "tinyrainbow": "^1.2.0" }, @@ -10699,7 +10698,6 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -10709,7 +10707,6 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", "dev": true, - "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -10726,7 +10723,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" } @@ -10736,7 +10732,6 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -10746,7 +10741,6 @@ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, - "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } @@ -10756,17 +10750,15 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14.16" } }, "node_modules/@vitest/pretty-format": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.2.tgz", - "integrity": "sha512-SBCyOXfGVvddRd9r2PwoVR0fonQjh9BMIcBMlSzbcNwFfGr6ZhOhvBzurjvi2F4ryut2HcqiFhNeDVGwru8tLg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.4.tgz", + "integrity": "sha512-RYZl31STbNGqf4l2eQM1nvKPXE0NhC6Eq0suTTePc4mtMQ1Fn8qZmjV4emZdEdG2NOWGKSCrHZjmTqDCDoeFBw==", "dev": true, - "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" }, @@ -10775,13 +10767,12 @@ } }, "node_modules/@vitest/runner": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.2.tgz", - "integrity": "sha512-OCh437Vi8Wdbif1e0OvQcbfM3sW4s2lpmOjAE7qfLrpzJX2M7J1IQlNvEcb/fu6kaIB9n9n35wS0G2Q3en5kHg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.4.tgz", + "integrity": "sha512-Gk+9Su/2H2zNfNdeJR124gZckd5st4YoSuhF1Rebi37qTXKnqYyFCd9KP4vl2cQHbtuVKjfEKrNJxHHCW8thbQ==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/utils": "2.0.2", + "@vitest/utils": "2.0.4", "pathe": "^1.1.2" }, "funding": { @@ -10789,13 +10780,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.2.tgz", - "integrity": "sha512-Yc2ewhhZhx+0f9cSUdfzPRcsM6PhIb+S43wxE7OG0kTxqgqzo8tHkXFuFlndXeDMp09G3sY/X5OAo/RfYydf1g==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.4.tgz", + "integrity": "sha512-or6Mzoz/pD7xTvuJMFYEtso1vJo1S5u6zBTinfl+7smGUhqybn6VjzCDMhmTyVOFWwkCMuNjmNNxnyXPgKDoPw==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.2", + "@vitest/pretty-format": "2.0.4", "magic-string": "^0.30.10", "pathe": "^1.1.2" }, @@ -10804,11 +10794,10 @@ } }, "node_modules/@vitest/spy": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.2.tgz", - "integrity": "sha512-MgwJ4AZtCgqyp2d7WcQVE8aNG5vQ9zu9qMPYQHjsld/QVsrvg78beNrXdO4HYkP0lDahCO3P4F27aagIag+SGQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.4.tgz", + "integrity": "sha512-uTXU56TNoYrTohb+6CseP8IqNwlNdtPwEO0AWl+5j7NelS6x0xZZtP0bDWaLvOfUbaYwhhWp1guzXUxkC7mW7Q==", "dev": true, - "license": "MIT", "dependencies": { "tinyspy": "^3.0.0" }, @@ -10817,13 +10806,12 @@ } }, "node_modules/@vitest/utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.2.tgz", - "integrity": "sha512-pxCY1v7kmOCWYWjzc0zfjGTA3Wmn8PKnlPvSrsA643P1NHl1fOyXj2Q9SaNlrlFE+ivCsxM80Ov3AR82RmHCWQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.4.tgz", + "integrity": "sha512-Zc75QuuoJhOBnlo99ZVUkJIuq4Oj0zAkrQ2VzCqNCx6wAwViHEh5Fnp4fiJTE9rA+sAoXRf00Z9xGgfEzV6fzQ==", "dev": true, - "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.2", + "@vitest/pretty-format": "2.0.4", "estree-walker": "^3.0.3", "loupe": "^3.1.1", "tinyrainbow": "^1.2.0" @@ -10837,7 +10825,6 @@ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, - "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } @@ -35889,7 +35876,6 @@ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -35899,7 +35885,6 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.0.tgz", "integrity": "sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -37413,11 +37398,10 @@ } }, "node_modules/vite-node": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.2.tgz", - "integrity": "sha512-w4vkSz1Wo+NIQg8pjlEn0jQbcM/0D+xVaYjhw3cvarTanLLBh54oNiRbsT8PNK5GfuST0IlVXjsNRoNlqvY/fw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.4.tgz", + "integrity": "sha512-ZpJVkxcakYtig5iakNeL7N3trufe3M6vGuzYAr4GsbCTwobDeyPJpE4cjDhhPluv8OvQCFzu2LWp6GkoKRITXA==", "dev": true, - "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.5", @@ -37842,19 +37826,18 @@ } }, "node_modules/vitest": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.2.tgz", - "integrity": "sha512-WlpZ9neRIjNBIOQwBYfBSr0+of5ZCbxT2TVGKW4Lv0c8+srCFIiRdsP7U009t8mMn821HQ4XKgkx5dVWpyoyLw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.4.tgz", + "integrity": "sha512-luNLDpfsnxw5QSW4bISPe6tkxVvv5wn2BBs/PuDRkhXZ319doZyLOBr1sjfB5yCEpTiU7xCAdViM8TNVGPwoog==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", - "@vitest/expect": "2.0.2", - "@vitest/pretty-format": "^2.0.2", - "@vitest/runner": "2.0.2", - "@vitest/snapshot": "2.0.2", - "@vitest/spy": "2.0.2", - "@vitest/utils": "2.0.2", + "@vitest/expect": "2.0.4", + "@vitest/pretty-format": "^2.0.4", + "@vitest/runner": "2.0.4", + "@vitest/snapshot": "2.0.4", + "@vitest/spy": "2.0.4", + "@vitest/utils": "2.0.4", "chai": "^5.1.1", "debug": "^4.3.5", "execa": "^8.0.1", @@ -37865,8 +37848,8 @@ "tinypool": "^1.0.0", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.0.2", - "why-is-node-running": "^2.2.2" + "vite-node": "2.0.4", + "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" @@ -37880,8 +37863,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.0.2", - "@vitest/ui": "2.0.2", + "@vitest/browser": "2.0.4", + "@vitest/ui": "2.0.4", "happy-dom": "*", "jsdom": "*" }, @@ -38907,9 +38890,9 @@ } }, "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "dependencies": { "siginfo": "^2.0.0", @@ -47536,15 +47519,72 @@ "prop-types": "^15.8.1" }, "devDependencies": { + "@instructure/ui-axe-check": "9.5.0", "@instructure/ui-babel-preset": "9.5.0", "@instructure/ui-color-utils": "9.5.0", "@instructure/ui-test-utils": "9.5.0", - "@instructure/ui-themes": "9.5.0" + "@instructure/ui-themes": "9.5.0", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^15.0.7", + "@testing-library/user-event": "^14.5.2", + "vitest": "^2.0.2" }, "peerDependencies": { "react": ">=16.8 <=18" } }, + "packages/ui-table/node_modules/@testing-library/dom": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.3.2.tgz", + "integrity": "sha512-0bxIdP9mmPiOJ6wHLj8bdJRq+51oddObeCGdEf6PNEhYd93ZYAN+lPRnEOVFtheVwDM7+p+tza3LAQgp0PTudg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "packages/ui-table/node_modules/@testing-library/react": { + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", + "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^10.0.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "packages/ui-table/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, "packages/ui-tabs": { "name": "@instructure/ui-tabs", "version": "9.5.0", diff --git a/packages/ui-table/package.json b/packages/ui-table/package.json index d7987201ff..954539ddd4 100644 --- a/packages/ui-table/package.json +++ b/packages/ui-table/package.json @@ -23,10 +23,15 @@ }, "license": "MIT", "devDependencies": { + "@instructure/ui-axe-check": "9.5.0", "@instructure/ui-babel-preset": "9.5.0", "@instructure/ui-color-utils": "9.5.0", "@instructure/ui-test-utils": "9.5.0", - "@instructure/ui-themes": "9.5.0" + "@instructure/ui-themes": "9.5.0", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^15.0.7", + "@testing-library/user-event": "^14.5.2", + "vitest": "^2.0.2" }, "dependencies": { "@babel/runtime": "^7.24.5", diff --git a/packages/ui-table/src/Table/__tests__/Table.test.tsx b/packages/ui-table/src/Table/__new-tests__/Table.test.tsx similarity index 54% rename from packages/ui-table/src/Table/__tests__/Table.test.tsx rename to packages/ui-table/src/Table/__new-tests__/Table.test.tsx index b99bb2f3ff..799c2bab27 100644 --- a/packages/ui-table/src/Table/__tests__/Table.test.tsx +++ b/packages/ui-table/src/Table/__new-tests__/Table.test.tsx @@ -23,113 +23,136 @@ */ import React from 'react' -import { expect, mount, stub, find, within } from '@instructure/ui-test-utils' -//TODO -/* eslint-disable no-restricted-imports */ -// @ts-ignore: Cannot find module -import { SimpleSelectLocator } from '@instructure/ui-simple-select/es/SimpleSelect/SimpleSelectLocator' +import { render, screen, waitFor } from '@testing-library/react' +import { vi } from 'vitest' +import { userEvent } from '@testing-library/user-event' +import '@testing-library/jest-dom' + import { Table } from '../index' import type { TableProps } from '../props' import type { TableColHeaderProps } from '../ColHeader/props' +import { runAxeCheck } from '@instructure/ui-axe-check' + describe('', async () => { - const render = (props?: TableProps) => - mount( + let consoleErrorMock: any + + beforeEach(() => { + // Mocking console to prevent test output pollution + consoleErrorMock = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleErrorMock.mockRestore() + }) + + const renderTable = (props?: TableProps) => + render(
- Foo - Bar + ColHeader + Bar-header - foo - bar + RowHeader + Cell
) it('should render a caption', async () => { - await render() - const table = await find('table') + const { container } = renderTable() + const caption = container.querySelector('caption') - expect(await table.find('caption:contains(Test table)')).to.exist() + expect(caption).toBeInTheDocument() + expect(caption).toHaveTextContent('Test table') }) it('should meet a11y standards', async () => { - await render() - const table = await find('table') - expect(await table.accessible()).to.be.true() + const { container } = renderTable() + const axeCheck = await runAxeCheck(container) + + expect(axeCheck).toBe(true) }) it('applies a fixed column layout', async () => { - await render({ + await renderTable({ layout: 'fixed' }) - const table = await find('table') - const tableNode = within(table.getDOMNode()) + const table = screen.getByRole('table') - expect(tableNode.getComputedStyle().tableLayout).to.equal('fixed') + expect(table).toHaveStyle({ tableLayout: 'fixed' }) }) it('passes hover to table row', async () => { - await render({ + renderTable({ hover: true }) - const tr = await find('tbody tr') - const trNode = within(tr.getDOMNode()) + const tableRows = screen.getAllByRole('row') - expect(trNode.getComputedStyle().borderLeftStyle).to.not.equal('none') - expect(trNode.getComputedStyle().borderRightStyle).to.not.equal('none') + tableRows.forEach((tableRow) => { + expect(tableRow).not.toHaveAttribute('border-left', 'none') + expect(tableRow).not.toHaveAttribute('border-right', 'none') + }) }) it('sets the scope of column header to col', async () => { - await render() - const th = await find('thead th') - const thNode = within(th.getDOMNode()) + await renderTable() + const columnHeaders = screen.getAllByRole('columnheader') - expect(thNode.getAttribute('scope')).to.equal('col') + columnHeaders.forEach((columnHeader) => { + expect(columnHeader).toHaveAttribute('scope', 'col') + }) }) it('sets the scope of row header to row', async () => { - await render() - const th = await find('tbody th') - const thNode = within(th.getDOMNode()) + renderTable() + const rowHeaders = screen.getAllByRole('rowheader') - expect(thNode.getAttribute('scope')).to.equal('row') + rowHeaders.forEach((rowHeader) => { + expect(rowHeader).toHaveAttribute('scope', 'row') + }) }) it('can render table in stacked layout', async () => { - const stackedTable = await render({ + renderTable({ layout: 'stacked' }) + const stackedTable = screen.getByRole('table') - expect(stackedTable).to.exist() + expect(stackedTable).toBeInTheDocument() + expect(stackedTable).toHaveTextContent('RowHeader') + expect(stackedTable).toHaveTextContent('Cell') + expect(stackedTable).not.toHaveTextContent('ColHeader') }) it('can handle non-existent head in stacked layout', async () => { - const stackedTable = await mount( + render(
) + const stackedTable = screen.getByRole('table') - expect(stackedTable).to.exist() + expect(stackedTable).toBeInTheDocument() }) it('can handle empty head in stacked layout', async () => { - const stackedTable = await mount( + render(
) + const stackedTable = screen.getByRole('table') - expect(stackedTable).to.exist() + expect(stackedTable).toBeInTheDocument() }) it('can handle invalid header in stacked layout', async () => { - const stackedTable = await mount( + render( @@ -138,8 +161,10 @@ describe('
', async () => {
) + const stackedTable = screen.getByRole('table') - expect(stackedTable).to.exist() + expect(stackedTable).toBeInTheDocument() + expect(stackedTable).not.toHaveTextContent('Foo') }) describe('when table is sortable', async () => { @@ -148,7 +173,7 @@ describe('', async () => { handlers = {}, layout: TableProps['layout'] = 'auto' ) => - mount( + render(
@@ -168,29 +193,28 @@ describe('
', async () => { ) it('can render up arrow for ascending order', async () => { - await renderSortableTable({ + const { container } = renderSortableTable({ id: 'id', sortDirection: 'ascending' }) - const arrow = await find('svg[name="IconMiniArrowUp"]') + const arrow = container.querySelector('svg') - expect(arrow).to.exist() + expect(arrow).toHaveAttribute('name', 'IconMiniArrowUp') }) it('can render down arrow for descending order', async () => { - await renderSortableTable({ + const { container } = renderSortableTable({ id: 'id', sortDirection: 'descending' }) - const arrow = await find('svg[name="IconMiniArrowDown"]') + const arrow = container.querySelector('svg') - expect(arrow).to.exist() + expect(arrow).toHaveAttribute('name', 'IconMiniArrowDown') }) it('calls onRequestSort when column header is clicked', async () => { - const onRequestSort = stub() - - await renderSortableTable( + const onRequestSort = vi.fn() + renderSortableTable( { id: 'id' }, @@ -198,95 +222,72 @@ describe('
', async () => { onRequestSort } ) - const button = await find('th button') - - await button.click() - expect(onRequestSort).to.have.been.calledOnce() - }) - - it('can render table head as a combobox when in stacked layout', async () => { - const sortFoo = stub() - - await renderSortableTable( - { - id: 'id' - }, - { - onRequestSort: sortFoo - }, - 'stacked' - ) - const select = await SimpleSelectLocator.find() - const input = await select.findInput() + const button = screen.getByRole('button', { name: 'Foo' }) - await input.click() + userEvent.click(button) - const list = await select.findOptionsList() - const options = await list.findAll('[role="option"]') - - await options[1].click() - expect(sortFoo).to.have.been.calledOnce() + await waitFor(() => { + expect(onRequestSort).toHaveBeenCalledTimes(1) + }) }) it('can display custom label in the select in stacked layout', async () => { - await renderSortableTable( + renderSortableTable( { id: 'id', stackedSortByLabel: 'Custom Text' }, { - onRequestSort: stub() + onRequestSort: vi.fn() }, 'stacked' ) - const select = await SimpleSelectLocator.find() - const input = await select.findInput() + const input = screen.getByRole('combobox') - await input.click() + userEvent.click(input) - const list = await select.findOptionsList() - const options = await list.findAll('[role="option"]') + await waitFor(async () => { + const options = screen.getAllByRole('option') - // with stackedSortByLabel provided - expect(options[0].text()).to.equal('Custom Text') - // the id by default - expect(options[1].text()).to.equal('bar') + expect(options[0]).toHaveTextContent('Custom Text') + expect(options[1]).toHaveTextContent('bar') + }) }) it('can render check mark for sorted column in stacked layout', async () => { - await renderSortableTable( + const { container } = renderSortableTable( { id: 'id', sortDirection: 'ascending' }, { - onRequestSort: stub() + onRequestSort: vi.fn() }, 'stacked' ) - const icon = await find('svg[name="IconCheck"]') + const icon = container.querySelector('svg') - expect(icon).to.exist() + expect(icon).toHaveAttribute('name', 'IconCheck') }) it('creates proper aria-sort attributes (ascending)', async () => { - await renderSortableTable({ + renderSortableTable({ id: 'id', sortDirection: 'ascending' }) - const sortedHeader = await find('th[aria-sort="ascending"]') + const header = screen.getByRole('columnheader', { name: 'Foo' }) - expect(sortedHeader).to.exist() + expect(header).toHaveAttribute('aria-sort', 'ascending') }) it('creates proper aria-sort attributes (descending)', async () => { - await renderSortableTable({ + renderSortableTable({ id: 'id', sortDirection: 'descending' }) - const sortedHeader = await find('th[aria-sort="descending"]') + const header = screen.getByRole('columnheader', { name: 'Foo' }) - expect(sortedHeader).to.exist() + expect(header).toHaveAttribute('aria-sort', 'descending') }) }) }) diff --git a/packages/ui-table/tsconfig.build.json b/packages/ui-table/tsconfig.build.json index 0ffd8f3545..795ebf6e1b 100644 --- a/packages/ui-table/tsconfig.build.json +++ b/packages/ui-table/tsconfig.build.json @@ -7,6 +7,7 @@ }, "include": ["src"], "references": [ + { "path": "../ui-axe-check/tsconfig.build.json" }, { "path": "../ui-babel-preset/tsconfig.build.json" }, { "path": "../ui-color-utils/tsconfig.build.json" }, { "path": "../ui-test-utils/tsconfig.build.json" },