diff --git a/package-lock.json b/package-lock.json
index ddbc4481580e3..51c497707eb38 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": {
@@ -31781,9 +31711,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 3bd45a39f8faa..8ddfe99083e0d 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/url-input/test/button.js b/packages/block-editor/src/components/url-input/test/button.js
index 04601dfea51c4..87414916780cc 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/button/test/index.js b/packages/components/src/button/test/index.js
index b4dc89eaaf092..7201a7d09148f 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/disabled/test/index.js b/packages/components/src/disabled/test/index.js
index 1369c737dcfd2..0333a98b4f063 100644
--- a/packages/components/src/disabled/test/index.js
+++ b/packages/components/src/disabled/test/index.js
@@ -1,12 +1,7 @@
-/**
- * External dependencies
- */
-import TestUtils from 'react-dom/test-utils';
-
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { createRoot } from '@wordpress/element';
/**
* Internal dependencies
@@ -65,30 +60,18 @@ describe( 'Disabled', () => {
);
- // This is needed because TestUtils does not accept a stateless component.
- class DisabledComponent extends Component {
- render() {
- const { children, isDisabled } = this.props;
-
- return { children } ;
- }
- }
-
it( 'will disable all fields', () => {
- const wrapper = TestUtils.renderIntoDocument(
-
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render(
+
-
+
);
+ jest.runAllTimers();
- const input = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'input'
- );
- const div = TestUtils.scryRenderedDOMComponentsWithTag(
- wrapper,
- 'div'
- )[ 1 ];
+ const input = container.querySelector( 'input' );
+ const div = container.querySelectorAll( 'div' )[ 1 ];
expect( input.hasAttribute( 'disabled' ) ).toBe( true );
expect( div.getAttribute( 'contenteditable' ) ).toBe( 'false' );
@@ -96,83 +79,30 @@ describe( 'Disabled', () => {
expect( div.hasAttribute( 'disabled' ) ).toBe( false );
} );
- it( 'should cleanly un-disable via reconciliation', () => {
- // If this test suddenly starts failing, it means React has become
- // smarter about reusing children into grandfather element when the
- // parent is dropped, so we'd need to find another way to restore
- // original form state.
- // Using state for this test for easier manipulation of the child props.
- class MaybeDisable extends Component {
- constructor() {
- super( ...arguments );
- this.state = { isDisabled: true };
- }
-
- render() {
- return this.state.isDisabled ? (
-
-
-
- ) : (
-
- );
- }
- }
-
- const wrapper = TestUtils.renderIntoDocument( );
- wrapper.setState( { isDisabled: false } );
-
- const input = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'input'
- );
- const div = TestUtils.findRenderedDOMComponentWithTag( wrapper, 'div' );
-
- expect( input.hasAttribute( 'disabled' ) ).toBe( false );
- expect( div.getAttribute( 'contenteditable' ) ).toBe( 'true' );
- expect( div.hasAttribute( 'tabindex' ) ).toBe( true );
- } );
-
it( 'will disable or enable descendant fields based on the isDisabled prop value', () => {
- class MaybeDisable extends Component {
- constructor() {
- super( ...arguments );
- this.state = { isDisabled: true };
- }
-
- render() {
- return (
-
-
-
- );
- }
+ function MaybeDisable( props ) {
+ return (
+
+
+
+ );
}
- const wrapper = TestUtils.renderIntoDocument( );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
- const input = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'input'
- );
- const div = TestUtils.scryRenderedDOMComponentsWithTag(
- wrapper,
- 'div'
- )[ 1 ];
+ const input = container.querySelector( 'input' );
+ const div = container.querySelectorAll( 'div' )[ 1 ];
expect( input.hasAttribute( 'disabled' ) ).toBe( true );
expect( div.getAttribute( 'contenteditable' ) ).toBe( 'false' );
+ root.render( );
+ jest.runAllTimers();
- wrapper.setState( { isDisabled: false } );
-
- const input2 = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'input'
- );
- const div2 = TestUtils.scryRenderedDOMComponentsWithTag(
- wrapper,
- 'div'
- )[ 0 ];
+ const input2 = container.querySelector( 'input' );
+ const div2 = container.querySelector( 'div' );
expect( input2.hasAttribute( 'disabled' ) ).toBe( false );
expect( div2.getAttribute( 'contenteditable' ) ).not.toBe( 'false' );
@@ -188,52 +118,50 @@ describe( 'Disabled', () => {
// https://github.com/jsdom/jsdom/issues/639
describe( 'Consumer', () => {
- class DisabledStatus extends Component {
- render() {
- return (
-
-
- { ( isDisabled ) =>
- isDisabled ? 'Disabled' : 'Not disabled'
- }
-
-
- );
- }
+ function DisabledStatus() {
+ return (
+
+
+ { ( isDisabled ) =>
+ isDisabled ? 'Disabled' : 'Not disabled'
+ }
+
+
+ );
}
test( "lets components know that they're disabled via context", () => {
- const wrapper = TestUtils.renderIntoDocument(
-
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render(
+
-
- );
- const wrapperElement = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'p'
+
);
+ jest.runAllTimers();
+ const wrapperElement = container.querySelector( 'p' );
expect( wrapperElement.textContent ).toBe( 'Disabled' );
} );
test( "lets components know that they're not disabled via context when isDisabled is false", () => {
- const wrapper = TestUtils.renderIntoDocument(
-
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render(
+
-
- );
- const wrapperElement = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'p'
+
);
+ jest.runAllTimers();
+ const wrapperElement = container.querySelector( 'p' );
expect( wrapperElement.textContent ).toBe( 'Not disabled' );
} );
test( "lets components know that they're not disabled via context", () => {
- const wrapper = TestUtils.renderIntoDocument( );
- const wrapperElement = TestUtils.findRenderedDOMComponentWithTag(
- wrapper,
- 'p'
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
+ const wrapperElement = container.querySelector( 'p' );
expect( wrapperElement.textContent ).toBe( 'Not disabled' );
} );
} );
diff --git a/packages/components/src/form-token-field/test/index.js b/packages/components/src/form-token-field/test/index.js
index 61fe4ccc2fea2..399a60d765eae 100644
--- a/packages/components/src/form-token-field/test/index.js
+++ b/packages/components/src/form-token-field/test/index.js
@@ -3,14 +3,17 @@
*/
import { filter, map } from 'lodash';
import TestUtils, { act } from 'react-dom/test-utils';
-import ReactDOM from 'react-dom';
+
+/**
+ * WordPress dependencies
+ */
+import { createRoot } from '@wordpress/element';
/**
* Internal dependencies
*/
import fixtures from './lib/fixtures';
import TokenFieldWrapper from './lib/token-field-wrapper';
-import TokenInput from '../token-input';
/**
* Module variables
@@ -32,7 +35,9 @@ const charCodes = {
};
describe( 'FormTokenField', () => {
- let wrapper, wrapperElement, textInputElement, textInputComponent;
+ let textInputElement;
+ let wrapperElement;
+ let wrapperRef;
function setText( text ) {
TestUtils.Simulate.change( textInputElement(), {
@@ -40,6 +45,7 @@ describe( 'FormTokenField', () => {
value: text,
},
} );
+ jest.runAllTimers();
}
function sendKeyDown( keyCode, shiftKey ) {
@@ -47,10 +53,12 @@ describe( 'FormTokenField', () => {
keyCode,
shiftKey: !! shiftKey,
} );
+ jest.runAllTimers();
}
function sendKeyPress( charCode ) {
TestUtils.Simulate.keyPress( wrapperElement(), { charCode } );
+ jest.runAllTimers();
}
function getTokensHTML() {
@@ -96,37 +104,38 @@ describe( 'FormTokenField', () => {
}
function setUp( props ) {
- wrapper = TestUtils.renderIntoDocument(
-
- );
- /* eslint-disable react/no-find-dom-node */
- wrapperElement = () => ReactDOM.findDOMNode( wrapper );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ wrapperRef = { current: null };
+ root.render( );
+ jest.runAllTimers();
+ wrapperElement = () => container.firstChild;
textInputElement = () =>
- TestUtils.findRenderedDOMComponentWithClass(
- wrapper,
- 'components-form-token-field__input'
- );
- textInputComponent = () =>
- TestUtils.findRenderedComponentWithType( wrapper, TokenInput );
- /* eslint-enable react/no-find-dom-node */
+ container.querySelector( '.components-form-token-field__input' );
TestUtils.Simulate.focus( textInputElement() );
+ jest.runAllTimers();
}
describe( 'displaying tokens', () => {
it( 'should render default tokens', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ jest.runAllTimers();
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should display tokens with escaped special characters properly', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokens: fixtures.specialTokens.textEscaped,
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getTokensHTML() ).toEqual(
fixtures.specialTokens.htmlEscaped
);
@@ -140,10 +149,11 @@ describe( 'FormTokenField', () => {
// worth testing, so we can be sure that token values with
// dangerous characters in them don't have these characters carried
// through unescaped to the HTML.
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokens: fixtures.specialTokens.textUnescaped,
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getTokensHTML() ).toEqual(
fixtures.specialTokens.htmlUnescaped
);
@@ -153,9 +163,10 @@ describe( 'FormTokenField', () => {
describe( 'suggestions', () => {
it( 'should not render suggestions unless we type at least two characters', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).toEqual( [] );
setText( 'th' );
expect( getSuggestionsText() ).toEqual(
@@ -165,25 +176,28 @@ describe( 'FormTokenField', () => {
it( 'should show suggestions when when input is empty if expandOnFocus is set to true', () => {
setUp( { __experimentalExpandOnFocus: true } );
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).not.toEqual( [] );
} );
it( 'should remove already added tags from suggestions', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokens: Object.freeze( [ 'of', 'and' ] ),
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).not.toEqual( getTokensHTML() );
} );
it( 'suggestions that begin with match are boosted', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
+ jest.runAllTimers();
setText( 'so' );
expect( getSuggestionsText() ).toEqual(
fixtures.matchingSuggestions.so
@@ -192,10 +206,11 @@ describe( 'FormTokenField', () => {
it( 'should match against the unescaped values of suggestions with special characters', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
isExpanded: true,
} );
+ jest.runAllTimers();
setText( '& S' );
expect( getSuggestionsText() ).toEqual(
fixtures.specialSuggestions.matchAmpersandUnescaped
@@ -204,10 +219,11 @@ describe( 'FormTokenField', () => {
it( 'should match against the unescaped values of suggestions with special characters (including spaces)', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
isExpanded: true,
} );
+ jest.runAllTimers();
setText( 's &' );
expect( getSuggestionsText() ).toEqual(
fixtures.specialSuggestions.matchAmpersandSequence
@@ -217,10 +233,11 @@ describe( 'FormTokenField', () => {
it( 'should not match against the escaped values of suggestions with special characters', () => {
setUp();
setText( 'amp' );
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).toEqual(
fixtures.specialSuggestions.matchAmpersandEscaped
);
@@ -228,9 +245,10 @@ describe( 'FormTokenField', () => {
it( 'should match suggestions even with trailing spaces', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
+ jest.runAllTimers();
setText( ' at ' );
expect( getSuggestionsText() ).toEqual(
fixtures.matchingSuggestions.at
@@ -239,9 +257,10 @@ describe( 'FormTokenField', () => {
it( 'should manage the selected suggestion based on both keyboard and mouse events', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
isExpanded: true,
} );
+ jest.runAllTimers();
setText( 'th' );
expect( getSuggestionsText() ).toEqual(
fixtures.matchingSuggestions.th
@@ -267,36 +286,41 @@ describe( 'FormTokenField', () => {
} );
TestUtils.Simulate.mouseEnter( hoverSuggestion );
+ jest.runAllTimers();
expect( getSelectedSuggestion() ).toEqual( [ 'wi', 'th' ] );
sendKeyDown( keyCodes.upArrow );
expect( getSelectedSuggestion() ).toEqual( [ 'th', 'is' ] );
sendKeyDown( keyCodes.upArrow );
expect( getSelectedSuggestion() ).toEqual( [ 'th', 'at' ] );
TestUtils.Simulate.click( hoverSuggestion );
+ jest.runAllTimers();
expect( getSelectedSuggestion() ).toBe( null );
expect( getTokensHTML() ).toEqual( [ 'foo', 'bar', 'with' ] );
} );
it( 'should re-render when suggestions prop has changed', () => {
setUp();
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: [],
isExpanded: true,
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).toEqual( [] );
setText( 'so' );
expect( getSuggestionsText() ).toEqual( [] );
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: fixtures.specialSuggestions.default,
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).toEqual(
fixtures.matchingSuggestions.so
);
- wrapper.setState( {
+ wrapperRef.current.setState( {
tokenSuggestions: [],
} );
+ jest.runAllTimers();
expect( getSuggestionsText() ).toEqual( [] );
} );
} );
@@ -305,57 +329,82 @@ describe( 'FormTokenField', () => {
it( 'should not allow adding blank tokens with Tab', () => {
setUp();
sendKeyDown( keyCodes.tab );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should not allow adding whitespace tokens with Tab', () => {
setUp();
setText( ' ' );
sendKeyDown( keyCodes.tab );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should add a token when Enter pressed', () => {
setUp();
setText( 'baz' );
sendKeyDown( keyCodes.enter );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar', 'baz' ] );
- const textNode = textInputComponent();
- expect( textNode.props.value ).toBe( '' );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ 'baz',
+ ] );
} );
it( 'should not allow adding blank tokens with Enter', () => {
setUp();
sendKeyDown( keyCodes.enter );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should not allow adding whitespace tokens with Enter', () => {
setUp();
setText( ' ' );
sendKeyDown( keyCodes.enter );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should not allow adding whitespace tokens with comma', () => {
setUp();
setText( ' ' );
sendKeyPress( charCodes.comma );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
it( 'should add a token when comma pressed', () => {
setUp();
setText( 'baz' );
sendKeyPress( charCodes.comma );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar', 'baz' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ 'baz',
+ ] );
} );
it( 'should trim token values when adding', () => {
setUp();
setText( ' baz ' );
sendKeyDown( keyCodes.enter );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar', 'baz' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ 'baz',
+ ] );
} );
it( "should not add values that don't pass the validation", () => {
@@ -364,7 +413,10 @@ describe( 'FormTokenField', () => {
} );
setText( 'baz' );
sendKeyDown( keyCodes.enter );
- expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
+ expect( wrapperRef.current.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ ] );
} );
} );
@@ -375,7 +427,8 @@ describe( 'FormTokenField', () => {
'.components-form-token-field__remove-token'
).firstChild;
TestUtils.Simulate.click( forClickNode );
- expect( wrapper.state.tokens ).toEqual( [ 'bar' ] );
+ jest.runAllTimers();
+ expect( wrapperRef.current.state.tokens ).toEqual( [ 'bar' ] );
} );
} );
} );
diff --git a/packages/components/src/higher-order/with-filters/test/index.js b/packages/components/src/higher-order/with-filters/test/index.js
index 46360927347b0..c7630736d1834 100644
--- a/packages/components/src/higher-order/with-filters/test/index.js
+++ b/packages/components/src/higher-order/with-filters/test/index.js
@@ -2,50 +2,24 @@
* External dependencies
*/
import { shallow } from 'enzyme';
-import TestUtils from 'react-dom/test-utils';
-import ReactDOM from 'react-dom';
/**
* WordPress dependencies
*/
import { addFilter, removeAllFilters, removeFilter } from '@wordpress/hooks';
-import { Component } from '@wordpress/element';
+import { createRoot } from '@wordpress/element';
/**
* Internal dependencies
*/
import withFilters from '..';
-const assertExpectedHtml = ( wrapper, expectedHTML ) => {
- // eslint-disable-next-line react/no-find-dom-node
- const element = ReactDOM.findDOMNode( wrapper );
- expect( element.outerHTML ).toBe( expectedHTML );
-};
-
-// This is needed because TestUtils does not accept a stateless component.
-// anything run through a HOC ends up as a stateless component.
-const getTestComponent = ( WrappedComponent ) => {
- class TestComponent extends Component {
- render() {
- return ;
- }
- }
- return ;
-};
-
describe( 'withFilters', () => {
- let shallowWrapper, wrapper;
-
+ let shallowWrapper;
const hookName = 'EnhancedComponent';
const MyComponent = () => My component
;
afterEach( () => {
- if ( wrapper ) {
- ReactDOM.unmountComponentAtNode(
- // eslint-disable-next-line react/no-find-dom-node
- ReactDOM.findDOMNode( wrapper ).parentNode
- );
- }
if ( shallowWrapper ) {
shallowWrapper.unmount();
}
@@ -114,15 +88,15 @@ describe( 'withFilters', () => {
);
const EnhancedComponent = withFilters( hookName )( SpiedComponent );
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent )
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
jest.runAllTimers();
expect( spy ).toHaveBeenCalledTimes( 1 );
- assertExpectedHtml(
- wrapper,
+
+ expect( container.innerHTML ).toBe(
'Spied component
'
);
} );
@@ -135,9 +109,9 @@ describe( 'withFilters', () => {
};
const EnhancedComponent = withFilters( hookName )( SpiedComponent );
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent )
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
spy.mockClear();
addFilter(
@@ -152,8 +126,7 @@ describe( 'withFilters', () => {
jest.runAllTimers();
expect( spy ).toHaveBeenCalledTimes( 1 );
- assertExpectedHtml(
- wrapper,
+ expect( container.innerHTML ).toBe(
'Spied component
'
);
} );
@@ -165,9 +138,9 @@ describe( 'withFilters', () => {
return Spied component
;
};
const EnhancedComponent = withFilters( hookName )( SpiedComponent );
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent )
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
spy.mockClear();
@@ -192,8 +165,7 @@ describe( 'withFilters', () => {
jest.runAllTimers();
expect( spy ).toHaveBeenCalledTimes( 1 );
- assertExpectedHtml(
- wrapper,
+ expect( container.innerHTML ).toBe(
''
);
} );
@@ -205,9 +177,9 @@ describe( 'withFilters', () => {
return Spied component
;
};
const EnhancedComponent = withFilters( hookName )( SpiedComponent );
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent )
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
spy.mockClear();
addFilter(
@@ -225,7 +197,7 @@ describe( 'withFilters', () => {
jest.runAllTimers();
expect( spy ).toHaveBeenCalledTimes( 2 );
- assertExpectedHtml( wrapper, 'Spied component
' );
+ expect( container.innerHTML ).toBe( 'Spied component
' );
} );
it( 'should re-render both components once each when one filter added', () => {
@@ -241,9 +213,9 @@ describe( 'withFilters', () => {
);
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( CombinedComponents )
- );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
spy.mockClear();
addFilter(
@@ -258,8 +230,7 @@ describe( 'withFilters', () => {
jest.runAllTimers();
expect( spy ).toHaveBeenCalledTimes( 2 );
- assertExpectedHtml(
- wrapper,
+ expect( container.innerHTML ).toBe(
'Spied component
Spied component
'
);
} );
diff --git a/packages/components/src/higher-order/with-focus-outside/test/index.js b/packages/components/src/higher-order/with-focus-outside/test/index.js
index f310506f2d9dc..99f084d7017fa 100644
--- a/packages/components/src/higher-order/with-focus-outside/test/index.js
+++ b/packages/components/src/higher-order/with-focus-outside/test/index.js
@@ -6,18 +6,17 @@ import TestUtils from 'react-dom/test-utils';
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { Component, createRoot } from '@wordpress/element';
/**
* Internal dependencies
*/
import withFocusOutside from '../';
-import ReactDOM from 'react-dom';
-let wrapper, onFocusOutside;
+let onFocusOutside;
describe( 'withFocusOutside', () => {
- let origHasFocus;
+ let origHasFocus, container, root;
const EnhancedComponent = withFocusOutside(
class extends Component {
@@ -36,22 +35,8 @@ describe( 'withFocusOutside', () => {
}
);
- // This is needed because TestUtils does not accept a stateless component.
- // anything run through a HOC ends up as a stateless component.
- const getTestComponent = ( WrappedComponent, props ) => {
- class TestComponent extends Component {
- render() {
- return ;
- }
- }
- return ;
- };
-
const simulateEvent = ( event, index = 0 ) => {
- const element = TestUtils.scryRenderedDOMComponentsWithTag(
- wrapper,
- 'input'
- );
+ const element = container.querySelectorAll( 'input' );
TestUtils.Simulate[ event ]( element[ index ] );
};
@@ -62,9 +47,11 @@ describe( 'withFocusOutside', () => {
document.hasFocus = () => true;
onFocusOutside = jest.fn();
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent, { onFocusOutside } )
- );
+
+ container = document.createElement( 'div' );
+ root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
} );
afterEach( () => {
@@ -75,7 +62,6 @@ describe( 'withFocusOutside', () => {
simulateEvent( 'focus' );
simulateEvent( 'blur' );
simulateEvent( 'focus', 1 );
-
jest.runAllTimers();
expect( onFocusOutside ).not.toHaveBeenCalled();
@@ -85,21 +71,19 @@ describe( 'withFocusOutside', () => {
simulateEvent( 'focus' );
simulateEvent( 'mouseDown', 1 );
simulateEvent( 'blur' );
+ jest.runAllTimers();
// In most browsers, the input at index 1 would receive a focus event
// at this point, but this is not guaranteed, which is the intention of
// the normalization behavior tested here.
simulateEvent( 'mouseUp', 1 );
- jest.runAllTimers();
-
expect( onFocusOutside ).not.toHaveBeenCalled();
} );
it( 'should call handler if focus doesn’t shift to element within component', () => {
simulateEvent( 'focus' );
simulateEvent( 'blur' );
-
jest.runAllTimers();
expect( onFocusOutside ).toHaveBeenCalled();
@@ -112,7 +96,6 @@ describe( 'withFocusOutside', () => {
simulateEvent( 'focus' );
simulateEvent( 'blur' );
-
jest.runAllTimers();
expect( onFocusOutside ).not.toHaveBeenCalled();
@@ -121,13 +104,8 @@ describe( 'withFocusOutside', () => {
it( 'should cancel check when unmounting while queued', () => {
simulateEvent( 'focus' );
simulateEvent( 'input' );
-
- ReactDOM.unmountComponentAtNode(
- // eslint-disable-next-line react/no-find-dom-node
- ReactDOM.findDOMNode( wrapper ).parentNode
- );
-
jest.runAllTimers();
+ root.unmount();
expect( onFocusOutside ).not.toHaveBeenCalled();
} );
diff --git a/packages/components/src/scroll-lock/test/index.js b/packages/components/src/scroll-lock/test/index.js
index 4579806908c97..d6ea8eb0a18b7 100644
--- a/packages/components/src/scroll-lock/test/index.js
+++ b/packages/components/src/scroll-lock/test/index.js
@@ -1,7 +1,7 @@
/**
- * External dependencies
+ * WordPress dependencies
*/
-import { mount } from 'enzyme';
+import { createRoot } from '@wordpress/element';
/**
* Internal dependencies
@@ -12,7 +12,7 @@ describe( 'scroll-lock', () => {
const lockingClassName = 'lockscroll';
// Use a separate document to reduce the risk of test side-effects.
- let wrapper = null;
+ let root = null;
function expectLocked( locked ) {
expect(
@@ -25,22 +25,28 @@ describe( 'scroll-lock', () => {
}
afterEach( () => {
- if ( wrapper && wrapper.length ) {
- wrapper.unmount();
- wrapper = null;
+ if ( root ) {
+ root.unmount();
}
} );
it( 'locks when mounted', () => {
expectLocked( false );
- wrapper = mount( );
+ const container = document.createElement( 'div' );
+ root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
expectLocked( true );
} );
it( 'unlocks when unmounted', () => {
- wrapper = mount( );
+ const container = document.createElement( 'div' );
+ root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
expectLocked( true );
- wrapper.unmount();
+ root.unmount();
+ jest.runAllTimers();
// Running cleanup functions now works asynchronously. the unofficial
// enzyme adapter for react 17 we're currently using does not account
diff --git a/packages/components/src/tab-panel/test/index.js b/packages/components/src/tab-panel/test/index.js
index b3d9bd0477685..319cf168b768e 100644
--- a/packages/components/src/tab-panel/test/index.js
+++ b/packages/components/src/tab-panel/test/index.js
@@ -11,36 +11,12 @@ import TabPanel from '../';
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { createRoot } from '@wordpress/element';
describe( 'TabPanel', () => {
- const getElementByClass = ( wrapper, className ) => {
- return TestUtils.findRenderedDOMComponentWithClass(
- wrapper,
- className
- );
- };
-
- const getElementsByClass = ( wrapper, className ) => {
- return TestUtils.scryRenderedDOMComponentsWithClass(
- wrapper,
- className
- );
- };
-
const elementClick = ( element ) => {
TestUtils.Simulate.click( element );
- };
-
- // This is needed because TestUtils does not accept a stateless component.
- // anything run through a HOC ends up as a stateless component.
- const getTestComponent = ( WrappedComponent, props ) => {
- class TestComponent extends Component {
- render() {
- return ;
- }
- }
- return ;
+ jest.runAllTimers();
};
describe( 'basic rendering', () => {
@@ -74,31 +50,26 @@ describe( 'TabPanel', () => {
},
};
- let wrapper;
- TestUtils.act( () => {
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( TabPanel, props )
- );
- } );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
- const alphaTab = getElementByClass( wrapper, 'alpha' );
- const betaTab = getElementByClass( wrapper, 'beta' );
- const gammaTab = getElementByClass( wrapper, 'gamma' );
+ const alphaTab = container.querySelector( '.alpha' );
+ const betaTab = container.querySelector( '.beta' );
+ const gammaTab = container.querySelector( '.gamma' );
const getAlphaViews = () =>
- getElementsByClass( wrapper, 'alpha-view' );
+ container.querySelectorAll( '.alpha-view' );
const getBetaViews = () =>
- getElementsByClass( wrapper, 'beta-view' );
+ container.querySelectorAll( '.beta-view' );
const getGammaViews = () =>
- getElementsByClass( wrapper, 'gamma-view' );
+ container.querySelectorAll( '.gamma-view' );
- const getActiveTab = () =>
- getElementByClass( wrapper, 'active-tab' );
+ const getActiveTab = () => container.querySelector( '.active-tab' );
const getActiveView = () =>
- getElementByClass(
- wrapper,
- 'components-tab-panel__tab-content'
- ).firstChild.textContent;
+ container.querySelector( '.components-tab-panel__tab-content' )
+ .firstChild.textContent;
expect( getActiveTab().innerHTML ).toBe( 'Alpha' );
expect( getAlphaViews() ).toHaveLength( 1 );
@@ -166,14 +137,12 @@ describe( 'TabPanel', () => {
},
};
- let wrapper;
- TestUtils.act( () => {
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( TabPanel, props )
- );
- } );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
- const getActiveTab = () => getElementByClass( wrapper, 'active-tab' );
+ const getActiveTab = () => container.querySelector( '.active-tab' );
expect( getActiveTab().innerHTML ).toBe( 'Beta' );
} );
} );
diff --git a/packages/components/src/text-highlight/test/index.js b/packages/components/src/text-highlight/test/index.js
index 342a2e8595052..89e758593afbf 100644
--- a/packages/components/src/text-highlight/test/index.js
+++ b/packages/components/src/text-highlight/test/index.js
@@ -1,25 +1,36 @@
/**
* External dependencies
*/
-import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
+/**
+ * WordPress dependencies
+ */
+import { createRoot } from '@wordpress/element';
+
/**
* Internal dependencies
*/
import TextHighlight from '../index';
let container = null;
+let root = null;
beforeEach( () => {
// Setup a DOM element as a render target.
container = document.createElement( 'div' );
document.body.appendChild( container );
+ root = createRoot( container );
+
+ // This is needed due to some kind of bug in JSDOM that conflicts with React 18.
+ global.IS_REACT_ACT_ENVIRONMENT = true;
} );
afterEach( () => {
// Cleanup on exiting.
- unmountComponentAtNode( container );
+ act( () => {
+ root.unmount();
+ } );
container.remove();
container = null;
} );
@@ -32,12 +43,11 @@ describe( 'Basic rendering', () => {
'should highlight the singular occurance of the text "%s" in the text if it exists',
( highlight ) => {
act( () => {
- render(
+ root.render(
,
- container
+ />
);
} );
@@ -57,9 +67,8 @@ describe( 'Basic rendering', () => {
const highlight = 'edit';
act( () => {
- render(
- ,
- container
+ root.render(
+
);
} );
@@ -80,9 +89,8 @@ describe( 'Basic rendering', () => {
const highlight = 'The'; // Note this occurs in both sentance of lowercase forms.
act( () => {
- render(
- ,
- container
+ root.render(
+
);
} );
@@ -105,9 +113,8 @@ describe( 'Basic rendering', () => {
const highlight = 'Antidisestablishmentarianism';
act( () => {
- render(
- ,
- container
+ root.render(
+
);
} );
diff --git a/packages/compose/src/higher-order/pure/test/index.js b/packages/compose/src/higher-order/pure/test/index.js
index b3bcf24c4e5bc..8facc2c4ca15d 100644
--- a/packages/compose/src/higher-order/pure/test/index.js
+++ b/packages/compose/src/higher-order/pure/test/index.js
@@ -1,12 +1,7 @@
-/**
- * External dependencies
- */
-import { mount } from 'enzyme';
-
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { Component, createRoot } from '@wordpress/element';
/**
* Internal dependencies
@@ -19,15 +14,20 @@ describe( 'pure', () => {
const MyComp = pure( () => {
return { ++i }
;
} );
- const wrapper = mount( );
- wrapper.update(); // Updating with same props doesn't rerender.
- expect( wrapper.html() ).toBe( '1
' );
- wrapper.setProps( { prop: 'a' } ); // New prop should trigger a rerender.
- expect( wrapper.html() ).toBe( '2
' );
- wrapper.setProps( { prop: 'a' } ); // Keeping the same prop value should not rerender.
- expect( wrapper.html() ).toBe( '2
' );
- wrapper.setProps( { prop: 'b' } ); // Changing the prop value should rerender.
- expect( wrapper.html() ).toBe( '3
' );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '1
' );
+ root.render( ); // New prop should trigger a rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '2
' );
+ root.render( ); // Keeping the same prop value should not rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '2
' );
+ root.render( ); // Changing the prop value should rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '3
' );
} );
it( 'class component should rerender if the props or state change', () => {
@@ -43,18 +43,26 @@ describe( 'pure', () => {
}
}
);
- const wrapper = mount( );
- wrapper.update(); // Updating with same props doesn't rerender.
- expect( wrapper.html() ).toBe( '1
' );
- wrapper.setProps( { prop: 'a' } ); // New prop should trigger a rerender.
- expect( wrapper.html() ).toBe( '2
' );
- wrapper.setProps( { prop: 'a' } ); // Keeping the same prop value should not rerender.
- expect( wrapper.html() ).toBe( '2
' );
- wrapper.setProps( { prop: 'b' } ); // Changing the prop value should rerender.
- expect( wrapper.html() ).toBe( '3
' );
- wrapper.setState( { state: 'a' } ); // New state value should trigger a rerender.
- expect( wrapper.html() ).toBe( '4
' );
- wrapper.setState( { state: 'a' } ); // Keeping the same state value should not trigger a rerender.
- expect( wrapper.html() ).toBe( '4
' );
+ const ref = { current: null };
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '1
' );
+ root.render( ); // New prop should trigger a rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '2
' );
+ root.render( ); // Keeping the same prop value should not rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '2
' );
+ root.render( ); // Changing the prop value should rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '3
' );
+ ref.current.setState( { state: 'a' } ); // New state value should trigger a rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '4
' );
+ ref.current.setState( { state: 'a' } ); // Keeping the same state value should not trigger a rerender.
+ jest.runAllTimers();
+ expect( container.innerHTML ).toBe( '4
' );
} );
} );
diff --git a/packages/compose/src/higher-order/with-state/test/index.js b/packages/compose/src/higher-order/with-state/test/index.js
index 16728b09d21a1..9d1cf3fc6a3f2 100644
--- a/packages/compose/src/higher-order/with-state/test/index.js
+++ b/packages/compose/src/higher-order/with-state/test/index.js
@@ -11,18 +11,7 @@ import withState from '../';
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
-
-// This is needed because TestUtils does not accept a stateless component.
-// anything run through a HOC ends up as a stateless component.
-const getTestComponent = ( WrappedComponent ) => {
- class TestComponent extends Component {
- render() {
- return ;
- }
- }
- return ;
-};
+import { createRoot } from '@wordpress/element';
describe( 'withState', () => {
it( 'should pass initial state and allow updates', () => {
@@ -38,16 +27,16 @@ describe( 'withState', () => {
) );
- const wrapper = TestUtils.renderIntoDocument(
- getTestComponent( EnhancedComponent )
- );
-
- const buttonElement = () =>
- TestUtils.findRenderedDOMComponentWithTag( wrapper, 'button' );
+ const container = document.createElement( 'div' );
+ const root = createRoot( container );
+ root.render( );
+ jest.runAllTimers();
+ const buttonElement = () => container.querySelector( 'button' );
expect( console ).toHaveWarned();
expect( buttonElement().outerHTML ).toBe( '0 ' );
TestUtils.Simulate.click( buttonElement() );
+ jest.runAllTimers();
expect( buttonElement().outerHTML ).toBe( '1 ' );
} );
} );
diff --git a/packages/compose/src/hooks/use-focus-outside/test/index.js b/packages/compose/src/hooks/use-focus-outside/test/index.js
index 23c7c36cf43e3..205327eb5e8e4 100644
--- a/packages/compose/src/hooks/use-focus-outside/test/index.js
+++ b/packages/compose/src/hooks/use-focus-outside/test/index.js
@@ -6,15 +6,14 @@ import TestUtils from 'react-dom/test-utils';
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { createRoot } from '@wordpress/element';
/**
* Internal dependencies
*/
import useFocusOutside from '../';
-import ReactDOM from 'react-dom';
-let wrapper, onFocusOutside;
+let container, onFocusOutside, root;
describe( 'useFocusOutside', () => {
let origHasFocus;
@@ -26,22 +25,8 @@ describe( 'useFocusOutside', () => {
);
- // This is needed because TestUtils does not accept a stateless component.
- // anything run through a HOC ends up as a stateless component.
- const getTestComponent = ( WrappedComponent, props ) => {
- class TestComponent extends Component {
- render() {
- return ;
- }
- }
- return ;
- };
-
const simulateEvent = ( event, index = 0 ) => {
- const element = TestUtils.scryRenderedDOMComponentsWithTag(
- wrapper,
- 'input'
- );
+ const element = container.querySelectorAll( 'input' );
TestUtils.Simulate[ event ]( element[ index ] );
};
@@ -52,9 +37,13 @@ describe( 'useFocusOutside', () => {
document.hasFocus = () => true;
onFocusOutside = jest.fn();
- wrapper = TestUtils.renderIntoDocument(
- getTestComponent( FocusOutsideComponent, { onFocusOutside } )
+
+ container = document.createElement( 'div' );
+ root = createRoot( container );
+ root.render(
+
);
+ jest.runAllTimers();
} );
afterEach( () => {
@@ -112,11 +101,7 @@ describe( 'useFocusOutside', () => {
simulateEvent( 'focus' );
simulateEvent( 'input' );
- ReactDOM.unmountComponentAtNode(
- // eslint-disable-next-line react/no-find-dom-node
- ReactDOM.findDOMNode( wrapper ).parentNode
- );
-
+ root.unmount();
jest.runAllTimers();
expect( onFocusOutside ).not.toHaveBeenCalled();
diff --git a/packages/compose/src/hooks/use-merge-refs/test/index.js b/packages/compose/src/hooks/use-merge-refs/test/index.js
index 6893148462583..24347316b74d7 100644
--- a/packages/compose/src/hooks/use-merge-refs/test/index.js
+++ b/packages/compose/src/hooks/use-merge-refs/test/index.js
@@ -1,12 +1,7 @@
-/**
- * External dependencies
- */
-import ReactDOM from 'react-dom';
-
/**
* WordPress dependencies
*/
-import { useCallback } from '@wordpress/element';
+import { useCallback, createRoot } from '@wordpress/element';
/**
* Internal dependencies
@@ -80,8 +75,9 @@ describe( 'useMergeRefs', () => {
it( 'should work', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
@@ -90,7 +86,8 @@ describe( 'useMergeRefs', () => {
[ [ originalElement ], [ originalElement ] ],
] );
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
// Render 2: the new callback functions should not be called! There has
// been no dependency change.
@@ -99,7 +96,8 @@ describe( 'useMergeRefs', () => {
[ [], [] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: the initial callback functions should receive null.
expect( renderCallback.history ).toEqual( [
@@ -113,12 +111,14 @@ describe( 'useMergeRefs', () => {
it( 'should work for node change', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
const newElement = rootElement.firstElementChild;
@@ -135,7 +135,8 @@ describe( 'useMergeRefs', () => {
[ [], [] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: the initial callback functions should receive null.
expect( renderCallback.history ).toEqual( [
@@ -149,8 +150,9 @@ describe( 'useMergeRefs', () => {
it( 'should work with dependencies', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
@@ -158,7 +160,8 @@ describe( 'useMergeRefs', () => {
[ [ originalElement ], [ originalElement ] ],
] );
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
// After a second render with a dependency change, expect the inital
// callback function to be called with null and the new callback
@@ -169,7 +172,8 @@ describe( 'useMergeRefs', () => {
[ [], [ originalElement ] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: current callback functions should be called with null.
expect( renderCallback.history ).toEqual( [
@@ -183,8 +187,9 @@ describe( 'useMergeRefs', () => {
it( 'should simultaneously update node and dependencies', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
@@ -192,10 +197,8 @@ describe( 'useMergeRefs', () => {
[ [ originalElement ], [ originalElement ] ],
] );
- ReactDOM.render(
- ,
- rootElement
- );
+ root.render( );
+ jest.runAllTimers();
const newElement = rootElement.firstElementChild;
@@ -212,7 +215,8 @@ describe( 'useMergeRefs', () => {
[ [], [ newElement ] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: current callback functions should be called with null.
expect( renderCallback.history ).toEqual( [
@@ -226,12 +230,14 @@ describe( 'useMergeRefs', () => {
it( 'should work for dependency change after node change', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
const newElement = rootElement.firstElementChild;
@@ -248,10 +254,8 @@ describe( 'useMergeRefs', () => {
[ [], [] ],
] );
- ReactDOM.render(
- ,
- rootElement
- );
+ root.render( );
+ jest.runAllTimers();
// After a third render with a dependency change, expect the inital
// callback function to be called with null and the new callback
@@ -266,7 +270,8 @@ describe( 'useMergeRefs', () => {
[ [], [ newElement ] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: current callback functions should be called with null.
expect( renderCallback.history ).toEqual( [
@@ -281,8 +286,9 @@ describe( 'useMergeRefs', () => {
it( 'should allow disabling a ref', () => {
const rootElement = document.getElementById( 'root' );
-
- ReactDOM.render( , rootElement );
+ const root = createRoot( rootElement );
+ root.render( );
+ jest.runAllTimers();
const originalElement = rootElement.firstElementChild;
@@ -291,7 +297,8 @@ describe( 'useMergeRefs', () => {
[ [], [ originalElement ] ],
] );
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
// Render 2: ref 1 should be enabled and receive the ref. Note that the
// callback hasn't changed, so the original callback function will be
@@ -301,7 +308,8 @@ describe( 'useMergeRefs', () => {
[ [], [] ],
] );
- ReactDOM.render( , rootElement );
+ root.render( );
+ jest.runAllTimers();
// Render 3: ref 1 should again be disabled. Ref 2 to should receive a
// ref with the new callback function because the count has been
@@ -315,7 +323,8 @@ describe( 'useMergeRefs', () => {
[ [], [ originalElement ] ],
] );
- ReactDOM.render( null, rootElement );
+ root.render( null );
+ jest.runAllTimers();
// Unmount: current callback functions should receive null.
expect( renderCallback.history ).toEqual( [
diff --git a/packages/element/src/react-platform.js b/packages/element/src/react-platform.js
index 2c03e96b32107..08fb75b59abc3 100644
--- a/packages/element/src/react-platform.js
+++ b/packages/element/src/react-platform.js
@@ -6,8 +6,8 @@ import {
findDOMNode,
render,
unmountComponentAtNode,
- createRoot,
} from 'react-dom';
+import { createRoot } from 'react-dom/client';
/**
* Creates a portal into which a component can be rendered.
diff --git a/packages/element/src/react.js b/packages/element/src/react.js
index 48ff95a4ce0e7..a658228b9a728 100644
--- a/packages/element/src/react.js
+++ b/packages/element/src/react.js
@@ -26,7 +26,6 @@ import {
useDebugValue,
lazy,
Suspense,
- createRoot,
} from 'react';
import { isString } from 'lodash';