From 878ad7d91ae29cd31c7128bd0797a7c9d8b7c672 Mon Sep 17 00:00:00 2001
From: Isaiah Thomason <47364027+ITenthusiasm@users.noreply.github.com>
Date: Mon, 17 Jul 2023 19:12:15 -0400
Subject: [PATCH 1/2] fix: Conform `toHaveErrorMessage` to Spec and Rename
Included Changes:
- According to the WAI-ARIA spec, passing an invalid
`id` to `aria-errormessage` now fails assertion.
This means that any empty spaces inside
`aria-errormessage` will now cause test failures.
- According to the WAI-ARIA spec, developers can now
assert that an accessible error message is missing
if `aria-invalid` is `false` (or if the
`aria-errormessage` attribute is invalid).
- Updated the error message and test cases surrounding
the requirement for `aria-invalid`. They are now
more detailed/accurate.
- Renamed `toHaveErrorMessage` to
`toHaveAccessibleErrorMessage` to be consistent with
the other a11y-related methods (`toHaveAccessibleName`
and `toHaveAccessibleDescription`).
- Note: This deprecates the previous
`toHaveErrorMessage` method.
- Updated documentation. Similar to the
`toHaveAccessibleDescription` method, this description
is much more lean, as the reader can simply read the
WAI ARIA spec for additional details/requirements.
---
README.md | 62 ++++
.../to-have-accessible-errormessage.js | 277 ++++++++++++++++++
src/matchers.js | 2 +
src/to-have-accessible-errormessage.js | 85 ++++++
src/to-have-errormessage.js | 3 +-
5 files changed, 428 insertions(+), 1 deletion(-)
create mode 100644 src/__tests__/to-have-accessible-errormessage.js
create mode 100644 src/to-have-accessible-errormessage.js
diff --git a/README.md b/README.md
index 1778f8fe..7c6d3c65 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ clear to read and to maintain.
- [`toContainElement`](#tocontainelement)
- [`toContainHTML`](#tocontainhtml)
- [`toHaveAccessibleDescription`](#tohaveaccessibledescription)
+ - [`toHaveAccessibleErrorMessage`](#tohaveaccessibleerrormessage)
- [`toHaveAccessibleName`](#tohaveaccessiblename)
- [`toHaveAttribute`](#tohaveattribute)
- [`toHaveClass`](#tohaveclass)
@@ -561,6 +562,63 @@ expect(getByTestId('logo')).toHaveAccessibleDescription(
+### `toHaveAccessibleErrorMessage`
+
+```typescript
+toHaveAccessibleErrorMessage(expectedAccessibleErrorMessage?: string | RegExp)
+```
+
+This allows you to assert that an element has the expected
+[accessible error message](https://w3c.github.io/aria/#aria-errormessage).
+
+You can pass the exact string of the expected accessible error message.
+Alternatively, you can perform a partial match by passing a regular expression
+or by using
+[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectnotstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).
+
+#### Examples
+
+```html
+
+
This field is invalid
+
+
+
+```
+
+```js
+// Inputs with Valid Error Messages
+expect(getByRole('textbox', {name: 'Has Error'})).toHaveAccessibleErrorMessage()
+expect(getByRole('textbox', {name: 'Has Error'})).toHaveAccessibleErrorMessage(
+ 'This field is invalid',
+)
+expect(getByRole('textbox', {name: 'Has Error'})).toHaveAccessibleErrorMessage(
+ /invalid/i,
+)
+expect(
+ getByRole('textbox', {name: 'Has Error'}),
+).not.toHaveAccessibleErrorMessage('This field is absolutely correct!')
+
+// Inputs without Valid Error Messages
+expect(
+ getByRole('textbox', {name: 'No Error Attributes'}),
+).not.toHaveAccessibleErrorMessage()
+
+expect(
+ getByRole('textbox', {name: 'Not Invalid'}),
+).not.toHaveAccessibleErrorMessage()
+```
+
+
+
### `toHaveAccessibleName`
```typescript
@@ -1069,6 +1127,10 @@ expect(inputCheckboxIndeterminate).toBePartiallyChecked()
### `toHaveErrorMessage`
+> This custom matcher is deprecated. Prefer
+> [`toHaveAccessibleErrorMessage`](#tohaveaccessibleerrormessage) instead, which
+> is more comprehensive in implementing the official spec.
+
```typescript
toHaveErrorMessage(text: string | RegExp)
```
diff --git a/src/__tests__/to-have-accessible-errormessage.js b/src/__tests__/to-have-accessible-errormessage.js
new file mode 100644
index 00000000..1586020f
--- /dev/null
+++ b/src/__tests__/to-have-accessible-errormessage.js
@@ -0,0 +1,277 @@
+import {render} from './helpers/test-utils'
+
+describe('.toHaveAccessibleErrorMessage', () => {
+ const input = 'input'
+ const errorId = 'error-id'
+ const error = 'This field is invalid'
+ const strings = {true: String(true), false: String(false)}
+
+ describe('Positive Test Cases', () => {
+ it("Fails the test if an invalid `id` is provided for the target element's `aria-errormessage`", () => {
+ const secondId = 'id2'
+ const secondError = 'LISTEN TO ME!!!'
+
+ const {queryByTestId} = render(`
+
+ `)
+
+ const field = queryByTestId(input)
+ expect(field).toHaveAccessibleErrorMessage('Step 1 of 9000')
+ })
+ })
+
+ // These tests for the `.not` use cases will help us cover our bases and complete test coverage
+ describe('Negated Test Cases', () => {
+ it("Passes the test if an invalid `id` is provided for the target element's `aria-errormessage`", () => {
+ const secondId = 'id2'
+ const secondError = 'LISTEN TO ME!!!'
+
+ const {queryByTestId} = render(`
+
+ `)
+
+ const field = queryByTestId('input')
+ expect(field).not.toHaveAccessibleErrorMessage()
+ expect(field).not.toHaveAccessibleErrorMessage(error)
+ expect(field).not.toHaveAccessibleErrorMessage(new RegExp(error[0]))
+ expect(field).not.toHaveAccessibleErrorMessage(secondError)
+ expect(field).not.toHaveAccessibleErrorMessage(new RegExp(secondError[0]))
+ })
+
+ it('Passes the test if the target element is valid according to the WAI-ARIA spec', () => {
+ const {queryByTestId} = render(`
+