Skip to content
Merged
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
9 changes: 7 additions & 2 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 @@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
}