From ac9a6b78968e39547d1383e51f74752259fbe2f2 Mon Sep 17 00:00:00 2001 From: Philipp Fritsche Date: Fri, 19 Feb 2021 16:37:06 +0100 Subject: [PATCH 01/24] fix: remove side-effect from runWithRealTimers (#887) --- src/__tests__/helpers.js | 69 ++++++++++++++++++++-------------------- src/helpers.js | 60 +++++++++++++++------------------- 2 files changed, 60 insertions(+), 69 deletions(-) diff --git a/src/__tests__/helpers.js b/src/__tests__/helpers.js index 1bc858374..8e5d436fc 100644 --- a/src/__tests__/helpers.js +++ b/src/__tests__/helpers.js @@ -5,10 +5,6 @@ import { runWithRealTimers, } from '../helpers' -const globalObj = typeof window === 'undefined' ? global : window - -afterEach(() => jest.useRealTimers()) - test('returns global document if exists', () => { expect(getDocument()).toBe(document) }) @@ -53,42 +49,47 @@ describe('query container validation throws when validation fails', () => { }) }) -test('should always use realTimers before using callback when timers are faked with useFakeTimers', () => { - const originalSetTimeout = globalObj.setTimeout +describe('run with real timers', () => { + const realSetTimeout = global.setTimeout - // legacy timers use mocks and do not rely on a clock instance - jest.useFakeTimers('legacy') - runWithRealTimers(() => { - expect(originalSetTimeout).toEqual(globalObj.setTimeout) + afterEach(() => { + // restore timers replaced by jest.useFakeTimers() + jest.useRealTimers() + // restore setTimeout replaced by assignment + global.setTimeout = realSetTimeout }) - expect(globalObj.setTimeout._isMockFunction).toBe(true) - expect(globalObj.setTimeout.clock).toBeUndefined() - jest.useRealTimers() - - // modern timers use a clock instance instead of a mock - jest.useFakeTimers('modern') - runWithRealTimers(() => { - expect(originalSetTimeout).toEqual(globalObj.setTimeout) + test('use real timers when timers are faked with jest.useFakeTimers(legacy)', () => { + // legacy timers use mocks and do not rely on a clock instance + jest.useFakeTimers('legacy') + runWithRealTimers(() => { + expect(global.setTimeout).toBe(realSetTimeout) + }) + expect(global.setTimeout._isMockFunction).toBe(true) + expect(global.setTimeout.clock).toBeUndefined() }) - expect(globalObj.setTimeout._isMockFunction).toBeUndefined() - expect(globalObj.setTimeout.clock).toBeDefined() -}) -test('should not use realTimers when timers are not faked with useFakeTimers', () => { - const originalSetTimeout = globalObj.setTimeout - - // useFakeTimers is not used, timers are faked in some other way - const fakedSetTimeout = callback => { - callback() - } - fakedSetTimeout.clock = jest.fn() + test('use real timers when timers are faked with jest.useFakeTimers(modern)', () => { + // modern timers use a clock instance instead of a mock + jest.useFakeTimers('modern') + runWithRealTimers(() => { + expect(global.setTimeout).toBe(realSetTimeout) + }) + expect(global.setTimeout._isMockFunction).toBeUndefined() + expect(global.setTimeout.clock).toBeDefined() + }) - globalObj.setTimeout = fakedSetTimeout + test('do not use real timers when timers are not faked with jest.useFakeTimers', () => { + // useFakeTimers is not used, timers are faked in some other way + const fakedSetTimeout = callback => { + callback() + } + fakedSetTimeout.clock = jest.fn() + global.setTimeout = fakedSetTimeout - runWithRealTimers(() => { - expect(fakedSetTimeout).toEqual(globalObj.setTimeout) + runWithRealTimers(() => { + expect(global.setTimeout).toBe(fakedSetTimeout) + }) + expect(global.setTimeout).toBe(fakedSetTimeout) }) - - globalObj.setTimeout = originalSetTimeout }) diff --git a/src/helpers.js b/src/helpers.js index f686d46ba..7b8d95e56 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -5,52 +5,42 @@ const TEXT_NODE = 3 // Currently this fn only supports jest timers, but it could support other test runners in the future. function runWithRealTimers(callback) { - const fakeTimersType = getJestFakeTimersType() - if (fakeTimersType) { + return _runWithRealTimers(callback).callbackReturnValue +} + +function _runWithRealTimers(callback) { + const timerAPI = { + clearImmediate, + clearInterval, + clearTimeout, + setImmediate, + setInterval, + setTimeout, + } + + // istanbul ignore else + if (typeof jest !== 'undefined') { jest.useRealTimers() } const callbackReturnValue = callback() - if (fakeTimersType) { - jest.useFakeTimers(fakeTimersType) - } + const usedJestFakeTimers = Object.entries(timerAPI).some( + ([name, func]) => func !== globalObj[name], + ) - return callbackReturnValue -} - -function getJestFakeTimersType() { - // istanbul ignore if - if ( - typeof jest === 'undefined' || - typeof globalObj.setTimeout === 'undefined' - ) { - return null + if (usedJestFakeTimers) { + jest.useFakeTimers(timerAPI.setTimeout?.clock ? 'modern' : 'legacy') } - if ( - typeof globalObj.setTimeout._isMockFunction !== 'undefined' && - globalObj.setTimeout._isMockFunction - ) { - return 'legacy' - } - - if ( - typeof globalObj.setTimeout.clock !== 'undefined' && - typeof jest.getRealSystemTime !== 'undefined' - ) { - try { - // jest.getRealSystemTime is only supported for Jest's `modern` fake timers and otherwise throws - jest.getRealSystemTime() - return 'modern' - } catch { - // not using Jest's modern fake timers - } + return { + callbackReturnValue, + usedJestFakeTimers, } - return null } -const jestFakeTimersAreEnabled = () => Boolean(getJestFakeTimersType()) +const jestFakeTimersAreEnabled = () => + Boolean(_runWithRealTimers(() => {}).usedJestFakeTimers) // we only run our tests in node, and setImmediate is supported in node. // istanbul ignore next From 47e52d1328d019f046adfa9ce673020a66afba35 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 19 Feb 2021 16:37:47 +0100 Subject: [PATCH 02/24] docs: add ph-fritsche as a contributor (#896) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 74a0edf5c..5b02bee1c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1320,6 +1320,15 @@ "contributions": [ "code" ] + }, + { + "login": "ph-fritsche", + "name": "Philipp Fritsche", + "avatar_url": "https://avatars.githubusercontent.com/u/39068198?v=4", + "profile": "https://github.com/ph-fritsche", + "contributions": [ + "code" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index 5301407f1..8ebb7d84e 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,7 @@ Thanks goes to these people ([emoji key][emojis]):
Nathan Force

πŸ’» +
Philipp Fritsche

πŸ’» From a25149d6ad2cc34401fac3c2c350bbf8c51f844d Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Fri, 19 Feb 2021 16:54:18 +0100 Subject: [PATCH 03/24] chore: Fix missing codecov report in PRs (#897) --- .github/workflows/validate.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index c1802ea6a..7ad174a60 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,6 +26,9 @@ jobs: - name: ⬇️ Checkout repo uses: actions/checkout@v2 + with: + # required by codecov/codecov-action + fetch-depth: 0 - name: βŽ” Setup node uses: actions/setup-node@v1 @@ -42,6 +45,9 @@ jobs: - name: ⬆️ Upload coverage report uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: true + flags: node-${{ matrix.node }} release: needs: main From f7b5c33c44632fba1579cb44f9f175be1ec46087 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Fri, 19 Feb 2021 21:39:33 +0100 Subject: [PATCH 04/24] fix: Don't assume mocked timers imply jest fake timers (#900) * fix: Don't assume mocked timers imply jest fake timers * Create dedicated jest timer functions The naming should indicate that they should only be called in a jest-like environment * No implicit return * I don't know how istanbul works and I don't care --- src/helpers.js | 32 +++++++++++++++++++++----------- src/wait-for.js | 6 +++--- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/helpers.js b/src/helpers.js index 7b8d95e56..176b606ff 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -5,10 +5,16 @@ const TEXT_NODE = 3 // Currently this fn only supports jest timers, but it could support other test runners in the future. function runWithRealTimers(callback) { - return _runWithRealTimers(callback).callbackReturnValue + // istanbul ignore else + if (typeof jest !== 'undefined') { + return runWithJestRealTimers(callback).callbackReturnValue + } + + // istanbul ignore next + return callback() } -function _runWithRealTimers(callback) { +function runWithJestRealTimers(callback) { const timerAPI = { clearImmediate, clearInterval, @@ -18,29 +24,33 @@ function _runWithRealTimers(callback) { setTimeout, } - // istanbul ignore else - if (typeof jest !== 'undefined') { - jest.useRealTimers() - } + jest.useRealTimers() const callbackReturnValue = callback() - const usedJestFakeTimers = Object.entries(timerAPI).some( + const usedFakeTimers = Object.entries(timerAPI).some( ([name, func]) => func !== globalObj[name], ) - if (usedJestFakeTimers) { + if (usedFakeTimers) { jest.useFakeTimers(timerAPI.setTimeout?.clock ? 'modern' : 'legacy') } return { callbackReturnValue, - usedJestFakeTimers, + usedFakeTimers, } } -const jestFakeTimersAreEnabled = () => - Boolean(_runWithRealTimers(() => {}).usedJestFakeTimers) +function jestFakeTimersAreEnabled() { + // istanbul ignore else + if (typeof jest !== 'undefined') { + return runWithJestRealTimers(() => {}).usedFakeTimers + } + + // istanbul ignore next + return false +} // we only run our tests in node, and setImmediate is supported in node. // istanbul ignore next diff --git a/src/wait-for.js b/src/wait-for.js index 9eb448421..860b7a15c 100644 --- a/src/wait-for.js +++ b/src/wait-for.js @@ -52,8 +52,8 @@ function waitFor( const overallTimeoutTimer = setTimeout(handleTimeout, timeout) - const usingFakeTimers = jestFakeTimersAreEnabled() - if (usingFakeTimers) { + const usingJestFakeTimers = jestFakeTimersAreEnabled() + if (usingJestFakeTimers) { checkCallback() // this is a dangerous rule to disable because it could lead to an // infinite loop. However, eslint isn't smart enough to know that we're @@ -107,7 +107,7 @@ function waitFor( finished = true clearTimeout(overallTimeoutTimer) - if (!usingFakeTimers) { + if (!usingJestFakeTimers) { clearInterval(intervalId) observer.disconnect() } From 300bfe26f253b8f045da24bf3c75a83d1cc0f49c Mon Sep 17 00:00:00 2001 From: Juan Carlos Medina Date: Sun, 7 Mar 2021 02:41:16 -0800 Subject: [PATCH 05/24] feat: Improve error message when passing an Array while a single Element is expected (#906) --- src/__tests__/helpers.js | 5 +++++ src/helpers.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/__tests__/helpers.js b/src/__tests__/helpers.js index 8e5d436fc..9749a0906 100644 --- a/src/__tests__/helpers.js +++ b/src/__tests__/helpers.js @@ -17,6 +17,11 @@ describe('window retrieval throws when given something other than a node', () => `"It looks like you passed a Promise object instead of a DOM node. Did you do something like \`fireEvent.click(screen.findBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`, or await the findBy query \`fireEvent.click(await screen.findBy...\`?"`, ) }) + test('Array as node', () => { + expect(() => getWindowFromNode([])).toThrowErrorMatchingInlineSnapshot( + `"It looks like you passed an Array instead of a DOM node. Did you do something like \`fireEvent.click(screen.getAllBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`?"`, + ) + }) test('unknown as node', () => { expect(() => getWindowFromNode({})).toThrowErrorMatchingInlineSnapshot( `"Unable to find the \\"window\\" object for the given node. Please file an issue with the code that's causing you to see this error: https://github.com/testing-library/dom-testing-library/issues/new"`, diff --git a/src/helpers.js b/src/helpers.js index 176b606ff..7634bf9d2 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -92,6 +92,10 @@ function getWindowFromNode(node) { throw new Error( `It looks like you passed a Promise object instead of a DOM node. Did you do something like \`fireEvent.click(screen.findBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`, or await the findBy query \`fireEvent.click(await screen.findBy...\`?`, ) + } else if (Array.isArray(node)) { + throw new Error( + `It looks like you passed an Array instead of a DOM node. Did you do something like \`fireEvent.click(screen.getAllBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`?`, + ) } else { // The user passed something unusual to a calling function throw new Error( From f6c5fee40621473561b2141a8939793ca7d64dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Sun, 7 Mar 2021 12:57:36 +0200 Subject: [PATCH 06/24] docs: remove outdated pre-commit instructions (#909) Co-authored-by: Sebastian Silbermann --- CONTRIBUTING.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a38dda93..813d02f79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,18 +32,6 @@ Please make sure to run the tests before you commit your changes. You can run `npm run test:update` which will update any snapshots that need updating. Make sure to include those changes (if they exist) in your commit. -### opt into git hooks - -There are git hooks set up with this project that are automatically installed -when you install dependencies. They're really handy, but are turned off by -default (so as to not hinder new contributors). You can opt into these by -creating a file called `.opt-in` at the root of the project and putting this -inside: - -``` -pre-commit -``` - ## Help needed Please checkout the [the open issues][issues] From c6acb0a3775f841dbce9db5388c172d03daf7a80 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 7 Mar 2021 11:58:40 +0100 Subject: [PATCH 07/24] docs: add AriPerkkio as a contributor (#910) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 5b02bee1c..739c0eb2b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1309,7 +1309,8 @@ "profile": "https://codepen.io/ariperkkio/", "contributions": [ "bug", - "code" + "code", + "doc" ] }, { diff --git a/README.md b/README.md index 8ebb7d84e..d47c3bda2 100644 --- a/README.md +++ b/README.md @@ -300,7 +300,7 @@ Thanks goes to these people ([emoji key][emojis]):
Romain Trotard

πŸ’»
Thomas Marshall

πŸ’» ⚠️
johnjessewood

πŸ› πŸ’» -
Ari PerkkiΓΆ

πŸ› πŸ’» +
Ari PerkkiΓΆ

πŸ› πŸ’» πŸ“–
Nathan Force

πŸ’» From 14788b6098242ce62037ba748f4402042d170b41 Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Thu, 25 Mar 2021 15:13:46 -0300 Subject: [PATCH 08/24] fix(timers): safe check for setImmediate and clearImmediate (#916) Co-authored-by: Kent C. Dodds --- src/__tests__/helpers.js | 19 +++++++++++++++++++ src/helpers.js | 11 +++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/__tests__/helpers.js b/src/__tests__/helpers.js index 9749a0906..eb86a1d10 100644 --- a/src/__tests__/helpers.js +++ b/src/__tests__/helpers.js @@ -97,4 +97,23 @@ describe('run with real timers', () => { }) expect(global.setTimeout).toBe(fakedSetTimeout) }) + + describe('run with setImmediate and clearImmediate deleted', () => { + const setImmediate = global.setImmediate + const clearImmediate = global.clearImmediate + + beforeEach(() => { + delete global.setImmediate + delete global.clearImmediate + }) + + afterEach(() => { + global.setImmediate = setImmediate + global.clearImmediate = clearImmediate + }) + + test('safe check for setImmediate and clearImmediate', () => { + expect(() => runWithRealTimers(() => {})).not.toThrow() + }) + }) }) diff --git a/src/helpers.js b/src/helpers.js index 7634bf9d2..559e39d26 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -16,14 +16,21 @@ function runWithRealTimers(callback) { function runWithJestRealTimers(callback) { const timerAPI = { - clearImmediate, clearInterval, clearTimeout, - setImmediate, setInterval, setTimeout, } + // For more on why we have the check here, + // checkout https://github.com/testing-library/dom-testing-library/issues/914 + if (typeof setImmediate === 'function') { + timerAPI.setImmediate = setImmediate + } + if (typeof clearImmediate === 'function') { + timerAPI.clearImmediate = clearImmediate + } + jest.useRealTimers() const callbackReturnValue = callback() From df4bbe52c03187ce627a7ff22d6d9f1a4d8108cf Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 25 Mar 2021 12:14:27 -0600 Subject: [PATCH 09/24] docs: add renatoalencar as a contributor (#918) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 10 ++++++++++ README.md | 1 + 2 files changed, 11 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 739c0eb2b..af28d8dcb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1330,6 +1330,16 @@ "contributions": [ "code" ] + }, + { + "login": "renatoalencar", + "name": "Renato Alencar", + "avatar_url": "https://avatars.githubusercontent.com/u/6964593?v=4", + "profile": "https://medium.com/@renatoalencar", + "contributions": [ + "code", + "test" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index d47c3bda2..e7713e71a 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,7 @@ Thanks goes to these people ([emoji key][emojis]):
Nathan Force

πŸ’»
Philipp Fritsche

πŸ’» +
Renato Alencar

πŸ’» ⚠️ From d2ef13db1f759deba07960c65b7c5f87cf16b7bd Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 25 Mar 2021 12:14:46 -0600 Subject: [PATCH 10/24] docs: add SimenB as a contributor (#919) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index af28d8dcb..7f230dab6 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1340,6 +1340,15 @@ "code", "test" ] + }, + { + "login": "SimenB", + "name": "Simen Bekkhus", + "avatar_url": "https://avatars.githubusercontent.com/u/1404810?v=4", + "profile": "https://github.com/SimenB", + "contributions": [ + "bug" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index e7713e71a..65601fdaa 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,7 @@ Thanks goes to these people ([emoji key][emojis]):
Nathan Force

πŸ’»
Philipp Fritsche

πŸ’»
Renato Alencar

πŸ’» ⚠️ +
Simen Bekkhus

πŸ› From 4ea2124896f1726dc3fe8256dfbc666292bce594 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 25 Mar 2021 12:15:51 -0600 Subject: [PATCH 11/24] docs: add gaearon as a contributor (#920) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 10 ++++++++++ README.md | 1 + 2 files changed, 11 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7f230dab6..0171418b2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1349,6 +1349,16 @@ "contributions": [ "bug" ] + }, + { + "login": "gaearon", + "name": "Dan Abramov", + "avatar_url": "https://avatars.githubusercontent.com/u/810438?v=4", + "profile": "https://github.com/gaearon", + "contributions": [ + "bug", + "review" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index 65601fdaa..18eb57c61 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,7 @@ Thanks goes to these people ([emoji key][emojis]):
Philipp Fritsche

πŸ’»
Renato Alencar

πŸ’» ⚠️
Simen Bekkhus

πŸ› +
Dan Abramov

πŸ› πŸ‘€ From bb83d8c540e95701826e31897374227b1e1cc33a Mon Sep 17 00:00:00 2001 From: Nick McCurdy Date: Tue, 30 Mar 2021 06:32:10 -0400 Subject: [PATCH 12/24] fix(types): exclude tsconfig from types folder in publish flow (#923) Port of https://github.com/testing-library/react-testing-library/pull/893 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 27747f6ee..9327135e8 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "files": [ "dist", - "types" + "types/*.d.ts" ], "dependencies": { "@babel/code-frame": "^7.10.4", From 7edd2bd734f93b79e50059b65dd9beb61bdfae26 Mon Sep 17 00:00:00 2001 From: Matan Borenkraout Date: Tue, 30 Mar 2021 15:03:09 +0300 Subject: [PATCH 13/24] fix(types): missing ignore parameter for SelectorMatcherOptions --- types/query-helpers.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/query-helpers.d.ts b/types/query-helpers.d.ts index 26c80f191..2e32020ed 100644 --- a/types/query-helpers.d.ts +++ b/types/query-helpers.d.ts @@ -3,6 +3,7 @@ import {waitForOptions} from './wait-for' export interface SelectorMatcherOptions extends MatcherOptions { selector?: string + ignore?: string | boolean } export type QueryByAttribute = ( From 3b585160f5e19febc9daf62266e36410aff13b94 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 31 Mar 2021 05:09:32 -0400 Subject: [PATCH 14/24] docs: add MatanBobi as a contributor (#925) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 0171418b2..de1773e54 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1359,6 +1359,15 @@ "bug", "review" ] + }, + { + "login": "MatanBobi", + "name": "Matan Borenkraout", + "avatar_url": "https://avatars.githubusercontent.com/u/12711091?v=4", + "profile": "https://matan.io", + "contributions": [ + "code" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index 18eb57c61..5acc06b8e 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ Thanks goes to these people ([emoji key][emojis]):
Renato Alencar

πŸ’» ⚠️
Simen Bekkhus

πŸ›
Dan Abramov

πŸ› πŸ‘€ +
Matan Borenkraout

πŸ’» From 793d59814e341aa0734748527c75d7655b351fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Wed, 21 Apr 2021 17:26:15 +0200 Subject: [PATCH 15/24] chore: add tests for Node 16 (#933) --- .github/workflows/validate.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7ad174a60..f10f98348 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,13 +16,11 @@ jobs: if: ${{ !contains(github.head_ref, 'all-contributors') }} strategy: matrix: - node: [10.14.2, 12, 14, 15] + node: [10.14.2, 12, 14, 16] runs-on: ubuntu-latest steps: - name: πŸ›‘ Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.6.0 - with: - access_token: ${{ secrets.GITHUB_TOKEN }} + uses: styfle/cancel-workflow-action@0.9.0 - name: ⬇️ Checkout repo uses: actions/checkout@v2 @@ -31,7 +29,7 @@ jobs: fetch-depth: 0 - name: βŽ” Setup node - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.node }} @@ -58,15 +56,13 @@ jobs: github.ref) && github.event_name == 'push' }} steps: - name: πŸ›‘ Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.6.0 - with: - access_token: ${{ secrets.GITHUB_TOKEN }} + uses: styfle/cancel-workflow-action@0.9.0 - name: ⬇️ Checkout repo uses: actions/checkout@v2 - name: βŽ” Setup node - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: 14 From 1b19094d6531f365c4bb317043267df75bdd5bbc Mon Sep 17 00:00:00 2001 From: Philipp Fritsche Date: Thu, 22 Apr 2021 14:35:30 +0200 Subject: [PATCH 16/24] fix: Guard against `jest.useRealTimers` not existing (#934) Co-authored-by: Sebastian Silbermann --- src/helpers.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/helpers.js b/src/helpers.js index 559e39d26..4536ddd52 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -5,13 +5,18 @@ const TEXT_NODE = 3 // Currently this fn only supports jest timers, but it could support other test runners in the future. function runWithRealTimers(callback) { - // istanbul ignore else - if (typeof jest !== 'undefined') { - return runWithJestRealTimers(callback).callbackReturnValue - } + return hasJestTimers() + ? runWithJestRealTimers(callback).callbackReturnValue + : // istanbul ignore next + callback() +} - // istanbul ignore next - return callback() +function hasJestTimers() { + return ( + typeof jest !== 'undefined' && + jest !== null && + typeof jest.useRealTimers === 'function' + ) } function runWithJestRealTimers(callback) { @@ -50,13 +55,10 @@ function runWithJestRealTimers(callback) { } function jestFakeTimersAreEnabled() { - // istanbul ignore else - if (typeof jest !== 'undefined') { - return runWithJestRealTimers(() => {}).usedFakeTimers - } - - // istanbul ignore next - return false + return hasJestTimers() + ? runWithJestRealTimers(() => {}).usedFakeTimers + : // istanbul ignore next + false } // we only run our tests in node, and setImmediate is supported in node. From 9c03efa5f37c1444c68d3dbfa0ea3d357014a5c0 Mon Sep 17 00:00:00 2001 From: Nick McCurdy Date: Fri, 23 Apr 2021 09:03:20 -0400 Subject: [PATCH 17/24] chore: continue testing on Node 15 (#935) --- .github/workflows/validate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index f10f98348..b744b1365 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,7 +16,7 @@ jobs: if: ${{ !contains(github.head_ref, 'all-contributors') }} strategy: matrix: - node: [10.14.2, 12, 14, 16] + node: [10.14.2, 12, 14, 15, 16] runs-on: ubuntu-latest steps: - name: πŸ›‘ Cancel Previous Runs From ffc8f26d48543de95c7fff4e5d961cc4beaa3872 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 23 Apr 2021 15:18:56 +0200 Subject: [PATCH 18/24] docs: add nickmccurdy as a contributor (#936) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index de1773e54..1cb9b8492 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1020,7 +1020,8 @@ "doc", "code", "test", - "review" + "review", + "infra" ] }, { diff --git a/README.md b/README.md index 5acc06b8e..1b6efa749 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ Thanks goes to these people ([emoji key][emojis]):
Ben Monro

πŸ’» πŸ€” ⚠️ πŸ“–
Stephan Meijer

πŸ€” πŸ’» ⚠️
JoΓ£o Forja

πŸ’» ⚠️ -
Nick McCurdy

πŸ“– πŸ’» ⚠️ πŸ‘€ +
Nick McCurdy

πŸ“– πŸ’» ⚠️ πŸ‘€ πŸš‡
Caleb Meredith

πŸ’»
Marco Moretti

πŸ’» ⚠️ πŸ‘€ From b00dff949f4ec633282fbd4bf4808f2800be9096 Mon Sep 17 00:00:00 2001 From: simcha90 <56388545+simcha90@users.noreply.github.com> Date: Wed, 5 May 2021 17:59:57 +0300 Subject: [PATCH 19/24] chore(refactor): move queries to TS / prettify some code according ABC (#948) --- src/config.ts | 2 +- src/{get-node-text.js => get-node-text.ts} | 4 +- src/label-helpers.ts | 13 +++-- src/queries/{all-utils.js => all-utils.ts} | 0 src/queries/{alt-text.js => alt-text.ts} | 13 +++-- .../{display-value.js => display-value.ts} | 42 +++++++++------- src/queries/{index.js => index.ts} | 0 src/queries/{label-text.js => label-text.ts} | 38 +++++++++----- ...laceholder-text.js => placeholder-text.ts} | 12 +++-- src/queries/{test-id.js => test-id.ts} | 12 +++-- src/queries/{text.js => text.ts} | 23 ++++++--- src/queries/{title.js => title.ts} | 15 +++--- types/__tests__/type-tests.ts | 2 +- types/config.d.ts | 2 +- types/get-queries-for-element.d.ts | 49 ++++++++++++------- types/matches.d.ts | 2 +- types/queries.d.ts | 2 +- types/query-helpers.d.ts | 6 ++- types/screen.d.ts | 2 +- types/suggestions.d.ts | 20 ++++---- types/wait-for-element-to-be-removed.d.ts | 8 +-- types/wait-for.d.ts | 2 +- 22 files changed, 163 insertions(+), 106 deletions(-) rename src/{get-node-text.js => get-node-text.ts} (75%) rename src/queries/{all-utils.js => all-utils.ts} (100%) rename src/queries/{alt-text.js => alt-text.ts} (76%) rename src/queries/{display-value.js => display-value.ts} (58%) rename src/queries/{index.js => index.ts} (100%) rename src/queries/{label-text.js => label-text.ts} (84%) rename src/queries/{placeholder-text.js => placeholder-text.ts} (68%) rename src/queries/{test-id.js => test-id.ts} (67%) rename src/queries/{text.js => text.ts} (68%) rename src/queries/{title.js => title.ts} (77%) diff --git a/src/config.ts b/src/config.ts index d37e46d01..8ff2675a2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -53,7 +53,7 @@ export function runWithExpensiveErrorDiagnosticsDisabled( } } -export function configure(newConfig: Partial | ConfigFn) { +export function configure(newConfig: ConfigFn | Partial) { if (typeof newConfig === 'function') { // Pass the existing config out to the provided function // and accept a delta in return diff --git a/src/get-node-text.js b/src/get-node-text.ts similarity index 75% rename from src/get-node-text.js rename to src/get-node-text.ts index 54b29b7ce..fe718e0dd 100644 --- a/src/get-node-text.js +++ b/src/get-node-text.ts @@ -1,8 +1,8 @@ import {TEXT_NODE} from './helpers' -function getNodeText(node) { +function getNodeText(node: HTMLElement): string { if (node.matches('input[type=submit], input[type=button]')) { - return node.value + return (node as HTMLInputElement).value } return Array.from(node.childNodes) diff --git a/src/label-helpers.ts b/src/label-helpers.ts index e8010a1b8..720e92024 100644 --- a/src/label-helpers.ts +++ b/src/label-helpers.ts @@ -1,3 +1,4 @@ +import {Nullish} from '../types' import {TEXT_NODE} from './helpers' const labelledNodeNames = [ @@ -11,7 +12,7 @@ const labelledNodeNames = [ ] function getTextContent( - node: Node | Element | HTMLInputElement, + node: Element | HTMLInputElement | Node, ): string | null { if (labelledNodeNames.includes(node.nodeName.toLowerCase())) { return '' @@ -24,7 +25,7 @@ function getTextContent( .join('') } -function getLabelContent(element: Element): string | null { +function getLabelContent(element: Element): Nullish { let textContent: string | null if (element.tagName.toLowerCase() === 'label') { textContent = getTextContent(element) @@ -58,12 +59,14 @@ function getLabels( container: Element, element: Element, {selector = '*'} = {}, -) { +): {content: Nullish; formControl: Nullish}[] { const ariaLabelledBy = element.getAttribute('aria-labelledby') const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : [] return labelsId.length ? labelsId.map(labelId => { - const labellingElement = container.querySelector(`[id="${labelId}"]`) + const labellingElement = container.querySelector( + `[id="${labelId}"]`, + ) return labellingElement ? {content: getLabelContent(labellingElement), formControl: null} : {content: '', formControl: null} @@ -73,7 +76,7 @@ function getLabels( const formControlSelector = 'button, input, meter, output, progress, select, textarea' const labelledFormControl = Array.from( - label.querySelectorAll(formControlSelector), + label.querySelectorAll(formControlSelector), ).filter(formControlElement => formControlElement.matches(selector))[0] return {content: textToMatch, formControl: labelledFormControl} }) diff --git a/src/queries/all-utils.js b/src/queries/all-utils.ts similarity index 100% rename from src/queries/all-utils.js rename to src/queries/all-utils.ts diff --git a/src/queries/alt-text.js b/src/queries/alt-text.ts similarity index 76% rename from src/queries/alt-text.js rename to src/queries/alt-text.ts index a31c5164e..6be732773 100644 --- a/src/queries/alt-text.js +++ b/src/queries/alt-text.ts @@ -1,23 +1,26 @@ import {wrapAllByQueryWithSuggestion} from '../query-helpers' import {checkContainerType} from '../helpers' +import {AllByBoundAttribute, GetErrorFunction} from '../../types' import {matches, fuzzyMatches, makeNormalizer, buildQueries} from './all-utils' -function queryAllByAltText( +const queryAllByAltText: AllByBoundAttribute = ( container, alt, {exact = true, collapseWhitespace, trim, normalizer} = {}, -) { +) => { checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - return Array.from(container.querySelectorAll('img,input,area')).filter(node => + return Array.from( + container.querySelectorAll('img,input,area'), + ).filter(node => matcher(node.getAttribute('alt'), node, alt, matchNormalizer), ) } -const getMultipleError = (c, alt) => +const getMultipleError: GetErrorFunction = (c, alt) => `Found multiple elements with the alt text: ${alt}` -const getMissingError = (c, alt) => +const getMissingError: GetErrorFunction = (c, alt) => `Unable to find an element with the alt text: ${alt}` const queryAllByAltTextWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/src/queries/display-value.js b/src/queries/display-value.ts similarity index 58% rename from src/queries/display-value.js rename to src/queries/display-value.ts index 75ab083fe..bab8a136e 100644 --- a/src/queries/display-value.js +++ b/src/queries/display-value.ts @@ -1,5 +1,6 @@ import {wrapAllByQueryWithSuggestion} from '../query-helpers' import {checkContainerType} from '../helpers' +import {AllByBoundAttribute, GetErrorFunction} from '../../types' import { getNodeText, matches, @@ -8,33 +9,38 @@ import { buildQueries, } from './all-utils' -function queryAllByDisplayValue( +const queryAllByDisplayValue: AllByBoundAttribute = ( container, value, {exact = true, collapseWhitespace, trim, normalizer} = {}, -) { +) => { checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - 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, matchNormalizer), - ) - } else { - return matcher(node.value, node, value, matchNormalizer) - } - }, - ) + return Array.from( + container.querySelectorAll(`input,textarea,select`), + ).filter(node => { + if (node.tagName === 'SELECT') { + const selectedOptions = Array.from( + (node as HTMLSelectElement).options, + ).filter(option => option.selected) + return selectedOptions.some(optionNode => + matcher(getNodeText(optionNode), optionNode, value, matchNormalizer), + ) + } else { + return matcher( + (node as HTMLInputElement).value, + node, + value, + matchNormalizer, + ) + } + }) } -const getMultipleError = (c, value) => +const getMultipleError: GetErrorFunction = (c, value) => `Found multiple elements with the display value: ${value}.` -const getMissingError = (c, value) => +const getMissingError: GetErrorFunction = (c, value) => `Unable to find an element with the display value: ${value}.` const queryAllByDisplayValueWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/src/queries/index.js b/src/queries/index.ts similarity index 100% rename from src/queries/index.js rename to src/queries/index.ts diff --git a/src/queries/label-text.js b/src/queries/label-text.ts similarity index 84% rename from src/queries/label-text.js rename to src/queries/label-text.ts index b844fb9c1..0d25c8807 100644 --- a/src/queries/label-text.js +++ b/src/queries/label-text.ts @@ -1,6 +1,7 @@ import {getConfig} from '../config' import {checkContainerType} from '../helpers' import {getLabels, getRealLabels, getLabelContent} from '../label-helpers' +import {AllByText, GetErrorFunction, Nullish} from '../../types' import { fuzzyMatches, matches, @@ -12,19 +13,21 @@ import { wrapSingleQueryWithSuggestion, } from './all-utils' -function queryAllLabels(container) { - return Array.from(container.querySelectorAll('label,input')) +function queryAllLabels( + container: HTMLElement, +): {textToMatch: Nullish; node: HTMLElement}[] { + return Array.from(container.querySelectorAll('label,input')) .map(node => { return {node, textToMatch: getLabelContent(node)} }) .filter(({textToMatch}) => textToMatch !== null) } -function queryAllLabelsByText( +const queryAllLabelsByText: AllByText = ( container, text, {exact = true, trim, collapseWhitespace, normalizer} = {}, -) { +) => { const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) @@ -37,27 +40,32 @@ function queryAllLabelsByText( .map(({node}) => node) } -function queryAllByLabelText( +const queryAllByLabelText: AllByText = ( container, text, {selector = '*', exact = true, collapseWhitespace, trim, normalizer} = {}, -) { +) => { checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - const matchingLabelledElements = Array.from(container.querySelectorAll('*')) + const matchingLabelledElements = Array.from( + container.querySelectorAll('*'), + ) .filter(element => { return ( getRealLabels(element).length || element.hasAttribute('aria-labelledby') ) }) - .reduce((labelledElements, labelledElement) => { + .reduce((labelledElements, labelledElement) => { const labelList = getLabels(container, labelledElement, {selector}) labelList .filter(label => Boolean(label.formControl)) .forEach(label => { - if (matcher(label.content, label.formControl, text, matchNormalizer)) + if ( + matcher(label.content, label.formControl, text, matchNormalizer) && + label.formControl + ) labelledElements.push(label.formControl) }) const labelsValue = labelList @@ -92,6 +100,9 @@ function queryAllByLabelText( return labelledElements }, []) .concat( + // TODO: Remove ignore after `queryAllByAttribute` will be moved to TS + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error queryAllByAttribute('aria-label', container, text, { exact, normalizer: matchNormalizer, @@ -110,7 +121,7 @@ function queryAllByLabelText( // ) // however, we can give a more helpful error message than the generic one, // so we're writing this one out by hand. -const getAllByLabelText = (container, text, ...rest) => { +const getAllByLabelText: AllByText = (container, text, ...rest) => { const els = queryAllByLabelText(container, text, ...rest) if (!els.length) { const labels = queryAllLabelsByText(container, text, ...rest) @@ -146,7 +157,10 @@ const getAllByLabelText = (container, text, ...rest) => { return els } -function getTagNameOfElementAssociatedWithLabelViaFor(container, label) { +function getTagNameOfElementAssociatedWithLabelViaFor( + container: Element, + label: Element, +): Nullish { const htmlFor = label.getAttribute('for') if (!htmlFor) { return null @@ -157,7 +171,7 @@ function getTagNameOfElementAssociatedWithLabelViaFor(container, label) { } // the reason mentioned above is the same reason we're not using buildQueries -const getMultipleError = (c, text) => +const getMultipleError: GetErrorFunction = (c, text) => `Found multiple elements with the text of: ${text}` const queryByLabelText = wrapSingleQueryWithSuggestion( makeSingleQuery(queryAllByLabelText, getMultipleError), diff --git a/src/queries/placeholder-text.js b/src/queries/placeholder-text.ts similarity index 68% rename from src/queries/placeholder-text.js rename to src/queries/placeholder-text.ts index bdea59458..9c07c1371 100644 --- a/src/queries/placeholder-text.js +++ b/src/queries/placeholder-text.ts @@ -1,14 +1,18 @@ import {wrapAllByQueryWithSuggestion} from '../query-helpers' import {checkContainerType} from '../helpers' +import {AllByBoundAttribute, GetErrorFunction} from '../../types' import {queryAllByAttribute, buildQueries} from './all-utils' -function queryAllByPlaceholderText(...args) { - checkContainerType(...args) +const queryAllByPlaceholderText: AllByBoundAttribute = (...args) => { + checkContainerType(args[0]) + // TODO: Remove ignore after `queryAllByAttribute` will be moved to TS + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error return queryAllByAttribute('placeholder', ...args) } -const getMultipleError = (c, text) => +const getMultipleError: GetErrorFunction = (c, text) => `Found multiple elements with the placeholder text of: ${text}` -const getMissingError = (c, text) => +const getMissingError: GetErrorFunction = (c, text) => `Unable to find an element with the placeholder text of: ${text}` const queryAllByPlaceholderTextWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/src/queries/test-id.js b/src/queries/test-id.ts similarity index 67% rename from src/queries/test-id.js rename to src/queries/test-id.ts index f2ef5a9df..6a9c9c812 100644 --- a/src/queries/test-id.js +++ b/src/queries/test-id.ts @@ -1,17 +1,21 @@ import {checkContainerType} from '../helpers' import {wrapAllByQueryWithSuggestion} from '../query-helpers' +import {AllByBoundAttribute, GetErrorFunction} from '../../types' import {queryAllByAttribute, getConfig, buildQueries} from './all-utils' const getTestIdAttribute = () => getConfig().testIdAttribute -function queryAllByTestId(...args) { - checkContainerType(...args) +const queryAllByTestId: AllByBoundAttribute = (...args) => { + checkContainerType(args[0]) + // TODO: Remove ignore after `queryAllByAttribute` will be moved to TS + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error return queryAllByAttribute(getTestIdAttribute(), ...args) } -const getMultipleError = (c, id) => +const getMultipleError: GetErrorFunction = (c, id) => `Found multiple elements by: [${getTestIdAttribute()}="${id}"]` -const getMissingError = (c, id) => +const getMissingError: GetErrorFunction = (c, id) => `Unable to find an element by: [${getTestIdAttribute()}="${id}"]` const queryAllByTestIdWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/src/queries/text.js b/src/queries/text.ts similarity index 68% rename from src/queries/text.js rename to src/queries/text.ts index 903bba25c..17faa17c7 100644 --- a/src/queries/text.js +++ b/src/queries/text.ts @@ -1,6 +1,7 @@ import {wrapAllByQueryWithSuggestion} from '../query-helpers' import {checkContainerType} from '../helpers' import {DEFAULT_IGNORE_TAGS} from '../config' +import {AllByText, GetErrorFunction} from '../../types' import { fuzzyMatches, matches, @@ -9,7 +10,7 @@ import { buildQueries, } from './all-utils' -function queryAllByText( +const queryAllByText: AllByText = ( container, text, { @@ -20,22 +21,28 @@ function queryAllByText( ignore = DEFAULT_IGNORE_TAGS, normalizer, } = {}, -) { +) => { checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - let baseArray = [] + let baseArray: HTMLElement[] = [] if (typeof container.matches === 'function' && container.matches(selector)) { baseArray = [container] } - return [...baseArray, ...Array.from(container.querySelectorAll(selector))] - .filter(node => !ignore || !node.matches(ignore)) - .filter(node => matcher(getNodeText(node), node, text, matchNormalizer)) + return ( + [ + ...baseArray, + ...Array.from(container.querySelectorAll(selector)), + ] + // TODO: `matches` according lib.dom.d.ts can get only `string` but according our code it can handle also boolean :) + .filter(node => !ignore || !node.matches(ignore as string)) + .filter(node => matcher(getNodeText(node), node, text, matchNormalizer)) + ) } -const getMultipleError = (c, text) => +const getMultipleError: GetErrorFunction = (c, text) => `Found multiple elements with the text: ${text}` -const getMissingError = (c, text) => +const getMissingError: GetErrorFunction = (c, text) => `Unable to find an element with the text: ${text}. 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.` const queryAllByTextWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/src/queries/title.js b/src/queries/title.ts similarity index 77% rename from src/queries/title.js rename to src/queries/title.ts index b56e6e05d..82fdab6b9 100644 --- a/src/queries/title.js +++ b/src/queries/title.ts @@ -1,5 +1,6 @@ import {wrapAllByQueryWithSuggestion} from '../query-helpers' import {checkContainerType} from '../helpers' +import {AllByBoundAttribute, GetErrorFunction} from '../../types' import { fuzzyMatches, matches, @@ -8,19 +9,21 @@ import { buildQueries, } from './all-utils' -const isSvgTitle = node => +const isSvgTitle = (node: HTMLElement) => node.tagName.toLowerCase() === 'title' && node.parentElement?.tagName.toLowerCase() === 'svg' -function queryAllByTitle( +const queryAllByTitle: AllByBoundAttribute = ( container, text, {exact = true, collapseWhitespace, trim, normalizer} = {}, -) { +) => { checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - return Array.from(container.querySelectorAll('[title], svg > title')).filter( + return Array.from( + container.querySelectorAll('[title], svg > title'), + ).filter( node => matcher(node.getAttribute('title'), node, text, matchNormalizer) || (isSvgTitle(node) && @@ -28,9 +31,9 @@ function queryAllByTitle( ) } -const getMultipleError = (c, title) => +const getMultipleError: GetErrorFunction = (c, title) => `Found multiple elements with the title: ${title}.` -const getMissingError = (c, title) => +const getMissingError: GetErrorFunction = (c, title) => `Unable to find an element with the title: ${title}.` const queryAllByTitleWithSuggestions = wrapAllByQueryWithSuggestion( diff --git a/types/__tests__/type-tests.ts b/types/__tests__/type-tests.ts index 4f3dc5a93..9b5c81e8c 100644 --- a/types/__tests__/type-tests.ts +++ b/types/__tests__/type-tests.ts @@ -53,7 +53,7 @@ export async function testQueryHelpers() { content.split(/\s+/).some(id => id === automationId) const queryAllByAutomationId = ( container: HTMLElement, - automationId: string | string[], + automationId: string[] | string, options?: MatcherOptions, ) => queryAllByAttribute( diff --git a/types/config.d.ts b/types/config.d.ts index c8e239b65..c9c33633c 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -16,5 +16,5 @@ export interface ConfigFn { (existingConfig: Config): Partial } -export function configure(configDelta: Partial | ConfigFn): void +export function configure(configDelta: ConfigFn | Partial): void export function getConfig(): Config diff --git a/types/get-queries-for-element.d.ts b/types/get-queries-for-element.d.ts index b93adfe14..04a485396 100644 --- a/types/get-queries-for-element.d.ts +++ b/types/get-queries-for-element.d.ts @@ -1,29 +1,40 @@ -import * as queries from './queries'; +import * as queries from './queries' export type BoundFunction = T extends ( - attribute: string, - element: HTMLElement, - text: infer P, - options: infer Q, + attribute: string, + element: HTMLElement, + text: infer P, + options: infer Q, ) => infer R - ? (text: P, options?: Q) => R - : T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer W) => infer R - ? (text: P, options?: Q, waitForElementOptions?: W) => R - : T extends (a1: any, text: infer P, options: infer Q) => infer R - ? (text: P, options?: Q) => R - : never; -export type BoundFunctions = { [P in keyof T]: BoundFunction }; + ? (text: P, options?: Q) => R + : T extends ( + a1: any, + text: infer P, + options: infer Q, + waitForElementOptions: infer W, + ) => infer R + ? (text: P, options?: Q, waitForElementOptions?: W) => R + : T extends (a1: any, text: infer P, options: infer Q) => infer R + ? (text: P, options?: Q) => R + : never +export type BoundFunctions = {[P in keyof T]: BoundFunction} export type Query = ( - container: HTMLElement, - ...args: any[] -) => Error | Promise | Promise | HTMLElement[] | HTMLElement | null; + container: HTMLElement, + ...args: any[] +) => + | Error + | HTMLElement + | HTMLElement[] + | Promise + | Promise + | null export interface Queries { - [T: string]: Query; + [T: string]: Query } export function getQueriesForElement( - element: HTMLElement, - queriesToBind?: T, -): BoundFunctions; + element: HTMLElement, + queriesToBind?: T, +): BoundFunctions diff --git a/types/matches.d.ts b/types/matches.d.ts index 2d05d4ab1..85e9c9a7a 100644 --- a/types/matches.d.ts +++ b/types/matches.d.ts @@ -6,7 +6,7 @@ export type MatcherFunction = ( content: string, element: Nullish, ) => boolean -export type Matcher = MatcherFunction | RegExp | string | number +export type Matcher = MatcherFunction | RegExp | number | string // Get autocomplete for ARIARole union types, while still supporting another string // Ref: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-505826972 diff --git a/types/queries.d.ts b/types/queries.d.ts index d81fdceff..42777ffd3 100644 --- a/types/queries.d.ts +++ b/types/queries.d.ts @@ -108,8 +108,8 @@ export interface ByRoleOptions extends MatcherOptions { * Only considers elements with the specified accessible name. */ name?: - | string | RegExp + | string | ((accessibleName: string, element: Element) => boolean) } diff --git a/types/query-helpers.d.ts b/types/query-helpers.d.ts index 2e32020ed..a01462d13 100644 --- a/types/query-helpers.d.ts +++ b/types/query-helpers.d.ts @@ -1,9 +1,11 @@ -import {Matcher, MatcherOptions} from './matches' +import {Matcher, MatcherOptions, Nullish} from './matches' import {waitForOptions} from './wait-for' +export type GetErrorFunction = (c: Nullish, alt: string) => string + export interface SelectorMatcherOptions extends MatcherOptions { selector?: string - ignore?: string | boolean + ignore?: boolean | string } export type QueryByAttribute = ( diff --git a/types/screen.d.ts b/types/screen.d.ts index a25dfe236..4013af4a6 100644 --- a/types/screen.d.ts +++ b/types/screen.d.ts @@ -8,7 +8,7 @@ export type Screen = BoundFunctions & { * of elements */ debug: ( - element?: Element | HTMLDocument | Array, + element?: Array | Element | HTMLDocument, maxLength?: number, options?: OptionsReceived, ) => void diff --git a/types/suggestions.d.ts b/types/suggestions.d.ts index c27436417..e332dfdb9 100644 --- a/types/suggestions.d.ts +++ b/types/suggestions.d.ts @@ -14,30 +14,30 @@ export interface Suggestion { } export type Variant = + | 'find' + | 'findAll' | 'get' | 'getAll' | 'query' | 'queryAll' - | 'find' - | 'findAll' export type Method = - | 'Role' - | 'role' + | 'AltText' + | 'alttext' + | 'DisplayValue' + | 'displayvalue' | 'LabelText' | 'labeltext' | 'PlaceholderText' | 'placeholdertext' + | 'Role' + | 'role' + | 'TestId' + | 'testid' | 'Text' | 'text' - | 'DisplayValue' - | 'displayvalue' - | 'AltText' - | 'alttext' | 'Title' | 'title' - | 'TestId' - | 'testid' export function getSuggestedQuery( element: HTMLElement, diff --git a/types/wait-for-element-to-be-removed.d.ts b/types/wait-for-element-to-be-removed.d.ts index d0daae536..e570aac7c 100644 --- a/types/wait-for-element-to-be-removed.d.ts +++ b/types/wait-for-element-to-be-removed.d.ts @@ -1,6 +1,6 @@ -import { waitForOptions } from "./wait-for"; +import {waitForOptions} from './wait-for' export function waitForElementToBeRemoved( - callback: (() => T) | T, - options?: waitForOptions, -): Promise; + callback: T | (() => T), + options?: waitForOptions, +): Promise diff --git a/types/wait-for.d.ts b/types/wait-for.d.ts index f5850daca..ab1941695 100644 --- a/types/wait-for.d.ts +++ b/types/wait-for.d.ts @@ -7,6 +7,6 @@ export interface waitForOptions { } export function waitFor( - callback: () => T | Promise, + callback: () => Promise | T, options?: waitForOptions, ): Promise From d8a8d581b03fafb3dbee060ef7d5cbfe991aaf08 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 May 2021 17:03:27 +0200 Subject: [PATCH 20/24] docs: add simcha90 as a contributor (#951) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1cb9b8492..825ce4908 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1369,6 +1369,15 @@ "contributions": [ "code" ] + }, + { + "login": "simcha90", + "name": "simcha90", + "avatar_url": "https://avatars.githubusercontent.com/u/56388545?v=4", + "profile": "https://github.com/simcha90", + "contributions": [ + "code" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index 1b6efa749..89d0c0b13 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ Thanks goes to these people ([emoji key][emojis]):
Simen Bekkhus

πŸ›
Dan Abramov

πŸ› πŸ‘€
Matan Borenkraout

πŸ’» +
simcha90

πŸ’» From 37d1cc48d9e1a01c7bab5319ad4ede4135bb00df Mon Sep 17 00:00:00 2001 From: Amit Miran <47772523+amitmiran137@users.noreply.github.com> Date: Wed, 5 May 2021 18:15:11 +0300 Subject: [PATCH 21/24] chore: rename master to main (#942) Co-authored-by: Sebastian Silbermann --- .github/workflows/validate.yml | 6 +++--- CONTRIBUTING.md | 12 ++++++------ README.md | 8 ++++---- other/MAINTAINING.md | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b744b1365..d929715ae 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -3,7 +3,7 @@ on: push: branches: - '+([0-9])?(.{+([0-9]),x}).x' - - 'master' + - 'main' - 'next' - 'next-major' - 'beta' @@ -52,7 +52,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.repository == 'testing-library/dom-testing-library' && - contains('refs/heads/master,refs/heads/beta,refs/heads/next,refs/heads/alpha', + contains('refs/heads/main,refs/heads/beta,refs/heads/next,refs/heads/alpha', github.ref) && github.event_name == 'push' }} steps: - name: πŸ›‘ Cancel Previous Runs @@ -81,7 +81,7 @@ jobs: branches: | [ '+([0-9])?(.{+([0-9]),x}).x', - 'master', + 'main', 'next', 'next-major', {name: 'beta', prerelease: true}, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 813d02f79..1e90641b9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,20 +11,20 @@ series [How to Contribute to an Open Source Project on GitHub][egghead] 2. Run `npm run setup` to install dependencies and run validation 3. Create a branch for your PR with `git checkout -b pr/your-branch-name` -> Tip: Keep your `master` branch pointing at the original repository and make +> Tip: Keep your `main` branch pointing at the original repository and make > pull requests from branches on your fork. To do this, run: > > ``` > git remote add upstream https://github.com/testing-library/dom-testing-library.git > git fetch upstream -> git branch --set-upstream-to=upstream/master master +> git branch --set-upstream-to=upstream/main main > ``` > > This will add the original repository as a "remote" called "upstream," Then -> fetch the git information from that remote, then set your local `master` -> branch to use the upstream master branch whenever you run `git pull`. Then you -> can make all of your pull request branches based on this `master` branch. -> Whenever you want to update your version of `master`, do a regular `git pull`. +> fetch the git information from that remote, then set your local `main` +> branch to use the upstream main branch whenever you run `git pull`. Then you +> can make all of your pull request branches based on this `main` branch. +> Whenever you want to update your version of `main`, do a regular `git pull`. ## Committing and Pushing changes diff --git a/README.md b/README.md index 89d0c0b13..0aeef93e8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ height="80" width="80" alt="octopus" - src="https://raw.githubusercontent.com/testing-library/dom-testing-library/master/other/octopus.png" + src="https://raw.githubusercontent.com/testing-library/dom-testing-library/main/other/octopus.png" /> @@ -41,7 +41,7 @@ practices.

TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application. @@ -338,11 +338,11 @@ Contributions of any kind welcome! [downloads-badge]: https://img.shields.io/npm/dm/@testing-library/dom.svg?style=flat-square [npmtrends]: http://www.npmtrends.com/@testing-library/dom [license-badge]: https://img.shields.io/npm/l/@testing-library/dom.svg?style=flat-square -[license]: https://github.com/testing-library/dom-testing-library/blob/master/LICENSE +[license]: https://github.com/testing-library/dom-testing-library/blob/main/LICENSE [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square [prs]: http://makeapullrequest.com [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square -[coc]: https://github.com/testing-library/dom-testing-library/blob/master/CODE_OF_CONDUCT.md +[coc]: https://github.com/testing-library/dom-testing-library/blob/main/CODE_OF_CONDUCT.md [github-watch-badge]: https://img.shields.io/github/watchers/testing-library/dom-testing-library.svg?style=social [github-watch]: https://github.com/testing-library/dom-testing-library/watchers [github-star-badge]: https://img.shields.io/github/stars/testing-library/dom-testing-library.svg?style=social diff --git a/other/MAINTAINING.md b/other/MAINTAINING.md index 87d1f70b7..a2f1a4787 100644 --- a/other/MAINTAINING.md +++ b/other/MAINTAINING.md @@ -61,7 +61,7 @@ to release. See the next section on Releases for more about that. ## Release -Our releases are automatic. They happen whenever code lands into `master`. A +Our releases are automatic. They happen whenever code lands into `main`. A GitHub Action gets kicked off and if it's successful, a tool called [`semantic-release`](https://github.com/semantic-release/semantic-release) is used to automatically publish a new release to npm as well as a changelog to From e061cd1fddcb4bee826dda50a4e388607883f873 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 5 May 2021 17:16:27 +0200 Subject: [PATCH 22/24] docs: add amitmiran137 as a contributor (#952) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 +++ 2 files changed, 12 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 825ce4908..9a5fd3d65 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1378,6 +1378,15 @@ "contributions": [ "code" ] + }, + { + "login": "amitmiran137", + "name": "Amit Miran", + "avatar_url": "https://avatars.githubusercontent.com/u/47772523?v=4", + "profile": "https://github.com/amitmiran137", + "contributions": [ + "infra" + ] } ], "repoHost": "https://github.com" diff --git a/README.md b/README.md index 0aeef93e8..8a2494cfa 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,9 @@ Thanks goes to these people ([emoji key][emojis]):
Matan Borenkraout

πŸ’»
simcha90

πŸ’» + +
Amit Miran

πŸš‡ + From 13efbb3b1d63cbdde8b5b02cd52ff523287481d6 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Thu, 6 May 2021 16:29:52 +0200 Subject: [PATCH 23/24] chore: Remove unused Nullish type (#953) --- src/label-helpers.ts | 5 ++--- src/matches.ts | 14 ++++++-------- src/queries/label-text.ts | 6 +++--- types/matches.d.ts | 4 +--- types/query-helpers.d.ts | 4 ++-- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/label-helpers.ts b/src/label-helpers.ts index 720e92024..4e1a3fed8 100644 --- a/src/label-helpers.ts +++ b/src/label-helpers.ts @@ -1,4 +1,3 @@ -import {Nullish} from '../types' import {TEXT_NODE} from './helpers' const labelledNodeNames = [ @@ -25,7 +24,7 @@ function getTextContent( .join('') } -function getLabelContent(element: Element): Nullish { +function getLabelContent(element: Element): string | null { let textContent: string | null if (element.tagName.toLowerCase() === 'label') { textContent = getTextContent(element) @@ -59,7 +58,7 @@ function getLabels( container: Element, element: Element, {selector = '*'} = {}, -): {content: Nullish; formControl: Nullish}[] { +): {content: string | null; formControl: HTMLElement | null}[] { const ariaLabelledBy = element.getAttribute('aria-labelledby') const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : [] return labelsId.length diff --git a/src/matches.ts b/src/matches.ts index 5e27ad3e1..b649cb69d 100644 --- a/src/matches.ts +++ b/src/matches.ts @@ -5,8 +5,6 @@ import { DefaultNormalizerOptions, } from '../types' -type Nullish = T | null | undefined - function assertNotNullOrUndefined( matcher: T, ): asserts matcher is NonNullable { @@ -19,9 +17,9 @@ function assertNotNullOrUndefined( } function fuzzyMatches( - textToMatch: Nullish, - node: Nullish, - matcher: Nullish, + textToMatch: string | null, + node: Element | null, + matcher: Matcher | null, normalizer: NormalizerFn, ) { if (typeof textToMatch !== 'string') { @@ -43,9 +41,9 @@ function fuzzyMatches( } function matches( - textToMatch: Nullish, - node: Nullish, - matcher: Nullish, + textToMatch: string | null, + node: Element | null, + matcher: Matcher | null, normalizer: NormalizerFn, ) { if (typeof textToMatch !== 'string') { diff --git a/src/queries/label-text.ts b/src/queries/label-text.ts index 0d25c8807..0b59d2535 100644 --- a/src/queries/label-text.ts +++ b/src/queries/label-text.ts @@ -1,7 +1,7 @@ import {getConfig} from '../config' import {checkContainerType} from '../helpers' import {getLabels, getRealLabels, getLabelContent} from '../label-helpers' -import {AllByText, GetErrorFunction, Nullish} from '../../types' +import {AllByText, GetErrorFunction} from '../../types' import { fuzzyMatches, matches, @@ -15,7 +15,7 @@ import { function queryAllLabels( container: HTMLElement, -): {textToMatch: Nullish; node: HTMLElement}[] { +): {textToMatch: string | null; node: HTMLElement}[] { return Array.from(container.querySelectorAll('label,input')) .map(node => { return {node, textToMatch: getLabelContent(node)} @@ -160,7 +160,7 @@ const getAllByLabelText: AllByText = (container, text, ...rest) => { function getTagNameOfElementAssociatedWithLabelViaFor( container: Element, label: Element, -): Nullish { +): string | null { const htmlFor = label.getAttribute('for') if (!htmlFor) { return null diff --git a/types/matches.d.ts b/types/matches.d.ts index 85e9c9a7a..13fa36920 100644 --- a/types/matches.d.ts +++ b/types/matches.d.ts @@ -1,10 +1,8 @@ import {ARIARole} from 'aria-query' -type Nullish = T | null | undefined - export type MatcherFunction = ( content: string, - element: Nullish, + element: Element | null, ) => boolean export type Matcher = MatcherFunction | RegExp | number | string diff --git a/types/query-helpers.d.ts b/types/query-helpers.d.ts index a01462d13..28db0a317 100644 --- a/types/query-helpers.d.ts +++ b/types/query-helpers.d.ts @@ -1,7 +1,7 @@ -import {Matcher, MatcherOptions, Nullish} from './matches' +import {Matcher, MatcherOptions} from './matches' import {waitForOptions} from './wait-for' -export type GetErrorFunction = (c: Nullish, alt: string) => string +export type GetErrorFunction = (c: Element | null, alt: string) => string export interface SelectorMatcherOptions extends MatcherOptions { selector?: string From 4b2976d5161aa6ae3f35e5f9a9952e63c1997768 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 10 May 2021 09:31:08 +0200 Subject: [PATCH 24/24] chore: Format codebase with prettier (#955) --- .github/ISSUE_TEMPLATE.md | 1 + .github/workflows/validate.yml | 4 + CONTRIBUTING.md | 12 +- package.json | 1 + src/event-map.js | 698 +++++++++++++------------- src/wait-for-element-to-be-removed.js | 2 +- types/get-node-text.d.ts | 2 +- types/index.d.ts | 42 +- types/wait-for-dom-change.d.ts | 4 +- types/wait-for-element.d.ts | 7 +- types/wait.d.ts | 12 +- 11 files changed, 397 insertions(+), 388 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 33b5d0d84..816b629b7 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -31,6 +31,7 @@ supported version. Relevant code or config ```js + ``` What you did: diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index d929715ae..a937c57d5 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -38,6 +38,10 @@ jobs: with: useLockFile: false + # TODO: Can be removed if https://github.com/kentcdodds/kcd-scripts/pull/146 is released + - name: Verify format (`npm run format` committed?) + run: npm run format -- --check --no-write + - name: ▢️ Run validate script run: npm run validate diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e90641b9..5aa761468 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,8 +11,8 @@ series [How to Contribute to an Open Source Project on GitHub][egghead] 2. Run `npm run setup` to install dependencies and run validation 3. Create a branch for your PR with `git checkout -b pr/your-branch-name` -> Tip: Keep your `main` branch pointing at the original repository and make -> pull requests from branches on your fork. To do this, run: +> Tip: Keep your `main` branch pointing at the original repository and make pull +> requests from branches on your fork. To do this, run: > > ``` > git remote add upstream https://github.com/testing-library/dom-testing-library.git @@ -21,10 +21,10 @@ series [How to Contribute to an Open Source Project on GitHub][egghead] > ``` > > This will add the original repository as a "remote" called "upstream," Then -> fetch the git information from that remote, then set your local `main` -> branch to use the upstream main branch whenever you run `git pull`. Then you -> can make all of your pull request branches based on this `main` branch. -> Whenever you want to update your version of `main`, do a regular `git pull`. +> fetch the git information from that remote, then set your local `main` branch +> to use the upstream main branch whenever you run `git pull`. Then you can make +> all of your pull request branches based on this `main` branch. Whenever you +> want to update your version of `main`, do a regular `git pull`. ## Committing and Pushing changes diff --git a/package.json b/package.json index 9327135e8..0681a4c4d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "scripts": { "build": "kcd-scripts build --no-ts-defs --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --no-ts-defs --bundle --no-clean", + "format": "kcd-scripts format", "lint": "kcd-scripts lint", "setup": "npm install && npm run validate -s", "test": "kcd-scripts test", diff --git a/src/event-map.js b/src/event-map.js index 6b0260945..e8cb6a5d2 100644 --- a/src/event-map.js +++ b/src/event-map.js @@ -1,350 +1,350 @@ export const eventMap = { - // Clipboard Events - copy: { - EventType: 'ClipboardEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - cut: { - EventType: 'ClipboardEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - paste: { - EventType: 'ClipboardEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - // Composition Events - compositionEnd: { - EventType: 'CompositionEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - compositionStart: { - EventType: 'CompositionEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - compositionUpdate: { - EventType: 'CompositionEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - // Keyboard Events - keyDown: { - EventType: 'KeyboardEvent', - defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, - }, - keyPress: { - EventType: 'KeyboardEvent', - defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, - }, - keyUp: { - EventType: 'KeyboardEvent', - defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, - }, - // Focus Events - focus: { - EventType: 'FocusEvent', - defaultInit: {bubbles: false, cancelable: false, composed: true}, - }, - blur: { - EventType: 'FocusEvent', - defaultInit: {bubbles: false, cancelable: false, composed: true}, - }, - focusIn: { - EventType: 'FocusEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - focusOut: { - EventType: 'FocusEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - // Form Events - change: { - EventType: 'Event', - defaultInit: {bubbles: true, cancelable: false}, - }, - input: { - EventType: 'InputEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - invalid: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: true}, - }, - submit: { - EventType: 'Event', - defaultInit: {bubbles: true, cancelable: true}, - }, - reset: { - EventType: 'Event', - defaultInit: {bubbles: true, cancelable: true}, - }, - // Mouse Events - click: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, button: 0, composed: true}, - }, - contextMenu: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - dblClick: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - drag: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - dragEnd: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - dragEnter: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - dragExit: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - dragLeave: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - dragOver: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - dragStart: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - drop: { - EventType: 'DragEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - mouseDown: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - mouseEnter: { - EventType: 'MouseEvent', - defaultInit: {bubbles: false, cancelable: false, composed: true}, - }, - mouseLeave: { - EventType: 'MouseEvent', - defaultInit: {bubbles: false, cancelable: false, composed: true}, - }, - mouseMove: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - mouseOut: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - mouseOver: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - mouseUp: { - EventType: 'MouseEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - // Selection Events - select: { - EventType: 'Event', - defaultInit: {bubbles: true, cancelable: false}, - }, - // Touch Events - touchCancel: { - EventType: 'TouchEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - touchEnd: { - EventType: 'TouchEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - touchMove: { - EventType: 'TouchEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - touchStart: { - EventType: 'TouchEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - // UI Events - scroll: { - EventType: 'UIEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - // Wheel Events - wheel: { - EventType: 'WheelEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - // Media Events - abort: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - canPlay: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - canPlayThrough: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - durationChange: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - emptied: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - encrypted: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - ended: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - loadedData: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - loadedMetadata: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - loadStart: { - EventType: 'ProgressEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - pause: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - play: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - playing: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - progress: { - EventType: 'ProgressEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - rateChange: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - seeked: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - seeking: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - stalled: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - suspend: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - timeUpdate: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - volumeChange: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - waiting: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - // Image Events - load: { - EventType: 'UIEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - error: { - EventType: 'Event', - defaultInit: {bubbles: false, cancelable: false}, - }, - // Animation Events - animationStart: { - EventType: 'AnimationEvent', - defaultInit: {bubbles: true, cancelable: false}, - }, - animationEnd: { - EventType: 'AnimationEvent', - defaultInit: {bubbles: true, cancelable: false}, - }, - animationIteration: { - EventType: 'AnimationEvent', - defaultInit: {bubbles: true, cancelable: false}, - }, - // Transition Events - transitionEnd: { - EventType: 'TransitionEvent', - defaultInit: {bubbles: true, cancelable: true}, - }, - // pointer events - pointerOver: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - pointerEnter: { - EventType: 'PointerEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - pointerDown: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - pointerMove: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - pointerUp: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - pointerCancel: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - pointerOut: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: true, composed: true}, - }, - pointerLeave: { - EventType: 'PointerEvent', - defaultInit: {bubbles: false, cancelable: false}, - }, - gotPointerCapture: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - lostPointerCapture: { - EventType: 'PointerEvent', - defaultInit: {bubbles: true, cancelable: false, composed: true}, - }, - // history events - popState: { - EventType: 'PopStateEvent', - defaultInit: {bubbles: true, cancelable: false}, - }, - } - - export const eventAliasMap = { - doubleClick: 'dblClick', - } + // Clipboard Events + copy: { + EventType: 'ClipboardEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + cut: { + EventType: 'ClipboardEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + paste: { + EventType: 'ClipboardEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + // Composition Events + compositionEnd: { + EventType: 'CompositionEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + compositionStart: { + EventType: 'CompositionEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + compositionUpdate: { + EventType: 'CompositionEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + // Keyboard Events + keyDown: { + EventType: 'KeyboardEvent', + defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, + }, + keyPress: { + EventType: 'KeyboardEvent', + defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, + }, + keyUp: { + EventType: 'KeyboardEvent', + defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true}, + }, + // Focus Events + focus: { + EventType: 'FocusEvent', + defaultInit: {bubbles: false, cancelable: false, composed: true}, + }, + blur: { + EventType: 'FocusEvent', + defaultInit: {bubbles: false, cancelable: false, composed: true}, + }, + focusIn: { + EventType: 'FocusEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + focusOut: { + EventType: 'FocusEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + // Form Events + change: { + EventType: 'Event', + defaultInit: {bubbles: true, cancelable: false}, + }, + input: { + EventType: 'InputEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + invalid: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: true}, + }, + submit: { + EventType: 'Event', + defaultInit: {bubbles: true, cancelable: true}, + }, + reset: { + EventType: 'Event', + defaultInit: {bubbles: true, cancelable: true}, + }, + // Mouse Events + click: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, button: 0, composed: true}, + }, + contextMenu: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + dblClick: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + drag: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + dragEnd: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + dragEnter: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + dragExit: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + dragLeave: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + dragOver: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + dragStart: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + drop: { + EventType: 'DragEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + mouseDown: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + mouseEnter: { + EventType: 'MouseEvent', + defaultInit: {bubbles: false, cancelable: false, composed: true}, + }, + mouseLeave: { + EventType: 'MouseEvent', + defaultInit: {bubbles: false, cancelable: false, composed: true}, + }, + mouseMove: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + mouseOut: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + mouseOver: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + mouseUp: { + EventType: 'MouseEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + // Selection Events + select: { + EventType: 'Event', + defaultInit: {bubbles: true, cancelable: false}, + }, + // Touch Events + touchCancel: { + EventType: 'TouchEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + touchEnd: { + EventType: 'TouchEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + touchMove: { + EventType: 'TouchEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + touchStart: { + EventType: 'TouchEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + // UI Events + scroll: { + EventType: 'UIEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + // Wheel Events + wheel: { + EventType: 'WheelEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + // Media Events + abort: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + canPlay: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + canPlayThrough: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + durationChange: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + emptied: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + encrypted: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + ended: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + loadedData: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + loadedMetadata: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + loadStart: { + EventType: 'ProgressEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + pause: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + play: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + playing: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + progress: { + EventType: 'ProgressEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + rateChange: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + seeked: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + seeking: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + stalled: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + suspend: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + timeUpdate: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + volumeChange: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + waiting: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + // Image Events + load: { + EventType: 'UIEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + error: { + EventType: 'Event', + defaultInit: {bubbles: false, cancelable: false}, + }, + // Animation Events + animationStart: { + EventType: 'AnimationEvent', + defaultInit: {bubbles: true, cancelable: false}, + }, + animationEnd: { + EventType: 'AnimationEvent', + defaultInit: {bubbles: true, cancelable: false}, + }, + animationIteration: { + EventType: 'AnimationEvent', + defaultInit: {bubbles: true, cancelable: false}, + }, + // Transition Events + transitionEnd: { + EventType: 'TransitionEvent', + defaultInit: {bubbles: true, cancelable: true}, + }, + // pointer events + pointerOver: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + pointerEnter: { + EventType: 'PointerEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + pointerDown: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + pointerMove: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + pointerUp: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + pointerCancel: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + pointerOut: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: true, composed: true}, + }, + pointerLeave: { + EventType: 'PointerEvent', + defaultInit: {bubbles: false, cancelable: false}, + }, + gotPointerCapture: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + lostPointerCapture: { + EventType: 'PointerEvent', + defaultInit: {bubbles: true, cancelable: false, composed: true}, + }, + // history events + popState: { + EventType: 'PopStateEvent', + defaultInit: {bubbles: true, cancelable: false}, + }, +} + +export const eventAliasMap = { + doubleClick: 'dblClick', +} diff --git a/src/wait-for-element-to-be-removed.js b/src/wait-for-element-to-be-removed.js index ff9adb9d1..2b5bcb9a9 100644 --- a/src/wait-for-element-to-be-removed.js +++ b/src/wait-for-element-to-be-removed.js @@ -20,7 +20,7 @@ async function waitForElementToBeRemoved(callback, options) { const elements = Array.isArray(callback) ? callback : [callback] const getRemainingElements = elements.map(element => { let parent = element.parentElement - if(parent === null) return () => null + if (parent === null) return () => null while (parent.parentElement) parent = parent.parentElement return () => (parent.contains(element) ? element : null) }) diff --git a/types/get-node-text.d.ts b/types/get-node-text.d.ts index 5c5654b5c..3f01b6291 100644 --- a/types/get-node-text.d.ts +++ b/types/get-node-text.d.ts @@ -1 +1 @@ -export function getNodeText(node: HTMLElement): string; +export function getNodeText(node: HTMLElement): string diff --git a/types/index.d.ts b/types/index.d.ts index 5b199dcf2..38830ff44 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,25 +1,25 @@ // TypeScript Version: 3.8 -import { getQueriesForElement } from './get-queries-for-element'; -import * as queries from './queries'; -import * as queryHelpers from './query-helpers'; +import {getQueriesForElement} from './get-queries-for-element' +import * as queries from './queries' +import * as queryHelpers from './query-helpers' -declare const within: typeof getQueriesForElement; -export { queries, queryHelpers, within }; +declare const within: typeof getQueriesForElement +export {queries, queryHelpers, within} -export * from './queries'; -export * from './query-helpers'; -export * from './screen'; -export * from './wait'; -export * from './wait-for'; -export * from './wait-for-dom-change'; -export * from './wait-for-element'; -export * from './wait-for-element-to-be-removed'; -export * from './matches'; -export * from './get-node-text'; -export * from './events'; -export * from './get-queries-for-element'; -export * from './pretty-dom'; -export * from './role-helpers'; -export * from './config'; -export * from './suggestions'; +export * from './queries' +export * from './query-helpers' +export * from './screen' +export * from './wait' +export * from './wait-for' +export * from './wait-for-dom-change' +export * from './wait-for-element' +export * from './wait-for-element-to-be-removed' +export * from './matches' +export * from './get-node-text' +export * from './events' +export * from './get-queries-for-element' +export * from './pretty-dom' +export * from './role-helpers' +export * from './config' +export * from './suggestions' diff --git a/types/wait-for-dom-change.d.ts b/types/wait-for-dom-change.d.ts index 5b69a6294..44a098754 100644 --- a/types/wait-for-dom-change.d.ts +++ b/types/wait-for-dom-change.d.ts @@ -1,7 +1,7 @@ -import { waitForOptions } from "./wait-for"; +import {waitForOptions} from './wait-for' /** * @deprecated `waitForDomChange` has been deprecated. * Use `waitFor` instead: https://testing-library.com/docs/dom-testing-library/api-async#waitfor. */ -export function waitForDomChange(options?: waitForOptions): Promise; +export function waitForDomChange(options?: waitForOptions): Promise diff --git a/types/wait-for-element.d.ts b/types/wait-for-element.d.ts index 051227cb5..29e7e72cc 100644 --- a/types/wait-for-element.d.ts +++ b/types/wait-for-element.d.ts @@ -1,8 +1,11 @@ -import { waitForOptions } from "./wait-for"; +import {waitForOptions} from './wait-for' /** * @deprecated `waitForElement` has been deprecated. * Use a `find*` query (preferred: https://testing-library.com/docs/dom-testing-library/api-queries#findby) * or use `waitFor` instead: https://testing-library.com/docs/dom-testing-library/api-async#waitfor */ -export function waitForElement(callback: () => T, options?: waitForOptions): Promise; +export function waitForElement( + callback: () => T, + options?: waitForOptions, +): Promise diff --git a/types/wait.d.ts b/types/wait.d.ts index 473e35f03..88015e713 100644 --- a/types/wait.d.ts +++ b/types/wait.d.ts @@ -4,9 +4,9 @@ * Learn more: https://testing-library.com/docs/dom-testing-library/api-async#waitfor. */ export function wait( - callback?: () => void, - options?: { - timeout?: number; - interval?: number; - }, -): Promise; + callback?: () => void, + options?: { + timeout?: number + interval?: number + }, +): Promise