From c37ea2e711af79184a4a71c68feefc08a53618b5 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sun, 29 Jan 2023 10:30:07 +0100 Subject: [PATCH 1/4] feat: Drop support for Node.js 12.x (#1207) BREAKING CHANGE: Minimum supported Node.js version is now 14.x --- .codesandbox/ci.json | 2 +- .github/workflows/validate.yml | 2 +- package.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 6457dc94..e650cd6f 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -1,5 +1,5 @@ { "installCommand": "install:csb", "sandboxes": ["github/kentcdodds/react-testing-library-examples"], - "node": "12" + "node": "14" } diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 8d626849..e6ee331b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,7 +26,7 @@ jobs: # Otherwise we would not know if the problem is tied to the Node.js version fail-fast: false matrix: - node: [12, 14, 16] + node: [14, 16, 18] runs-on: ubuntu-latest steps: - name: 🛑 Cancel Previous Runs diff --git a/package.json b/package.json index a1f50bd2..15e38757 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "author": "Kent C. Dodds (https://kentcdodds.com)", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=14" }, "browserslist": [ "and_chr 103", @@ -40,7 +40,7 @@ "safari 15.5", "samsung 17.0", "samsung 16.0", - "node 12.0" + "node 14.0" ], "scripts": { "build": "kcd-scripts build --no-ts-defs --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --no-ts-defs --bundle --no-clean", From 6e2e864272872549b26b16f46ea1229ee00bbae5 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sun, 29 Jan 2023 10:40:34 +0100 Subject: [PATCH 2/4] Bump kcd-scripts to 12.x (#1208) * Bump kcd-scripts to 9.x * Fix lint issues * fix lint --- package.json | 7 +++++-- src/__tests__/config.js | 7 ++++--- src/__tests__/fake-timers.js | 1 + src/__tests__/role.js | 9 +++++---- src/__tests__/wait-for-element-to-be-removed.js | 1 + src/__tests__/wait-for.js | 3 ++- src/helpers.ts | 1 + src/queries/label-text.ts | 12 ++++++++---- src/query-helpers.ts | 16 ++++++++-------- src/screen.ts | 2 +- 10 files changed, 36 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 15e38757..1ad836c1 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "jest-in-case": "^1.0.2", "jest-snapshot-serializer-ansi": "^1.0.0", "jest-watch-select-projects": "^2.0.0", - "jsdom": "^16.4.0", - "kcd-scripts": "^11.0.0", + "jsdom": "19.0.0", + "kcd-scripts": "^12.3.0", "typescript": "^4.1.2" }, "eslintConfig": { @@ -83,6 +83,9 @@ "./node_modules/kcd-scripts/eslint.js", "plugin:import/typescript" ], + "parserOptions": { + "ecmaVersion": 2020 + }, "rules": { "@typescript-eslint/prefer-optional-chain": "off", "@typescript-eslint/no-explicit-any": "off", diff --git a/src/__tests__/config.js b/src/__tests__/config.js index 40123a53..21729a58 100644 --- a/src/__tests__/config.js +++ b/src/__tests__/config.js @@ -11,14 +11,15 @@ describe('configuration API', () => { return {} }) }) - afterEach(() => { - configure(originalConfig) - }) beforeEach(() => { configure({other: 123}) }) + afterEach(() => { + configure(originalConfig) + }) + describe('getConfig', () => { test('returns existing configuration', () => { const conf = getConfig() diff --git a/src/__tests__/fake-timers.js b/src/__tests__/fake-timers.js index b9700af3..6cf7ca5f 100644 --- a/src/__tests__/fake-timers.js +++ b/src/__tests__/fake-timers.js @@ -70,6 +70,7 @@ test('recursive timers do not cause issues', async () => { let recurse = true function startTimer() { setTimeout(() => { + // eslint-disable-next-line jest/no-conditional-in-test -- false-positive if (recurse) startTimer() }, 1) } diff --git a/src/__tests__/role.js b/src/__tests__/role.js index c709d82e..63872cda 100644 --- a/src/__tests__/role.js +++ b/src/__tests__/role.js @@ -274,6 +274,7 @@ test('accessible name filter implements TextMatch', () => { expect( getByRole('heading', { name: (name, element) => { + // eslint-disable-next-line jest/no-conditional-in-test -- false-positive return element.nodeName === 'H2' && name === 'Your Signature' }, }), @@ -564,11 +565,11 @@ describe('configuration', () => { queryByRole('button', {name: 'Hello, Dave!'}) expect(console.error).toHaveBeenCalledTimes(2) - expect(console.error.mock.calls[0][0]).toMatch( - 'Error: Not implemented: window.computedStyle(elt, pseudoElt)', + expect(console.error.mock.calls[0][0].message).toMatch( + 'Not implemented: window.computedStyle(elt, pseudoElt)', ) - expect(console.error.mock.calls[1][0]).toMatch( - 'Error: Not implemented: window.computedStyle(elt, pseudoElt)', + expect(console.error.mock.calls[1][0].message).toMatch( + 'Not implemented: window.computedStyle(elt, pseudoElt)', ) } finally { jest.restoreAllMocks() diff --git a/src/__tests__/wait-for-element-to-be-removed.js b/src/__tests__/wait-for-element-to-be-removed.js index 775b8b82..6ea0a091 100644 --- a/src/__tests__/wait-for-element-to-be-removed.js +++ b/src/__tests__/wait-for-element-to-be-removed.js @@ -98,6 +98,7 @@ test('rethrows non-testing-lib errors', () => { const error = new Error('my own error') return expect( waitForElementToBeRemoved(() => { + // eslint-disable-next-line jest/no-conditional-in-test -- false-positive if (throwIt) { throw error } diff --git a/src/__tests__/wait-for.js b/src/__tests__/wait-for.js index a80b9fe4..03814020 100644 --- a/src/__tests__/wait-for.js +++ b/src/__tests__/wait-for.js @@ -275,7 +275,7 @@ test('does not work after it resolves', async () => { context = 'act' try { const result = callback() - // eslint-disable-next-line jest/no-if + // eslint-disable-next-line jest/no-if, jest/no-conditional-in-test -- false-positive if (typeof result?.then === 'function') { const thenable = result return { @@ -319,6 +319,7 @@ test('does not work after it resolves', async () => { await waitFor( () => { + // eslint-disable-next-line jest/no-conditional-in-test -- false-positive if (data === null) { throw new Error('not found') } diff --git a/src/helpers.ts b/src/helpers.ts index 5a068300..77d30d6a 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -10,6 +10,7 @@ function jestFakeTimersAreEnabled() { // legacy timers (setTimeout as any)._isMockFunction === true || // modern timers + // eslint-disable-next-line prefer-object-has-own -- not supported by our support matrix Object.prototype.hasOwnProperty.call(setTimeout, 'clock') ) } diff --git a/src/queries/label-text.ts b/src/queries/label-text.ts index 39e766d5..33eaba6b 100644 --- a/src/queries/label-text.ts +++ b/src/queries/label-text.ts @@ -71,20 +71,23 @@ const queryAllByLabelText: AllByText = ( if ( matcher(label.content, label.formControl, text, matchNormalizer) && label.formControl - ) + ) { labelledElements.push(label.formControl) + } }) const labelsValue = labelList .filter(label => Boolean(label.content)) .map(label => label.content) if ( matcher(labelsValue.join(' '), labelledElement, text, matchNormalizer) - ) + ) { labelledElements.push(labelledElement) + } if (labelsValue.length > 1) { labelsValue.forEach((labelValue, index) => { - if (matcher(labelValue, labelledElement, text, matchNormalizer)) + if (matcher(labelValue, labelledElement, text, matchNormalizer)) { labelledElements.push(labelledElement) + } const labelsFiltered = [...labelsValue] labelsFiltered.splice(index, 1) @@ -97,8 +100,9 @@ const queryAllByLabelText: AllByText = ( text, matchNormalizer, ) - ) + ) { labelledElements.push(labelledElement) + } } }) } diff --git a/src/query-helpers.ts b/src/query-helpers.ts index 155210e1..8de75a23 100644 --- a/src/query-helpers.ts +++ b/src/query-helpers.ts @@ -1,11 +1,11 @@ -import type { - GetErrorFunction, - Matcher, - MatcherOptions, - QueryMethod, - Variant, - waitForOptions as WaitForOptions, - WithSuggest, +import { + type GetErrorFunction, + type Matcher, + type MatcherOptions, + type QueryMethod, + type Variant, + type waitForOptions as WaitForOptions, + type WithSuggest, } from '../types' import {getSuggestedQuery} from './suggestions' import {fuzzyMatches, matches, makeNormalizer} from './matches' diff --git a/src/screen.ts b/src/screen.ts index 9034b159..fbe372ff 100644 --- a/src/screen.ts +++ b/src/screen.ts @@ -1,7 +1,7 @@ // WARNING: `lz-string` only has a default export but statically we assume named exports are allowd // TODO: Statically verify we don't rely on NodeJS implicit named imports. import lzString from 'lz-string' -import type {OptionsReceived} from 'pretty-format' +import {type OptionsReceived} from 'pretty-format' import {getQueriesForElement} from './get-queries-for-element' import {getDocument} from './helpers' import {logDOM} from './pretty-dom' From 25dc8a9053f81bf4688afceb33352c28bc1bf6e4 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Sun, 29 Jan 2023 13:55:10 +0100 Subject: [PATCH 3/4] Bump kcd-scripts to 13.0.0 (#1209) * Bump kcd-scripts to 13.0.0 * Fix Jest warnings --- package.json | 4 ++-- src/__tests__/suggestions.js | 10 +++++----- tests/jest.config.dom.js | 11 +++++++++-- tests/jest.config.node.js | 11 +++++++++-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 1ad836c1..11ad8217 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "jest-in-case": "^1.0.2", "jest-snapshot-serializer-ansi": "^1.0.0", "jest-watch-select-projects": "^2.0.0", - "jsdom": "19.0.0", - "kcd-scripts": "^12.3.0", + "jsdom": "20.0.0", + "kcd-scripts": "^13.0.0", "typescript": "^4.1.2" }, "eslintConfig": { diff --git a/src/__tests__/suggestions.js b/src/__tests__/suggestions.js index 79a12821..08ce2f7c 100644 --- a/src/__tests__/suggestions.js +++ b/src/__tests__/suggestions.js @@ -612,8 +612,8 @@ test('should suggest hidden option if element is not in the accessibility tree', suggestion.toString() expect(console.warn.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ + [ + [ Element is inaccessible. This means that the element and all its children are invisible to screen readers. If you are using the aria-hidden prop, make sure this is the right choice for your case. , @@ -649,9 +649,9 @@ test('should find label text using the aria-labelledby', () => { warning: '', }, ` - Object { - queryArgs: Array [ - Object {}, + { + queryArgs: [ + {}, ], queryMethod: getByLabelText, queryName: LabelText, diff --git a/tests/jest.config.dom.js b/tests/jest.config.dom.js index 72b3b24b..d67874d9 100644 --- a/tests/jest.config.dom.js +++ b/tests/jest.config.dom.js @@ -1,7 +1,12 @@ const path = require('path') -const baseConfig = require('kcd-scripts/jest') +const { + // global config options that would trigger warnings in project configs + collectCoverageFrom, + watchPlugins, + ...baseConfig +} = require('kcd-scripts/jest') -module.exports = { +const projectConfig = { ...baseConfig, rootDir: path.join(__dirname, '..'), displayName: 'dom', @@ -12,3 +17,5 @@ module.exports = { ], testEnvironment: 'jest-environment-jsdom', } + +module.exports = projectConfig diff --git a/tests/jest.config.node.js b/tests/jest.config.node.js index bf37b60b..e387de9a 100644 --- a/tests/jest.config.node.js +++ b/tests/jest.config.node.js @@ -1,7 +1,12 @@ const path = require('path') -const baseConfig = require('kcd-scripts/jest') +const { + // global config options that would trigger warnings in project configs + collectCoverageFrom, + watchPlugins, + ...baseConfig +} = require('kcd-scripts/jest') -module.exports = { +const projectConfig = { ...baseConfig, rootDir: path.join(__dirname, '..'), displayName: 'node', @@ -13,3 +18,5 @@ module.exports = { ], testMatch: ['**/__node_tests__/**.js'], } + +module.exports = projectConfig From be5a2521859c1f4c3221c8068fe64c849b6fbe06 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Sat, 28 Jan 2023 10:38:54 +0100 Subject: [PATCH 4/4] Bump JSDOM to 21.x --- package.json | 7 ++++++- patches/jest-environment-jsdom+29.4.1.patch | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 patches/jest-environment-jsdom+29.4.1.patch diff --git a/package.json b/package.json index 11ad8217..55ba7af2 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "format": "kcd-scripts format", "install:csb": "npm install", "lint": "kcd-scripts lint", + "postinstall": "patch-package", "setup": "npm install && npm run validate -s", "test": "kcd-scripts test", "test:debug": "node --inspect-brk ./node_modules/.bin/jest --watch --runInBand", @@ -68,14 +69,18 @@ "lz-string": "^1.4.4", "pretty-format": "^27.0.2" }, + "overrides": { + "jsdom": "^21.1.0" + }, "devDependencies": { "@testing-library/jest-dom": "^5.11.6", "@types/lz-string": "^1.3.34", "jest-in-case": "^1.0.2", "jest-snapshot-serializer-ansi": "^1.0.0", "jest-watch-select-projects": "^2.0.0", - "jsdom": "20.0.0", + "jsdom": "^21.1.0", "kcd-scripts": "^13.0.0", + "patch-package": "^6.5.1", "typescript": "^4.1.2" }, "eslintConfig": { diff --git a/patches/jest-environment-jsdom+29.4.1.patch b/patches/jest-environment-jsdom+29.4.1.patch new file mode 100644 index 00000000..f1e0e6d8 --- /dev/null +++ b/patches/jest-environment-jsdom+29.4.1.patch @@ -0,0 +1,20 @@ +diff --git a/node_modules/jest-environment-jsdom/build/index.js b/node_modules/jest-environment-jsdom/build/index.js +index f2f6731..7fcd5ed 100644 +--- a/node_modules/jest-environment-jsdom/build/index.js ++++ b/node_modules/jest-environment-jsdom/build/index.js +@@ -161,15 +161,6 @@ class JSDOMEnvironment { + this.global.removeEventListener('error', this.errorEventListener); + } + this.global.close(); +- +- // Dispose "document" to prevent "load" event from triggering. +- +- // Note that this.global.close() will trigger the CustomElement::disconnectedCallback +- // Do not reset the document before CustomElement disconnectedCallback function has finished running, +- // document should be accessible within disconnectedCallback. +- Object.defineProperty(this.global, 'document', { +- value: null +- }); + } + this.errorEventListener = null; + // @ts-expect-error: this.global not allowed to be `null`