Skip to content

Commit

Permalink
feat(findBy*): adds findBy* query type allowing for async element que…
Browse files Browse the repository at this point in the history
…ries (#224)

* feat(findBy*): adds findBy* query type allowing for async element queries

Closes #203

* undo something

* add a real async test
  • Loading branch information
Kent C. Dodds committed Mar 19, 2019
1 parent df8863f commit 8b29d43
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 13 deletions.
1 change: 0 additions & 1 deletion src/__tests__/element-queries.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'jest-dom/extend-expect'
import {configure} from '../config'
import {render, renderIntoDocument} from './helpers/test-utils'

Expand Down
2 changes: 0 additions & 2 deletions src/__tests__/example.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// query utilities:
import {getByLabelText, getByText, getByTestId, queryByTestId, wait} from '../'
// adds special assertions like toHaveTextContent
import 'jest-dom/extend-expect'

function getExampleDOM() {
// This is just a raw example of setting up some DOM
Expand Down
8 changes: 5 additions & 3 deletions src/__tests__/helpers/test-utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {getQueriesForElement} from '../../get-queries-for-element'

function render(html) {
const container = document.createElement('div')
function render(html, {container = document.createElement('div')} = {}) {
container.innerHTML = html
const containerQueries = getQueriesForElement(container)
return {container, ...containerQueries}
function rerender(newHtml) {
return render(newHtml, {container})
}
return {container, rerender, ...containerQueries}
}

function renderIntoDocument(html) {
Expand Down
125 changes: 125 additions & 0 deletions src/__tests__/queries.find.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {render} from './helpers/test-utils'

test('find asynchronously finds elements', async () => {
const {
findByLabelText,
findAllByLabelText,

findByPlaceholderText,
findAllByPlaceholderText,

findByText,
findAllByText,

findByAltText,
findAllByAltText,

findByTitle,
findAllByTitle,

findByDisplayValue,
findAllByDisplayValue,

findByRole,
findAllByRole,

findByTestId,
findAllByTestId,
} = render(`
<div>
<div data-testid="test-id" aria-label="test-label">test text content</div>
<select><option>display value</option></select>
<input placeholder="placeholder" />
<img alt="test alt text" src="/lucy-ricardo.png" />
<span title="test title" />
<div role="dialog"></div>
</div>
`)
await expect(findByLabelText('test-label')).resolves.toBeTruthy()
await expect(findAllByLabelText('test-label')).resolves.toHaveLength(1)

await expect(findByPlaceholderText('placeholder')).resolves.toBeTruthy()
await expect(findAllByPlaceholderText('placeholder')).resolves.toHaveLength(1)

await expect(findByText('test text content')).resolves.toBeTruthy()
await expect(findAllByText('test text content')).resolves.toHaveLength(1)

await expect(findByAltText('test alt text')).resolves.toBeTruthy()
await expect(findAllByAltText('test alt text')).resolves.toHaveLength(1)

await expect(findByTitle('test title')).resolves.toBeTruthy()
await expect(findAllByTitle('test title')).resolves.toHaveLength(1)

await expect(findByDisplayValue('display value')).resolves.toBeTruthy()
await expect(findAllByDisplayValue('display value')).resolves.toHaveLength(1)

await expect(findByRole('dialog')).resolves.toBeTruthy()
await expect(findAllByRole('dialog')).resolves.toHaveLength(1)

await expect(findByTestId('test-id')).resolves.toBeTruthy()
await expect(findAllByTestId('test-id')).resolves.toHaveLength(1)
})

test('find rejects when something cannot be found', async () => {
const {
findByLabelText,
findAllByLabelText,

findByPlaceholderText,
findAllByPlaceholderText,

findByText,
findAllByText,

findByAltText,
findAllByAltText,

findByTitle,
findAllByTitle,

findByDisplayValue,
findAllByDisplayValue,

findByRole,
findAllByRole,

findByTestId,
findAllByTestId,
} = render(`<div />`)

// I just don't want multiple lines for these.
// qo = queryOptions
// wo = waitForElementOptions
const qo = {} // query options
const wo = {timeout: 10} // wait options

await expect(findByLabelText('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByLabelText('x', qo, wo)).rejects.toThrow('x')

await expect(findByPlaceholderText('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByPlaceholderText('x', qo, wo)).rejects.toThrow('x')

await expect(findByText('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByText('x', qo, wo)).rejects.toThrow('x')

await expect(findByAltText('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByAltText('x', qo, wo)).rejects.toThrow('x')

await expect(findByTitle('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByTitle('x', qo, wo)).rejects.toThrow('x')

await expect(findByDisplayValue('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByDisplayValue('x', qo, wo)).rejects.toThrow('x')

await expect(findByRole('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByRole('x', qo, wo)).rejects.toThrow('x')

await expect(findByTestId('x', qo, wo)).rejects.toThrow('x')
await expect(findAllByTestId('x', qo, wo)).rejects.toThrow('x')
})

test('actually works with async code', async () => {
const {findByTestId, container, rerender} = render(`<div />`)
setTimeout(() => rerender(`<div data-testid="div">correct dom</div>`), 20)
await expect(findByTestId('div', {}, {container})).resolves.toBeTruthy()
})
1 change: 0 additions & 1 deletion src/__tests__/text-matchers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'jest-dom/extend-expect'
import cases from 'jest-in-case'

import {getDefaultNormalizer} from '../'
Expand Down
2 changes: 0 additions & 2 deletions src/__tests__/wait-for-dom-change.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {waitForDomChange} from '../'
// adds special assertions like toBeTruthy
import 'jest-dom/extend-expect'
import {render} from './helpers/test-utils'

const skipSomeTime = delayMs =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'jest-dom/extend-expect'
import {waitForElementToBeRemoved} from '../'
import {render} from './helpers/test-utils'

Expand Down
1 change: 0 additions & 1 deletion src/__tests__/wait-for-element-to-be-removed.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'jest-dom/extend-expect'
import {waitForElementToBeRemoved} from '../'
import {renderIntoDocument} from './helpers/test-utils'

Expand Down
2 changes: 0 additions & 2 deletions src/__tests__/wait-for-element.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {waitForElement, wait} from '../'
// adds special assertions like toBeTruthy
import 'jest-dom/extend-expect'
import {render} from './helpers/test-utils'

const skipSomeTime = delayMs =>
Expand Down
33 changes: 33 additions & 0 deletions src/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
queryAllByAttribute,
queryByAttribute,
} from './query-helpers'
import {waitForElement} from './wait-for-element'
import {getConfig} from './config'

// Here are the queries for the library.
Expand Down Expand Up @@ -375,6 +376,38 @@ function getByDisplayValue(...args) {
return firstResultOrNull(getAllByDisplayValue, ...args)
}

function makeFinder(getter) {
return (container, text, options, waitForElementOptions) =>
waitForElement(
() => getter(container, text, options),
waitForElementOptions,
)
}

export const findByLabelText = makeFinder(getByLabelText)
export const findAllByLabelText = makeFinder(getAllByLabelText)

export const findByPlaceholderText = makeFinder(getByPlaceholderText)
export const findAllByPlaceholderText = makeFinder(getAllByPlaceholderText)

export const findByText = makeFinder(getByText)
export const findAllByText = makeFinder(getAllByText)

export const findByAltText = makeFinder(getByAltText)
export const findAllByAltText = makeFinder(getAllByAltText)

export const findByTitle = makeFinder(getByTitle)
export const findAllByTitle = makeFinder(getAllByTitle)

export const findByDisplayValue = makeFinder(getByDisplayValue)
export const findAllByDisplayValue = makeFinder(getAllByDisplayValue)

export const findByRole = makeFinder(getByRole)
export const findAllByRole = makeFinder(getAllByRole)

export const findByTestId = makeFinder(getByTestId)
export const findAllByTestId = makeFinder(getAllByTestId)

export {
queryByPlaceholderText,
queryAllByPlaceholderText,
Expand Down
1 change: 1 addition & 0 deletions tests/setup-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import 'jest-dom/extend-expect'

0 comments on commit 8b29d43

Please sign in to comment.