From 9ae3db6128573cb8a0b7aac4ee6c730d501e26a8 Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sat, 27 Jan 2024 23:06:22 +0200 Subject: [PATCH 1/7] Initial implementation and tests of toHaveRole --- src/__tests__/to-have-role.js | 46 ++++++ src/matchers.js | 1 + src/to-have-role.js | 156 ++++++++++++++++++ .../bun/bun-custom-expect-types.test.ts | 2 + types/__tests__/bun/bun-types.test.ts | 2 + .../jest-globals/jest-globals-types.test.ts | 2 + types/__tests__/jest/jest-types.test.ts | 2 + types/__tests__/vitest/vitest-types.test.ts | 2 + types/matchers.d.ts | 13 ++ 9 files changed, 226 insertions(+) create mode 100644 src/__tests__/to-have-role.js create mode 100644 src/to-have-role.js diff --git a/src/__tests__/to-have-role.js b/src/__tests__/to-have-role.js new file mode 100644 index 00000000..7a562b72 --- /dev/null +++ b/src/__tests__/to-have-role.js @@ -0,0 +1,46 @@ +import {render} from './helpers/test-utils' + +describe('.toHaveRole', () => { + it('matches implicit role', () => { + const {queryByTestId} = render(` +
+ +
+ `) + + const continueButton = queryByTestId('continue-button') + + expect(continueButton).not.toHaveRole('listitem') + expect(continueButton).toHaveRole('button') + + expect(() => { + expect(continueButton).toHaveRole('listitem') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(continueButton).not.toHaveRole('button') + }).toThrow(/expected element not to have role/i) + }) + + it('matches explicit role', () => { + const {queryByTestId} = render(` +
+
Continue
+
+ `) + + const continueButton = queryByTestId('continue-button') + + expect(continueButton).not.toHaveRole('listitem') + expect(continueButton).toHaveRole('button') + + expect(() => { + expect(continueButton).toHaveRole('listitem') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(continueButton).not.toHaveRole('button') + }).toThrow(/expected element not to have role/i) + }) + it.todo('handles multiple explicit roles') + it.todo('handles multiple implicit roles') + it.todo('handles implicit roles with multiple conditions') +}) diff --git a/src/matchers.js b/src/matchers.js index f49b489a..46803f30 100644 --- a/src/matchers.js +++ b/src/matchers.js @@ -7,6 +7,7 @@ export {toContainHTML} from './to-contain-html' export {toHaveTextContent} from './to-have-text-content' export {toHaveAccessibleDescription} from './to-have-accessible-description' export {toHaveAccessibleErrorMessage} from './to-have-accessible-errormessage' +export {toHaveRole} from './to-have-role' export {toHaveAccessibleName} from './to-have-accessible-name' export {toHaveAttribute} from './to-have-attribute' export {toHaveClass} from './to-have-class' diff --git a/src/to-have-role.js b/src/to-have-role.js new file mode 100644 index 00000000..076e32e6 --- /dev/null +++ b/src/to-have-role.js @@ -0,0 +1,156 @@ +import {elementRoles} from 'aria-query' +import {checkHtmlElement, getMessage} from './utils' + +const elementRoleList = buildElementRoleList(elementRoles) + +export function toHaveRole(htmlElement, expectedRole) { + checkHtmlElement(htmlElement, toHaveRole, this) + + const actualRoles = getExplicitOrImplicitRoles(htmlElement) + + // TODO: There might be a helper on this. to check `some` + const pass = actualRoles.some(el => el === expectedRole) + + return { + pass, + + message: () => { + const to = this.isNot ? 'not to' : 'to' + return getMessage( + this, + this.utils.matcherHint( + `${this.isNot ? '.not' : ''}.${toHaveRole.name}`, + 'element', + '', + ), + `Expected element ${to} have role`, + expectedRole, + 'Received', + actualRoles.join(', '), + ) + }, + } +} + +function getExplicitOrImplicitRoles(htmlElement) { + const isRoleSpecifiedExplicitly = htmlElement.hasAttribute('role') + + if (isRoleSpecifiedExplicitly) { + const roleValue = htmlElement.getAttribute('role') + + // TODO: For explicit role, we will have to handle fallbacks, since more than one role can be provided. + // if (queryFallbacks) { + // return roleValue + // .split(' ') + // .filter(Boolean) + // .some(roleAttributeToken => roleAttributeToken === role) + // } + + // For now, only return the first matching token + const [firstRoleAttributeToken] = roleValue.split(' ') + return [firstRoleAttributeToken] + } + + // TODO: The implicit roles have a series of attributes and constraints, that + // quantify extra conditions for an implicit role to be assigned. We should + // handle them. + const implicitRoles = getImplicitAriaRoles(htmlElement) + console.log({implicitRoles}) + + return implicitRoles +} + +function getImplicitAriaRoles(currentNode) { + for (const {match, roles} of elementRoleList) { + if (match(currentNode)) { + return [...roles] + } + } + + return [] +} + +/** + * Transform the standard role mapping to a list of roles, paired with functions + * to match an element against them. The list is sorted by specificity, so that + * a search from the start of the array will find the more specific role. + * + * Copied over from dom-testing-library: + * @see + * {@link https://github.com/testing-library/dom-testing-library/blob/bd04cf95a1ed85a2238f7dfc1a77d5d16b4f59dc/src/role-helpers.js#L80} + */ +function buildElementRoleList(elementRolesMap) { + function makeElementSelector({name, attributes}) { + return `${name}${attributes + .map(({name: attributeName, value, constraints = []}) => { + const shouldNotExist = constraints.indexOf('undefined') !== -1 + if (shouldNotExist) { + return `:not([${attributeName}])` + } else if (value) { + return `[${attributeName}="${value}"]` + } else { + return `[${attributeName}]` + } + }) + .join('')}` + } + + function getSelectorSpecificity({attributes = []}) { + return attributes.length + } + + function bySelectorSpecificity( + {specificity: leftSpecificity}, + {specificity: rightSpecificity}, + ) { + return rightSpecificity - leftSpecificity + } + + function match(element) { + let {attributes = []} = element + + // https://github.com/testing-library/dom-testing-library/issues/814 + const typeTextIndex = attributes.findIndex( + attribute => + attribute.value && + attribute.name === 'type' && + attribute.value === 'text', + ) + + if (typeTextIndex >= 0) { + // not using splice to not mutate the attributes array + attributes = [ + ...attributes.slice(0, typeTextIndex), + ...attributes.slice(typeTextIndex + 1), + ] + } + + const selector = makeElementSelector({...element, attributes}) + + return node => { + if (typeTextIndex >= 0 && node.type !== 'text') { + return false + } + + // TODO: This technique relies on CSS selectors; are those consistently + // available in all jest-dom environments? Why do other matchers in this + // package not use them like this? + return node.matches(selector) + } + } + + let result = [] + + for (const [element, roles] of elementRolesMap.entries()) { + result = [ + ...result, + { + match: match(element), + roles: Array.from(roles), + specificity: getSelectorSpecificity(element), + }, + ] + } + + return result.sort(bySelectorSpecificity) +} diff --git a/types/__tests__/bun/bun-custom-expect-types.test.ts b/types/__tests__/bun/bun-custom-expect-types.test.ts index 051d785c..1467e913 100644 --- a/types/__tests__/bun/bun-custom-expect-types.test.ts +++ b/types/__tests__/bun/bun-custom-expect-types.test.ts @@ -94,5 +94,7 @@ customExpect(element).toHaveErrorMessage( expect.stringContaining('Invalid time'), ) +customExpect(element).toHaveRole('button') + // @ts-expect-error The types accidentally allowed any property by falling back to "any" customExpect(element).nonExistentProperty() diff --git a/types/__tests__/bun/bun-types.test.ts b/types/__tests__/bun/bun-types.test.ts index ae03a17e..432dd867 100644 --- a/types/__tests__/bun/bun-types.test.ts +++ b/types/__tests__/bun/bun-types.test.ts @@ -66,6 +66,7 @@ expect(element).toHaveErrorMessage( ) expect(element).toHaveErrorMessage(/invalid time/i) expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) +expect(element).toHaveRole('button') expect(element).not.toBeInTheDOM() expect(element).not.toBeInTheDOM(document.body) @@ -113,6 +114,7 @@ expect(element).not.toHaveAccessibleName() expect(element).not.toBePartiallyChecked() expect(element).not.toHaveErrorMessage() expect(element).not.toHaveErrorMessage('Pikachu!') +expect(element).not.toHaveRole('button') // @ts-expect-error The types accidentally allowed any property by falling back to "any" expect(element).nonExistentProperty() diff --git a/types/__tests__/jest-globals/jest-globals-types.test.ts b/types/__tests__/jest-globals/jest-globals-types.test.ts index 645f44ec..150f8250 100644 --- a/types/__tests__/jest-globals/jest-globals-types.test.ts +++ b/types/__tests__/jest-globals/jest-globals-types.test.ts @@ -66,6 +66,7 @@ expect(element).toHaveErrorMessage( ) expect(element).toHaveErrorMessage(/invalid time/i) expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) +expect(element).toHaveRole('button') expect(element).not.toBeInTheDOM() expect(element).not.toBeInTheDOM(document.body) @@ -113,6 +114,7 @@ expect(element).not.toHaveAccessibleName() expect(element).not.toBePartiallyChecked() expect(element).not.toHaveErrorMessage() expect(element).not.toHaveErrorMessage('Pikachu!') +expect(element).not.toHaveRole('button') // @ts-expect-error The types accidentally allowed any property by falling back to "any" expect(element).nonExistentProperty() diff --git a/types/__tests__/jest/jest-types.test.ts b/types/__tests__/jest/jest-types.test.ts index 404b9881..d9596c67 100644 --- a/types/__tests__/jest/jest-types.test.ts +++ b/types/__tests__/jest/jest-types.test.ts @@ -65,6 +65,7 @@ expect(element).toHaveErrorMessage( ) expect(element).toHaveErrorMessage(/invalid time/i) expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) +expect(element).toHaveRole('button') expect(element).not.toBeInTheDOM() expect(element).not.toBeInTheDOM(document.body) @@ -112,6 +113,7 @@ expect(element).not.toHaveAccessibleName() expect(element).not.toBePartiallyChecked() expect(element).not.toHaveErrorMessage() expect(element).not.toHaveErrorMessage('Pikachu!') +expect(element).not.toHaveRole('button') // @ts-expect-error The types accidentally allowed any property by falling back to "any" expect(element).nonExistentProperty() diff --git a/types/__tests__/vitest/vitest-types.test.ts b/types/__tests__/vitest/vitest-types.test.ts index 69f1dbc5..7a90be05 100644 --- a/types/__tests__/vitest/vitest-types.test.ts +++ b/types/__tests__/vitest/vitest-types.test.ts @@ -66,6 +66,7 @@ expect(element).toHaveErrorMessage( ) expect(element).toHaveErrorMessage(/invalid time/i) expect(element).toHaveErrorMessage(expect.stringContaining('Invalid time')) +expect(element).toHaveRole('button') expect(element).not.toBeInTheDOM() expect(element).not.toBeInTheDOM(document.body) @@ -113,6 +114,7 @@ expect(element).not.toHaveAccessibleName() expect(element).not.toBePartiallyChecked() expect(element).not.toHaveErrorMessage() expect(element).not.toHaveErrorMessage('Pikachu!') +expect(element).not.toHaveRole('button') // @ts-expect-error The types accidentally allowed any property by falling back to "any" expect(element).nonExistentProperty() diff --git a/types/matchers.d.ts b/types/matchers.d.ts index 213f94cd..cb75fb45 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -579,6 +579,19 @@ declare namespace matchers { * [testing-library/jest-dom#tohaveaccessiblename](https://github.com/testing-library/jest-dom#tohaveaccessiblename) */ toHaveAccessibleName(text?: string | RegExp | E): R + /** + * @description + * TODO: Write this out + * + * @example + * TODO: Write this out + * + * @see + * [testing-library/jest-dom#tohaverole](https://github.com/testing-library/jest-dom#tohaverole) + * + * TODO: Ideally, we should limit the role + */ + toHaveRole(role: string): R /** * @description * This allows you to check whether the given element is partially checked. From f07ed65b35298d6870be832527cb7b811bb4c98a Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sat, 27 Jan 2024 23:50:35 +0200 Subject: [PATCH 2/7] Handle implicit and multiple explicit roles --- src/__tests__/to-have-role.js | 67 +++++++++++++++++++++++++++++++++-- src/to-have-role.js | 38 ++++++++------------ 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/src/__tests__/to-have-role.js b/src/__tests__/to-have-role.js index 7a562b72..c9e039ca 100644 --- a/src/__tests__/to-have-role.js +++ b/src/__tests__/to-have-role.js @@ -40,7 +40,68 @@ describe('.toHaveRole', () => { expect(continueButton).not.toHaveRole('button') }).toThrow(/expected element not to have role/i) }) - it.todo('handles multiple explicit roles') - it.todo('handles multiple implicit roles') - it.todo('handles implicit roles with multiple conditions') + + it('matches multiple explicit roles', () => { + const {queryByTestId} = render(` +
+
Continue
+
+ `) + + const continueButton = queryByTestId('continue-button') + + expect(continueButton).not.toHaveRole('listitem') + expect(continueButton).toHaveRole('button') + expect(continueButton).toHaveRole('switch') + + expect(() => { + expect(continueButton).toHaveRole('listitem') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(continueButton).not.toHaveRole('button') + }).toThrow(/expected element not to have role/i) + expect(() => { + expect(continueButton).not.toHaveRole('switch') + }).toThrow(/expected element not to have role/i) + }) + + // At this point, we might be testing the details of getImplicitAriaRoles, but + // it's good to have a gut check + it('handles implicit roles with multiple conditions', () => { + const {queryByTestId} = render(` +
+ Actually a valid link + Not a valid link (missing href) +
+ `) + + const validLink = queryByTestId('link-valid') + const invalidLink = queryByTestId('link-invalid') + + // valid link has role 'link' + expect(validLink).not.toHaveRole('listitem') + expect(validLink).toHaveRole('link') + + expect(() => { + expect(validLink).toHaveRole('listitem') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(validLink).not.toHaveRole('link') + }).toThrow(/expected element not to have role/i) + + // invalid link has role 'generic' + expect(invalidLink).not.toHaveRole('listitem') + expect(invalidLink).not.toHaveRole('link') + expect(invalidLink).toHaveRole('generic') + + expect(() => { + expect(invalidLink).toHaveRole('listitem') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(invalidLink).toHaveRole('link') + }).toThrow(/expected element to have role/i) + expect(() => { + expect(invalidLink).not.toHaveRole('generic') + }).toThrow(/expected element not to have role/i) + }) }) diff --git a/src/to-have-role.js b/src/to-have-role.js index 076e32e6..f33c9513 100644 --- a/src/to-have-role.js +++ b/src/to-have-role.js @@ -7,8 +7,6 @@ export function toHaveRole(htmlElement, expectedRole) { checkHtmlElement(htmlElement, toHaveRole, this) const actualRoles = getExplicitOrImplicitRoles(htmlElement) - - // TODO: There might be a helper on this. to check `some` const pass = actualRoles.some(el => el === expectedRole) return { @@ -33,29 +31,19 @@ export function toHaveRole(htmlElement, expectedRole) { } function getExplicitOrImplicitRoles(htmlElement) { - const isRoleSpecifiedExplicitly = htmlElement.hasAttribute('role') + const hasExplicitRole = htmlElement.hasAttribute('role') - if (isRoleSpecifiedExplicitly) { + if (hasExplicitRole) { const roleValue = htmlElement.getAttribute('role') - // TODO: For explicit role, we will have to handle fallbacks, since more than one role can be provided. - // if (queryFallbacks) { - // return roleValue - // .split(' ') - // .filter(Boolean) - // .some(roleAttributeToken => roleAttributeToken === role) - // } - - // For now, only return the first matching token - const [firstRoleAttributeToken] = roleValue.split(' ') - return [firstRoleAttributeToken] + // Handle fallback roles, such as role="switch button" + // testing-library gates this behind the `queryFallbacks` flag; it is + // unclear why, but it makes sense to support this pattern out of the box + // https://testing-library.com/docs/queries/byrole/#queryfallbacks + return roleValue.split(' ').filter(Boolean) } - // TODO: The implicit roles have a series of attributes and constraints, that - // quantify extra conditions for an implicit role to be assigned. We should - // handle them. const implicitRoles = getImplicitAriaRoles(htmlElement) - console.log({implicitRoles}) return implicitRoles } @@ -71,13 +59,17 @@ function getImplicitAriaRoles(currentNode) { } /** - * Transform the standard role mapping to a list of roles, paired with functions - * to match an element against them. The list is sorted by specificity, so that - * a search from the start of the array will find the more specific role. + * Transform the roles map (with required attributes and constraints) to a list + * of roles. Each item in the list has functions to match an element against it. + * The list is sorted by specificity, so that a search from the start of the + * array will find the more specific role. * - * Copied over from dom-testing-library: + * Essentially copied over from dom-testing-library: * @see * {@link https://github.com/testing-library/dom-testing-library/blob/bd04cf95a1ed85a2238f7dfc1a77d5d16b4f59dc/src/role-helpers.js#L80} + * + * TODO: If we are truly just copying over stuff, would it make sense to move + * this to a separate package? */ function buildElementRoleList(elementRolesMap) { function makeElementSelector({name, attributes}) { From 809d365c25127088ca70eccc3ed4c0c2d851bff5 Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sun, 28 Jan 2024 13:08:00 +0200 Subject: [PATCH 3/7] Update docs --- README.md | 7 +++++++ types/matchers.d.ts | 32 +++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 913cf195..eb45df75 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ clear to read and to maintain. - [`toHaveDisplayValue`](#tohavedisplayvalue) - [`toBeChecked`](#tobechecked) - [`toBePartiallyChecked`](#tobepartiallychecked) + - [`toHaveRole`](#tohaverole) - [`toHaveErrorMessage`](#tohaveerrormessage) - [Deprecated matchers](#deprecated-matchers) - [`toBeEmpty`](#tobeempty) @@ -1189,6 +1190,12 @@ expect(inputCheckboxIndeterminate).toBePartiallyChecked()
+### `toHaveRole` + +TODO: Fill this out + +
+ ### `toHaveErrorMessage` > This custom matcher is deprecated. Prefer diff --git a/types/matchers.d.ts b/types/matchers.d.ts index cb75fb45..7496ecaa 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -581,15 +581,41 @@ declare namespace matchers { toHaveAccessibleName(text?: string | RegExp | E): R /** * @description - * TODO: Write this out + * This allows to assert that an element has the expected + * [role](https://www.w3.org/TR/html-aria/#docconformance). + * + * This is useful in cases where you already have access to an element via + * some query other than the role itself, and want to make additional + * assertions regarding its accessibility. + * + * The role can match either an explicit role (via the `role` attribute), or + * an implicit one via the [implicit ARIA + * semantics](https://www.w3.org/TR/html-aria/). + * + * Note: roles are matched literally by string equality, without inheriting + * from the ARIA role hierarchy. As a result, querying a superclass role + * like 'checkbox' will not include elements with a subclass role like + * 'switch'. * * @example - * TODO: Write this out + * + *
Continue + * + * About + * Invalid link + * + * expect(getByTestId('button')).toHaveRole('button') + * expect(getByTestId('button-explicit')).toHaveRole('button') + * expect(getByTestId('button-explicit-multiple')).toHaveRole('button') + * expect(getByTestId('button-explicit-multiple')).toHaveRole('switch') + * expect(getByTestId('link')).toHaveRole('link') + * expect(getByTestId('link-invalid')).not.toHaveRole('link') + * expect(getByTestId('link-invalid')).toHaveRole('generic') * * @see * [testing-library/jest-dom#tohaverole](https://github.com/testing-library/jest-dom#tohaverole) * - * TODO: Ideally, we should limit the role + * TODO: Ideally, we should limit the role to only valid ones; ask about this */ toHaveRole(role: string): R /** From 14248cf950537705babb8b008dc7e46a3d5f2acd Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sun, 28 Jan 2024 13:16:00 +0200 Subject: [PATCH 4/7] Add toHaveRole to README.md --- README.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eb45df75..be44bc97 100644 --- a/README.md +++ b/README.md @@ -1192,7 +1192,42 @@ expect(inputCheckboxIndeterminate).toBePartiallyChecked() ### `toHaveRole` -TODO: Fill this out +This allows to assert that an element has the expected +[role](https://www.w3.org/TR/html-aria/#docconformance). + +This is useful in cases where you already have access to an element via some +query other than the role itself, and want to make additional assertions +regarding its accessibility. + +The role can match either an explicit role (via the `role` attribute), or an +implicit one via the +[implicit ARIA semantics](https://www.w3.org/TR/html-aria/). + +Note: roles are matched literally by string equality, without inheriting from +the ARIA role hierarchy. As a result, querying a superclass role like 'checkbox' +will not include elements with a subclass role like 'switch'. + +```typescript +toHaveRole(expectedRole: string) +``` + +```html + +
Continue + +About +Invalid link +``` + +```javascript +expect(getByTestId('button')).toHaveRole('button') +expect(getByTestId('button-explicit')).toHaveRole('button') +expect(getByTestId('button-explicit-multiple')).toHaveRole('button') +expect(getByTestId('button-explicit-multiple')).toHaveRole('switch') +expect(getByTestId('link')).toHaveRole('link') +expect(getByTestId('link-invalid')).not.toHaveRole('link') +expect(getByTestId('link-invalid')).toHaveRole('generic') +```
From a9d3d004b6d0b4a79b14d9df61cf6abcead46ecc Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sun, 28 Jan 2024 13:48:08 +0200 Subject: [PATCH 5/7] Handle role types, check coverage --- src/to-have-role.js | 5 ++--- types/matchers.d.ts | 10 +++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/to-have-role.js b/src/to-have-role.js index f33c9513..92dbc946 100644 --- a/src/to-have-role.js +++ b/src/to-have-role.js @@ -55,14 +55,13 @@ function getImplicitAriaRoles(currentNode) { } } - return [] + /* istanbul ignore next */ + return [] // this does not get reached in practice, since elements have at least a 'generic' role } /** * Transform the roles map (with required attributes and constraints) to a list * of roles. Each item in the list has functions to match an element against it. - * The list is sorted by specificity, so that a search from the start of the - * array will find the more specific role. * * Essentially copied over from dom-testing-library: * @see diff --git a/types/matchers.d.ts b/types/matchers.d.ts index 7496ecaa..81bd40da 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -1,3 +1,9 @@ +import {ARIARole} from 'aria-query' + +// Get autocomplete for ARIARole union types, while still supporting another string +// Ref: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-567871939 +export type ByRoleMatcher = ARIARole | (string & {}) + declare namespace matchers { interface TestingLibraryMatchers { /** @@ -614,10 +620,8 @@ declare namespace matchers { * * @see * [testing-library/jest-dom#tohaverole](https://github.com/testing-library/jest-dom#tohaverole) - * - * TODO: Ideally, we should limit the role to only valid ones; ask about this */ - toHaveRole(role: string): R + toHaveRole(role: ByRoleMatcher): R /** * @description * This allows you to check whether the given element is partially checked. From f631f089752d8d5f97f754f34726a2a27be6bec7 Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Sun, 28 Jan 2024 14:20:39 +0200 Subject: [PATCH 6/7] Consolidate TODOs --- src/to-have-role.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/to-have-role.js b/src/to-have-role.js index 92dbc946..04b85ed8 100644 --- a/src/to-have-role.js +++ b/src/to-have-role.js @@ -63,12 +63,15 @@ function getImplicitAriaRoles(currentNode) { * Transform the roles map (with required attributes and constraints) to a list * of roles. Each item in the list has functions to match an element against it. * - * Essentially copied over from dom-testing-library: - * @see - * {@link https://github.com/testing-library/dom-testing-library/blob/bd04cf95a1ed85a2238f7dfc1a77d5d16b4f59dc/src/role-helpers.js#L80} + * Essentially copied over from [dom-testing-library's + * helpers](https://github.com/testing-library/dom-testing-library/blob/bd04cf95a1ed85a2238f7dfc1a77d5d16b4f59dc/src/role-helpers.js#L80) * * TODO: If we are truly just copying over stuff, would it make sense to move * this to a separate package? + * + * TODO: This technique relies on CSS selectors; are those consistently + * available in all jest-dom environments? Why do other matchers in this package + * not use them like this? */ function buildElementRoleList(elementRolesMap) { function makeElementSelector({name, attributes}) { @@ -123,9 +126,6 @@ function buildElementRoleList(elementRolesMap) { return false } - // TODO: This technique relies on CSS selectors; are those consistently - // available in all jest-dom environments? Why do other matchers in this - // package not use them like this? return node.matches(selector) } } From 338f1c7fc2c9582b8e5670429a414df1665bedf7 Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Mon, 29 Jan 2024 12:42:34 +0200 Subject: [PATCH 7/7] Typo fix allows to assert > allows you to assert --- README.md | 2 +- types/matchers.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be44bc97..d3b1bfff 100644 --- a/README.md +++ b/README.md @@ -1192,7 +1192,7 @@ expect(inputCheckboxIndeterminate).toBePartiallyChecked() ### `toHaveRole` -This allows to assert that an element has the expected +This allows you to assert that an element has the expected [role](https://www.w3.org/TR/html-aria/#docconformance). This is useful in cases where you already have access to an element via some diff --git a/types/matchers.d.ts b/types/matchers.d.ts index 81bd40da..cdd66c14 100755 --- a/types/matchers.d.ts +++ b/types/matchers.d.ts @@ -587,7 +587,7 @@ declare namespace matchers { toHaveAccessibleName(text?: string | RegExp | E): R /** * @description - * This allows to assert that an element has the expected + * This allows you to assert that an element has the expected * [role](https://www.w3.org/TR/html-aria/#docconformance). * * This is useful in cases where you already have access to an element via