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

feat: Add toHaveDisplayValue() matcher #223

Merged
merged 13 commits into from Apr 9, 2020
43 changes: 43 additions & 0 deletions README.md
Expand Up @@ -66,6 +66,7 @@ clear to read and to maintain.
- [`toHaveStyle`](#tohavestyle)
- [`toHaveTextContent`](#tohavetextcontent)
- [`toHaveValue`](#tohavevalue)
- [`toHaveDisplayValue`](#tohavedisplayvalue)
- [`toBeChecked`](#tobechecked)
- [Deprecated matchers](#deprecated-matchers)
- [`toBeInTheDOM`](#tobeinthedom)
Expand Down Expand Up @@ -765,6 +766,47 @@ expect(selectInput).not.toHaveValue(['second', 'third'])

<hr />

### `toHaveDisplayValue`

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

This allows you to check whether the given `<select>` element has the specified
value.
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved

#### Examples

```html
<label for="single-select-example">Fruit</label>
<select id="single-select-example">
<option value="">Select a fruit...</option>
<option value="banana">Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado">Avocado</option>
</select>

<label for="mutiple-select-example">Fruits</label>
<select id="multiple-select-example">
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved
<option value="">Select a fruit...</option>
<option value="banana" selected>Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado" selected>Avocado</option>
</select>
```

##### Using DOM Testing Library

```javascript
const inputSelect = screen.getByLabelText('Fruit')
const inputMultiple = screen.getByLabelText('Fruits')
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved

expect(inputSelect).toHaveDisplayValue('Select a fruit...')
expect(inputMultiple).toHaveDisplayValue(['Banana', 'Avocado'])
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved
```

<hr />

### `toBeChecked`

```typescript
Expand Down Expand Up @@ -940,6 +982,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
62 changes: 62 additions & 0 deletions src/__tests__/to-have-display-value.js
@@ -0,0 +1,62 @@
import {render} from './helpers/test-utils'

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

expect(queryByTestId('select')).toHaveDisplayValue('Select a fruit...')
expect(queryByTestId('select')).not.toHaveDisplayValue('Banana')
Comment on lines +13 to +14
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice if the test also covered the case of changing the selected option programmatically to banana and then check that toHaveDisplayValue('Banana') pass.

And maybe do it for the other cases as well (textarea and input).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I'm wondering why the repository is not using fireEvent from the testing-library core (or even userEvent) 🤔

expect(() =>
expect(queryByTestId('select')).not.toHaveDisplayValue('Select a fruit...'),
).toThrow()
expect(() =>
expect(queryByTestId('select')).toHaveDisplayValue('Ananas'),
).toThrow()
})

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>
`)

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

expect(queryByTestId('select')).not.toHaveDisplayValue('Ananas')
expect(() =>
expect(queryByTestId('select')).toHaveDisplayValue('Ananas'),
).toThrow()
})

test('it should throw if element is not valid', () => {
const {queryByTestId} = render(`
<input type="text" data-testid="input" value="Banana" />
`)

let errorMessage
try {
expect(queryByTestId('input')).toHaveDisplayValue('Banana')
} catch (err) {
errorMessage = err.message
}

expect(errorMessage).toMatchInlineSnapshot(
`".toHaveDisplayValue() currently supports select elements only, try to use .toHaveValue() or toBeChecked() instead."`,
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved
)
})
2 changes: 2 additions & 0 deletions src/matchers.js
Expand Up @@ -14,6 +14,7 @@ import {toBeDisabled, toBeEnabled} from './to-be-disabled'
import {toBeRequired} from './to-be-required'
import {toBeInvalid, toBeValid} from './to-be-invalid'
import {toHaveValue} from './to-have-value'
import {toHaveDisplayValue} from './to-have-display-value'
import {toBeChecked} from './to-be-checked'

export {
Expand All @@ -35,5 +36,6 @@ export {
toBeInvalid,
toBeValid,
toHaveValue,
toHaveDisplayValue,
toBeChecked,
}
34 changes: 34 additions & 0 deletions src/to-have-display-value.js
@@ -0,0 +1,34 @@
import {matcherHint} from 'jest-matcher-utils'

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

export function toHaveDisplayValue(htmlElement, expectedValue) {
checkHtmlElement(htmlElement, toHaveDisplayValue, this)

if (htmlElement.tagName.toLowerCase() !== 'select') {
throw new Error(
'.toHaveDisplayValue() currently supports select elements only, try to use .toHaveValue() or toBeChecked() instead.',
cloud-walker marked this conversation as resolved.
Show resolved Hide resolved
)
}

const value = Array.from(htmlElement)
.filter(option => option.selected)
.map(option => option.textContent)
.toString()

return {
pass: value === expectedValue.toString(),
gnapse marked this conversation as resolved.
Show resolved Hide resolved
message: () =>
getMessage(
matcherHint(
`${this.isNot ? '.not' : ''}.toHaveDisplayValue`,
'element',
'',
),
`Expected element ${this.isNot ? 'not ' : ''}to have display value`,
expectedValue,
'Received',
value,
),
}
}