diff --git a/package.json b/package.json
index 0681a4c4..a679be25 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
},
"devDependencies": {
"@testing-library/jest-dom": "^5.11.6",
+ "@types/lz-string": "^1.3.34",
"jest-in-case": "^1.0.2",
"jest-serializer-ansi": "^1.0.3",
"jest-watch-select-projects": "^2.0.0",
diff --git a/src/__tests__/__snapshots__/get-by-errors.js.snap b/src/__tests__/__snapshots__/get-by-errors.js.snap
index 45f4cde1..23d1446a 100644
--- a/src/__tests__/__snapshots__/get-by-errors.js.snap
+++ b/src/__tests__/__snapshots__/get-by-errors.js.snap
@@ -1,5 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`getByLabelText query will print the playground link when enabled in the config 1`] = `
+"Unable to find a label with the text of: TEST QUERY
+
+
+
+ Hello
+
+
+
+Open this markup in the Testing-Library Playground:
+https://testing-playground.com/#markup=DwEwlgbgfAEgpgGwQe2AenNIA"
+`;
+
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 print the playground link when enabled in the config 1`] = `
+"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.
+
+
+
+ Hello
+
+
+
+Open this markup in the Testing-Library Playground:
+https://testing-playground.com/#markup=DwEwlgbgfAEgpgGwQe2AenNIA"
+`;
+
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__/element-queries.js b/src/__tests__/element-queries.js
index 3e3ee6de..301e79ba 100644
--- a/src/__tests__/element-queries.js
+++ b/src/__tests__/element-queries.js
@@ -35,65 +35,65 @@ test('get throws a useful error message', () => {
} = render('')
expect(() => getByLabelText('LucyRicardo'))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find a label with the text of: LucyRicardo
+ "Unable to find a label with the text of: LucyRicardo
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByPlaceholderText('LucyRicardo'))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the placeholder text of: LucyRicardo
+ "Unable to find an element with the placeholder text of: LucyRicardo
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByText('LucyRicardo')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the text: LucyRicardo. 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.
+ "Unable to find an element with the text: LucyRicardo. 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.
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByTestId('LucyRicardo')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element by: [data-testid="LucyRicardo"]
+ "Unable to find an element by: [data-testid="LucyRicardo"]
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByAltText('LucyRicardo')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the alt text: LucyRicardo
+ "Unable to find an element with the alt text: LucyRicardo
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByTitle('LucyRicardo')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the title: LucyRicardo.
+ "Unable to find an element with the title: LucyRicardo.
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByDisplayValue('LucyRicardo'))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the display value: LucyRicardo.
+ "Unable to find an element with the display value: LucyRicardo.
-
-
-
"
-`)
+
+
+
"
+ `)
expect(() => getByRole('LucyRicardo')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "LucyRicardo"
+ "Unable to find an accessible element with the role "LucyRicardo"
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('can get elements by matching their text content', () => {
@@ -352,14 +352,14 @@ test('label with no form control', () => {
const {getByLabelText, queryByLabelText} = render(``)
expect(queryByLabelText(/alone/)).toBeNull()
expect(() => getByLabelText(/alone/)).toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: /alone/, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
+ "Found a label with the text of: /alone/, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('label with "for" attribute but no form control and fuzzy matcher', () => {
@@ -369,16 +369,16 @@ test('label with "for" attribute but no form control and fuzzy matcher', () => {
expect(queryByLabelText('alone', {exact: false})).toBeNull()
expect(() => getByLabelText('alone', {exact: false}))
.toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: alone, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
-
-
-
-
"
-`)
+ "Found a label with the text of: alone, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
+
+
+
+
"
+ `)
})
test('label with children with no form control', () => {
@@ -391,32 +391,32 @@ test('label with children with no form control', () => {
expect(queryByLabelText(/alone/, {selector: 'input'})).toBeNull()
expect(() => getByLabelText(/alone/, {selector: 'input'}))
.toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: /alone/, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
+ "Found a label with the text of: /alone/, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
-
-
-
-
-
"
-`)
+
+
+
+
+
"
+ `)
})
test('label with non-labellable element', () => {
@@ -431,35 +431,35 @@ test('label with non-labellable element', () => {
expect(queryByLabelText(/Label/)).toBeNull()
expect(() => getByLabelText(/Label/)).toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
+ "Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
-
-
-
-
-
-
-
-
-
-
+
- Hello
-
-
-
-
-
-
-
-
"
-`)
+
+
+
+
+
+
+
+
+
+ Hello
+
+
+
+
+
+
+
+
"
+ `)
})
test('multiple labels with non-labellable elements', () => {
@@ -478,65 +478,65 @@ test('multiple labels with non-labellable elements', () => {
expect(queryAllByLabelText(/Label/)).toEqual([])
expect(() => getAllByLabelText(/Label/)).toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
+ "Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
-Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
+ Found a label with the text of: /Label/, however the element associated with this label () is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a , you can use aria-label or aria-labelledby instead.
-
-
-
-
-
-
-
-
-
-
+
- Hello
-
-
-
-
-
-
-
-
- World
-
-
-
-
-
-
-
-
"
-`)
+
+
+
+
+
+
+
+
+ Hello
+
+
+
+
+
+
+
+
+
+ World
+
+
+
+
+
+
+
+
"
+ `)
})
test('totally empty label', () => {
const {getByLabelText, queryByLabelText} = render(``)
expect(queryByLabelText('')).toBeNull()
expect(() => getByLabelText('')).toThrowErrorMatchingInlineSnapshot(`
-"Found a label with the text of: , however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
+ "Found a label with the text of: , however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('getByLabelText with aria-label', () => {
@@ -1031,7 +1031,7 @@ test('the debug helper prints the dom state here', () => {
const {getByTestId} = renderIntoDocument(Hello)
process.env.DEBUG_PRINT_LIMIT = 5 // user should see `...`
expect(() => expect(getByTestId('not present')).toBeTruthy()).toThrowError(
- /\.\.\.$/,
+ /\.\.\./,
)
const {getByLabelText} = renderIntoDocument(Hello)
@@ -1219,14 +1219,14 @@ test('return a proper error message when no label is found and there is an aria-
expect(() => getByLabelText('LucyRicardo'))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find a label with the text of: LucyRicardo
-
-
-
-
"
-`)
+ "Unable to find a label with the text of: LucyRicardo
+
+
+
+
"
+ `)
})
// https://github.com/testing-library/dom-testing-library/issues/723
diff --git a/src/__tests__/get-by-errors.js b/src/__tests__/get-by-errors.js
index c7e8cadf..366ea471 100644
--- a/src/__tests__/get-by-errors.js
+++ b/src/__tests__/get-by-errors.js
@@ -4,7 +4,7 @@ import {configure, getConfig} from '../config'
import {render} from './helpers/test-utils'
const originalConfig = getConfig()
-beforeEach(() => {
+afterEach(() => {
configure(originalConfig)
})
@@ -97,6 +97,33 @@ cases(
},
)
+test.each([['getByText'], ['getByLabelText']])(
+ '%s query will print the playground link when enabled in the config',
+ query => {
+ configure({printPlaygroundLink: true})
+ document.body.innerHTML = '
Hello
'
+ expect(() => screen[query]('TEST QUERY')).toThrowErrorMatchingSnapshot()
+ },
+)
+
+test.each([['getByText'], ['getByLabelText']])(
+ '%s query will NOT print the playground link when disabled in the config',
+ query => {
+ configure({printPlaygroundLink: false})
+ document.body.innerHTML = '
Hello
'
+ expect(() => screen[query]('TEST QUERY')).not.toThrowError(/playground/i)
+ },
+)
+
+test.each([['getByText'], ['getByLabelText']])(
+ '%s query will NOT print the playground link when element has no children',
+ query => {
+ configure({printPlaygroundLink: true})
+ document.body.innerHTML = ''
+ expect(() => screen[query]('TEST QUERY')).not.toThrowError(/playground/i)
+ },
+)
+
describe('*ByDisplayValue queries throw an error when there are multiple elements returned', () => {
test('getByDisplayValue', () => {
const {getByDisplayValue} = render(
diff --git a/src/__tests__/query-helper.js b/src/__tests__/query-helper.js
index 7e53ab03..b36e0904 100644
--- a/src/__tests__/query-helper.js
+++ b/src/__tests__/query-helper.js
@@ -2,7 +2,7 @@ import * as queryHelpers from '../query-helpers'
import {configure, getConfig} from '../config'
const originalConfig = getConfig()
-beforeEach(() => {
+afterEach(() => {
configure(originalConfig)
})
diff --git a/src/__tests__/role.js b/src/__tests__/role.js
index 109d2e62..6787286c 100644
--- a/src/__tests__/role.js
+++ b/src/__tests__/role.js
@@ -5,95 +5,95 @@ import {render, renderIntoDocument} from './helpers/test-utils'
test('by default logs accessible roles when it fails', () => {
const {getByRole} = render(`
Hi
`)
expect(() => getByRole('article')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "article"
+ "Unable to find an accessible element with the role "article"
-Here are the accessible roles:
+ Here are the accessible roles:
- heading:
+ heading:
- Name "Hi":
-
+ Name "Hi":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
- Hi
-
-
"
-`)
+
+
+ Hi
+
+
"
+ `)
})
test('when hidden: true logs available roles when it fails', () => {
const {getByRole} = render(`
Hi
`)
expect(() => getByRole('article', {hidden: true}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the role "article"
+ "Unable to find an element with the role "article"
-Here are the available roles:
+ Here are the available roles:
- heading:
+ heading:
- Name "Hi":
-
+ Name "Hi":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
-
- Hi
-
-
-
"
-`)
+
+
+
+ Hi
+
+
+
"
+ `)
})
test('logs error when there are no accessible roles', () => {
const {getByRole} = render('')
expect(() => getByRole('article')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "article"
+ "Unable to find an accessible element with the role "article"
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('logs a different error if inaccessible roles should be included', () => {
const {getByRole} = render('')
expect(() => getByRole('article', {hidden: true}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an element with the role "article"
+ "Unable to find an element with the role "article"
-There are no available roles.
+ There are no available roles.
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('by default excludes elements that have the html hidden attribute or any of their parents', () => {
const {getByRole} = render('
')
expect(() => getByRole('list')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "list"
-
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
-
-
-
"
-`)
+ "Unable to find an accessible element with the role "list"
+
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+
+
+
+
+
+
"
+ `)
})
test('by default excludes elements which have display: none or any of their parents', () => {
@@ -102,20 +102,20 @@ test('by default excludes elements which have display: none or any of their pare
)
expect(() => getByRole('list')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "list"
-
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
-
-
-
"
-`)
+ "Unable to find an accessible element with the role "list"
+
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+
+
+
+
+
+
"
+ `)
})
test('by default excludes elements which have visibility hidden', () => {
@@ -124,18 +124,18 @@ test('by default excludes elements which have visibility hidden', () => {
const {getByRole} = render('
')
expect(() => getByRole('list')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "list"
-
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
-
-
-
"
-`)
+ "Unable to find an accessible element with the role "list"
+
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+
+
+
+
+
+
"
+ `)
})
test('by default excludes elements which have aria-hidden="true" or any of their parents', () => {
@@ -148,20 +148,20 @@ test('by default excludes elements which have aria-hidden="true" or any of their
)
expect(() => getByRole('list')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "list"
-
-There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
-
-
-
-
-
-
"
-`)
+ "Unable to find an accessible element with the role "list"
+
+ There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the \`hidden\` option to \`true\`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
+
+
+
+
+
+
"
+ `)
})
test('considers the computed visibility style not the parent', () => {
@@ -230,26 +230,26 @@ test('accessible name comparison is case sensitive', () => {
expect(() => getByRole('heading', {name: 'something that does not match'}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "heading" and name "something that does not match"
+ "Unable to find an accessible element with the role "heading" and name "something that does not match"
-Here are the accessible roles:
+ Here are the accessible roles:
- heading:
+ heading:
- Name "Sign up":
-
+ Name "Sign up":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
- Sign
-
- up
-
-
-
"
-`)
+
+
+ Sign
+
+ up
+
+
+
"
+ `)
})
test('accessible name filter implements TextMatch', () => {
@@ -276,49 +276,49 @@ test('TextMatch serialization in error message', () => {
expect(() => getByRole('heading', {name: /something that does not match/}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "heading" and name \`/something that does not match/\`
+ "Unable to find an accessible element with the role "heading" and name \`/something that does not match/\`
-Here are the accessible roles:
+ Here are the accessible roles:
- heading:
+ heading:
- Name "Sign up":
-
+ Name "Sign up":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
- Sign
-
- up
-
-
-
"
-`)
+
+
+ Sign
+
+ up
+
+
+
"
+ `)
expect(() => getByRole('heading', {name: () => false}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "heading" and name \`() => false\`
+ "Unable to find an accessible element with the role "heading" and name \`() => false\`
-Here are the accessible roles:
+ Here are the accessible roles:
- heading:
+ heading:
- Name "Sign up":
-
+ Name "Sign up":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
- Sign
-
- up
-
-
-
"
-`)
+
+
+ Sign
+
+ up
+
+
+
"
+ `)
})
test('does not include the container in the queryable roles', () => {
@@ -326,21 +326,21 @@ test('does not include the container in the queryable roles', () => {
container: document.createElement('ul'),
})
expect(() => getByRole('list')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "list"
+ "Unable to find an accessible element with the role "list"
-Here are the accessible roles:
+ Here are the accessible roles:
- listitem:
+ listitem:
- Name "":
-
+ Name "":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
-
"
-`)
+
+
+
"
+ `)
})
test('has no useful error message in findBy', async () => {
@@ -357,27 +357,27 @@ test('explicit role is most specific', () => {
)
expect(() => getByRole('button')).toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "button"
+ "Unable to find an accessible element with the role "button"
-Here are the accessible roles:
+ Here are the accessible roles:
- tab:
+ tab:
- Name "my-tab":
-
+ Name "my-tab":
+
- --------------------------------------------------
+ --------------------------------------------------
-
-
-"
-`)
+
+
+ "
+ `)
})
test('accessible regex name in error message for multiple found', () => {
@@ -390,36 +390,36 @@ test('accessible regex name in error message for multiple found', () => {
expect(() => getByRole('button', {name: /value/i}))
.toThrowErrorMatchingInlineSnapshot(`
-"Found multiple elements with the role "button" and name \`/value/i\`
-
-Here are the matching elements:
-
-
-
-
-
-
-
-(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
-
-
-
-
-
-
"
-`)
+ "Found multiple elements with the role "button" and name \`/value/i\`
+
+ Here are the matching elements:
+
+
+
+
+
+
+
+ (If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
+
+
+
+
+
+
"
+ `)
})
test('accessible string name in error message for multiple found', () => {
@@ -432,36 +432,36 @@ test('accessible string name in error message for multiple found', () => {
expect(() => getByRole('button', {name: 'Submit'}))
.toThrowErrorMatchingInlineSnapshot(`
-"Found multiple elements with the role "button" and name "Submit"
-
-Here are the matching elements:
-
-
-
-
-
-
-
-(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
-
-
-
-
-
-
"
-`)
+ "Found multiple elements with the role "button" and name "Submit"
+
+ Here are the matching elements:
+
+
+
+
+
+
+
+ (If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
+
+
+
+
+
+
"
+ `)
})
test('matching elements in error for multiple found', () => {
@@ -475,35 +475,35 @@ test('matching elements in error for multiple found', () => {
expect(() => getByRole('button', {name: /value/i}))
.toThrowErrorMatchingInlineSnapshot(`
-"Found multiple elements with the role "button" and name \`/value/i\`
-
-Here are the matching elements:
-
-
-
-
-
-(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
-
-
-
-
-
- Wrong role
-
-
-
"
-`)
+ "Found multiple elements with the role "button" and name \`/value/i\`
+
+ Here are the matching elements:
+
+
+
+
+
+ (If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).
+
+
+
+
+
+ Wrong role
+
+
+
"
+ `)
})
describe('configuration', () => {
diff --git a/src/__tests__/suggestions.js b/src/__tests__/suggestions.js
index 3bb5364d..3de58869 100644
--- a/src/__tests__/suggestions.js
+++ b/src/__tests__/suggestions.js
@@ -3,7 +3,7 @@ import {screen, getSuggestedQuery} from '..'
import {renderIntoDocument, render} from './helpers/test-utils'
beforeAll(() => {
- configure({throwSuggestions: true})
+ configure({throwSuggestions: true, printPlaygroundLink: false})
})
afterEach(() => {
@@ -107,18 +107,18 @@ test('should suggest getByRole when used with getBy', () => {
renderIntoDocument(``)
expect(() => screen.getByTestId('foo')).toThrowErrorMatchingInlineSnapshot(`
-"A better query is available, try this:
-getByRole('button', { name: /submit/i })
+ "A better query is available, try this:
+ getByRole('button', { name: /submit/i })
-
-
-"
-`)
+
+
+ "
+ `)
})
test('should suggest getAllByRole when used with getAllByTestId', () => {
@@ -128,27 +128,27 @@ test('should suggest getAllByRole when used with getAllByTestId', () => {
expect(() => screen.getAllByTestId('foo'))
.toThrowErrorMatchingInlineSnapshot(`
-"A better query is available, try this:
-getAllByRole('button', { name: /submit/i })
-
-
-
-
-
-
-
-
-
-"
-`)
+ "A better query is available, try this:
+ getAllByRole('button', { name: /submit/i })
+
+
+
+
+
+
+
+
+
+ "
+ `)
})
test('should suggest findByRole when used with findByTestId', async () => {
renderIntoDocument(`
diff --git a/src/config.ts b/src/config.ts
index 8ff2675a..272eb2bd 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,4 +1,5 @@
import {Config, ConfigFn} from '../types/config'
+import {getPlaygroundUrl} from './playground-helper'
import {prettyDOM} from './pretty-dom'
type Callback = () => T
@@ -31,14 +32,37 @@ let config: InternalConfig = {
// called when getBy* queries fail. (message, container) => Error
getElementError(message, container) {
+ const playgroundUrl = (() => {
+ try {
+ return (
+ message &&
+ getConfig().printPlaygroundLink &&
+ getPlaygroundUrl(container)
+ )
+ } catch {
+ return null
+ }
+ })()
+
const error = new Error(
- [message, prettyDOM(container)].filter(Boolean).join('\n\n'),
+ [
+ message,
+ prettyDOM(container),
+ playgroundUrl &&
+ `Open this markup in the Testing-Library Playground:\n${playgroundUrl}`,
+ ]
+ .filter(Boolean)
+ .join('\n\n'),
)
+
error.name = 'TestingLibraryElementError'
return error
},
_disableExpensiveErrorDiagnostics: false,
computedStyleSupportsPseudoElements: false,
+
+ // print a link to the playground when queries fail
+ printPlaygroundLink: true,
}
export const DEFAULT_IGNORE_TAGS = 'script, style'
diff --git a/src/playground-helper.ts b/src/playground-helper.ts
new file mode 100644
index 00000000..39c98517
--- /dev/null
+++ b/src/playground-helper.ts
@@ -0,0 +1,21 @@
+import {compressToEncodedURIComponent} from 'lz-string'
+
+function unindent(value: string) {
+ // remove white spaces first, to save a few bytes.
+ // testing-playground will reformat on load any ways.
+ return value.replace(/[ \t]*[\n][ \t]*/g, '\n')
+}
+
+function encode(value: string) {
+ return compressToEncodedURIComponent(unindent(value))
+}
+
+function getPlaygroundUrl(element: Element) {
+ if (!element.innerHTML) {
+ throw new Error(`The provided element doesn't have any children.`)
+ }
+
+ return `https://testing-playground.com/#markup=${encode(element.innerHTML)}`
+}
+
+export {getPlaygroundUrl}
diff --git a/src/screen.js b/src/screen.js
index 5cbdd2de..e1771fa4 100644
--- a/src/screen.js
+++ b/src/screen.js
@@ -1,23 +1,9 @@
-import {compressToEncodedURIComponent} from 'lz-string'
+import {getPlaygroundUrl} from './playground-helper'
import * as queries from './queries'
import {getQueriesForElement} from './get-queries-for-element'
import {logDOM} from './pretty-dom'
import {getDocument} from './helpers'
-function unindent(string) {
- // remove white spaces first, to save a few bytes.
- // testing-playground will reformat on load any ways.
- return string.replace(/[ \t]*[\n][ \t]*/g, '\n')
-}
-
-function encode(value) {
- return compressToEncodedURIComponent(unindent(value))
-}
-
-function getPlaygroundUrl(markup) {
- return `https://testing-playground.com/#markup=${encode(markup)}`
-}
-
const debug = (element, maxLength, options) =>
Array.isArray(element)
? element.forEach(el => logDOM(el, maxLength, options))
@@ -28,13 +14,13 @@ const logTestingPlaygroundURL = (element = getDocument().body) => {
console.log(`The element you're providing isn't a valid DOM element.`)
return
}
- if (!element.innerHTML) {
- console.log(`The provided element doesn't have any children.`)
- return
+
+ try {
+ const url = getPlaygroundUrl(element)
+ console.log(`Open this URL in your browser\n\n${url}`)
+ } catch (e) {
+ console.log(e.message)
}
- console.log(
- `Open this URL in your browser\n\n${getPlaygroundUrl(element.innerHTML)}`,
- )
}
const initialValue = {debug, logTestingPlaygroundURL}
diff --git a/tests/setup-env.js b/tests/setup-env.js
index 0a6d0af0..54e5159f 100644
--- a/tests/setup-env.js
+++ b/tests/setup-env.js
@@ -36,6 +36,13 @@ beforeAll(() => {
})
})
+beforeEach(() => {
+ // Using require here instead of importing it at the top, because the import resulted in
+ // a function being used before a test had the chance to mock it.
+ // https://github.com/testing-library/dom-testing-library/pull/852#discussion_r557077851
+ require('../src/config').configure({printPlaygroundLink: false})
+})
+
afterEach(() => {
if (jest.isMockFunction(global.setTimeout)) {
jest.useRealTimers()
diff --git a/types/config.d.ts b/types/config.d.ts
index c9c33633..38504748 100644
--- a/types/config.d.ts
+++ b/types/config.d.ts
@@ -10,6 +10,7 @@ export interface Config {
showOriginalStackTrace: boolean
throwSuggestions: boolean
getElementError: (message: string | null, container: Element) => Error
+ printPlaygroundLink: boolean
}
export interface ConfigFn {