{"id":51739948,"url":"https://github.com/trurl-master/accessibility-testing-toolkit","last_synced_at":"2026-07-18T11:42:08.927Z","repository":{"id":206882737,"uuid":"717902545","full_name":"trurl-master/accessibility-testing-toolkit","owner":"trurl-master","description":"Accessibility Testing Toolkit","archived":false,"fork":false,"pushed_at":"2024-06-17T19:33:18.000Z","size":499,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-30T13:27:02.323Z","etag":null,"topics":["a11y","accessibility","jest","matchers","swc-jest","testing","vitest"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trurl-master.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-11-12T23:38:34.000Z","updated_at":"2024-06-17T19:30:21.000Z","dependencies_parsed_at":"2023-11-18T02:05:06.821Z","dependency_job_id":null,"html_url":"https://github.com/trurl-master/accessibility-testing-toolkit","commit_stats":null,"previous_names":["trurl-master/accessibility-testing-toolkit"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/trurl-master/accessibility-testing-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Faccessibility-testing-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Faccessibility-testing-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Faccessibility-testing-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Faccessibility-testing-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trurl-master","download_url":"https://codeload.github.com/trurl-master/accessibility-testing-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trurl-master%2Faccessibility-testing-toolkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35616737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-18T02:00:07.223Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["a11y","accessibility","jest","matchers","swc-jest","testing","vitest"],"created_at":"2026-07-18T11:42:06.989Z","updated_at":"2026-07-18T11:42:08.917Z","avatar_url":"https://github.com/trurl-master.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# accessibility-testing-toolkit\n\n## Installation\n\nYou can install `accessibility-testing-toolkit` as a development dependency in your project using your preferred package manager:\n\nWith `npm`:\n\n```bash\nnpm install --save-dev accessibility-testing-toolkit\n```\n\nWith `Yarn`:\n\n```bash\nyarn add --dev accessibility-testing-toolkit\n```\n\n## Usage\n\nImport `accessibility-testing-toolkit/matchers` in your project once. The best place is to do it in your test setup file:\n\n```js\n// In your own jest-setup.js\nimport 'accessibility-testing-toolkit/matchers';\n\n// In jest.config.js add\nsetupFilesAfterEnv: ['\u003crootDir\u003e/jest-setup.js'];\n```\n\n## Custom matchers\n\n### `toHaveA11yTree`\n\n#### Description\n\nThe `toHaveA11yTree` matcher allows you to assert that a given HTML element's accessibility tree conforms to the expected structure. This powerful tool helps ensure that elements are presented correctly to assistive technologies, verifying that roles, states, and properties are set as intended.\n\nAccessible names, descriptions, and hierarchies can be validated against predefined expectations, making this matcher an essential part of accessibility testing for web applications.\n\n#### Syntax\n\n```js\nexpect(elementOrTree).toHaveA11yTree(expectedAccessibilityStructure, options?);\n```\n\n#### Parameters\n\n- `elementOrTree`: The `HTMLElement` to test or an `A11yTreeNode` object representing the accessibility tree (e.g., the output of `getAccessibilityTree`).\n- `expectedAccessibilityStructure`: An object that represents the expected accessibility tree.\n- `options` (optional): An object to configure the matching behavior.\n- `options.isNonLandmarkSubtree` (optional): A boolean that indicates whether the element is a non-landmark subtree. This is used to determine which roles to apply to `\u003cheader\u003e` and `\u003cfooter\u003e` elements. If manually set to `true`, the tree will be treated as a non-landmark, and the role will be set to `HeaderAsNonLandmark` or `FooterAsNonLandmark` instead of `banner` or `contentinfo`. By default (`false`), the appropriate role will be inferred from the tree structure.\n\nThe `toHaveA11yTree` matcher provides a clean and descriptive way to assert that an element's accessibility tree matches an expected structure. This allows developers to ensure that elements are semantically correct and accessible to assistive technology users.\n\n#### Example\n\nThis example demonstrates how to use the `toHaveA11yTree` matcher, along with the `byRole` helper, to validate an accessible dialog with a name, a description, a checkbox, a paragraph, and two buttons: \"Accept\" and \"Cancel\".\n\n```javascript\nimport { byRole } from 'accessibility-testing-toolkit';\n\ntest('accessible dialog has the correct accessibility tree', () =\u003e {\n  render(\n    \u003cdiv\n      role=\"dialog\"\n      aria-labelledby=\"dialog-title\"\n      aria-describedby=\"dialog-description\"\n    \u003e\n      \u003ch2 id=\"dialog-title\"\u003eConfirmation\u003c/h2\u003e\n      \u003clabel\u003e\n        \u003cspan id=\"dialog-description\"\u003e\n          Are you sure you want to proceed with this action?\n        \u003c/span\u003e\n        \u003cinput type=\"checkbox\" /\u003e\n      \u003c/label\u003e\n      \u003cp\u003eThis cannot be undone.\u003c/p\u003e\n      \u003cdiv\u003e\n        \u003cbutton\u003eAccept\u003c/button\u003e\n        \u003cbutton\u003eCancel\u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n\n  // Define the expected accessibility tree using byRole\n  const expectedTree = byRole(\n    'dialog',\n    {\n      name: 'Confirmation',\n      description: 'Are you sure you want to proceed with this action?',\n    },\n    [\n      byRole('heading', { name: 'Confirmation', level: 2 }),\n      byRole('LabelText', [\n        'Are you sure you want to proceed with this action?',\n        byRole(\n          'checkbox',\n          'Are you sure you want to proceed with this action?'\n        ),\n      ]),\n      byRole('paragraph', ['This cannot be undone.']),\n      // containers are ignored, so we don't need to specify the div\n      byRole('button', 'Accept'),\n      byRole('button', 'Cancel'),\n    ]\n  );\n\n  // Get the dialog element using a chosen query method, such as getByRole from Testing Library\n  const dialogElement = screen.getByRole('dialog');\n\n  // Perform the assertion\n  expect(dialogElement).toHaveA11yTree(expectedTree);\n});\n```\n\n#### Pruning Container Nodes\n\nContainer nodes in the DOM, such as non-semantic `\u003cdiv\u003e` and `\u003cspan\u003e` elements, can clutter the accessibility tree and obscure meaningful hierarchy in tests. The Accessibility Testing Toolkit automatically prunes these nodes (_except for the root node_), simplifying test assertions by focusing on semantically significant elements. This approach reduces test fragility against markup changes and enhances clarity, allowing developers to concentrate on the core accessibility features of their components. By ignoring container nodes, the toolkit promotes a development workflow that prioritizes user experience over structural implementation details.\n\n#### Handling Visibility\n\nWhen determining whether elements in the DOM are accessible, certain attributes and CSS properties signal that an element, along with its children, should not be considered visible:\n\n- Elements with the `hidden` attribute or `aria-hidden=\"true\"`\n- Styles that set `display: none` or `visibility: hidden`\n\nIn testing environments, relying on attribute checks may be necessary since `getComputedStyle` may not reflect styles defined in external stylesheets.\n\n##### Enhancing Visibility Detection\n\nExtend default visibility checks with custom logic to handle additional cases. In this example we consider elements with the `hidden` or `invisible` (used for example by `TailwindCSS`) classes as inaccessible:\n\n```ts\nimport { isSubtreeInaccessible as originalIsSubtreeInaccessible } from 'accessibility-testing-toolkit';\n\nfunction isSubtreeInaccessible(element: HTMLElement): boolean {\n  // Include original checks and additional conditions for TailwindCSS classes\n  return (\n    originalIsSubtreeInaccessible(element) ||\n    element.classList.contains('hidden') ||\n    element.classList.contains('invisible')\n  );\n}\n\n// Set globally in jest-setup.js\nconfigToolkit({\n  isInaccessibleOptions: { isSubtreeInaccessible },\n});\n\n// Or per matcher\nexpect(element).toHaveA11yTree(expectedTree, {\n  isInaccessibleOptions: { isSubtreeInaccessible },\n});\n```\n\nBy leveraging both the library's default visibility logic and custom class checks, this approach effectively accommodates the use of utility-first CSS frameworks within visibility determination processes.\n\n#### Calculating roles\n\nThe toolkit follows standardized role definitions, with some customizations to provide more specific roles for certain elements, similar to the approach used by Google Chrome\n\nSpecifically, the toolkit applies the following custom roles:\n\n- `abbr`: Mapped to `Abbr`\n- `audio`: Mapped to `Audio`\n- `canvas`: Mapped to `Canvas`\n- `dd`: Mapped to `DescriptionListDetails`\n- `dl`: Mapped to `DescriptionList`\n- `dt`: Mapped to `DescriptionListTerm`\n- `embed`: Mapped to `EmbeddedObject`\n- `figcaption`: Mapped to `Figcaption`\n- `object`: Mapped to `PluginObject`\n- `label`: Mapped to `LabelText`\n- `br`: Mapped to `LineBreak`\n- `summary`: Mapped to `DisclosureTriangle`\n- `video`: Mapped to `Video`\n\nThis list is _work in progress_ and will be expanded in the future.\n\n### `byRole` Helper\n\nThe `byRole` helper function is a convenience utility for defining the expected structure of an accessibility tree node that corresponds to a particular element. It simplifies the creation of expected node objects by allowing the specification of roles, names, accessible descriptions, state, and child elements.\n\n#### Syntax\n\nThe `byRole` helper can be invoked with different combinations of arguments to construct an `A11yTreeNodeMatch` object:\n\n```ts\nbyRole(role, properties);\nbyRole(role, properties, children);\nbyRole(role, children);\nbyRole(role, name);\nbyRole(role, name, children);\nbyRole(role);\n```\n\n#### Parameters\n\n`role`: A string representing the ARIA role of the element.\n`properties`: An object containing accessible name, description, state, and queries that match custom properties.\n`children`: An array of A11yTreeNodeMatch objects or text matchers that represent the expected child nodes.\n`name`: A string or regular expression to match the accessible name.\n\nThe properties object includes accessible name, description, and state properties—conforming to A11yTreeNodeMatch—but omits role and children, which are handled by the helper function itself.\n\nbyRole builds an accessibility tree node object with the specified role and any additional details you need to assert against.\n\n#### Properties\n\n- `name` (`TextMatcher`) - Matches the accessible name. Accepts strings, numbers, regex, or functions.\n- `description` (`TextMatcher`) - Matches additional descriptive text.\n- `busy` (`boolean`) - Indicates if the element is busy.\n- `checked` (`boolean`) - Represents the checked state of checkboxes or radios.\n- `current` (`string | boolean`) - Denotes the current status within a set (e.g. \"page\").\n- `disabled` (`boolean`) - States if the element is disabled.\n- `expanded` (`boolean`) - Reflects the expandable state of associated content.\n- `pressed` (`boolean`) - Indicates the pressed state of toggle buttons.\n- `selected` (`boolean`) - Signifies the selection state of selectable elements.\n- `level` (`number`) - Applies to elements within a hierarchy (like heading levels).\n- `value.min` (`number`) - Specifies the minimum value for the element.\n- `value.max` (`number`) - Specifies the maximum value for the element.\n- `value.now` (`number`) - Indicates the current value within the element's range.\n- `value.text` (`TextMatcher`) - Provides a textual representation of the element's value.\n\n#### `TextMatcher`\n\nThe `TextMatcher` type is used for matching text content and can take several forms:\n\n- `string`: Direct comparison with text content.\n- `number`: Matches text content with the number converted to a string.\n- `RegExp`: Tests text content against the regular expression.\n- `TextMatcherFunction`: A function that returns true if the content matches criteria; it takes the text content and the associated HTML element as arguments.\n\n#### Examples\n\n```ts\n// Define matchers with role and properties\nconst buttonNode = byRole('button', {\n  name: 'Submit',\n  disabled: false,\n});\n\nconst messageInput = byRole('textbox', {\n  name: 'Message',\n  description: 'Enter your message here',\n});\n\n// Define matchers with role, properties, and children\nconst preferenceGroup = byRole('group', { name: 'Preferences' }, [\n  byRole('checkbox', 'Newsletter'),\n  byRole('checkbox', 'Promotions'),\n]);\n\n// Define matchers with role and children\nconst navigation = byRole('navigation', [\n  byRole('link', 'Home'),\n  byRole('link', 'About'),\n]);\n\n// Define matchers with role and name\nconst buttonNode = byRole('button', /Submit/);\nconst buttonNode = byRole('button', 'Submit');\n\n// Define matchers with role, name, and children\nconst navigation = byRole('navigation', 'Main navigation', [\n  byRole('link', 'Home'),\n  byRole('link', 'About'),\n]);\n\n// Define matchers with role only\nconst buttonNode = byRole('button');\n```\n\nThe `byRole` helper abstracts away the repetitive task of creating node objects, promoting cleaner and more maintainable tests. Its signatures cater to a wide array of scenarios, from a simple button to more complex constructs like navigational elements with children.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrurl-master%2Faccessibility-testing-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrurl-master%2Faccessibility-testing-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrurl-master%2Faccessibility-testing-toolkit/lists"}