Skip to content

Commit 8714055

Browse files
authored
feat: toHaveFormValues matcher (#65)
closes #60
1 parent 33e836d commit 8714055

File tree

6 files changed

+523
-1
lines changed

6 files changed

+523
-1
lines changed

README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ to maintain.
5454
- [`toHaveAttribute`](#tohaveattribute)
5555
- [`toHaveClass`](#tohaveclass)
5656
- [`toHaveFocus`](#tohavefocus)
57+
- [`toHaveFormValues`](#tohaveformvalues)
5758
- [`toHaveStyle`](#tohavestyle)
5859
- [`toHaveTextContent`](#tohavetextcontent)
5960
- [Deprecated matchers](#deprecated-matchers)
@@ -476,6 +477,87 @@ expect(input).not.toHaveFocus()
476477
477478
<hr />
478479
480+
### `toHaveFormValues`
481+
482+
```typescript
483+
toHaveFormValues(expectedValues: {
484+
[name: string]: any
485+
})
486+
```
487+
488+
This allows you to check if a form or fieldset contains form controls for each
489+
given name, and having the specified value.
490+
491+
> It is important to stress that this matcher can only be invoked on a [form][]
492+
> or a [fieldset][] element.
493+
>
494+
> This allows it to take advantage of the [.elements][] property in `form` and
495+
> `fieldset` to reliably fetch all form controls within them.
496+
>
497+
> This also avoids the possibility that users provide a container that contains
498+
> more than one `form`, thereby intermixing form controls that are not related,
499+
> and could even conflict with one another.
500+
501+
This matcher abstracts away the particularities with which a form control value
502+
is obtained depending on the type of form control. For instance, `<input>`
503+
elements have a `value` attribute, but `<select>` elements do not. Here's a list
504+
of all cases covered:
505+
506+
- `<input type="number">` elements return the value as a **number**, instead of
507+
a string.
508+
- `<input type="checkbox">` elements:
509+
- if there's a single one with the given `name` attribute, it is treated as a
510+
**boolean**, returning `true` if the checkbox is checked, `false` if
511+
unchecked.
512+
- if there's more than one checkbox with the same `name` attribute, they are
513+
all treated collectively as a single form control, which returns the value
514+
as an **array** containing all the values of the selected checkboxes in the
515+
collection.
516+
- `<input type="radio">` elements are all grouped by the `name` attribute, and
517+
such a group treated as a single form control. This form control returns the
518+
value as a **string** corresponding to the `value` attribute of the selected
519+
radio button within the group.
520+
- `<input type="text">` elements return the value as a **string**. This also
521+
applies to `<input>` elements having any other possible `type` attribute
522+
that's not explicitly covered in different rules above (e.g. `search`,
523+
`email`, `date`, `password`, `hidden`, etc.)
524+
- `<select>` elements without the `multiple` attribute return the value as a
525+
**string** corresponding to the `value` attribute of the selected `option`, or
526+
`undefined` if there's no selected option.
527+
- `<select multiple>` elements return the value as an **array** containing all
528+
the values of the [selected options][].
529+
- `<textarea>` elements return their value as a **string**. The value
530+
corresponds to their node content.
531+
532+
The above rules make it easy, for instance, to switch from using a single select
533+
control to using a group of radio buttons. Or to switch from a multi select
534+
control, to using a group of checkboxes. The resulting set of form values used
535+
by this matcher to compare against would be the same.
536+
537+
[selected options]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedOptions
538+
[form]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement
539+
[fieldset]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFieldSetElement
540+
[.elements]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
541+
542+
#### Examples
543+
544+
```html
545+
<form data-testid="login-form">
546+
<input type="text" name="username" value="jane.doe" />
547+
<input type="password" name="password" value="12345678" />
548+
<input type="checkbox" name="rememberMe" checked />
549+
<button type="submit">Sign in</button>
550+
</form>
551+
```
552+
553+
```javascript
554+
const form = document.querySelector('[data-testid="login-form"]')
555+
expect(form).toHaveFormValues({
556+
username: 'jane.doe',
557+
rememberMe: true,
558+
})
559+
```
560+
479561
### `toHaveStyle`
480562
481563
```typescript

extend-expect.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ declare namespace jest {
1212
toContainHTML(htmlText: string): R
1313
toHaveAttribute(attr: string, value?: string): R
1414
toHaveClass(...classNames: string[]): R
15+
toHaveFocus(): R
16+
toHaveFormValues(expectedValues: {[name: string]: any}): R
1517
toHaveStyle(css: string): R
1618
toHaveTextContent(
1719
text: string | RegExp,
1820
options?: {normalizeWhitespace: boolean},
1921
): R
20-
toHaveFocus(): R
2122
}
2223
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"css": "^2.2.3",
3838
"jest-diff": "^23.6.0",
3939
"jest-matcher-utils": "^23.6.0",
40+
"lodash": "^4.17.11",
4041
"pretty-format": "^23.6.0",
4142
"redent": "^2.0.0"
4243
},

0 commit comments

Comments
 (0)