From 5ba1c8650b321dc9ef7aa9cfd6c89597396f424d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 17 Jun 2021 10:56:22 +0100 Subject: [PATCH 01/17] Try using React 18 --- package-lock.json | 67 ++++++++++++++++++++++++++--------- package.json | 6 ++-- packages/element/package.json | 4 +-- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5252259f0d1d2f..9923bb38de3616 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16983,6 +16983,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true + }, + "react-test-renderer": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", + "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "react-is": "^17.0.2", + "react-shallow-renderer": "^16.13.1", + "scheduler": "^0.20.2" + } } } }, @@ -17702,8 +17714,8 @@ "@types/react-dom": "^17.0.11", "@wordpress/escape-html": "file:packages/escape-html", "lodash": "^4.17.21", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0-rc.0", + "react-dom": "^18.0.0-rc.0" } }, "@wordpress/env": { @@ -50259,9 +50271,9 @@ } }, "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.0.0-rc.0.tgz", + "integrity": "sha512-PawosMBgF8k5Nlc3++ibzjFqPvo1XKv80MNtVYqz3abHHB2w3IpU65sSdSmBd2ooCwVhcp9b1vkx/twqhakNtA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -50643,13 +50655,24 @@ "dev": true }, "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0-rc.0.tgz", + "integrity": "sha512-tdD1n0svTndHBQvVAq/f2Kx7FgQ30CpSLp87/neQKAHPW5WtdgW1sBSwmFAcMQOrmstTuP0M+zRlH86f9kMX/A==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.21.0-rc.0" + }, + "dependencies": { + "scheduler": { + "version": "0.21.0-rc.0-next-fe905f152-20220107", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0-rc.0-next-fe905f152-20220107.tgz", + "integrity": "sha512-+sY0WajWdMjoxbmHM8P6P1FKGw8sSVKKG/HthqTFQFPxVGbKLmV1BiFPaVF9gOyQWqmnLYSXJMN+4Bs5ZygsTw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } } }, "react-draggable": { @@ -51252,22 +51275,32 @@ } }, "react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", + "version": "18.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.0.0-rc.0.tgz", + "integrity": "sha512-F2+eDS0iQXwsLGa9laE6xyfmLcMzPOOy93bhQ1gq1r6kxn8/3eOnVxuw8itt7bT/mjgad/O6qzy/oAth9hhWEw==", "dev": true, "requires": { "object-assign": "^4.1.1", - "react-is": "^17.0.2", + "react-is": "^18.0.0-rc.0", "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" + "scheduler": "^0.21.0-rc.0" }, "dependencies": { "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.0.0-rc.0-next-fe905f152-20220107", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0-rc.0-next-fe905f152-20220107.tgz", + "integrity": "sha512-5c9EzyTgd/O1GfULP2fNS7HvielcXr3SEPao5VTJpSMMoCrpXp4TYMuKPc7cENPSd9A/EE5hv4kvwSSGLrgcZQ==", "dev": true + }, + "scheduler": { + "version": "0.21.0-rc.0-next-fe905f152-20220107", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0-rc.0-next-fe905f152-20220107.tgz", + "integrity": "sha512-+sY0WajWdMjoxbmHM8P6P1FKGw8sSVKKG/HthqTFQFPxVGbKLmV1BiFPaVF9gOyQWqmnLYSXJMN+4Bs5ZygsTw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } } } }, diff --git a/package.json b/package.json index 916241b07f34b0..fa3ed841afbb43 100755 --- a/package.json +++ b/package.json @@ -204,12 +204,12 @@ "postcss-loader": "6.2.1", "prettier": "npm:wp-prettier@2.2.1-beta-1", "progress": "2.0.3", - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "18.0.0-rc.0", + "react-dom": "18.0.0-rc.0", "react-native": "0.66.2", "react-native-url-polyfill": "1.1.2", "react-refresh": "0.10.0", - "react-test-renderer": "17.0.2", + "react-test-renderer": "18.0.0-rc.0", "redux": "4.1.2", "rimraf": "3.0.2", "rtlcss": "2.6.2", diff --git a/packages/element/package.json b/packages/element/package.json index fe32749db97bae..7c9f8849e28559 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -33,8 +33,8 @@ "@types/react-dom": "^17.0.11", "@wordpress/escape-html": "file:../escape-html", "lodash": "^4.17.21", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0-rc.0", + "react-dom": "^18.0.0-rc.0" }, "publishConfig": { "access": "public" From 346ce3c6e9cd76b202c6c82741b034f88457ec35 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 17 Jun 2021 11:05:51 +0100 Subject: [PATCH 02/17] Move to the new root API for edit-post --- packages/edit-post/README.md | 1 + packages/edit-post/src/index.js | 17 ++++++++++------- packages/element/README.md | 4 ++++ packages/element/src/react-platform.js | 3 +++ packages/element/src/react.js | 1 + 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/edit-post/README.md b/packages/edit-post/README.md index add8d802ed4961..27a9b0b60c4762 100644 --- a/packages/edit-post/README.md +++ b/packages/edit-post/README.md @@ -484,6 +484,7 @@ an initial state from prior to the crash. _Parameters_ +- _root_ `Object`: React Root. - _postType_ `Object`: Post type of the post to edit. - _postId_ `Object`: ID of the post to edit. - _target_ `Element`: DOM node in which editor is rendered. diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index 6ff6a7603d89f0..2db1ea4377fa7e 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -6,7 +6,7 @@ import { registerCoreBlocks, __experimentalRegisterExperimentalCoreBlocks, } from '@wordpress/block-library'; -import { render, unmountComponentAtNode } from '@wordpress/element'; +import { createRoot, unmountComponentAtNode } from '@wordpress/element'; import { dispatch, select } from '@wordpress/data'; import { addFilter } from '@wordpress/hooks'; import { store as preferencesStore } from '@wordpress/preferences'; @@ -24,6 +24,7 @@ import { store as editPostStore } from './store'; * an unhandled error occurs, replacing previously mounted editor element using * an initial state from prior to the crash. * + * @param {Object} root React Root. * @param {Object} postType Post type of the post to edit. * @param {Object} postId ID of the post to edit. * @param {Element} target DOM node in which editor is rendered. @@ -33,6 +34,7 @@ import { store as editPostStore } from './store'; * unsaved changes prompt). */ export function reinitializeEditor( + root, postType, postId, target, @@ -42,6 +44,7 @@ export function reinitializeEditor( unmountComponentAtNode( target ); const reboot = reinitializeEditor.bind( null, + root, postType, postId, target, @@ -49,7 +52,7 @@ export function reinitializeEditor( initialEdits ); - render( + root.render( , - target + /> ); } @@ -97,8 +99,10 @@ export function initializeEditor( ); const target = document.getElementById( id ); + const root = createRoot( target ); const reboot = reinitializeEditor.bind( null, + root, postType, postId, target, @@ -170,15 +174,14 @@ export function initializeEditor( } ); } - render( + root.render( , - target + /> ); } diff --git a/packages/element/README.md b/packages/element/README.md index 5fb25a346f9d59..c46f189e5e7c1a 100755 --- a/packages/element/README.md +++ b/packages/element/README.md @@ -198,6 +198,10 @@ _Returns_ - `Object`: Ref object. +### createRoot + +Undocumented declaration. + ### findDOMNode Finds the dom node of a React component. diff --git a/packages/element/src/react-platform.js b/packages/element/src/react-platform.js index 4c29f7da795dd8..2c03e96b321070 100644 --- a/packages/element/src/react-platform.js +++ b/packages/element/src/react-platform.js @@ -6,6 +6,7 @@ import { findDOMNode, render, unmountComponentAtNode, + createRoot, } from 'react-dom'; /** @@ -40,3 +41,5 @@ export { render }; * @param {Element} target DOM node in which element is to be removed */ export { unmountComponentAtNode }; + +export { createRoot }; diff --git a/packages/element/src/react.js b/packages/element/src/react.js index a658228b9a7281..48ff95a4ce0e70 100644 --- a/packages/element/src/react.js +++ b/packages/element/src/react.js @@ -26,6 +26,7 @@ import { useDebugValue, lazy, Suspense, + createRoot, } from 'react'; import { isString } from 'lodash'; From 4c74b9b7c6873e876919fcb6559bb50542df7b57 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 17 Jun 2021 11:17:37 +0100 Subject: [PATCH 03/17] Temporarily ignore types build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa3ed841afbb43..7ae269a5299465 100755 --- a/package.json +++ b/package.json @@ -239,7 +239,7 @@ "clean:packages": "rimraf \"./packages/*/@(build|build-module|build-style)\"", "clean:package-types": "tsc --build --clean", "prebuild:packages": "npm run clean:packages && lerna run build", - "build:packages": "npm run build:package-types && node ./bin/packages/build.js", + "build:packages": "node ./bin/packages/build.js", "build:package-types": "node ./bin/packages/validate-typescript-version.js && tsc --build", "build:plugin-zip": "bash ./bin/build-plugin-zip.sh", "build": "npm run build:packages && wp-scripts build", From 13ee8f03506bda0f3094968cfecd717c386d7e5e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 30 Mar 2022 07:51:51 +0100 Subject: [PATCH 04/17] Update to React 18 stable --- package-lock.json | 57 ++++++++++++++++------------------- package.json | 6 ++-- packages/element/package.json | 4 +-- 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9923bb38de3616..be4105aadd8b21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17714,8 +17714,8 @@ "@types/react-dom": "^17.0.11", "@wordpress/escape-html": "file:packages/escape-html", "lodash": "^4.17.21", - "react": "^18.0.0-rc.0", - "react-dom": "^18.0.0-rc.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "@wordpress/env": { @@ -50271,12 +50271,11 @@ } }, "react": { - "version": "18.0.0-rc.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.0.0-rc.0.tgz", - "integrity": "sha512-PawosMBgF8k5Nlc3++ibzjFqPvo1XKv80MNtVYqz3abHHB2w3IpU65sSdSmBd2ooCwVhcp9b1vkx/twqhakNtA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz", + "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "react-addons-shallow-compare": { @@ -50655,22 +50654,20 @@ "dev": true }, "react-dom": { - "version": "18.0.0-rc.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0-rc.0.tgz", - "integrity": "sha512-tdD1n0svTndHBQvVAq/f2Kx7FgQ30CpSLp87/neQKAHPW5WtdgW1sBSwmFAcMQOrmstTuP0M+zRlH86f9kMX/A==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz", + "integrity": "sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.21.0-rc.0" + "scheduler": "^0.21.0" }, "dependencies": { "scheduler": { - "version": "0.21.0-rc.0-next-fe905f152-20220107", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0-rc.0-next-fe905f152-20220107.tgz", - "integrity": "sha512-+sY0WajWdMjoxbmHM8P6P1FKGw8sSVKKG/HthqTFQFPxVGbKLmV1BiFPaVF9gOyQWqmnLYSXJMN+4Bs5ZygsTw==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } } } @@ -51275,31 +51272,29 @@ } }, "react-test-renderer": { - "version": "18.0.0-rc.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.0.0-rc.0.tgz", - "integrity": "sha512-F2+eDS0iQXwsLGa9laE6xyfmLcMzPOOy93bhQ1gq1r6kxn8/3eOnVxuw8itt7bT/mjgad/O6qzy/oAth9hhWEw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.0.0.tgz", + "integrity": "sha512-SyZTP/FSkwfiKOZuTZiISzsrC8A80KNlQ8PyyoGoOq+VzMAab6Em1POK/CiX3+XyXG6oiJa1C53zYDbdrJu9fw==", "dev": true, "requires": { - "object-assign": "^4.1.1", - "react-is": "^18.0.0-rc.0", + "react-is": "^18.0.0", "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.21.0-rc.0" + "scheduler": "^0.21.0" }, "dependencies": { "react-is": { - "version": "18.0.0-rc.0-next-fe905f152-20220107", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0-rc.0-next-fe905f152-20220107.tgz", - "integrity": "sha512-5c9EzyTgd/O1GfULP2fNS7HvielcXr3SEPao5VTJpSMMoCrpXp4TYMuKPc7cENPSd9A/EE5hv4kvwSSGLrgcZQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz", + "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==", "dev": true }, "scheduler": { - "version": "0.21.0-rc.0-next-fe905f152-20220107", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0-rc.0-next-fe905f152-20220107.tgz", - "integrity": "sha512-+sY0WajWdMjoxbmHM8P6P1FKGw8sSVKKG/HthqTFQFPxVGbKLmV1BiFPaVF9gOyQWqmnLYSXJMN+4Bs5ZygsTw==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", "dev": true, "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } } } diff --git a/package.json b/package.json index 7ae269a5299465..21bf7ce39a640d 100755 --- a/package.json +++ b/package.json @@ -204,12 +204,12 @@ "postcss-loader": "6.2.1", "prettier": "npm:wp-prettier@2.2.1-beta-1", "progress": "2.0.3", - "react": "18.0.0-rc.0", - "react-dom": "18.0.0-rc.0", + "react": "18.0.0", + "react-dom": "18.0.0", "react-native": "0.66.2", "react-native-url-polyfill": "1.1.2", "react-refresh": "0.10.0", - "react-test-renderer": "18.0.0-rc.0", + "react-test-renderer": "18.0.0", "redux": "4.1.2", "rimraf": "3.0.2", "rtlcss": "2.6.2", diff --git a/packages/element/package.json b/packages/element/package.json index 7c9f8849e28559..d87d854568caae 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -33,8 +33,8 @@ "@types/react-dom": "^17.0.11", "@wordpress/escape-html": "file:../escape-html", "lodash": "^4.17.21", - "react": "^18.0.0-rc.0", - "react-dom": "^18.0.0-rc.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "publishConfig": { "access": "public" From 2134074ebf53d1efb2cea1706f0e7f6af4468e7c Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 30 Mar 2022 10:11:01 +0100 Subject: [PATCH 05/17] Fix unit tests --- package-lock.json | 132 +--- package.json | 2 +- .../src/components/block-edit/test/edit.js | 11 +- .../components/block-switcher/test/index.js | 80 +-- .../src/components/colors/test/with-colors.js | 44 +- .../components/contrast-checker/test/index.js | 149 +++-- .../line-height-control/test/index.js | 26 +- .../src/components/link-control/test/index.js | 609 ++++++++---------- .../media-placeholder/test/index.js | 4 +- .../media-replace-flow/test/index.js | 55 +- .../responsive-block-control/test/index.js | 82 +-- .../src/components/url-input/test/button.js | 20 - .../alignment-matrix-control/test/index.js | 23 +- .../src/border-box-control/test/index.js | 18 +- .../src/border-control/test/index.js | 16 +- .../components/src/box-control/test/index.js | 130 ++-- packages/components/src/button/test/index.js | 10 +- .../src/dimension-control/test/index.test.js | 50 +- .../components/src/disabled/test/index.js | 195 ++---- .../src/font-size-picker/test/index.js | 34 +- .../src/form-token-field/test/index.js | 227 ++++--- .../higher-order/with-filters/test/index.js | 75 +-- .../with-focus-outside/test/index.js | 44 +- .../with-focus-return/test/index.js | 69 +- .../src/input-control/test/index.js | 17 +- .../src/keyboard-shortcuts/test/index.js | 32 +- .../src/number-control/test/index.js | 208 ++++-- .../src/range-control/test/index.js | 100 ++- .../components/src/scroll-lock/test/index.js | 24 +- .../components/src/tab-panel/test/index.js | 71 +- .../src/text-highlight/test/index.js | 44 +- packages/components/src/tooltip/test/index.js | 235 ++++--- .../components/src/unit-control/test/index.js | 2 +- .../src/higher-order/pure/test/index.js | 64 +- .../src/higher-order/with-state/test/index.js | 25 +- .../src/hooks/use-focus-outside/test/index.js | 35 +- .../src/hooks/use-merge-refs/test/index.js | 85 +-- .../plugin-post-publish-panel/test/index.js | 36 +- .../plugin-pre-publish-panel/test/index.js | 14 +- .../components/document-outline/test/index.js | 44 +- .../components/page-attributes/test/order.js | 105 ++- .../components/post-saved-state/test/index.js | 12 +- packages/element/src/react-platform.js | 2 +- packages/element/src/react.js | 1 - 44 files changed, 1571 insertions(+), 1690 deletions(-) diff --git a/package-lock.json b/package-lock.json index be4105aadd8b21..58309bb98b294a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15489,125 +15489,55 @@ "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==" }, "@testing-library/dom": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.0.tgz", - "integrity": "sha512-0hhuJSmw/zLc6ewR9cVm84TehuTd7tbqBX9pRNSp8znJ9gTmSgesdbiGZtt8R6dL+2rgaPFp9Yjr7IU1HWm49w==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.12.0.tgz", + "integrity": "sha512-rBrJk5WjI02X1edtiUcZhgyhgBhiut96r5Jp8J5qktKdcvLcZpKDW8i2hkGMMItxrghjXuQ5AM6aE0imnFawaw==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", + "aria-query": "^5.0.0", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.4", + "dom-accessibility-api": "^0.5.9", "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "pretty-format": "^27.0.2" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "aria-query": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", + "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", "dev": true }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -15756,13 +15686,13 @@ } }, "@testing-library/react": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.2.tgz", - "integrity": "sha512-jaxm0hwUjv+hzC+UFEywic7buDC9JQ1q3cDsrWVSDAPmLotfA6E6kUHlYm/zOeGCac6g48DR36tFHxl7Zb+N5A==", + "version": "13.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.0.0-alpha.6.tgz", + "integrity": "sha512-AVJTnwLlnjvXDNe91P6Nt9pN2fMS4csAzTmIbOewja+LVKzhlr53EONhv3ck0J3GzSZ5MIN5qL3BfISX/Wf1Jg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@testing-library/dom": "^8.5.0" } }, "@testing-library/react-native": { @@ -31771,9 +31701,9 @@ } }, "dom-accessibility-api": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.13.tgz", + "integrity": "sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw==", "dev": true }, "dom-converter": { diff --git a/package.json b/package.json index 21bf7ce39a640d..9f4e9943832db0 100755 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "@storybook/manager-webpack5": "6.4.9", "@storybook/react": "6.4.9", "@testing-library/jest-dom": "5.16.1", - "@testing-library/react": "11.2.2", + "@testing-library/react": "13.0.0-alpha.6", "@testing-library/react-native": "9.0.0", "@testing-library/user-event": "14.0.0-beta.13", "@types/classnames": "2.3.1", diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 5525bcf30aaab0..b8143cc2c398fd 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -1,8 +1,9 @@ /** * External dependencies */ -import { shallow, mount } from 'enzyme'; +import { shallow } from 'enzyme'; import { noop } from 'lodash'; +import { render } from '@testing-library/react'; /** * WordPress dependencies @@ -91,13 +92,13 @@ describe( 'Edit', () => { save: noop, } ); - const wrapper = mount( + const { container } = render( ); - expect( wrapper.html() ).toBe( 'Ok' ); + expect( container.innerHTML ).toBe( 'Ok' ); } ); describe( 'light wrapper', () => { @@ -112,13 +113,13 @@ describe( 'Edit', () => { save: noop, } ); - const wrapper = mount( + const { container } = render( ); - expect( wrapper.html() ).toBe( 'Ok' ); + expect( container.innerHTML ).toBe( 'Ok' ); } ); } ); } ); diff --git a/packages/block-editor/src/components/block-switcher/test/index.js b/packages/block-editor/src/components/block-switcher/test/index.js index 43811b2380403a..5fcf2426b8628c 100644 --- a/packages/block-editor/src/components/block-switcher/test/index.js +++ b/packages/block-editor/src/components/block-switcher/test/index.js @@ -1,15 +1,13 @@ /** * External dependencies */ -import { shallow, mount } from 'enzyme'; +import { shallow } from 'enzyme'; /** * WordPress dependencies */ import { useSelect } from '@wordpress/data'; import { registerBlockType, unregisterBlockType } from '@wordpress/blocks'; -import { DOWN } from '@wordpress/keycodes'; -import { Button } from '@wordpress/components'; import { copy } from '@wordpress/icons'; /** @@ -156,80 +154,4 @@ describe( 'BlockSwitcherDropdownMenu', () => { ); expect( wrapper ).toMatchSnapshot(); } ); - - describe( 'Dropdown', () => { - beforeAll( () => { - useSelect.mockImplementation( () => ( { - possibleBlockTransformations: [ - { name: 'core/paragraph', frecency: 3 }, - ], - canRemove: true, - } ) ); - } ); - const getDropdown = () => - mount( - - ).find( 'Dropdown' ); - - test( 'should dropdown exist', () => { - expect( getDropdown() ).toHaveLength( 1 ); - } ); - - describe( '.renderToggle', () => { - const onToggleStub = jest.fn(); - const mockKeyDown = { - preventDefault: () => {}, - keyCode: DOWN, - }; - - afterEach( () => { - onToggleStub.mockReset(); - } ); - - test( 'should simulate a keydown event, which should call onToggle and open transform toggle.', () => { - const toggleClosed = mount( - getDropdown().props().renderToggle( { - onToggle: onToggleStub, - isOpen: false, - } ) - ); - const iconButtonClosed = toggleClosed.find( Button ); - - iconButtonClosed.simulate( 'keydown', mockKeyDown ); - - expect( onToggleStub ).toHaveBeenCalledTimes( 1 ); - } ); - - test( 'should simulate a click event, which should call onToggle.', () => { - const toggleOpen = mount( - getDropdown().props().renderToggle( { - onToggle: onToggleStub, - isOpen: true, - } ) - ); - const iconButtonOpen = toggleOpen.find( Button ); - - iconButtonOpen.simulate( 'keydown', mockKeyDown ); - - expect( onToggleStub ).toHaveBeenCalledTimes( 0 ); - } ); - } ); - - describe( '.renderContent', () => { - test( 'should create the transform items for the chosen block. A heading block will have 3 items', () => { - const onCloseStub = jest.fn(); - const content = shallow( -
- { getDropdown() - .props() - .renderContent( { onClose: onCloseStub } ) } -
- ); - const blockList = content.find( 'BlockTransformationsMenu' ); - expect( - blockList.prop( 'possibleBlockTransformations' ) - ).toHaveLength( 1 ); - } ); - } ); - } ); } ); diff --git a/packages/block-editor/src/components/colors/test/with-colors.js b/packages/block-editor/src/components/colors/test/with-colors.js index acbc8659953ce0..95e81cfae2e3ce 100644 --- a/packages/block-editor/src/components/colors/test/with-colors.js +++ b/packages/block-editor/src/components/colors/test/with-colors.js @@ -1,7 +1,8 @@ /** * External dependencies */ -import { shallow, mount } from 'enzyme'; +import { shallow } from 'enzyme'; +import { render, act, fireEvent } from '@testing-library/react'; /** * Internal dependencies @@ -38,14 +39,21 @@ describe( 'createCustomColorsHOC', () => { const setAttributes = jest.fn(); - const wrapper = mount( - - ); + let container; + act( () => { + container = render( + + ).container; + } ); + + act( () => { + const button = container.querySelector( 'button' ); + fireEvent.click( button ); + } ); - wrapper.find( 'button' ).simulate( 'click' ); expect( setAttributes ).toHaveBeenCalledWith( { backgroundColor: 'red', customBackgroundColor: undefined, @@ -66,14 +74,20 @@ describe( 'createCustomColorsHOC', () => { const setAttributes = jest.fn(); - const wrapper = mount( - - ); + let container; + act( () => { + container = render( + + ).container; + } ); + act( () => { + const button = container.querySelector( 'button' ); + fireEvent.click( button ); + } ); - wrapper.find( 'button' ).simulate( 'click' ); expect( setAttributes ).toHaveBeenCalledWith( { backgroundColor: undefined, customBackgroundColor: '000000', diff --git a/packages/block-editor/src/components/contrast-checker/test/index.js b/packages/block-editor/src/components/contrast-checker/test/index.js index a686762a3c8fcb..c84dade77d97ff 100644 --- a/packages/block-editor/src/components/contrast-checker/test/index.js +++ b/packages/block-editor/src/components/contrast-checker/test/index.js @@ -1,14 +1,11 @@ /** * External dependencies */ -import { mount } from 'enzyme'; -import { render } from 'react-dom'; -import { act } from 'react-dom/test-utils'; +import { act, render } from '@testing-library/react'; /** * WordPress dependencies */ -import { Notice } from '@wordpress/components'; import { speak } from '@wordpress/a11y'; /** @@ -33,11 +30,12 @@ describe( 'ContrastChecker', () => { } ); test( 'should render null when no colors are provided', () => { - expect( mount( ).html() ).toBeNull(); + const { container } = render( ); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render null when no background or fallback background color is provided', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render null when the colors meet AA WCAG guidelines.', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render component when the text and background colors do not meet AA WCAG guidelines.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); } ); test( 'should render component when the link and background colors do not meet AA WCAG guidelines.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color.' ); } ); test( 'should render component when the link and text and background colors do not meet AA WCAG guidelines.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); } ); test( 'should render render null if background color contains a transparency', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render render null if text color contains a transparency', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render render null if link color contains a transparency', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render different message matching snapshot when background color has less brightness than text color.', () => { const darkerShade = '#555'; - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a darker background color and/or a brighter text color.' ); } ); test( 'should take into consideration wherever text is large or not', () => { - const wrapperSmallText = mount( + const { container: wrapperSmallText } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapperSmallText.find( Notice ).children().text() ).toBe( + expect( + wrapperSmallText.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); - const wrapperLargeText = mount( + const { container: wrapperLargeText } = render( { /> ); - expect( wrapperLargeText.html() ).toBeNull(); + expect( wrapperLargeText.innerHTML ).toBe( '' ); } ); test( 'should take into consideration the font size passed', () => { - const wrapperSmallFontSize = mount( + const { container: wrapperSmallFontSize } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapperSmallFontSize.find( Notice ).children().text() ).toBe( + expect( + wrapperSmallFontSize.querySelector( '.components-notice' ) + .textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); - const wrapperLargeText = mount( + const { container: wrapperLargeText } = render( { /> ); - expect( wrapperLargeText.html() ).toBeNull(); + expect( wrapperLargeText.innerHTML ).toBe( '' ); } ); test( 'should use isLargeText to make decisions if both isLargeText and fontSize props are passed', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); - const wrapperNoLargeText = mount( + const { container: wrapperNoLargeText } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapperNoLargeText.find( Notice ).children().text() ).toBe( + expect( + wrapperNoLargeText.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); } ); test( 'should render null when the colors meet AA WCAG guidelines, with only fallback colors.', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render messages when the textColor is valid, but the fallback backgroundColor conflicts.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.' ); } ); test( 'should render messages when the linkColor is valid, but the fallback backgroundColor conflicts.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color.' ); } ); @@ -349,7 +366,7 @@ describe( 'ContrastChecker', () => { // enableAlphaChecker tests test( 'should render null when the colors meet AA WCAG guidelines and alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render component when the colors meet AA WCAG guidelines but the text color only has alpha transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'Transparent text may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( - 'Transparent text may be hard for people to read.' - ); + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'Transparent text may be hard for people to read.' ); } ); test( 'should render component when the colors meet AA WCAG guidelines but the link color only has alpha transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'Transparent text may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( - 'Transparent text may be hard for people to read.' - ); + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'Transparent text may be hard for people to read.' ); } ); test( 'should render null when the colors meet AA WCAG guidelines but the background color only has alpha transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render null if background color contains a transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { ); expect( speak ).not.toHaveBeenCalled(); - expect( wrapper.html() ).toBeNull(); + expect( container.innerHTML ).toBe( '' ); } ); test( 'should render transparency warning only if one text is not readable but the other is transparent and the background color contains a transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'Transparent text may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( - 'Transparent text may be hard for people to read.' - ); + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'Transparent text may be hard for people to read.' ); } ); test( 'should render component and prioritize contrast warning when the colors do no meet AA WCAG guidelines and text has alpha transparency with the alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'This color combination may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'This color combination may be hard for people to read. Try using a brighter background color and/or a darker link color.' ); } ); test( 'should render component when the colors meet AA WCAG guidelines but all colors have alpha transparency with alpha checker enabled.', () => { - const wrapper = mount( + const { container } = render( { expect( speak ).toHaveBeenCalledWith( 'Transparent text may be hard for people to read.' ); - expect( wrapper.find( Notice ).children().text() ).toBe( - 'Transparent text may be hard for people to read.' - ); + expect( + container.querySelector( '.components-notice' ).textContent + ).toBe( 'Transparent text may be hard for people to read.' ); } ); } ); diff --git a/packages/block-editor/src/components/line-height-control/test/index.js b/packages/block-editor/src/components/line-height-control/test/index.js index c6a16f5db3cad0..b4731d94190b2d 100644 --- a/packages/block-editor/src/components/line-height-control/test/index.js +++ b/packages/block-editor/src/components/line-height-control/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; /** * WordPress dependencies @@ -30,32 +30,40 @@ describe( 'LineHeightControl', () => { it( 'should immediately step up from the default value if up-arrowed from an unset state', () => { render( ); const input = screen.getByRole( 'spinbutton' ); - input.focus(); - fireEvent.keyDown( input, { keyCode: UP } ); + act( () => { + input.focus(); + fireEvent.keyDown( input, { keyCode: UP } ); + } ); expect( input ).toHaveValue( BASE_DEFAULT_VALUE + STEP ); } ); it( 'should immediately step down from the default value if down-arrowed from an unset state', () => { render( ); const input = screen.getByRole( 'spinbutton' ); - input.focus(); - fireEvent.keyDown( input, { keyCode: DOWN } ); + act( () => { + input.focus(); + fireEvent.keyDown( input, { keyCode: DOWN } ); + } ); expect( input ).toHaveValue( BASE_DEFAULT_VALUE - STEP ); } ); it( 'should immediately step up from the default value if spin button up was clicked from an unset state', () => { render( ); const input = screen.getByRole( 'spinbutton' ); - input.focus(); - fireEvent.change( input, { target: { value: 0.1 } } ); // simulates click on spin button up + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: 0.1 } } ); // simulates click on spin button up + } ); expect( input ).toHaveValue( BASE_DEFAULT_VALUE + STEP ); } ); it( 'should immediately step down from the default value if spin button down was clicked from an unset state', () => { render( ); const input = screen.getByRole( 'spinbutton' ); - input.focus(); - fireEvent.change( input, { target: { value: 0 } } ); // simulates click on spin button down + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: 0 } } ); // simulates click on spin button down + } ); expect( input ).toHaveValue( BASE_DEFAULT_VALUE - STEP ); } ); } ); diff --git a/packages/block-editor/src/components/link-control/test/index.js b/packages/block-editor/src/components/link-control/test/index.js index 6bbf2ea47b8ca9..5f0612423be89b 100644 --- a/packages/block-editor/src/components/link-control/test/index.js +++ b/packages/block-editor/src/components/link-control/test/index.js @@ -1,19 +1,22 @@ /** * External dependencies */ -import { render, unmountComponentAtNode } from 'react-dom'; -import { act, Simulate } from 'react-dom/test-utils'; -import { queryByText, queryByRole } from '@testing-library/react'; +import { + render, + act, + queryByText, + queryByRole, + fireEvent, +} from '@testing-library/react'; import { default as lodash, first, last, nth, uniqueId } from 'lodash'; + /** * WordPress dependencies */ import { useState } from '@wordpress/element'; import { UP, DOWN, ENTER } from '@wordpress/keycodes'; -/** - * WordPress dependencies - */ import { useSelect } from '@wordpress/data'; + /** * Internal dependencies */ @@ -68,17 +71,10 @@ function eventLoopTick() { let container = null; beforeEach( () => { - // Setup a DOM element as a render target. - container = document.createElement( 'div' ); - document.body.appendChild( container ); mockFetchSearchSuggestions.mockImplementation( fetchFauxEntitySuggestions ); } ); afterEach( () => { - // Cleanup on exiting. - unmountComponentAtNode( container ); - container.remove(); - container = null; mockFetchSearchSuggestions.mockReset(); mockFetchRichUrlData?.mockReset(); // Conditionally reset as it may NOT be a mock. } ); @@ -108,7 +104,7 @@ function getCurrentLink() { describe( 'Basic rendering', () => { it( 'should render', () => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -140,19 +136,19 @@ describe( 'Basic rendering', () => { const searchTerm = 'Hello'; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); - // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); - } ); + await act( async () => { + // Simulate searching for a term. + fireEvent.change( searchInput, { target: { value: searchTerm } } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); + } ); // Find all elements with link // Filter out the element with the text 'ENTER' because it doesn't contain link. @@ -172,10 +168,9 @@ describe( 'Basic rendering', () => { it( 'undefined', () => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); expect( isEditing() ).toBe( false ); @@ -183,13 +178,12 @@ describe( 'Basic rendering', () => { it( 'true', () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( isEditing() ).toBe( true ); @@ -197,10 +191,9 @@ describe( 'Basic rendering', () => { it( 'false', () => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); // Click the "Edit" button to trigger into the editing mode. @@ -209,7 +202,7 @@ describe( 'Basic rendering', () => { } ); act( () => { - Simulate.click( editButton ); + fireEvent.click( editButton ); } ); expect( isEditing() ).toBe( true ); @@ -217,13 +210,12 @@ describe( 'Basic rendering', () => { // If passed `forceIsEditingLink` of `false` while editing, should // forcefully reset to the preview state. act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( isEditing() ).toBe( false ); @@ -244,13 +236,12 @@ describe( 'Basic rendering', () => { }; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const linkPreview = queryByRole( container, 'generic', { @@ -267,10 +258,9 @@ describe( 'Basic rendering', () => { describe( 'Unlinking', () => { it( 'should not show "Unlink" button if no onRemove handler is provided', () => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); const unLinkButton = queryByRole( container, 'button', { @@ -284,13 +274,12 @@ describe( 'Basic rendering', () => { it( 'should show "Unlink" button if a onRemove handler is provided', () => { const mockOnRemove = jest.fn(); act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const unLinkButton = queryByRole( container, 'button', { @@ -300,7 +289,7 @@ describe( 'Basic rendering', () => { expect( unLinkButton ).toBeInTheDocument(); act( () => { - Simulate.click( unLinkButton ); + fireEvent.click( unLinkButton ); } ); expect( mockOnRemove ).toHaveBeenCalled(); @@ -322,20 +311,19 @@ describe( 'Searching for a link', () => { mockFetchSearchSuggestions.mockImplementation( fauxRequest ); act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm } } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); let loadingUI = container.querySelector( '.components-spinner' ); @@ -344,12 +332,11 @@ describe( 'Searching for a link', () => { expect( loadingUI ).not.toBeNull(); - act( () => { + await act( async () => { resolver( fauxEntitySuggestions ); + await eventLoopTick(); } ); - await eventLoopTick(); - loadingUI = container.querySelector( '.components-spinner' ); expect( loadingUI ).toBeNull(); @@ -360,19 +347,19 @@ describe( 'Searching for a link', () => { const firstFauxSuggestion = first( fauxEntitySuggestions ); act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm } } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = getSearchResults(); @@ -405,7 +392,7 @@ describe( 'Searching for a link', () => { const searchTerm = ' Hello '; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -414,13 +401,12 @@ describe( 'Searching for a link', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm } } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultTextHighlightElements = Array.from( container.querySelectorAll( '[role="listbox"] button[role="option"] mark' @@ -452,23 +438,24 @@ describe( 'Searching for a link', () => { it( 'should not call search handler when showSuggestions is false', async () => { act( () => { - render( , container ); + container = render( ) + .container; } ); // Search Input UI. const searchInput = getURLInput(); + let searchResultElements; // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: 'anything' }, } ); - } ); - - const searchResultElements = getSearchResults(); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); + searchResultElements = getSearchResults(); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); + } ); // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. expect( searchResultElements ).toHaveLength( 0 ); @@ -482,21 +469,20 @@ describe( 'Searching for a link', () => { 'should display a URL suggestion as a default fallback for the search term "%s" which could potentially be a valid url.', async ( searchTerm ) => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = getSearchResults(); @@ -527,21 +513,21 @@ describe( 'Searching for a link', () => { it( 'should not display a URL suggestion as a default fallback when noURLSuggestion is passed.', async () => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: 'couldbeurlorentitysearchterm' }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = getSearchResults(); @@ -562,22 +548,21 @@ describe( 'Manual link entry', () => { 'should display a single suggestion result when the current input value is URL-like (eg: %s)', async ( searchTerm ) => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); const firstSearchResultItemHTML = @@ -610,7 +595,7 @@ describe( 'Manual link entry', () => { 'should not allow creation of links %s when using the keyboard', async ( _desc, searchString ) => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -625,18 +610,17 @@ describe( 'Manual link entry', () => { expect( submitButton ).toBeInTheDocument(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchString }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - // Attempt to submit the empty search value in the input. act( () => { - Simulate.keyDown( searchInput, { keyCode: ENTER } ); + fireEvent.keyDown( searchInput, { keyCode: ENTER } ); } ); submitButton = queryByRole( container, 'button', { @@ -655,7 +639,7 @@ describe( 'Manual link entry', () => { 'should not allow creation of links %s via the UI "submit" button', async ( _desc, searchString ) => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -670,18 +654,17 @@ describe( 'Manual link entry', () => { expect( submitButton ).toBeInTheDocument(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchString }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - // Attempt to submit the empty search value in the input. act( () => { - Simulate.click( submitButton ); + fireEvent.click( submitButton ); } ); submitButton = queryByRole( container, 'button', { @@ -706,22 +689,21 @@ describe( 'Manual link entry', () => { 'should recognise "%s" as a %s link and handle as manual entry by displaying a single suggestion', async ( searchTerm, searchType ) => { act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); const firstSearchResultItemHTML = @@ -749,12 +731,12 @@ describe( 'Default search suggestions', () => { it( 'should display a list of initial search suggestions when there is no search value or suggestions', async () => { const expectedResultsLength = 3; // Set within `LinkControl`. - act( () => { - render( , container ); + await act( async () => { + container = render( ) + .container; + await eventLoopTick(); } ); - await eventLoopTick(); - // Search Input UI. const searchInput = getURLInput(); @@ -789,18 +771,16 @@ describe( 'Default search suggestions', () => { it( 'should not display initial suggestions when input value is present', async () => { // Render with an initial value an ensure that no initial suggestions // are shown. - act( () => { - render( + await act( async () => { + container = render( , - container - ); + /> + ).container; + await eventLoopTick(); } ); - await eventLoopTick(); - expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled(); // Click the "Edit/Change" button and check initial suggestions are not @@ -809,13 +789,15 @@ describe( 'Default search suggestions', () => { const currentLinkBtn = currentLinkUI.querySelector( 'button' ); act( () => { - Simulate.click( currentLinkBtn ); + fireEvent.click( currentLinkBtn ); } ); const searchInput = getURLInput(); - searchInput.focus(); - await eventLoopTick(); + await act( async () => { + searchInput.focus(); + await eventLoopTick(); + } ); const searchResultElements = getSearchResults(); @@ -834,7 +816,8 @@ describe( 'Default search suggestions', () => { const searchTerm = 'Hello world'; act( () => { - render( , container ); + container = render( ) + .container; } ); let searchResultElements; @@ -844,24 +827,22 @@ describe( 'Default search suggestions', () => { searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm } } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - expect( searchInput.value ).toBe( searchTerm ); searchResultElements = getSearchResults(); // Delete the text. - act( () => { - Simulate.change( searchInput, { target: { value: '' } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: '' } } ); + await eventLoopTick(); } ); - await eventLoopTick(); - searchResultElements = getSearchResults(); searchInput = getURLInput(); @@ -885,12 +866,12 @@ describe( 'Default search suggestions', () => { Promise.resolve( noResults ) ); - act( () => { - render( , container ); + await act( async () => { + container = render( ) + .container; + await eventLoopTick(); } ); - await eventLoopTick(); - const searchInput = getURLInput(); const searchResultElements = getSearchResults(); @@ -954,7 +935,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -963,14 +944,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: entityNameText }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -989,12 +969,11 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { // No need to wait in this test because we control the Promise // resolution manually via the `resolver` reference. - act( () => { - Simulate.click( createButton ); + await act( async () => { + fireEvent.click( createButton ); + await eventLoopTick(); } ); - await eventLoopTick(); - // Check for loading indicator. const loadingIndicator = container.querySelector( '.block-editor-link-control__loading' @@ -1051,7 +1030,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -1060,14 +1039,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: 'Some new page to create' }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -1080,11 +1058,10 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); await act( async () => { - Simulate.click( createButton ); + fireEvent.click( createButton ); + await eventLoopTick(); } ); - await eventLoopTick(); - const currentLink = container.querySelector( '[aria-label="Currently selected"]' ); @@ -1124,7 +1101,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -1133,14 +1110,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: entityNameText }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -1153,19 +1129,18 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { // Step down into the search results, highlighting the first result item. act( () => { - Simulate.keyDown( searchInput, { keyCode: DOWN } ); + fireEvent.keyDown( searchInput, { keyCode: DOWN } ); } ); act( () => { - Simulate.keyDown( createButton, { keyCode: ENTER } ); + fireEvent.keyDown( createButton, { keyCode: ENTER } ); } ); await act( async () => { - Simulate.keyDown( searchInput, { keyCode: ENTER } ); + fireEvent.keyDown( searchInput, { keyCode: ENTER } ); + await eventLoopTick(); } ); - await eventLoopTick(); - const currentLink = container.querySelector( '[aria-label="Currently selected"]' ); @@ -1190,7 +1165,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -1199,14 +1174,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: entityNameText }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -1225,14 +1199,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { it.each( [ [ undefined ], [ null ], [ false ] ] )( 'should not show not show an option to create an entity when "createSuggestion" handler is %s', async ( handler ) => { - act( () => { - render( - , - container - ); + await act( async () => { + container = render( + + ).container; + // Await the initial suggestions to be fetched. + await eventLoopTick(); } ); - // Await the initial suggestions to be fetched. - await eventLoopTick(); // Search Input UI. const searchInput = container.querySelector( @@ -1256,17 +1229,16 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); it( 'should not show not show an option to create an entity when input is empty', async () => { - act( () => { - render( + await act( async () => { + container = render( , - container - ); + /> + ).container; + // Await the initial suggestions to be fetched. + await eventLoopTick(); } ); - // Await the initial suggestions to be fetched. - await eventLoopTick(); // Search Input UI. const searchInput = container.querySelector( @@ -1298,10 +1270,9 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { 'should not show option to "Create Page" when text is a form of direct entry (eg: %s)', async ( inputText ) => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); // Search Input UI. @@ -1310,14 +1281,13 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: inputText }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. const searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -1346,24 +1316,22 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { const createSuggestion = () => Promise.reject( throwsError() ); act( () => { - render( - , - container - ); + container = render( + + ).container; } ); // Search Input UI. searchInput = container.querySelector( 'input[aria-label="URL"]' ); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchText }, } ); + await eventLoopTick(); } ); - await eventLoopTick(); - // TODO: select these by aria relationship to autocomplete rather than arbitrary selector. let searchResultElements = container.querySelectorAll( '[role="listbox"] [role="option"]' @@ -1375,11 +1343,10 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => { ); await act( async () => { - Simulate.click( createButton ); + fireEvent.click( createButton ); + await eventLoopTick(); } ); - await eventLoopTick(); - searchInput = container.querySelector( 'input[aria-label="URL"]' ); // This is a Notice component @@ -1429,7 +1396,7 @@ describe( 'Selecting links', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // TODO: select by aria role or visible text. @@ -1463,7 +1430,7 @@ describe( 'Selecting links', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Required in order to select the button below. @@ -1472,7 +1439,7 @@ describe( 'Selecting links', () => { // Simulate searching for a term. act( () => { - Simulate.click( currentLinkBtn ); + fireEvent.click( currentLinkBtn ); } ); const searchInput = getURLInput(); @@ -1512,29 +1479,28 @@ describe( 'Selecting links', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); const firstSearchSuggestion = first( searchResultElements ); // Simulate selecting the first of the search suggestions. act( () => { - Simulate.click( firstSearchSuggestion ); + fireEvent.click( firstSearchSuggestion ); } ); const currentLink = container.querySelector( @@ -1585,7 +1551,7 @@ describe( 'Selecting links', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. @@ -1593,18 +1559,17 @@ describe( 'Selecting links', () => { searchInput.focus(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - // Step down into the search results, highlighting the first result item. act( () => { - Simulate.keyDown( searchInput, { keyCode: DOWN } ); + fireEvent.keyDown( searchInput, { keyCode: DOWN } ); } ); const searchResultElements = getSearchResults(); @@ -1625,7 +1590,7 @@ describe( 'Selecting links', () => { if ( type === 'entity' ) { // Check we can go down again using the down arrow. act( () => { - Simulate.keyDown( searchInput, { keyCode: DOWN } ); + fireEvent.keyDown( searchInput, { keyCode: DOWN } ); } ); selectedSearchResultElement = container.querySelector( @@ -1640,7 +1605,7 @@ describe( 'Selecting links', () => { // Check we can go back up via up arrow. act( () => { - Simulate.keyDown( searchInput, { keyCode: UP } ); + fireEvent.keyDown( searchInput, { keyCode: UP } ); } ); selectedSearchResultElement = container.querySelector( @@ -1656,7 +1621,7 @@ describe( 'Selecting links', () => { // Submit the selected item as the current link. act( () => { - Simulate.keyDown( searchInput, { keyCode: ENTER } ); + fireEvent.keyDown( searchInput, { keyCode: ENTER } ); } ); // Check that the suggestion selected via is now shown as selected. @@ -1684,12 +1649,12 @@ describe( 'Selecting links', () => { ); it( 'should allow selection of initial search results via the keyboard', async () => { - act( () => { - render( , container ); + await act( async () => { + container = render( ) + .container; + await eventLoopTick(); } ); - await eventLoopTick(); - const searchResultsWrapper = container.querySelector( '[role="listbox"]' ); @@ -1706,12 +1671,11 @@ describe( 'Selecting links', () => { const searchInput = getURLInput(); // Step down into the search results, highlighting the first result item. - act( () => { - Simulate.keyDown( searchInput, { keyCode: DOWN } ); + await act( async () => { + fireEvent.keyDown( searchInput, { keyCode: DOWN } ); + await eventLoopTick(); } ); - await eventLoopTick(); - const searchResultElements = getSearchResults(); const firstSearchSuggestion = first( searchResultElements ); @@ -1728,7 +1692,7 @@ describe( 'Selecting links', () => { // Check we can go down again using the down arrow. act( () => { - Simulate.keyDown( searchInput, { keyCode: DOWN } ); + fireEvent.keyDown( searchInput, { keyCode: DOWN } ); } ); selectedSearchResultElement = container.querySelector( @@ -1742,7 +1706,7 @@ describe( 'Selecting links', () => { // Check we can go back up via up arrow. act( () => { - Simulate.keyDown( searchInput, { keyCode: UP } ); + fireEvent.keyDown( searchInput, { keyCode: UP } ); } ); selectedSearchResultElement = container.querySelector( @@ -1771,7 +1735,7 @@ describe( 'Addition Settings UI', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); const newTabSettingLabel = Array.from( @@ -1824,7 +1788,7 @@ describe( 'Addition Settings UI', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); // Grab the elements using user perceivable DOM queries. @@ -1868,20 +1832,19 @@ describe( 'Post types', () => { const searchTerm = 'Hello world'; act( () => { - render( , container ); + container = render( ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { target: { value: searchTerm } } ); + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm } } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); searchResultElements.forEach( ( resultItem, index ) => { @@ -1897,25 +1860,23 @@ describe( 'Post types', () => { const searchTerm = 'Hello world'; act( () => { - render( - , - container - ); + container = render( + + ).container; } ); // Search Input UI. const searchInput = getURLInput(); // Simulate searching for a term. - act( () => { - Simulate.change( searchInput, { + await act( async () => { + fireEvent.change( searchInput, { target: { value: searchTerm }, } ); + // fetchFauxEntitySuggestions resolves on next "tick" of event loop. + await eventLoopTick(); } ); - // fetchFauxEntitySuggestions resolves on next "tick" of event loop. - await eventLoopTick(); - const searchResultElements = getSearchResults(); searchResultElements.forEach( ( resultItem, index ) => { @@ -1960,12 +1921,10 @@ describe( 'Rich link previews', () => { } ) ); - act( () => { - render( , container ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( ) + .container; await eventLoopTick(); } ); @@ -1991,15 +1950,11 @@ describe( 'Rich link previews', () => { } ) ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2022,15 +1977,11 @@ describe( 'Rich link previews', () => { } ) ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2062,15 +2013,11 @@ describe( 'Rich link previews', () => { } ) ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2101,15 +2048,11 @@ describe( 'Rich link previews', () => { } ) ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2147,15 +2090,11 @@ describe( 'Rich link previews', () => { return Promise.resolve( data ); } ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2186,15 +2125,11 @@ describe( 'Rich link previews', () => { Promise.resolve( data ) ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2215,15 +2150,11 @@ describe( 'Rich link previews', () => { mockFetchRichUrlData.mockImplementation( nonResolvingPromise ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2245,15 +2176,11 @@ describe( 'Rich link previews', () => { mockFetchRichUrlData.mockImplementation( simulateFailedFetch ); - act( () => { - render( - , - container - ); - } ); - // mockFetchRichUrlData resolves on next "tick" of event loop. await act( async () => { + container = render( + + ).container; await eventLoopTick(); } ); @@ -2282,10 +2209,9 @@ describe( 'Controlling link title text', () => { it( 'should not show a means to alter the link title text by default', async () => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); expect( @@ -2302,14 +2228,13 @@ describe( 'Controlling link title text', () => { }; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( @@ -2320,14 +2245,13 @@ describe( 'Controlling link title text', () => { it( 'should show a text input to alter the link title text when hasTextControl prop is truthy', async () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( @@ -2349,14 +2273,13 @@ describe( 'Controlling link title text', () => { async ( _unused, titleValue ) => { const linkWithTitle = { ...selectedLink, title: titleValue }; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const textInput = queryByRole( container, 'textbox', { @@ -2372,21 +2295,20 @@ describe( 'Controlling link title text', () => { const textValue = 'My new text value'; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); let textInput = queryByRole( container, 'textbox', { name: 'Text' } ); act( () => { - Simulate.change( textInput, { + fireEvent.change( textInput, { target: { value: textValue }, } ); } ); @@ -2400,7 +2322,7 @@ describe( 'Controlling link title text', () => { } ); act( () => { - Simulate.click( submitButton ); + fireEvent.click( submitButton ); } ); expect( mockOnChange ).toHaveBeenCalledWith( @@ -2414,15 +2336,14 @@ describe( 'Controlling link title text', () => { const textValue = 'My new text value'; const mockOnChange = jest.fn(); act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const textInput = queryByRole( container, 'textbox', { name: 'Text' } ); @@ -2430,14 +2351,14 @@ describe( 'Controlling link title text', () => { expect( textInput ).toBeTruthy(); act( () => { - Simulate.change( textInput, { + fireEvent.change( textInput, { target: { value: textValue }, } ); } ); // Attempt to submit the empty search value in the input. act( () => { - Simulate.keyDown( textInput, { keyCode: ENTER } ); + fireEvent.keyDown( textInput, { keyCode: ENTER } ); } ); expect( mockOnChange ).toHaveBeenCalledWith( { diff --git a/packages/block-editor/src/components/media-placeholder/test/index.js b/packages/block-editor/src/components/media-placeholder/test/index.js index 5dacf563e56d7d..a6915081c00c04 100644 --- a/packages/block-editor/src/components/media-placeholder/test/index.js +++ b/packages/block-editor/src/components/media-placeholder/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; /** * Internal dependencies @@ -13,6 +13,6 @@ jest.mock( '@wordpress/data/src/components/use-select', () => () => ( {} ) ); describe( 'MediaPlaceholder', () => { it( 'renders successfully when allowedTypes property is not specified', () => { - expect( () => mount( ) ).not.toThrow(); + expect( () => render( ) ).not.toThrow(); } ); } ); diff --git a/packages/block-editor/src/components/media-replace-flow/test/index.js b/packages/block-editor/src/components/media-replace-flow/test/index.js index 18219daf0acf9e..0861f622b24954 100644 --- a/packages/block-editor/src/components/media-replace-flow/test/index.js +++ b/packages/block-editor/src/components/media-replace-flow/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { render, fireEvent } from '@testing-library/react'; +import { render, fireEvent, act } from '@testing-library/react'; /** * Internal dependencies @@ -11,18 +11,21 @@ import MediaReplaceFlow from '../'; const noop = () => {}; function setUpMediaReplaceFlow() { - const { container } = render( - - ); + let container; + act( () => { + container = render( + + ).container; + } ); return container; } @@ -43,7 +46,9 @@ describe( 'General media replace flow', () => { const mediaReplaceButton = container.querySelector( 'button[aria-expanded="false"]' ); - mediaReplaceButton.click(); + act( () => { + mediaReplaceButton.click(); + } ); const uploadMenu = container.querySelector( '.block-editor-media-replace-flow__media-upload-menu' @@ -58,7 +63,9 @@ describe( 'General media replace flow', () => { const mediaReplaceButton = container.querySelector( 'button[aria-expanded="false"]' ); - mediaReplaceButton.click(); + act( () => { + mediaReplaceButton.click(); + } ); const mediaURL = container.querySelector( '.components-external-link' ); @@ -71,27 +78,35 @@ describe( 'General media replace flow', () => { const mediaReplaceButton = container.querySelector( 'button[aria-expanded="false"]' ); - mediaReplaceButton.click(); + act( () => { + mediaReplaceButton.click(); + } ); const editMediaURL = container.querySelector( '.block-editor-link-control__search-item-action' ); - editMediaURL.click(); + act( () => { + editMediaURL.click(); + } ); const mediaURLInput = container.querySelector( '.block-editor-url-input__input' ); - fireEvent.change( mediaURLInput, { - target: { value: 'https://new.example.media' }, + act( () => { + fireEvent.change( mediaURLInput, { + target: { value: 'https://new.example.media' }, + } ); } ); const saveMediaURLButton = container.querySelector( '.block-editor-link-control__search-submit' ); - saveMediaURLButton.click(); + act( () => { + saveMediaURLButton.click(); + } ); const mediaURL = container.querySelector( '.components-external-link' ); diff --git a/packages/block-editor/src/components/responsive-block-control/test/index.js b/packages/block-editor/src/components/responsive-block-control/test/index.js index 745dd459f4a188..ee893b55f66b3c 100644 --- a/packages/block-editor/src/components/responsive-block-control/test/index.js +++ b/packages/block-editor/src/components/responsive-block-control/test/index.js @@ -1,8 +1,8 @@ /** * External dependencies */ -import { render, unmountComponentAtNode } from 'react-dom'; -import { act, Simulate } from 'react-dom/test-utils'; +import { act, render } from '@testing-library/react'; +import { Simulate } from 'react-dom/test-utils'; import { uniqueId } from 'lodash'; /** @@ -18,19 +18,6 @@ import { SelectControl } from '@wordpress/components'; import ResponsiveBlockControl from '../index'; let container = null; -beforeEach( () => { - // Setup a DOM element as a render target. - container = document.createElement( 'div' ); - document.body.appendChild( container ); -} ); - -afterEach( () => { - // Cleanup on exiting. - unmountComponentAtNode( container ); - container.remove(); - container = null; -} ); - const inputId = uniqueId(); const sizeOptions = [ @@ -67,14 +54,13 @@ const renderTestDefaultControlComponent = ( labelComponent, device ) => { describe( 'Basic rendering', () => { it( 'should render with required props', () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const activePropertyLabel = Array.from( @@ -122,13 +108,12 @@ describe( 'Basic rendering', () => { it( 'should not render without valid legend', () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( container.innerHTML ).toBe( '' ); @@ -136,13 +121,12 @@ describe( 'Basic rendering', () => { it( 'should not render without valid property', () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); expect( container.innerHTML ).toBe( '' ); @@ -150,10 +134,9 @@ describe( 'Basic rendering', () => { it( 'should not render without valid default control render prop', () => { act( () => { - render( - , - container - ); + container = render( + + ).container; } ); expect( container.innerHTML ).toBe( '' ); @@ -163,15 +146,14 @@ describe( 'Basic rendering', () => { const customToggleLabel = 'Utilise a matching padding value on all viewports'; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const actualToggleLabel = container.querySelector( @@ -185,15 +167,14 @@ describe( 'Basic rendering', () => { const customDefaultControlGroupLabel = 'Everything'; act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const defaultControlLabel = Array.from( @@ -207,15 +188,14 @@ describe( 'Basic rendering', () => { describe( 'Default and Responsive modes', () => { it( 'should render in responsive mode when isResponsive prop is set to true', () => { act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const defaultControlGroup = container.querySelector( @@ -254,16 +234,15 @@ describe( 'Default and Responsive modes', () => { ); act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const defaultRenderControlCall = 1; @@ -305,7 +284,7 @@ describe( 'Default and Responsive modes', () => { }; act( () => { - render( , container ); + container = render( ).container; } ); let defaultControlGroup = container.querySelector( @@ -383,16 +362,15 @@ describe( 'Default and Responsive modes', () => { } ); act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); // The user should see "range" controls so we can legitimately query for them here. diff --git a/packages/block-editor/src/components/url-input/test/button.js b/packages/block-editor/src/components/url-input/test/button.js index 04601dfea51c4c..87414916780cc3 100644 --- a/packages/block-editor/src/components/url-input/test/button.js +++ b/packages/block-editor/src/components/url-input/test/button.js @@ -2,8 +2,6 @@ * External dependencies */ import { shallow } from 'enzyme'; -import TestUtils from 'react-dom/test-utils'; -import ReactDOM from 'react-dom'; /** * Internal dependencies @@ -70,22 +68,4 @@ describe( 'URLInputButton', () => { wrapper.find( '.block-editor-url-input__back' ).simulate( 'click' ); expect( wrapper.state().expanded ).toBe( false ); } ); - it( 'should close the form when user submits it', () => { - const wrapper = TestUtils.renderIntoDocument( ); - const buttonElement = () => - TestUtils.scryRenderedDOMComponentsWithClass( - wrapper, - 'components-toolbar__control' - ); - const formElement = () => - TestUtils.scryRenderedDOMComponentsWithTag( wrapper, 'form' ); - TestUtils.Simulate.click( buttonElement().shift() ); - expect( wrapper.state.expanded ).toBe( true ); - TestUtils.Simulate.submit( formElement().shift() ); - expect( wrapper.state.expanded ).toBe( false ); - ReactDOM.unmountComponentAtNode( - // eslint-disable-next-line react/no-find-dom-node - ReactDOM.findDOMNode( wrapper ).parentNode - ); - } ); } ); diff --git a/packages/components/src/alignment-matrix-control/test/index.js b/packages/components/src/alignment-matrix-control/test/index.js index eaa28941048c14..093b12531d2dcf 100644 --- a/packages/components/src/alignment-matrix-control/test/index.js +++ b/packages/components/src/alignment-matrix-control/test/index.js @@ -1,8 +1,7 @@ /** * External dependencies */ -import { render, unmountComponentAtNode } from 'react-dom'; -import { act } from 'react-dom/test-utils'; +import { render, act } from '@testing-library/react'; /** * Internal dependencies @@ -21,17 +20,6 @@ afterAll( () => { let container = null; -beforeEach( () => { - container = document.createElement( 'div' ); - document.body.appendChild( container ); -} ); - -afterEach( () => { - unmountComponentAtNode( container ); - container.remove(); - container = null; -} ); - const getControl = () => { return container.querySelector( '.component-alignment-matrix-control' ); }; @@ -45,7 +33,7 @@ describe( 'AlignmentMatrixControl', () => { describe( 'Basic rendering', () => { it( 'should render', () => { act( () => { - render( , container ); + container = render( ).container; } ); const control = getControl(); @@ -58,13 +46,12 @@ describe( 'AlignmentMatrixControl', () => { const spy = jest.fn(); act( () => { - render( + container = render( , - container - ); + /> + ).container; } ); const cells = getCells(); diff --git a/packages/components/src/border-box-control/test/index.js b/packages/components/src/border-box-control/test/index.js index f2c152f71ea870..99aca50edaf970 100644 --- a/packages/components/src/border-box-control/test/index.js +++ b/packages/components/src/border-box-control/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; /** * Internal dependencies @@ -53,7 +53,9 @@ const renderBorderBoxControl = ( customProps ) => { }; const clickButton = ( name ) => { - fireEvent.click( screen.getByRole( 'button', { name } ) ); + act( () => { + fireEvent.click( screen.getByRole( 'button', { name } ) ); + } ); }; const queryButton = ( name ) => { @@ -62,14 +64,18 @@ const queryButton = ( name ) => { const updateLinkedWidthInput = ( value ) => { const widthInput = screen.getByRole( 'spinbutton' ); - widthInput.focus(); - fireEvent.change( widthInput, { target: { value } } ); + act( () => { + widthInput.focus(); + fireEvent.change( widthInput, { target: { value } } ); + } ); }; const updateSplitWidthInput = ( value, index = 0 ) => { const splitInputs = screen.getAllByRole( 'spinbutton' ); - splitInputs[ index ].focus(); - fireEvent.change( splitInputs[ index ], { target: { value } } ); + act( () => { + splitInputs[ index ].focus(); + fireEvent.change( splitInputs[ index ], { target: { value } } ); + } ); }; describe( 'BorderBoxControl', () => { diff --git a/packages/components/src/border-control/test/index.js b/packages/components/src/border-control/test/index.js index b0960f2e96a7da..9ce7e45300295e 100644 --- a/packages/components/src/border-control/test/index.js +++ b/packages/components/src/border-control/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; /** * Internal dependencies @@ -43,7 +43,9 @@ const rerenderBorderControl = ( rerender, customProps ) => { const openPopover = () => { const toggleButton = screen.getByLabelText( toggleLabelRegex ); - fireEvent.click( toggleButton ); + act( () => { + fireEvent.click( toggleButton ); + } ); }; const getButton = ( name ) => { @@ -55,13 +57,17 @@ const queryButton = ( name ) => { }; const clickButton = ( name ) => { - fireEvent.click( getButton( name ) ); + act( () => { + fireEvent.click( getButton( name ) ); + } ); }; const setWidthInput = ( value ) => { const widthInput = screen.getByRole( 'spinbutton' ); - widthInput.focus(); - fireEvent.change( widthInput, { target: { value } } ); + act( () => { + widthInput.focus(); + fireEvent.change( widthInput, { target: { value } } ); + } ); }; const clearWidthInput = () => setWidthInput( '' ); diff --git a/packages/components/src/box-control/test/index.js b/packages/components/src/box-control/test/index.js index 4515c4885c90f7..c7c0002ba9ef81 100644 --- a/packages/components/src/box-control/test/index.js +++ b/packages/components/src/box-control/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, fireEvent, screen, act } from '@testing-library/react'; /** * WordPress dependencies @@ -28,9 +28,11 @@ describe( 'BoxControl', () => { const input = container.querySelector( 'input' ); const unitSelect = container.querySelector( 'select' ); - input.focus(); - fireEvent.change( input, { target: { value: '100%' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100%' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( '%' ); @@ -44,15 +46,19 @@ describe( 'BoxControl', () => { const unitSelect = container.querySelector( 'select' ); const reset = getByText( /Reset/ ); - input.focus(); - fireEvent.change( input, { target: { value: '100px' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100px' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( 'px' ); - reset.focus(); - fireEvent.click( reset ); + act( () => { + reset.focus(); + fireEvent.click( reset ); + } ); expect( input.value ).toBe( '' ); expect( unitSelect.value ).toBe( 'px' ); @@ -74,15 +80,19 @@ describe( 'BoxControl', () => { const unitSelect = container.querySelector( 'select' ); const reset = getByText( /Reset/ ); - input.focus(); - fireEvent.change( input, { target: { value: '100px' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100px' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( 'px' ); - reset.focus(); - fireEvent.click( reset ); + act( () => { + reset.focus(); + fireEvent.click( reset ); + } ); expect( input.value ).toBe( '' ); expect( unitSelect.value ).toBe( 'px' ); @@ -111,15 +121,19 @@ describe( 'BoxControl', () => { const unitSelect = container.querySelector( 'select' ); const reset = getByText( /Reset/ ); - input.focus(); - fireEvent.change( input, { target: { value: '100px' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100px' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( 'px' ); - reset.focus(); - fireEvent.click( reset ); + act( () => { + reset.focus(); + fireEvent.click( reset ); + } ); expect( input.value ).toBe( '' ); expect( unitSelect.value ).toBe( 'px' ); @@ -132,15 +146,19 @@ describe( 'BoxControl', () => { } ); const unitSelect = screen.getByLabelText( 'Select unit' ); - input.focus(); - fireEvent.change( input, { target: { value: '100%' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100%' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( '%' ); - fireEvent.change( input, { target: { value: '' } } ); - fireEvent.blur( input ); + act( () => { + fireEvent.change( input, { target: { value: '' } } ); + fireEvent.blur( input ); + } ); expect( input.value ).toBe( '' ); } ); @@ -159,14 +177,19 @@ describe( 'BoxControl', () => { ); const unlink = getByLabelText( /Unlink Sides/ ); - fireEvent.click( unlink ); + + act( () => { + fireEvent.click( unlink ); + } ); const input = container.querySelector( 'input' ); const unitSelect = container.querySelector( 'select' ); - input.focus(); - fireEvent.change( input, { target: { value: '100px' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100px' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( 'px' ); @@ -192,14 +215,19 @@ describe( 'BoxControl', () => { ); const unlink = getByLabelText( /Unlink Sides/ ); - fireEvent.click( unlink ); + + act( () => { + fireEvent.click( unlink ); + } ); const input = container.querySelector( 'input' ); const unitSelect = container.querySelector( 'select' ); - input.focus(); - fireEvent.change( input, { target: { value: '100px' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '100px' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( input.value ).toBe( '100' ); expect( unitSelect.value ).toBe( 'px' ); @@ -220,12 +248,18 @@ describe( 'BoxControl', () => { // Make unit selection on all input control. const allUnitSelect = screen.getByLabelText( 'Select unit' ); - allUnitSelect.focus(); - fireEvent.change( allUnitSelect, { target: { value: 'em' } } ); + + act( () => { + allUnitSelect.focus(); + fireEvent.change( allUnitSelect, { target: { value: 'em' } } ); + } ); // Unlink the controls. const unlink = screen.getByLabelText( /Unlink Sides/ ); - fireEvent.click( unlink ); + + act( () => { + fireEvent.click( unlink ); + } ); // Confirm that each individual control has the selected unit const unlinkedSelects = screen.getAllByDisplayValue( 'em' ); @@ -238,12 +272,18 @@ describe( 'BoxControl', () => { // Make unit selection on all input control. const allUnitSelect = screen.getByLabelText( 'Select unit' ); - allUnitSelect.focus(); - fireEvent.change( allUnitSelect, { target: { value: 'vw' } } ); + + act( () => { + allUnitSelect.focus(); + fireEvent.change( allUnitSelect, { target: { value: 'vw' } } ); + } ); // Unlink the controls. const unlink = screen.getByLabelText( /Unlink Sides/ ); - fireEvent.click( unlink ); + + act( () => { + fireEvent.click( unlink ); + } ); // Confirm that each individual control has the selected unit const unlinkedSelects = screen.getAllByDisplayValue( 'vw' ); @@ -270,9 +310,11 @@ describe( 'BoxControl', () => { selector: 'input', } ); - input.focus(); - fireEvent.change( input, { target: { value: '7.5rem' } } ); - fireEvent.keyDown( input, { keyCode: ENTER } ); + act( () => { + input.focus(); + fireEvent.change( input, { target: { value: '7.5rem' } } ); + fireEvent.keyDown( input, { keyCode: ENTER } ); + } ); expect( setState ).toHaveBeenCalledWith( { top: '7.5rem', @@ -288,8 +330,10 @@ describe( 'BoxControl', () => { render( ); const allUnitSelect = screen.getByLabelText( 'Select unit' ); - allUnitSelect.focus(); - fireEvent.change( allUnitSelect, { target: { value: 'rem' } } ); + act( () => { + allUnitSelect.focus(); + fireEvent.change( allUnitSelect, { target: { value: 'rem' } } ); + } ); expect( setState ).toHaveBeenCalledWith( { top: undefined, diff --git a/packages/components/src/button/test/index.js b/packages/components/src/button/test/index.js index b4dc89eaaf092b..7201a7d09148fc 100644 --- a/packages/components/src/button/test/index.js +++ b/packages/components/src/button/test/index.js @@ -2,11 +2,10 @@ * External dependencies */ import { shallow } from 'enzyme'; -import TestUtils from 'react-dom/test-utils'; /** * WordPress dependencies */ -import { createRef } from '@wordpress/element'; +import { createRef, createRoot } from '@wordpress/element'; import { plusCircle } from '@wordpress/icons'; /** @@ -245,10 +244,11 @@ describe( 'Button', () => { describe( 'ref forwarding', () => { it( 'should enable access to DOM element', () => { const ref = createRef(); + const container = document.createElement( 'div' ); + const root = createRoot( container ); + root.render( ); + jest.runAllTimers(); - TestUtils.renderIntoDocument( - - ); expect( ref.current.type ).toBe( 'button' ); } ); } ); diff --git a/packages/components/src/dimension-control/test/index.test.js b/packages/components/src/dimension-control/test/index.test.js index 21c59744bfcf0e..2b90e919d573e9 100644 --- a/packages/components/src/dimension-control/test/index.test.js +++ b/packages/components/src/dimension-control/test/index.test.js @@ -1,8 +1,10 @@ /** * External dependencies */ -import { shallow, mount } from 'enzyme'; +import { shallow } from 'enzyme'; import { uniqueId } from 'lodash'; +import { Simulate } from 'react-dom/test-utils'; +import { render } from '@testing-library/react'; /** * WordPress dependencies @@ -87,7 +89,7 @@ describe( 'DimensionControl', () => { describe( 'callbacks', () => { it( 'should call onChange handler with correct args on size change', () => { - const wrapper = mount( + const { container } = render( { /> ); - wrapper - .find( 'select' ) - .at( 0 ) - .simulate( 'change', { - target: { - value: 'small', - }, - } ); - - wrapper - .find( 'select' ) - .at( 0 ) - .simulate( 'change', { - target: { - value: 'medium', - }, - } ); + const select = container.querySelector( 'select' ); + Simulate.change( select, { + target: { + value: 'small', + }, + } ); + Simulate.change( select, { + target: { + value: 'medium', + }, + } ); expect( onChangeHandler ).toHaveBeenCalledTimes( 2 ); expect( onChangeHandler.mock.calls[ 0 ][ 0 ] ).toEqual( 'small' ); @@ -119,7 +115,7 @@ describe( 'DimensionControl', () => { } ); it( 'should call onChange handler with undefined value when no size is provided on change', () => { - const wrapper = mount( + const { container } = render( { /> ); - wrapper - .find( 'select' ) - .at( 0 ) - .simulate( 'change', { - target: { - value: '', // This happens when you select the "default"