diff --git a/README.md b/README.md index b1ce1155..26ffc741 100644 --- a/README.md +++ b/README.md @@ -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) @@ -732,8 +733,8 @@ toHaveValue(value: string | string[] | number) This allows you to check whether the given form element has the specified value. It accepts ``, ` + + + + + + +``` + +##### Using DOM Testing Library + +```javascript +const input = screen.getByLabelText('First name') +const textarea = screen.getByLabelText('Description') +const selectSingle = screen.getByLabelText('Fruit') +const selectMultiple = screen.getByLabelText('Fruits') + +expect(input).toHaveDisplayValue('Luca') +expect(textarea).toHaveDisplayValue('An example description here.') +expect(selectSingle).toHaveDisplayValue('Select a fruit...') +expect(selectMultiple).toHaveDisplayValue(['Banana', 'Avocado']) +``` + +
+ ### `toBeChecked` ```typescript @@ -959,6 +1015,7 @@ Thanks goes to these people ([emoji key][emojis]): + This project follows the [all-contributors][all-contributors] specification. diff --git a/src/__tests__/to-have-display-value.js b/src/__tests__/to-have-display-value.js new file mode 100644 index 00000000..e49749a9 --- /dev/null +++ b/src/__tests__/to-have-display-value.js @@ -0,0 +1,119 @@ +import {render} from './helpers/test-utils' + +test('it should work as expected', () => { + const {queryByTestId} = render(` + + `) + + expect(queryByTestId('select')).toHaveDisplayValue('Select a fruit...') + expect(queryByTestId('select')).not.toHaveDisplayValue('Banana') + expect(() => + expect(queryByTestId('select')).not.toHaveDisplayValue('Select a fruit...'), + ).toThrow() + expect(() => + expect(queryByTestId('select')).toHaveDisplayValue('Ananas'), + ).toThrow() + + queryByTestId('select').value = 'banana' + expect(queryByTestId('select')).toHaveDisplayValue('Banana') +}) + +test('it should work with select multiple', () => { + const {queryByTestId} = render(` + + `) + + 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() + + Array.from(queryByTestId('select').options).forEach(option => { + option.selected = ['ananas', 'banana'].includes(option.value) + }) + + expect(queryByTestId('select')).toHaveDisplayValue(['Ananas', 'Banana']) +}) + +test('it should work with input elements', () => { + const {queryByTestId} = render(` + + `) + + expect(queryByTestId('input')).toHaveDisplayValue('Luca') + + queryByTestId('input').value = 'Piero' + expect(queryByTestId('input')).toHaveDisplayValue('Piero') +}) + +test('it should work with textarea elements', () => { + const {queryByTestId} = render( + '', + ) + + expect(queryByTestId('textarea-example')).toHaveDisplayValue( + 'An example description here.', + ) + + queryByTestId('textarea-example').value = 'Another example' + expect(queryByTestId('textarea-example')).toHaveDisplayValue( + 'Another example', + ) +}) + +test('it should throw if element is not valid', () => { + const {queryByTestId} = render(` +
Banana
+ + + `) + + let errorMessage + try { + expect(queryByTestId('div')).toHaveDisplayValue('Banana') + } catch (err) { + errorMessage = err.message + } + + expect(errorMessage).toMatchInlineSnapshot( + `".toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead."`, + ) + + try { + expect(queryByTestId('radio')).toHaveDisplayValue('Something') + } catch (err) { + errorMessage = err.message + } + + expect(errorMessage).toMatchInlineSnapshot( + `".toHaveDisplayValue() currently does not support input[type=\\"radio\\"], try with another matcher instead."`, + ) + + try { + expect(queryByTestId('checkbox')).toHaveDisplayValue(true) + } catch (err) { + errorMessage = err.message + } + + expect(errorMessage).toMatchInlineSnapshot( + `".toHaveDisplayValue() currently does not support input[type=\\"checkbox\\"], try with another matcher instead."`, + ) +}) diff --git a/src/matchers.js b/src/matchers.js index 5e699d04..552f1300 100644 --- a/src/matchers.js +++ b/src/matchers.js @@ -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 { @@ -35,5 +36,6 @@ export { toBeInvalid, toBeValid, toHaveValue, + toHaveDisplayValue, toBeChecked, } diff --git a/src/to-have-display-value.js b/src/to-have-display-value.js new file mode 100644 index 00000000..c59d7181 --- /dev/null +++ b/src/to-have-display-value.js @@ -0,0 +1,44 @@ +import {matcherHint} from 'jest-matcher-utils' + +import {checkHtmlElement, getMessage} from './utils' + +export function toHaveDisplayValue(htmlElement, expectedValue) { + checkHtmlElement(htmlElement, toHaveDisplayValue, this) + const tagName = htmlElement.tagName.toLowerCase() + + if (!['select', 'input', 'textarea'].includes(tagName)) { + throw new Error( + '.toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead.', + ) + } + + if (tagName === 'input' && ['radio', 'checkbox'].includes(htmlElement.type)) { + throw new Error( + `.toHaveDisplayValue() currently does not support input[type="${htmlElement.type}"], try with another matcher instead.`, + ) + } + + const value = + tagName === 'select' + ? Array.from(htmlElement) + .filter(option => option.selected) + .map(option => option.textContent) + .toString() + : htmlElement.value + + return { + pass: value === expectedValue.toString(), + message: () => + getMessage( + matcherHint( + `${this.isNot ? '.not' : ''}.toHaveDisplayValue`, + 'element', + '', + ), + `Expected element ${this.isNot ? 'not ' : ''}to have display value`, + expectedValue, + 'Received', + value, + ), + } +}