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

Allow to use regex on toHaveDisplayValue #242

Merged
merged 10 commits into from May 7, 2020
9 changes: 7 additions & 2 deletions README.md
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 @@ -781,7 +782,7 @@ expect(selectInput).not.toHaveValue(['second', 'third'])
### `toHaveDisplayValue`

```typescript
toHaveDisplayValue(value: string | string[])
toHaveDisplayValue(value: string | RegExp | (string|RegExp)[])
```

This allows you to check whether the given form element has the specified
Expand Down Expand Up @@ -826,9 +827,12 @@ const selectSingle = screen.getByLabelText('Fruit')
const selectMultiple = screen.getByLabelText('Fruits')

expect(input).toHaveDisplayValue('Luca')
expect(input).toHaveDisplayValue(/Luc/)
expect(textarea).toHaveDisplayValue('An example description here.')
expect(textarea).toHaveDisplayValue(/example/)
expect(selectSingle).toHaveDisplayValue('Select a fruit...')
expect(selectMultiple).toHaveDisplayValue(['Banana', 'Avocado'])
expect(selectSingle).toHaveDisplayValue(/Select/)
expect(selectMultiple).toHaveDisplayValue([/Avocado/, 'Banana'])
```

<hr />
Expand Down Expand Up @@ -1084,6 +1088,7 @@ Thanks goes to these people ([emoji key][emojis]):

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors][all-contributors] specification.
Expand Down
78 changes: 56 additions & 22 deletions src/__tests__/to-have-display-value.js
Expand Up @@ -21,36 +21,68 @@ test('it should work as expected', () => {

queryByTestId('select').value = 'banana'
expect(queryByTestId('select')).toHaveDisplayValue('Banana')
expect(queryByTestId('select')).toHaveDisplayValue(/[bB]ana/)
})

test('it should work with select multiple', () => {
const {queryByTestId} = render(`
<select id="fruits" data-testid="select" multiple>
<option value="">Select a fruit...</option>
<option value="ananas" selected>Ananas</option>
<option value="banana">Banana</option>
<option value="avocado" selected>Avocado</option>
</select>
`)
describe('with multiple select', () => {
function mount() {
return render(`
<select id="fruits" data-testid="select" multiple>
<option value="">Select a fruit...</option>
<option value="ananas" selected>Ananas</option>
<option value="banana">Banana</option>
<option value="avocado" selected>Avocado</option>
</select>
`)
}

expect(queryByTestId('select')).toHaveDisplayValue(['Ananas', 'Avocado'])
expect(() =>
expect(queryByTestId('select')).not.toHaveDisplayValue([
it('matches only when all the multiple selected values are equal to all the expected values', () => {
const subject = mount()
expect(subject.queryByTestId('select')).toHaveDisplayValue([
'Ananas',
'Avocado',
]),
).toThrow()

expect(queryByTestId('select')).not.toHaveDisplayValue('Ananas')
expect(() =>
expect(queryByTestId('select')).toHaveDisplayValue('Ananas'),
).toThrow()
])
expect(() =>
expect(subject.queryByTestId('select')).not.toHaveDisplayValue([
'Ananas',
'Avocado',
]),
).toThrow()
expect(subject.queryByTestId('select')).not.toHaveDisplayValue([
'Ananas',
'Avocado',
'Orange',
])
expect(subject.queryByTestId('select')).not.toHaveDisplayValue('Ananas')
expect(() =>
expect(subject.queryByTestId('select')).toHaveDisplayValue('Ananas'),
).toThrow()

Array.from(subject.queryByTestId('select').options).forEach(option => {
option.selected = ['ananas', 'banana'].includes(option.value)
})

expect(subject.queryByTestId('select')).toHaveDisplayValue([
'Ananas',
'Banana',
])
})

Array.from(queryByTestId('select').options).forEach(option => {
option.selected = ['ananas', 'banana'].includes(option.value)
it('matches even when the expected values are unordered', () => {
const subject = mount()
expect(subject.queryByTestId('select')).toHaveDisplayValue([
'Avocado',
'Ananas',
])
})

expect(queryByTestId('select')).toHaveDisplayValue(['Ananas', 'Banana'])
it('matches with regex expected values', () => {
const subject = mount()
expect(subject.queryByTestId('select')).toHaveDisplayValue([
/[Aa]nanas/,
'Avocado',
])
})
})

test('it should work with input elements', () => {
Expand All @@ -59,6 +91,7 @@ test('it should work with input elements', () => {
`)

expect(queryByTestId('input')).toHaveDisplayValue('Luca')
expect(queryByTestId('input')).toHaveDisplayValue(/Luc/)

queryByTestId('input').value = 'Piero'
expect(queryByTestId('input')).toHaveDisplayValue('Piero')
Expand All @@ -72,6 +105,7 @@ test('it should work with textarea elements', () => {
expect(queryByTestId('textarea-example')).toHaveDisplayValue(
'An example description here.',
)
expect(queryByTestId('textarea-example')).toHaveDisplayValue(/example/)

queryByTestId('textarea-example').value = 'Another example'
expect(queryByTestId('textarea-example')).toHaveDisplayValue(
Expand Down
42 changes: 31 additions & 11 deletions src/to-have-display-value.js
@@ -1,6 +1,5 @@
import {matcherHint} from 'jest-matcher-utils'

import {checkHtmlElement, getMessage} from './utils'
import {matches, checkHtmlElement, getMessage} from './utils'

export function toHaveDisplayValue(htmlElement, expectedValue) {
checkHtmlElement(htmlElement, toHaveDisplayValue, this)
Expand All @@ -18,16 +17,19 @@ export function toHaveDisplayValue(htmlElement, expectedValue) {
)
}

const value =
tagName === 'select'
? Array.from(htmlElement)
.filter(option => option.selected)
.map(option => option.textContent)
.toString()
: htmlElement.value
const values = getValues(tagName, htmlElement)
const expectedValues = getExpectedValues(expectedValue)
const numberOfMatchesWithValues = getNumberOfMatchesBetweenArrays(
values,
expectedValues,
)

const matchedWithAllValues = numberOfMatchesWithValues === values.length
const matchedWithAllExpectedValues =
numberOfMatchesWithValues === expectedValues.length

return {
pass: value === expectedValue.toString(),
pass: matchedWithAllValues && matchedWithAllExpectedValues,
message: () =>
getMessage(
matcherHint(
Expand All @@ -38,7 +40,25 @@ export function toHaveDisplayValue(htmlElement, expectedValue) {
`Expected element ${this.isNot ? 'not ' : ''}to have display value`,
expectedValue,
'Received',
value,
values,
),
}
}

function getValues(tagName, htmlElement) {
return tagName === 'select'
? Array.from(htmlElement)
.filter(option => option.selected)
.map(option => option.textContent)
: [htmlElement.value]
}

function getExpectedValues(expectedValue) {
return expectedValue instanceof Array ? expectedValue : [expectedValue]
}

function getNumberOfMatchesBetweenArrays(arrayBase, array) {
return array.filter(
expected => arrayBase.filter(value => matches(value, expected)).length,
).length
}