Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added jest matcher support for .toHaveValue() #166

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ clear to read and to maintain.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Installation](#installation)
- [Usage](#usage)
- [Custom matchers](#custom-matchers)
Expand Down Expand Up @@ -86,9 +87,10 @@ should be installed as one of your project's `devDependencies`:
npm install --save-dev @testing-library/jest-dom
```

> Note: We also recommend installing the jest-dom eslint plugin which provides auto-fixable lint rules
> that prevent false positive tests and improve test readability by ensuring you are using the right
> matchers in your tests. More details can be found at
> Note: We also recommend installing the jest-dom eslint plugin which provides
> auto-fixable lint rules that prevent false positive tests and improve test
> readability by ensuring you are using the right matchers in your tests. More
> details can be found at
> [eslint-plugin-jest-dom](https://github.com/testing-library/eslint-plugin-jest-dom).

## Usage
Expand Down Expand Up @@ -610,7 +612,7 @@ toHaveAttribute(attr: string, value?: any)
This allows you to check whether the given element has an attribute or not. You
can also optionally check that the attribute has a specific expected value or
partial match using
[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectnotstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp)
[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).

#### Examples

Expand Down Expand Up @@ -922,10 +924,12 @@ expect(element).not.toHaveTextContent('content')
### `toHaveValue`

```typescript
toHaveValue(value: string | string[] | number)
toHaveValue(value?: any)
```

This allows you to check whether the given form element has the specified value.
This allows you to check whether the given form element has the specified value
or partial value using
[expect.stringContaining](https://jestjs.io/docs/en/expect.html#expectstringcontainingstring)/[expect.stringMatching](https://jestjs.io/docs/en/expect.html#expectstringmatchingstring-regexp).
It accepts `<input>`, `<select>` and `<textarea>` elements with the exception of
of `<input type="checkbox">` and `<input type="radio">`, which can be
meaningfully matched only using [`toBeChecked`](#tobechecked) or
Expand Down Expand Up @@ -1103,7 +1107,6 @@ expect(document.querySelector('.cancel-button')).toBeTruthy()
> replacing `toBeInTheDOM` to read through the documentation of the proposed
> alternatives to see which use case works better for your needs.


## Inspiration

This whole library was extracted out of Kent C. Dodds' [DOM Testing
Expand Down
2 changes: 1 addition & 1 deletion extend-expect.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ declare namespace jest {
text: string | RegExp,
options?: {normalizeWhitespace: boolean},
): R
toHaveValue(value?: string | string[] | number): R
toHaveValue(value?: any): R
toBeChecked(): R
}
}
48 changes: 43 additions & 5 deletions src/__tests__/to-have-value.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,36 @@ describe('.toHaveValue', () => {

expect(queryByTestId('value')).toHaveValue('foo')
expect(queryByTestId('value')).toHaveValue()
expect(queryByTestId('value')).toHaveValue(expect.stringContaining('fo'))
expect(queryByTestId('value')).toHaveValue(expect.stringMatching(/^f.*/))
expect(queryByTestId('value')).not.toHaveValue('bar')
expect(queryByTestId('value')).not.toHaveValue('')
expect(queryByTestId('value')).not.toHaveValue(
expect.stringContaining('bar'),
)
expect(queryByTestId('value')).not.toHaveValue(expect.stringMatching(/bar/))

expect(queryByTestId('empty')).toHaveValue('')
expect(queryByTestId('empty')).toHaveValue(expect.stringContaining(''))
expect(queryByTestId('empty')).toHaveValue(expect.stringMatching(/^$/))
expect(queryByTestId('empty')).not.toHaveValue()
expect(queryByTestId('empty')).not.toHaveValue('foo')
expect(queryByTestId('empty')).not.toHaveValue(
expect.stringContaining('foo'),
)
expect(queryByTestId('empty')).not.toHaveValue(expect.stringMatching(/foo/))

expect(queryByTestId('without')).toHaveValue('')
expect(queryByTestId('without')).toHaveValue(expect.stringContaining(''))
expect(queryByTestId('without')).toHaveValue(expect.stringMatching(/^$/))
expect(queryByTestId('without')).not.toHaveValue()
expect(queryByTestId('without')).not.toHaveValue('foo')
expect(queryByTestId('without')).not.toHaveValue(
expect.stringContaining('foo'),
)
expect(queryByTestId('without')).not.toHaveValue(
expect.stringMatching(/foo/),
)
queryByTestId('without').value = 'bar'
expect(queryByTestId('without')).toHaveValue('bar')
})
Expand All @@ -35,44 +55,56 @@ describe('.toHaveValue', () => {
expect(queryByTestId('number')).toHaveValue()
expect(queryByTestId('number')).not.toHaveValue(4)
expect(queryByTestId('number')).not.toHaveValue('5')
expect(queryByTestId('number')).not.toHaveValue(
expect.stringContaining('5'),
)

expect(queryByTestId('empty')).toHaveValue(null)
expect(queryByTestId('empty')).not.toHaveValue()
expect(queryByTestId('empty')).not.toHaveValue('5')
expect(queryByTestId('empty')).not.toHaveValue(expect.stringContaining('5'))

expect(queryByTestId('without')).toHaveValue(null)
expect(queryByTestId('without')).not.toHaveValue()
expect(queryByTestId('without')).not.toHaveValue('10')
expect(queryByTestId('without')).not.toHaveValue(
expect.stringContaining('10'),
)
queryByTestId('without').value = 10
expect(queryByTestId('without')).toHaveValue(10)
})

test('handles value of select element', () => {
const {queryByTestId} = render(`
<select data-testid="single">
<option value="first">First Value</option>
<option value="first">First Value</option>
<option value="second" selected>Second Value</option>
<option value="third">Third Value</option>
</select>

<select data-testid="multiple" multiple>
<option value="first">First Value</option>
<option value="first">First Value</option>
<option value="second" selected>Second Value</option>
<option value="third" selected>Third Value</option>
</select>

<select data-testid="not-selected" >
<option value="" disabled selected>- Select some value - </option>
<option value="first">First Value</option>
<option value="first">First Value</option>
<option value="second">Second Value</option>
<option value="third">Third Value</option>
</select>
`)

expect(queryByTestId('single')).toHaveValue('second')
expect(queryByTestId('single')).toHaveValue(expect.stringContaining('sec'))
expect(queryByTestId('single')).toHaveValue(expect.stringMatching(/^sec/))
expect(queryByTestId('single')).toHaveValue()

expect(queryByTestId('multiple')).toHaveValue(['second', 'third'])
expect(queryByTestId('multiple')).toHaveValue(
expect.arrayContaining(['second', 'third']),
)
expect(queryByTestId('multiple')).toHaveValue()

expect(queryByTestId('not-selected')).not.toHaveValue()
Expand All @@ -87,6 +119,12 @@ describe('.toHaveValue', () => {
<textarea data-testid="textarea">text value</textarea>
`)
expect(queryByTestId('textarea')).toHaveValue('text value')
expect(queryByTestId('textarea')).toHaveValue(
expect.stringContaining('text'),
)
expect(queryByTestId('textarea')).toHaveValue(
expect.stringMatching(/^text/),
)
})

test('throws when passed checkbox or radio', () => {
Expand Down
10 changes: 2 additions & 8 deletions src/to-have-value.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import {matcherHint} from 'jest-matcher-utils'
import isEqualWith from 'lodash/isEqualWith'
import {
checkHtmlElement,
compareArraysAsSet,
getMessage,
getSingleElementValue,
} from './utils'
import {checkHtmlElement, getMessage, getSingleElementValue} from './utils'

export function toHaveValue(htmlElement, expectedValue) {
checkHtmlElement(htmlElement, toHaveValue, this)
Expand All @@ -23,7 +17,7 @@ export function toHaveValue(htmlElement, expectedValue) {
const expectsValue = expectedValue !== undefined
return {
pass: expectsValue
? isEqualWith(receivedValue, expectedValue, compareArraysAsSet)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change would mean we can no longer match arrays regardless of order, as per my comment. But we wouldn't be able to support jest matchers without it, e.g. expect.arrayContaining(['second', 'third'])

? this.equals(receivedValue, expectedValue)
: Boolean(receivedValue),
message: () => {
const to = this.isNot ? 'not to' : 'to'
Expand Down