Skip to content

Commit 567d3ad

Browse files
jsphstlsgnapse
authored andcommitted
feat: toBeValid supports <form/> element (#127)
* add `"form"` to toBeValid tag list * add tests for `toBeValid` usage with `"form"` * simplify invalid element * update readme to include form usage
1 parent 170b5ed commit 567d3ad

File tree

3 files changed

+146
-75
lines changed

3 files changed

+146
-75
lines changed

README.md

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,14 @@ expect(
260260
toBeInvalid()
261261
```
262262
263-
This allows you to check if an form element is currently invalid.
263+
This allows you to check if a form element, or the entire `form`, is currently
264+
invalid.
264265
265-
An element is invalid if it is having an
266+
An `input`, `select`, `textarea`, or `form` element is invalid if it has an
266267
[`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute)
267-
or if the result of
268+
with no value or a value of `"true"`, or if the result of
268269
[`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)
269-
are false.
270+
is `false`.
270271
271272
#### Examples
272273
@@ -275,6 +276,14 @@ are false.
275276
<input data-testid="aria-invalid" aria-invalid />
276277
<input data-testid="aria-invalid-value" aria-invalid="true" />
277278
<input data-testid="aria-invalid-false" aria-invalid="false" />
279+
280+
<form data-testid="valid-form">
281+
<input />
282+
</form>
283+
284+
<form data-testid="invalid-form">
285+
<input required />
286+
</form>
278287
```
279288
280289
##### Using document.querySelector
@@ -284,6 +293,9 @@ expect(queryByTestId('no-aria-invalid')).not.toBeInvalid()
284293
expect(queryByTestId('aria-invalid')).toBeInvalid()
285294
expect(queryByTestId('aria-invalid-value')).toBeInvalid()
286295
expect(queryByTestId('aria-invalid-false')).not.toBeInvalid()
296+
297+
expect(queryByTestId('valid-form')).not.toBeInvalid()
298+
expect(queryByTestId('invalid-form')).toBeInvalid()
287299
```
288300
289301
##### Using DOM Testing Library
@@ -293,6 +305,9 @@ expect(getByTestId(container, 'no-aria-invalid')).not.toBeInvalid()
293305
expect(getByTestId(container, 'aria-invalid')).toBeInvalid()
294306
expect(getByTestId(container, 'aria-invalid-value')).toBeInvalid()
295307
expect(getByTestId(container, 'aria-invalid-false')).not.toBeInvalid()
308+
309+
expect(getByTestId(container, 'valid-form')).not.toBeInvalid()
310+
expect(getByTestId(container, 'invalid-form')).toBeInvalid()
296311
```
297312
298313
<hr />
@@ -372,12 +387,14 @@ expect(getByTestId(container, 'supported-role-aria')).toBeRequired()
372387
toBeValid()
373388
```
374389
375-
This allows you to check if the value of a form element is currently valid.
390+
This allows you to check if the value of a form element, or the entire `form`,
391+
is currently valid.
376392
377-
An element is valid if it is not having an
393+
An `input`, `select`, `textarea`, or `form` element is valid if it has no
378394
[`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute)
379-
or having `false` as a value and returning `true` when calling
380-
[`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation).
395+
or an attribute value of `"false"`. The result of
396+
[`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)
397+
must also be `true`.
381398
382399
#### Examples
383400
@@ -386,6 +403,14 @@ or having `false` as a value and returning `true` when calling
386403
<input data-testid="aria-invalid" aria-invalid />
387404
<input data-testid="aria-invalid-value" aria-invalid="true" />
388405
<input data-testid="aria-invalid-false" aria-invalid="false" />
406+
407+
<form data-testid="valid-form">
408+
<input />
409+
</form>
410+
411+
<form data-testid="invalid-form">
412+
<input required />
413+
</form>
389414
```
390415
391416
##### Using document.querySelector
@@ -395,6 +420,9 @@ expect(queryByTestId('no-aria-invalid')).toBeValid()
395420
expect(queryByTestId('aria-invalid')).not.toBeValid()
396421
expect(queryByTestId('aria-invalid-value')).not.toBeValid()
397422
expect(queryByTestId('aria-invalid-false')).toBeValid()
423+
424+
expect(queryByTestId('valid-form')).toBeValid()
425+
expect(queryByTestId('invalid-form')).not.toBeValid()
398426
```
399427
400428
##### Using DOM Testing Library
@@ -404,6 +432,9 @@ expect(getByTestId(container, 'no-aria-invalid')).toBeValid()
404432
expect(getByTestId(container, 'aria-invalid')).not.toBeValid()
405433
expect(getByTestId(container, 'aria-invalid-value')).not.toBeValid()
406434
expect(getByTestId(container, 'aria-invalid-false')).toBeValid()
435+
436+
expect(getByTestId(container, 'valid-form')).toBeValid()
437+
expect(getByTestId(container, 'invalid-form')).not.toBeValid()
407438
```
408439
409440
<hr />

src/__tests__/to-be-invalid.js

Lines changed: 106 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -19,74 +19,114 @@ import {render} from './helpers/test-utils'
1919
* @link https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
2020
* @link https://github.com/jsdom/jsdom
2121
*/
22-
function getDOMInput(htmlString) {
23-
const dom = new JSDOM(htmlString)
24-
25-
return dom.window.document.querySelector('input')
22+
function getDOMElement(htmlString, selector) {
23+
return new JSDOM(htmlString).window.document.querySelector(selector)
2624
}
2725

28-
const invalidInputNode = getDOMInput(
29-
`<input pattern="[a-z]{1,3}" value="test+">`,
30-
)
31-
32-
test('.toBeInvalid', () => {
33-
const {queryByTestId} = render(`
34-
<div>
35-
<input data-testid="no-aria-invalid">
36-
<input data-testid="aria-invalid" aria-invalid>
37-
<input data-testid="aria-invalid-value" aria-invalid="true">
38-
<input data-testid="aria-invalid-false" aria-invalid="false">
39-
</div>
40-
`)
41-
42-
expect(queryByTestId('no-aria-invalid')).not.toBeInvalid()
43-
expect(queryByTestId('aria-invalid')).toBeInvalid()
44-
expect(queryByTestId('aria-invalid-value')).toBeInvalid()
45-
expect(queryByTestId('aria-invalid-false')).not.toBeInvalid()
46-
expect(invalidInputNode).toBeInvalid()
47-
48-
// negative test cases wrapped in throwError assertions for coverage.
49-
expect(() =>
50-
expect(queryByTestId('no-aria-invalid')).toBeInvalid(),
51-
).toThrowError()
52-
expect(() =>
53-
expect(queryByTestId('aria-invalid')).not.toBeInvalid(),
54-
).toThrowError()
55-
expect(() =>
56-
expect(queryByTestId('aria-invalid-value')).not.toBeInvalid(),
57-
).toThrowError()
58-
expect(() =>
59-
expect(queryByTestId('aria-invalid-false')).toBeInvalid(),
60-
).toThrowError()
61-
expect(() => expect(invalidInputNode).not.toBeInvalid()).toThrowError()
26+
// A required field without a value is invalid
27+
const invalidInputHtml = `<input required>`
28+
29+
const invalidInputNode = getDOMElement(invalidInputHtml, 'input')
30+
31+
// A form is invalid if it contains an invalid input
32+
const invalidFormHtml = `<form>${invalidInputHtml}</form>`
33+
34+
const invalidFormNode = getDOMElement(invalidFormHtml, 'form')
35+
36+
describe('.toBeInvalid', () => {
37+
test('handles <input/>', () => {
38+
const {queryByTestId} = render(`
39+
<div>
40+
<input data-testid="no-aria-invalid">
41+
<input data-testid="aria-invalid" aria-invalid>
42+
<input data-testid="aria-invalid-value" aria-invalid="true">
43+
<input data-testid="aria-invalid-false" aria-invalid="false">
44+
</div>
45+
`)
46+
47+
expect(queryByTestId('no-aria-invalid')).not.toBeInvalid()
48+
expect(queryByTestId('aria-invalid')).toBeInvalid()
49+
expect(queryByTestId('aria-invalid-value')).toBeInvalid()
50+
expect(queryByTestId('aria-invalid-false')).not.toBeInvalid()
51+
expect(invalidInputNode).toBeInvalid()
52+
53+
// negative test cases wrapped in throwError assertions for coverage.
54+
expect(() =>
55+
expect(queryByTestId('no-aria-invalid')).toBeInvalid(),
56+
).toThrowError()
57+
expect(() =>
58+
expect(queryByTestId('aria-invalid')).not.toBeInvalid(),
59+
).toThrowError()
60+
expect(() =>
61+
expect(queryByTestId('aria-invalid-value')).not.toBeInvalid(),
62+
).toThrowError()
63+
expect(() =>
64+
expect(queryByTestId('aria-invalid-false')).toBeInvalid(),
65+
).toThrowError()
66+
expect(() => expect(invalidInputNode).not.toBeInvalid()).toThrowError()
67+
})
68+
69+
test('handles <form/>', () => {
70+
const {queryByTestId} = render(`
71+
<form data-testid="valid">
72+
<input>
73+
</form>
74+
`)
75+
76+
expect(queryByTestId('valid')).not.toBeInvalid()
77+
expect(invalidFormNode).toBeInvalid()
78+
79+
// negative test cases wrapped in throwError assertions for coverage.
80+
expect(() => expect(queryByTestId('valid')).toBeInvalid()).toThrowError()
81+
expect(() => expect(invalidFormNode).not.toBeInvalid()).toThrowError()
82+
})
6283
})
6384

64-
test('.toBeValid', () => {
65-
const {queryByTestId} = render(`
66-
<div>
67-
<input data-testid="no-aria-invalid">
68-
<input data-testid="aria-invalid" aria-invalid>
69-
<input data-testid="aria-invalid-value" aria-invalid="true">
70-
<input data-testid="aria-invalid-false" aria-invalid="false">
71-
</div>
72-
`)
73-
74-
expect(queryByTestId('no-aria-invalid')).toBeValid()
75-
expect(queryByTestId('aria-invalid')).not.toBeValid()
76-
expect(queryByTestId('aria-invalid-value')).not.toBeValid()
77-
expect(queryByTestId('aria-invalid-false')).toBeValid()
78-
expect(invalidInputNode).not.toBeValid()
79-
80-
// negative test cases wrapped in throwError assertions for coverage.
81-
expect(() =>
82-
expect(queryByTestId('no-aria-invalid')).not.toBeValid(),
83-
).toThrowError()
84-
expect(() => expect(queryByTestId('aria-invalid')).toBeValid()).toThrowError()
85-
expect(() =>
86-
expect(queryByTestId('aria-invalid-value')).toBeValid(),
87-
).toThrowError()
88-
expect(() =>
89-
expect(queryByTestId('aria-invalid-false')).not.toBeValid(),
90-
).toThrowError()
91-
expect(() => expect(invalidInputNode).toBeValid()).toThrowError()
85+
describe('.toBeValid', () => {
86+
test('handles <input/>', () => {
87+
const {queryByTestId} = render(`
88+
<div>
89+
<input data-testid="no-aria-invalid">
90+
<input data-testid="aria-invalid" aria-invalid>
91+
<input data-testid="aria-invalid-value" aria-invalid="true">
92+
<input data-testid="aria-invalid-false" aria-invalid="false">
93+
</div>
94+
`)
95+
96+
expect(queryByTestId('no-aria-invalid')).toBeValid()
97+
expect(queryByTestId('aria-invalid')).not.toBeValid()
98+
expect(queryByTestId('aria-invalid-value')).not.toBeValid()
99+
expect(queryByTestId('aria-invalid-false')).toBeValid()
100+
expect(invalidInputNode).not.toBeValid()
101+
102+
// negative test cases wrapped in throwError assertions for coverage.
103+
expect(() =>
104+
expect(queryByTestId('no-aria-invalid')).not.toBeValid(),
105+
).toThrowError()
106+
expect(() =>
107+
expect(queryByTestId('aria-invalid')).toBeValid(),
108+
).toThrowError()
109+
expect(() =>
110+
expect(queryByTestId('aria-invalid-value')).toBeValid(),
111+
).toThrowError()
112+
expect(() =>
113+
expect(queryByTestId('aria-invalid-false')).not.toBeValid(),
114+
).toThrowError()
115+
expect(() => expect(invalidInputNode).toBeValid()).toThrowError()
116+
})
117+
118+
test('handles <form/>', () => {
119+
const {queryByTestId} = render(`
120+
<form data-testid="valid">
121+
<input>
122+
</form>
123+
`)
124+
125+
expect(queryByTestId('valid')).toBeValid()
126+
expect(invalidFormNode).not.toBeValid()
127+
128+
// negative test cases wrapped in throwError assertions for coverage.
129+
expect(() => expect(queryByTestId('valid')).not.toBeValid()).toThrowError()
130+
expect(() => expect(invalidFormNode).toBeValid()).toThrowError()
131+
})
92132
})

src/to-be-invalid.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {matcherHint, printReceived} from 'jest-matcher-utils'
22
import {checkHtmlElement, getTag} from './utils'
33

4-
const FORM_TAGS = ['input', 'select', 'textarea']
4+
const FORM_TAGS = ['form', 'input', 'select', 'textarea']
55

66
function isElementHavingAriaInvalid(element) {
77
return (

0 commit comments

Comments
 (0)