diff --git a/.all-contributorsrc b/.all-contributorsrc index 5e2bca49..11163e3b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -440,6 +440,15 @@ "contributions": [ "code" ] + }, + { + "login": "eunjae-lee", + "name": "Eunjae Lee", + "avatar_url": "https://avatars3.githubusercontent.com/u/499898?v=4", + "profile": "https://twitter.com/eunjae_lee", + "contributions": [ + "code" + ] } ] } diff --git a/README.md b/README.md index fd22e28a..2bbb1b84 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ [![downloads][downloads-badge]][npmtrends] [![MIT License][license-badge]][license] -[![All Contributors](https://img.shields.io/badge/all_contributors-44-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-45-orange.svg?style=flat-square)](#contributors) [![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc] @@ -81,11 +81,10 @@ when a real user uses it. - [Usage](#usage) - [`getByLabelText`](#getbylabeltext) - [`getByPlaceholderText`](#getbyplaceholdertext) - - [`getBySelectText`](#getbyselecttext) - [`getByText`](#getbytext) - [`getByAltText`](#getbyalttext) - [`getByTitle`](#getbytitle) - - [`getByValue`](#getbyvalue) + - [`getByDisplayValue`](#getbydisplayvalue) - [`getByRole`](#getbyrole) - [`getByTestId`](#getbytestid) - [`wait`](#wait) @@ -275,35 +274,6 @@ const inputNode = getByPlaceholderText(container, 'Username') > NOTE: a placeholder is not a good substitute for a label so you should > generally use `getByLabelText` instead. -### `getBySelectText` - -```typescript -getBySelectText( - container: HTMLElement, - text: TextMatch, - options?: { - exact?: boolean = true, - collapseWhitespace?: boolean = true, - trim?: boolean = true, - }): HTMLElement -``` - -This will search for a `` node in a situation -where the first value acts as a sort of placeholder for the dropdown. - -```javascript -// -const selectNode = getBySelectText(container, 'Day of the Week') -``` - -> Note: It is highly preferred to use `getByLabelText` over this method. This -> method should only be used in the event where there is no label text available. - ### `getByText` ```typescript @@ -389,10 +359,10 @@ Will also find a `title` element within an SVG. const closeElement = getByTitle(container, 'Close') ``` -### `getByValue` +### `getByDisplayValue` ```typescript -getByValue( +getByDisplayValue( container: HTMLElement, value: TextMatch, options?: { @@ -402,13 +372,41 @@ getByValue( }): HTMLElement ``` -Returns the element that has the matching value. +Returns the `input`, `textarea`, or `select` element that has the matching display value. + +#### `input` + +```javascript +// +// document.getElementById('lastName').value = 'Norris' + +const lastNameInput = getByDisplayValue(container, 'Norris') +``` + +#### `textarea` ```javascript -// -const lastNameInput = getByValue('Norris') +// +// document.getElementById('messageTextArea').value = 'Hello World' + +const messageTextArea = getByDisplayValue(container, 'Hello World') ``` +#### `select` + +```javascript +// + +const selectElement = getByDisplayName(container, 'Alaska') +``` + +In case of `select`, this will search for a ` + + `) + expect(getByDisplayValue('Mercury').placeholder).toEqual('name') + expect(queryByDisplayValue('Mercury').placeholder).toEqual('name') + + getByTestId('name').value = 'Norris' + expect(getByDisplayValue('Norris').placeholder).toEqual('name') + expect(queryByDisplayValue('Norris').placeholder).toEqual('name') + + expect(queryByDisplayValue('Nor', {exact: false}).placeholder).toEqual('name') +}) + +test('get/query select element by current value', () => { + const { + getByDisplayValue, + queryByDisplayValue, + getByTestId, + } = renderIntoDocument(` + + `) + + expect(getByDisplayValue('Alaska').id).toEqual('state-select') + expect(queryByDisplayValue('Alaska').id).toEqual('state-select') + + getByTestId('state').value = 'AL' + expect(getByDisplayValue('Alabama').id).toEqual('state-select') + expect(queryByDisplayValue('Alabama').id).toEqual('state-select') +}) + +test('get/query textarea element by current value', () => { + const { + getByDisplayValue, + queryByDisplayValue, + getByTestId, + } = renderIntoDocument(` + + `) + + expect(getByDisplayValue('Hello').id).toEqual('content-textarea') + expect(queryByDisplayValue('Hello').id).toEqual('content-textarea') + + getByTestId('content').value = 'World' + expect(getByDisplayValue('World').id).toEqual('content-textarea') + expect(queryByDisplayValue('World').id).toEqual('content-textarea') +}) + /* eslint jsx-a11y/label-has-for:0 */ diff --git a/src/queries.js b/src/queries.js index c0d738a3..d9bf7c7d 100644 --- a/src/queries.js +++ b/src/queries.js @@ -180,6 +180,33 @@ function queryByAltText(...args) { return firstResultOrNull(queryAllByAltText, ...args) } +function queryAllByDisplayValue( + container, + value, + {exact = true, collapseWhitespace = true, trim = true} = {}, +) { + const matcher = exact ? matches : fuzzyMatches + const matchOpts = {collapseWhitespace, trim} + return Array.from(container.querySelectorAll(`input,textarea,select`)).filter( + node => { + if (node.tagName === 'SELECT') { + const selectedOptions = Array.from(node.options).filter( + option => option.selected, + ) + return selectedOptions.some(optionNode => + matcher(getNodeText(optionNode), optionNode, value, matchOpts), + ) + } else { + return matcher(node.value, node, value, matchOpts) + } + }, + ) +} + +function queryByDisplayValue(...args) { + return firstResultOrNull(queryAllByDisplayValue, ...args) +} + // getters // the reason we're not dynamically generating these functions that look so similar: // 1. The error messages are specific to each one and depend on arguments @@ -325,6 +352,21 @@ function getBySelectText(...args) { return firstResultOrNull(getAllBySelectText, ...args) } +function getAllByDisplayValue(container, value, ...rest) { + const els = queryAllByDisplayValue(container, value, ...rest) + if (!els.length) { + throw getElementError( + `Unable to find an element with the value: ${value}.`, + container, + ) + } + return els +} + +function getByDisplayValue(...args) { + return firstResultOrNull(getAllByDisplayValue, ...args) +} + export { queryByPlaceholderText, queryAllByPlaceholderText, @@ -358,6 +400,10 @@ export { queryAllByValue, getByValue, getAllByValue, + queryByDisplayValue, + queryAllByDisplayValue, + getByDisplayValue, + getAllByDisplayValue, queryByRole, queryAllByRole, getAllByRole,