diff --git a/README.md b/README.md index c9461bcb..b21a10d9 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ clear to read and to maintain. + - [Installation](#installation) - [Usage](#usage) - [Custom matchers](#custom-matchers) @@ -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 @@ -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']) ```
@@ -1084,6 +1088,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 index e49749a9..8cae8734 100644 --- a/src/__tests__/to-have-display-value.js +++ b/src/__tests__/to-have-display-value.js @@ -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(` - - `) +describe('with multiple select', () => { + function mount() { + return render(` + + `) + } - 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', () => { @@ -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') @@ -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( diff --git a/src/to-have-display-value.js b/src/to-have-display-value.js index c59d7181..11d35c5c 100644 --- a/src/to-have-display-value.js +++ b/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) @@ -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( @@ -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 +}