From 8b8307a3802a0fb3e256541cbf1d4ae4f8d9eb56 Mon Sep 17 00:00:00 2001 From: davidsa Date: Tue, 3 Mar 2020 17:04:01 -0500 Subject: [PATCH 1/2] feat(config): Add customGetElementError config option closes #360 --- .../__snapshots__/get-by-errors.js.snap | 5 +++++ src/__tests__/get-by-errors.js | 20 +++++++++++++++++++ src/config.js | 3 +++ src/query-helpers.js | 5 +++++ 4 files changed, 33 insertions(+) create mode 100644 src/__tests__/__snapshots__/get-by-errors.js.snap diff --git a/src/__tests__/__snapshots__/get-by-errors.js.snap b/src/__tests__/__snapshots__/get-by-errors.js.snap new file mode 100644 index 00000000..1cc79a39 --- /dev/null +++ b/src/__tests__/__snapshots__/get-by-errors.js.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getByLabelText query will throw the custom error returned by config.customGetElementError 1`] = `"My custom error: Unable to find a label with the text of: TEST QUERY"`; + +exports[`getByText query will throw the custom error returned by config.customGetElementError 1`] = `"My custom error: Unable to find an element with the text: TEST QUERY. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible."`; diff --git a/src/__tests__/get-by-errors.js b/src/__tests__/get-by-errors.js index 6069caec..62f529b6 100644 --- a/src/__tests__/get-by-errors.js +++ b/src/__tests__/get-by-errors.js @@ -1,6 +1,13 @@ import cases from 'jest-in-case' +import {screen} from '../' +import {configure, getConfig} from '../config' import {render} from './helpers/test-utils' +const originalConfig = getConfig() +beforeEach(() => { + configure(originalConfig) +}) + cases( 'getBy* queries throw an error when there are multiple elements returned', ({name, query, html}) => { @@ -39,6 +46,19 @@ cases( }, ) +test.each([['getByText'], ['getByLabelText']])( + '%s query will throw the custom error returned by config.customGetElementError', + query => { + const customGetElementError = jest.fn( + (message, _container) => new Error(`My custom error: ${message}`), + ) + configure({customGetElementError}) + document.body.innerHTML = '
Hello
' + expect(() => screen[query]('TEST QUERY')).toThrowErrorMatchingSnapshot() + expect(customGetElementError).toBeCalledTimes(1) + }, +) + cases( 'queryBy* queries throw an error when there are multiple elements returned', ({name, query, html}) => { diff --git a/src/config.js b/src/config.js index f8109352..f00042e9 100644 --- a/src/config.js +++ b/src/config.js @@ -14,6 +14,9 @@ let config = { asyncWrapper: cb => cb(), // default value for the `hidden` option in `ByRole` queries defaultHidden: false, + + // called when getBy* queries fail. (message, container) => Error + customGetElementError: null, } export function configure(newConfig) { diff --git a/src/query-helpers.js b/src/query-helpers.js index 062e9df9..08c7d9ba 100644 --- a/src/query-helpers.js +++ b/src/query-helpers.js @@ -1,8 +1,13 @@ import {prettyDOM} from './pretty-dom' import {fuzzyMatches, matches, makeNormalizer} from './matches' import {waitForElement} from './wait-for-element' +import {getConfig} from './config' function getElementError(message, container) { + const customGetElementError = getConfig().customGetElementError + if (customGetElementError) { + return customGetElementError(message, container) + } return new Error([message, prettyDOM(container)].filter(Boolean).join('\n\n')) } From 31040e511c07f7ceb2c9398bbdc81583f52776f1 Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Tue, 3 Mar 2020 19:38:26 -0700 Subject: [PATCH 2/2] move config around a bit --- .../__snapshots__/get-by-errors.js.snap | 4 ++-- src/__tests__/get-by-errors.js | 8 ++++---- src/config.js | 8 +++++++- src/queries/label-text.js | 6 +++--- src/query-helpers.js | 17 +++++------------ 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/__tests__/__snapshots__/get-by-errors.js.snap b/src/__tests__/__snapshots__/get-by-errors.js.snap index 1cc79a39..45f4cde1 100644 --- a/src/__tests__/__snapshots__/get-by-errors.js.snap +++ b/src/__tests__/__snapshots__/get-by-errors.js.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getByLabelText query will throw the custom error returned by config.customGetElementError 1`] = `"My custom error: Unable to find a label with the text of: TEST QUERY"`; +exports[`getByLabelText query will throw the custom error returned by config.getElementError 1`] = `"My custom error: Unable to find a label with the text of: TEST QUERY"`; -exports[`getByText query will throw the custom error returned by config.customGetElementError 1`] = `"My custom error: Unable to find an element with the text: TEST QUERY. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible."`; +exports[`getByText query will throw the custom error returned by config.getElementError 1`] = `"My custom error: Unable to find an element with the text: TEST QUERY. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible."`; diff --git a/src/__tests__/get-by-errors.js b/src/__tests__/get-by-errors.js index 62f529b6..c7e8cadf 100644 --- a/src/__tests__/get-by-errors.js +++ b/src/__tests__/get-by-errors.js @@ -47,15 +47,15 @@ cases( ) test.each([['getByText'], ['getByLabelText']])( - '%s query will throw the custom error returned by config.customGetElementError', + '%s query will throw the custom error returned by config.getElementError', query => { - const customGetElementError = jest.fn( + const getElementError = jest.fn( (message, _container) => new Error(`My custom error: ${message}`), ) - configure({customGetElementError}) + configure({getElementError}) document.body.innerHTML = '
Hello
' expect(() => screen[query]('TEST QUERY')).toThrowErrorMatchingSnapshot() - expect(customGetElementError).toBeCalledTimes(1) + expect(getElementError).toBeCalledTimes(1) }, ) diff --git a/src/config.js b/src/config.js index f00042e9..dbb80da0 100644 --- a/src/config.js +++ b/src/config.js @@ -1,3 +1,5 @@ +import {prettyDOM} from './pretty-dom' + // It would be cleaner for this to live inside './queries', but // other parts of the code assume that all exports from // './queries' are query functions. @@ -16,7 +18,11 @@ let config = { defaultHidden: false, // called when getBy* queries fail. (message, container) => Error - customGetElementError: null, + getElementError(message, container) { + return new Error( + [message, prettyDOM(container)].filter(Boolean).join('\n\n'), + ) + }, } export function configure(newConfig) { diff --git a/src/queries/label-text.js b/src/queries/label-text.js index 3669db20..59fce539 100644 --- a/src/queries/label-text.js +++ b/src/queries/label-text.js @@ -1,8 +1,8 @@ +import {getConfig} from '../config' import { fuzzyMatches, matches, makeNormalizer, - getElementError, queryAllByAttribute, makeFindQuery, makeSingleQuery, @@ -104,12 +104,12 @@ function getAllByLabelText(container, text, ...rest) { if (!els.length) { const labels = queryAllLabelsByText(container, text, ...rest) if (labels.length) { - throw getElementError( + throw getConfig().getElementError( `Found a label with the text of: ${text}, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.`, container, ) } else { - throw getElementError( + throw getConfig().getElementError( `Unable to find a label with the text of: ${text}`, container, ) diff --git a/src/query-helpers.js b/src/query-helpers.js index 08c7d9ba..3c3295ae 100644 --- a/src/query-helpers.js +++ b/src/query-helpers.js @@ -1,18 +1,9 @@ -import {prettyDOM} from './pretty-dom' import {fuzzyMatches, matches, makeNormalizer} from './matches' import {waitForElement} from './wait-for-element' import {getConfig} from './config' -function getElementError(message, container) { - const customGetElementError = getConfig().customGetElementError - if (customGetElementError) { - return customGetElementError(message, container) - } - return new Error([message, prettyDOM(container)].filter(Boolean).join('\n\n')) -} - function getMultipleElementsFoundError(message, container) { - return getElementError( + return getConfig().getElementError( `${message}\n\n(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).`, container, ) @@ -64,7 +55,10 @@ function makeGetAllQuery(allQuery, getMissingError) { return (container, ...args) => { const els = allQuery(container, ...args) if (!els.length) { - throw getElementError(getMissingError(container, ...args), container) + throw getConfig().getElementError( + getMissingError(container, ...args), + container, + ) } return els } @@ -91,7 +85,6 @@ function buildQueries(queryAllBy, getMultipleError, getMissingError) { } export { - getElementError, getMultipleElementsFoundError, queryAllByAttribute, queryByAttribute,