Commit 29810a89eea for woocommerce
commit 29810a89eeaf759e9672571075cb7486bef356c1
Author: Marin Atanasov <8436925+tyxla@users.noreply.github.com>
Date: Thu Jul 9 16:21:36 2026 +0300
Migrate tests off react-test-renderer to @testing-library (#66436)
* Migrate tests off react-test-renderer to @testing-library
* Add changelog entry for react-test-renderer removal
diff --git a/.syncpackrc b/.syncpackrc
index ad044294492..860beab38c4 100644
--- a/.syncpackrc
+++ b/.syncpackrc
@@ -119,7 +119,6 @@
"dependencies": [
"react",
"react-dom",
- "react-test-renderer",
"@types/react-dom",
"@types/react"
],
diff --git a/plugins/woocommerce/changelog/dev-remove-react-test-renderer b/plugins/woocommerce/changelog/dev-remove-react-test-renderer
new file mode 100644
index 00000000000..66271b83a89
--- /dev/null
+++ b/plugins/woocommerce/changelog/dev-remove-react-test-renderer
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Migrate unit tests from react-test-renderer to the @testing-library family and drop the react-test-renderer dependency.
diff --git a/plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/test/use-import-status.test.ts b/plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/test/use-import-status.test.ts
index c9353b43d56..aef33dc20f4 100644
--- a/plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/test/use-import-status.test.ts
+++ b/plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/test/use-import-status.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
import apiFetch from '@wordpress/api-fetch';
/**
diff --git a/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginAvailability.test.ts b/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginAvailability.test.ts
index a6f81d4472c..d745fca55ce 100644
--- a/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginAvailability.test.ts
+++ b/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginAvailability.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
import apiFetch from '@wordpress/api-fetch';
/**
diff --git a/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginToken.test.ts b/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginToken.test.ts
index cfaaf23e6f2..ca5757a7fd4 100644
--- a/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginToken.test.ts
+++ b/plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/test/useQRLoginToken.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
import apiFetch from '@wordpress/api-fetch';
/**
diff --git a/plugins/woocommerce/client/admin/client/hooks/test/use-endpoint-dismiss.test.ts b/plugins/woocommerce/client/admin/client/hooks/test/use-endpoint-dismiss.test.ts
index a932f9c0199..f112e298fa2 100644
--- a/plugins/woocommerce/client/admin/client/hooks/test/use-endpoint-dismiss.test.ts
+++ b/plugins/woocommerce/client/admin/client/hooks/test/use-endpoint-dismiss.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
import apiFetch from '@wordpress/api-fetch';
/**
diff --git a/plugins/woocommerce/client/admin/client/hooks/test/use-option-dismiss.test.ts b/plugins/woocommerce/client/admin/client/hooks/test/use-option-dismiss.test.ts
index d1a1062c239..59338abe850 100644
--- a/plugins/woocommerce/client/admin/client/hooks/test/use-option-dismiss.test.ts
+++ b/plugins/woocommerce/client/admin/client/hooks/test/use-option-dismiss.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
import { useDispatch, useSelect } from '@wordpress/data';
/**
diff --git a/plugins/woocommerce/client/admin/client/hooks/test/use-tasklists-state.test.ts b/plugins/woocommerce/client/admin/client/hooks/test/use-tasklists-state.test.ts
index a0f26152d57..a3db1ca7a9d 100644
--- a/plugins/woocommerce/client/admin/client/hooks/test/use-tasklists-state.test.ts
+++ b/plugins/woocommerce/client/admin/client/hooks/test/use-tasklists-state.test.ts
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook } from '@testing-library/react-hooks';
+import { renderHook } from '@testing-library/react-hooks/dom';
import { useSelect } from '@wordpress/data';
import { TaskType } from '@woocommerce/data';
diff --git a/plugins/woocommerce/client/admin/client/utils/react-hooks/test/use-network-status.test.tsx b/plugins/woocommerce/client/admin/client/utils/react-hooks/test/use-network-status.test.tsx
index 324386b30c1..2d42a7600fd 100644
--- a/plugins/woocommerce/client/admin/client/utils/react-hooks/test/use-network-status.test.tsx
+++ b/plugins/woocommerce/client/admin/client/utils/react-hooks/test/use-network-status.test.tsx
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { renderHook, act } from '@testing-library/react-hooks';
+import { renderHook, act } from '@testing-library/react-hooks/dom';
/**
* Internal dependencies
diff --git a/plugins/woocommerce/client/admin/package.json b/plugins/woocommerce/client/admin/package.json
index 3c033df7386..4fb15dab12f 100644
--- a/plugins/woocommerce/client/admin/package.json
+++ b/plugins/woocommerce/client/admin/package.json
@@ -206,7 +206,6 @@
"prop-types": "^15.8.1",
"raw-loader": "4.0.x",
"react-refresh": "^0.14.0",
- "react-test-renderer": "18.3.x",
"readline-sync": "^1.4.10",
"replace": "^1.2.2",
"rimraf": "5.0.5",
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/__snapshots__/index.js.snap b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/__snapshots__/index.js.snap
index 4181ab5b446..5a8b4636777 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/__snapshots__/index.js.snap
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/__snapshots__/index.js.snap
@@ -1,48 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ProductName should merge classes and props 1`] = `
-<a
- className="wc-block-components-product-name lorem-ipsum"
- dangerouslySetInnerHTML={
- {
- "__html": "Test product",
- }
- }
- href="/"
-/>
+<div>
+ <a
+ class="wc-block-components-product-name lorem-ipsum"
+ href="/"
+ >
+ Test product
+ </a>
+</div>
`;
exports[`ProductName should not render a link if disabled is true 1`] = `
-<span
- className="wc-block-components-product-name"
- dangerouslySetInnerHTML={
- {
- "__html": "Test product",
- }
- }
-/>
+<div>
+ <span
+ class="wc-block-components-product-name"
+ >
+ Test product
+ </span>
+</div>
`;
exports[`ProductName should render a link if disabled is false 1`] = `
-<a
- className="wc-block-components-product-name"
- dangerouslySetInnerHTML={
- {
- "__html": "Test product",
- }
- }
- href="/"
-/>
+<div>
+ <a
+ class="wc-block-components-product-name"
+ href="/"
+ >
+ Test product
+ </a>
+</div>
`;
exports[`ProductName should render a link if disabled is not defined 1`] = `
-<a
- className="wc-block-components-product-name"
- dangerouslySetInnerHTML={
- {
- "__html": "Test product",
- }
- }
- href="/"
-/>
+<div>
+ <a
+ class="wc-block-components-product-name"
+ href="/"
+ >
+ Test product
+ </a>
+</div>
`;
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/index.js b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/index.js
index 890a7aafbe9..bf1d501d0ac 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/index.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render } from '@testing-library/react';
/**
* Internal dependencies
@@ -10,31 +10,31 @@ import ProductName from '..';
describe( 'ProductName', () => {
test( 'should not render a link if disabled is true', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductName disabled={ true } name="Test product" permalink="/" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render a link if disabled is false', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductName disabled={ false } name="Test product" permalink="/" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render a link if disabled is not defined', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductName name="Test product" permalink="/" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should merge classes and props', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductName
className="lorem-ipsum"
name="Test product"
@@ -43,6 +43,6 @@ describe( 'ProductName', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/__snapshots__/index.js.snap b/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/__snapshots__/index.js.snap
index 27d4a1312fa..983dcc38272 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/__snapshots__/index.js.snap
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/__snapshots__/index.js.snap
@@ -1,61 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ProductPrice should apply the format if one is provided 1`] = `
-<span
- className="price wc-block-components-product-price"
->
- pre price
+<div>
<span
- className="screen-reader-text"
+ class="price wc-block-components-product-price"
>
- Previous price:
+ pre price
+ <span
+ class="screen-reader-text"
+ >
+ Previous price:
+ </span>
+ <del
+ class="wc-block-components-product-price__regular"
+ translate="no"
+ >
+ £1.00
+ </del>
+ <span
+ class="screen-reader-text"
+ >
+ Discounted price:
+ </span>
+ <ins
+ class="wc-block-components-product-price__value is-discounted"
+ translate="no"
+ >
+ £0.50
+ </ins>
+ Test format
</span>
- <del
- className="wc-block-components-product-price__regular"
- translate="no"
- >
- £1.00
- </del>
- <span
- className="screen-reader-text"
- >
- Discounted price:
- </span>
- <ins
- className="wc-block-components-product-price__value is-discounted"
- translate="no"
- >
- £0.50
- </ins>
- Test format
-</span>
+</div>
`;
exports[`ProductPrice should use default price if no format is provided 1`] = `
-<span
- className="price wc-block-components-product-price"
->
+<div>
<span
- className="screen-reader-text"
+ class="price wc-block-components-product-price"
>
- Previous price:
+ <span
+ class="screen-reader-text"
+ >
+ Previous price:
+ </span>
+ <del
+ class="wc-block-components-product-price__regular"
+ translate="no"
+ >
+ £1.00
+ </del>
+ <span
+ class="screen-reader-text"
+ >
+ Discounted price:
+ </span>
+ <ins
+ class="wc-block-components-product-price__value is-discounted"
+ translate="no"
+ >
+ £0.50
+ </ins>
</span>
- <del
- className="wc-block-components-product-price__regular"
- translate="no"
- >
- £1.00
- </del>
- <span
- className="screen-reader-text"
- >
- Discounted price:
- </span>
- <ins
- className="wc-block-components-product-price__value is-discounted"
- translate="no"
- >
- £0.50
- </ins>
-</span>
+</div>
`;
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/index.js b/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/index.js
index 7a75da69e13..316cd29e0dd 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/index.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/product-price/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render } from '@testing-library/react';
/**
* Internal dependencies
@@ -37,7 +37,7 @@ describe( 'ProductPrice', () => {
};
test( 'should use default price if no format is provided', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductPrice
price={ 50 }
regularPrice={ 100 }
@@ -45,11 +45,11 @@ describe( 'ProductPrice', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should apply the format if one is provided', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<ProductPrice
price={ 50 }
regularPrice={ 100 }
@@ -58,6 +58,6 @@ describe( 'ProductPrice', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart-item-quantity.js b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart-item-quantity.js
index 5d49d2b6bf3..89b4e7c109d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart-item-quantity.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart-item-quantity.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook, act } from '@testing-library/react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
import { CART_STORE_KEY, CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
@@ -27,18 +27,14 @@ jest.mock( 'use-debounce', () => ( {
} ) );
describe( 'useStoreCartItemQuantity', () => {
- let registry, renderer;
+ let registry;
- const getWrappedComponents = ( Component ) => (
- <RegistryProvider value={ registry }>
- <Component />
- </RegistryProvider>
+ const wrapper = ( { children } ) => (
+ <RegistryProvider value={ registry }>{ children }</RegistryProvider>
);
- const getTestComponent = ( options ) => () => {
- const props = useStoreCartItemQuantity( options );
- return <div { ...props } />;
- };
+ const renderStoreCartItemQuantityHook = ( options ) =>
+ renderHook( () => useStoreCartItemQuantity( options ), { wrapper } );
let mockRemoveItemFromCart;
let mockChangeCartItemQuantity;
@@ -73,7 +69,6 @@ describe( 'useStoreCartItemQuantity', () => {
beforeEach( () => {
registry = createRegistry();
- renderer = null;
} );
afterEach( () => {
@@ -90,69 +85,41 @@ describe( 'useStoreCartItemQuantity', () => {
} );
it( 'update quantity value should happen instantly', () => {
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartItemQuantityHook( {
key: '123',
quantity: 1,
} );
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const { setItemQuantity, quantity } =
- renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- expect( quantity ).toBe( 1 );
+ expect( result.current.quantity ).toBe( 1 );
act( () => {
- setItemQuantity( 2 );
+ result.current.setItemQuantity( 2 );
} );
- const { quantity: newQuantity } =
- renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- expect( newQuantity ).toBe( 2 );
+ expect( result.current.quantity ).toBe( 2 );
} );
it( 'removeItem should call the dispatch action', () => {
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartItemQuantityHook( {
key: '123',
quantity: 1,
} );
act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const { removeItem } = renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- act( () => {
- removeItem();
+ result.current.removeItem();
} );
expect( mockRemoveItemFromCart ).toHaveBeenCalledWith( '123' );
} );
it( 'setItemQuantity should call the dispatch action', () => {
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartItemQuantityHook( {
key: '123',
quantity: 1,
} );
act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const { setItemQuantity } = renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- act( () => {
- setItemQuantity( 2 );
+ result.current.setItemQuantity( 2 );
} );
expect( mockChangeCartItemQuantity.mock.calls ).toEqual( [
@@ -171,21 +138,14 @@ describe( 'useStoreCartItemQuantity', () => {
cartErrors: mockCartErrors,
} );
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartItemQuantityHook( {
key: '123',
quantity: 1,
} );
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const { cartItemQuantityErrors } =
- renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- expect( cartItemQuantityErrors ).toEqual( mockCartErrors );
+ expect( result.current.cartItemQuantityErrors ).toEqual(
+ mockCartErrors
+ );
} );
it( 'isPendingDelete should depend on the value provided by the store', () => {
@@ -197,19 +157,11 @@ describe( 'useStoreCartItemQuantity', () => {
cartErrors: {},
} );
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartItemQuantityHook( {
key: '123',
quantity: 1,
} );
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const { isPendingDelete } = renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
-
- expect( isPendingDelete ).toBe( true );
+ expect( result.current.isPendingDelete ).toBe( true );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart.jsx b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart.jsx
index 4882c9ad672..778b04fde5d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/cart/test/use-store-cart.jsx
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
@@ -21,7 +21,7 @@ jest.mock( '@woocommerce/block-data', () => ( {
} ) );
describe( 'useStoreCart', () => {
- let registry, renderer;
+ let registry;
const mockCartItems = [ { key: '1', id: 1, name: 'Lorem Ipsum' } ];
const mockShippingAddress = {
@@ -78,23 +78,12 @@ describe( 'useStoreCart', () => {
hasPendingItemsOperations: false,
};
- const getWrappedComponents = ( Component ) => (
- <RegistryProvider value={ registry }>
- <Component />
- </RegistryProvider>
+ const wrapper = ( { children } ) => (
+ <RegistryProvider value={ registry }>{ children }</RegistryProvider>
);
- const getTestComponent = ( options ) => () => {
- const { receiveCart, receiveCartContents, ...results } =
- useStoreCart( options );
- return (
- <div
- data-results={ results }
- data-receiveCart={ receiveCart }
- data-receiveCartContents={ receiveCartContents }
- />
- );
- };
+ const renderStoreCartHook = ( options ) =>
+ renderHook( () => useStoreCart( options ), { wrapper } );
const setUpMocks = () => {
const mocks = {
@@ -120,7 +109,6 @@ describe( 'useStoreCart', () => {
beforeEach( () => {
registry = createRegistry();
- renderer = null;
setUpMocks();
} );
@@ -136,20 +124,12 @@ describe( 'useStoreCart', () => {
} );
it( 'return default data when shouldSelect is false', () => {
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartHook( {
shouldSelect: false,
} );
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const props = renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
- const results = props[ 'data-results' ];
- const receiveCart = props[ 'data-receiveCart' ];
- const receiveCartContents = props[ 'data-receiveCartContents' ];
+ const { receiveCart, receiveCartContents, ...results } =
+ result.current;
const {
receiveCart: defaultReceiveCart,
@@ -162,20 +142,12 @@ describe( 'useStoreCart', () => {
} );
it( 'return store data when shouldSelect is true', () => {
- const TestComponent = getTestComponent( {
+ const { result } = renderStoreCartHook( {
shouldSelect: true,
} );
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
- } );
-
- const props = renderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
- const results = props[ 'data-results' ];
- const receiveCart = props[ 'data-receiveCart' ];
- const receiveCartContents = props[ 'data-receiveCartContents' ];
+ const { receiveCart, receiveCartContents, ...results } =
+ result.current;
expect( results ).toEqual( mockStoreCartData );
expect( receiveCart ).toBeUndefined();
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/collections/test/use-collection.jsx b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/collections/test/use-collection.jsx
index f325d91df77..4d1eaa34c8b 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/collections/test/use-collection.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/collections/test/use-collection.jsx
@@ -1,9 +1,8 @@
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
-import { Component as ReactComponent } from '@wordpress/element';
import { COLLECTIONS_STORE_KEY as storeKey } from '@woocommerce/block-data';
/**
@@ -16,50 +15,30 @@ jest.mock( '@woocommerce/block-data', () => ( {
COLLECTIONS_STORE_KEY: 'test/store',
} ) );
-class TestErrorBoundary extends ReactComponent {
- constructor( props ) {
- super( props );
- this.state = { hasError: false, error: {} };
- }
- static getDerivedStateFromError( error ) {
- // Update state so the next render will show the fallback UI.
- return { hasError: true, error };
- }
-
- render() {
- if ( this.state.hasError ) {
- return <div data-error={ this.state.error } />;
- }
-
- return this.props.children;
- }
-}
-
describe( 'useCollection', () => {
- let registry, mocks, renderer;
- const getProps = ( testRenderer ) => {
- const { results, isLoading } =
- testRenderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
- return {
- results,
- isLoading,
- };
- };
+ let registry, mocks;
- const getWrappedComponents = ( Component, props ) => (
- <RegistryProvider value={ registry }>
- <TestErrorBoundary>
- <Component { ...props } />
- </TestErrorBoundary>
- </RegistryProvider>
+ const wrapper = ( { children } ) => (
+ <RegistryProvider value={ registry }>{ children }</RegistryProvider>
);
- const getTestComponent =
- () =>
- ( { options } ) => {
- const items = useCollection( options );
- return <div { ...items } />;
- };
+ const renderUseCollection = ( options ) =>
+ renderHook( ( props ) => useCollection( props.options ), {
+ initialProps: { options },
+ wrapper,
+ } );
+
+ // useCollection throws during render for invalid options or store errors;
+ // renderHook rethrows that error, so we capture it here.
+ const renderUseCollectionError = ( options ) => {
+ let error;
+ try {
+ renderUseCollection( options );
+ } catch ( caught ) {
+ error = caught;
+ }
+ return error;
+ };
const setUpMocks = () => {
// Memoize the fixture by selector args so wp-data's SCRIPT_DEBUG
@@ -92,161 +71,108 @@ describe( 'useCollection', () => {
beforeEach( () => {
registry = createRegistry();
mocks = {};
- renderer = null;
setUpMocks();
} );
it(
'should throw an error if an options object is provided without ' +
'a namespace property',
() => {
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- resourceName: 'products',
- query: { bar: 'foo' },
- },
- } )
- );
+ const error = renderUseCollectionError( {
+ resourceName: 'products',
+ query: { bar: 'foo' },
} );
- //eslint-disable-next-line testing-library/await-async-query
- const props = renderer.root.findByType( 'div' ).props;
- expect( props[ 'data-error' ].message ).toMatch( /options object/ );
+ expect( error.message ).toMatch( /options object/ );
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
}
);
it(
'should throw an error if an options object is provided without ' +
'a resourceName property',
() => {
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- query: { bar: 'foo' },
- },
- } )
- );
+ const error = renderUseCollectionError( {
+ namespace: 'test/store',
+ query: { bar: 'foo' },
} );
- //eslint-disable-next-line testing-library/await-async-query
- const props = renderer.root.findByType( 'div' ).props;
- expect( props[ 'data-error' ].message ).toMatch( /options object/ );
+ expect( error.message ).toMatch( /options object/ );
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
}
);
it(
'should return expected behaviour for equivalent query on props ' +
'across renders',
() => {
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- query: { bar: 'foo' },
- },
- } )
- );
+ const { result, rerender } = renderUseCollection( {
+ namespace: 'test/store',
+ resourceName: 'products',
+ query: { bar: 'foo' },
} );
- const { results } = getProps( renderer );
+ const { results } = result.current;
// rerender
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- query: { bar: 'foo' },
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'products',
+ query: { bar: 'foo' },
+ },
} );
// re-render should result in same products object because although
// query-state is a different instance, it's still equivalent.
- const { results: newResults } = getProps( renderer );
+ const { results: newResults } = result.current;
expect( newResults ).toBe( results );
// now let's change the query passed through to verify new object
// is created.
// remember this won't actually change the results because the mock
// selector is returning an equivalent object when it is called,
// however it SHOULD be a new object instance.
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- query: { foo: 'bar' },
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'products',
+ query: { foo: 'bar' },
+ },
} );
- const { results: resultsVerification } = getProps( renderer );
+ const { results: resultsVerification } = result.current;
expect( resultsVerification ).not.toBe( results );
expect( resultsVerification ).toEqual( results );
- renderer.unmount();
}
);
it(
'should return expected behaviour for equivalent resourceValues on' +
' props across renders',
() => {
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- resourceValues: [ 10, 20 ],
- },
- } )
- );
+ const { result, rerender } = renderUseCollection( {
+ namespace: 'test/store',
+ resourceName: 'products',
+ resourceValues: [ 10, 20 ],
} );
- const { results } = getProps( renderer );
+ const { results } = result.current;
// rerender
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- resourceValues: [ 10, 20 ],
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'products',
+ resourceValues: [ 10, 20 ],
+ },
} );
// re-render should result in same products object because although
// query-state is a different instance, it's still equivalent.
- const { results: newResults } = getProps( renderer );
+ const { results: newResults } = result.current;
expect( newResults ).toBe( results );
// now let's change the query passed through to verify new object
// is created.
// remember this won't actually change the results because the mock
// selector is returning an equivalent object when it is called,
// however it SHOULD be a new object instance.
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- resourceValues: [ 20, 10 ],
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'products',
+ resourceValues: [ 20, 10 ],
+ },
} );
- const { results: resultsVerification } = getProps( renderer );
+ const { results: resultsVerification } = result.current;
expect( resultsVerification ).not.toBe( results );
expect( resultsVerification ).toEqual( results );
- renderer.unmount();
}
);
it( 'should return previous query results if `shouldSelect` is false', () => {
@@ -264,19 +190,12 @@ describe( 'useCollection', () => {
return cache.get( key );
}
);
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- resourceValues: [ 10, 20 ],
- },
- } )
- );
+ const { result, rerender } = renderUseCollection( {
+ namespace: 'test/store',
+ resourceName: 'products',
+ resourceValues: [ 10, 20 ],
} );
- const { results } = getProps( renderer );
+ const { results } = result.current;
// Capture the call count after the first render so the next assertion
// measures whether the rerender caused additional invocations rather
// than the absolute total (wp-data's SCRIPT_DEBUG unstable-reference
@@ -285,19 +204,15 @@ describe( 'useCollection', () => {
const callsAfterFirstRender =
mocks.selectors.getCollection.mock.calls.length;
// rerender but with shouldSelect to false
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'productsb',
- resourceValues: [ 10, 30 ],
- shouldSelect: false,
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'productsb',
+ resourceValues: [ 10, 30 ],
+ shouldSelect: false,
+ },
} );
- const { results: results2 } = getProps( renderer );
+ const { results: results2 } = result.current;
expect( results2 ).toBe( results );
// `shouldSelect: false` should not have triggered any new selector
// invocations; the cached previous results should be returned.
@@ -307,19 +222,15 @@ describe( 'useCollection', () => {
// rerender again but set shouldSelect to true again and we should see
// new results
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'productsb',
- resourceValues: [ 10, 30 ],
- shouldSelect: true,
- },
- } )
- );
+ rerender( {
+ options: {
+ namespace: 'test/store',
+ resourceName: 'productsb',
+ resourceValues: [ 10, 30 ],
+ shouldSelect: true,
+ },
} );
- const { results: results3 } = getProps( renderer );
+ const { results: results3 } = result.current;
expect( results3 ).not.toEqual( results );
expect( results3 ).toEqual( [
'test/store',
@@ -330,54 +241,41 @@ describe( 'useCollection', () => {
} );
const renderWithStoreError = ( errorValue ) => {
mocks.selectors.getCollectionError.mockReturnValue( errorValue );
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- options: {
- namespace: 'test/store',
- resourceName: 'products',
- query: { bar: 'foo' },
- },
- } )
- );
+ return renderUseCollectionError( {
+ namespace: 'test/store',
+ resourceName: 'products',
+ query: { bar: 'foo' },
} );
- //eslint-disable-next-line testing-library/await-async-query
- return renderer.root.findByType( 'div' ).props;
};
it( 'should propagate an Error instance from the store via the error boundary', () => {
const error = new Error( 'A real error' );
- const props = renderWithStoreError( error );
- expect( props[ 'data-error' ] ).toBeInstanceOf( Error );
- expect( props[ 'data-error' ].message ).toBe( 'A real error' );
+ const caught = renderWithStoreError( error );
+ expect( caught ).toBeInstanceOf( Error );
+ expect( caught.message ).toBe( 'A real error' );
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
} );
it( 'should convert a non-Error object with a message into an Error instance', () => {
const error = { code: 'rest_no_route', message: 'No route found.' };
- const props = renderWithStoreError( error );
- expect( props[ 'data-error' ] ).toBeInstanceOf( Error );
- expect( props[ 'data-error' ].message ).toBe( 'No route found.' );
+ const caught = renderWithStoreError( error );
+ expect( caught ).toBeInstanceOf( Error );
+ expect( caught.message ).toBe( 'No route found.' );
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
} );
it( 'should use a fallback message when a non-Error object has no message', () => {
- const props = renderWithStoreError( { code: 500 } );
- expect( props[ 'data-error' ] ).toBeInstanceOf( Error );
- expect( props[ 'data-error' ].message ).toBe(
+ const caught = renderWithStoreError( { code: 500 } );
+ expect( caught ).toBeInstanceOf( Error );
+ expect( caught.message ).toBe(
'Something went wrong while loading data.'
);
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
} );
it( 'should use a fallback message when a primitive value is returned from the store', () => {
- const props = renderWithStoreError( 'oops' );
- expect( props[ 'data-error' ] ).toBeInstanceOf( Error );
- expect( props[ 'data-error' ].message ).toBe(
+ const caught = renderWithStoreError( 'oops' );
+ expect( caught ).toBeInstanceOf( Error );
+ expect( caught.message ).toBe(
'Something went wrong while loading data.'
);
expect( console ).toHaveErrored( /your React components:/ );
- renderer.unmount();
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-checkout-submit.js b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-checkout-submit.js
index 10e3114a249..13a89e20187 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-checkout-submit.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-checkout-submit.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
/**
@@ -30,38 +30,25 @@ jest.mock( '../../providers/cart-checkout/checkout-events', () => {
} );
describe( 'useCheckoutSubmit', () => {
- let registry, renderer;
+ let registry;
- const getWrappedComponents = ( Component ) => (
- <RegistryProvider value={ registry }>
- <Component />
- </RegistryProvider>
+ const wrapper = ( { children } ) => (
+ <RegistryProvider value={ registry }>{ children }</RegistryProvider>
);
- const getTestComponent = () => () => {
- const data = useCheckoutSubmit();
- return <div { ...data } />;
- };
-
beforeEach( () => {
registry = createRegistry( {
[ CHECKOUT_STORE_KEY ]: checkoutStoreConfig,
[ PAYMENT_STORE_KEY ]: paymentDataStoreConfig,
} );
- renderer = null;
} );
it( 'onSubmit calls the correct action in the checkout events context', () => {
- const TestComponent = getTestComponent();
-
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent )
- );
+ const { result } = renderHook( () => useCheckoutSubmit(), {
+ wrapper,
} );
- //eslint-disable-next-line testing-library/await-async-query
- const { onSubmit } = renderer.root.findByType( 'div' ).props;
+ const { onSubmit } = result.current;
onSubmit();
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-products.js b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-products.js
index ab5cefb8299..418d4989baf 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-products.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-products.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
import { createRegistry, RegistryProvider } from '@wordpress/data';
import { COLLECTIONS_STORE_KEY as storeKey } from '@woocommerce/block-data';
@@ -16,30 +16,12 @@ jest.mock( '@woocommerce/block-data', () => ( {
} ) );
describe( 'useStoreProducts', () => {
- let registry, mocks, renderer;
- const getProps = ( testRenderer ) => {
- const { products, totalProducts, productsLoading } =
- testRenderer.root.findByType( 'div' ).props; //eslint-disable-line testing-library/await-async-query
- return {
- products,
- totalProducts,
- productsLoading,
- };
- };
+ let registry, mocks;
- const getWrappedComponents = ( Component, props ) => (
- <RegistryProvider value={ registry }>
- <Component { ...props } />
- </RegistryProvider>
+ const wrapper = ( { children } ) => (
+ <RegistryProvider value={ registry }>{ children }</RegistryProvider>
);
- const getTestComponent =
- () =>
- ( { query } ) => {
- const items = useStoreProducts( query );
- return <div { ...items } />;
- };
-
const setUpMocks = () => {
// Memoize the fixture by selector args so wp-data's SCRIPT_DEBUG
// unstable-reference check (which double-invokes the selector with
@@ -72,50 +54,33 @@ describe( 'useStoreProducts', () => {
beforeEach( () => {
registry = createRegistry();
mocks = {};
- renderer = null;
setUpMocks();
} );
it(
'should return expected behaviour for equivalent query on props ' +
'across renders',
() => {
- const TestComponent = getTestComponent();
- act( () => {
- renderer = TestRenderer.create(
- getWrappedComponents( TestComponent, {
- query: { bar: 'foo' },
- } )
- );
- } );
- const { products } = getProps( renderer );
+ const { result, rerender, unmount } = renderHook(
+ ( { query } ) => useStoreProducts( query ),
+ { initialProps: { query: { bar: 'foo' } }, wrapper }
+ );
+ const { products } = result.current;
// rerender
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- query: { bar: 'foo' },
- } )
- );
- } );
+ rerender( { query: { bar: 'foo' } } );
// re-render should result in same products object because although
// query-state is a different instance, it's still equivalent.
- const { products: newProducts } = getProps( renderer );
+ const { products: newProducts } = result.current;
expect( newProducts ).toBe( products );
// now let's change the query passed through to verify new object
// is created.
// remember this won't actually change the results because the mock
// selector is returning an equivalent object when it is called,
// however it SHOULD be a new object instance.
- act( () => {
- renderer.update(
- getWrappedComponents( TestComponent, {
- query: { foo: 'bar' },
- } )
- );
- } );
- const { products: productsVerification } = getProps( renderer );
+ rerender( { query: { foo: 'bar' } } );
+ const { products: productsVerification } = result.current;
expect( productsVerification ).not.toBe( products );
expect( productsVerification ).toEqual( products );
- renderer.unmount();
+ unmount();
}
);
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/hocs/test/with-reviews.jsx b/plugins/woocommerce/client/blocks/assets/js/base/hocs/test/with-reviews.jsx
index 3ceb37f1148..736918f6dd4 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/hocs/test/with-reviews.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/hocs/test/with-reviews.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
/**
* Internal dependencies
@@ -37,39 +34,48 @@ const defaultArgs = {
per_page: 2,
product_id: 1,
};
-const TestComponent = withReviews( ( props ) => {
- return (
- <div
- data-error={ props.error }
- data-getReviews={ props.getReviews }
- data-appendReviews={ props.appendReviews }
- data-onChangeArgs={ props.onChangeArgs }
- data-isLoading={ props.isLoading }
- data-reviews={ props.reviews }
- data-totalReviews={ props.totalReviews }
- />
- );
+
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
} );
-const render = () => {
- return TestRenderer.create(
- <TestComponent
- attributes={ {} }
- order="desc"
- orderby="date_gmt"
- productId={ 1 }
- reviewsToDisplay={ 2 }
- />
- );
+const TestComponent = withReviews( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
};
describe( 'withReviews Component', () => {
- let renderer;
+ let renderResult;
+ const renderComponent = ( props ) =>
+ settle( () => {
+ renderResult = render(
+ <TestComponent
+ attributes={ {} }
+ order="desc"
+ orderby="date_gmt"
+ productId={ 1 }
+ reviewsToDisplay={ 2 }
+ { ...props }
+ />
+ );
+ } );
+
afterEach( () => {
mockUtils.getReviews.mockReset();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
describe( 'lifecycle events', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getReviews
.mockImplementationOnce( () =>
Promise.resolve( {
@@ -83,7 +89,7 @@ describe( 'withReviews Component', () => {
totalReviews: mockReviews.length,
} )
);
- renderer = render();
+ await renderComponent();
} );
it( 'getReviews is called on mount with default args', () => {
@@ -93,15 +99,17 @@ describe( 'withReviews Component', () => {
expect( getReviews ).toHaveBeenCalledTimes( 1 );
} );
- it( 'getReviews is called on component update', () => {
+ it( 'getReviews is called on component update', async () => {
const { getReviews } = mockUtils;
- renderer.update(
- <TestComponent
- order="desc"
- orderby="date_gmt"
- productId={ 1 }
- reviewsToDisplay={ 3 }
- />
+ await settle( () =>
+ renderResult.rerender(
+ <TestComponent
+ order="desc"
+ orderby="date_gmt"
+ productId={ 1 }
+ reviewsToDisplay={ 3 }
+ />
+ )
);
expect( getReviews ).toHaveBeenNthCalledWith( 2, {
@@ -114,54 +122,46 @@ describe( 'withReviews Component', () => {
} );
describe( 'when the API returns product data', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getReviews.mockImplementation( () =>
Promise.resolve( {
reviews: mockReviews.slice( 0, 2 ),
totalReviews: mockReviews.length,
} )
);
- renderer = render();
+ await renderComponent();
} );
it( 'sets reviews based on API response', () => {
- const props = renderer.root.findByType( 'div' ).props;
-
- expect( props[ 'data-error' ] ).toBeNull();
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-reviews' ] ).toEqual(
- mockReviews.slice( 0, 2 )
- );
- expect( props[ 'data-totalReviews' ] ).toEqual(
- mockReviews.length
- );
+ expect( lastProps.error ).toBeNull();
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.reviews ).toEqual( mockReviews.slice( 0, 2 ) );
+ expect( lastProps.totalReviews ).toEqual( mockReviews.length );
} );
} );
describe( 'when the API returns an error', () => {
const error = { message: 'There was an error.' };
- const getReviewsPromise = Promise.reject( error );
const formattedError = { message: 'There was an error.', type: 'api' };
- beforeEach( () => {
- mockUtils.getReviews.mockImplementation( () => getReviewsPromise );
+ beforeEach( async () => {
+ mockUtils.getReviews.mockImplementation( () =>
+ Promise.reject( error )
+ );
mockBaseUtils.formatError.mockImplementation(
() => formattedError
);
- renderer = render();
+ await renderComponent();
} );
- test( 'sets the error prop', async () => {
- await expect( () => getReviewsPromise() ).toThrow();
-
+ test( 'sets the error prop', () => {
const { formatError } = mockBaseUtils;
- const props = renderer.root.findByType( 'div' ).props;
expect( formatError ).toHaveBeenCalledWith( error );
expect( formatError ).toHaveBeenCalledTimes( 1 );
- expect( props[ 'data-error' ] ).toEqual( formattedError );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-reviews' ] ).toEqual( [] );
+ expect( lastProps.error ).toEqual( formattedError );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.reviews ).toEqual( [] );
} );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/hocs/with-scroll-to-top/test/index.js b/plugins/woocommerce/client/blocks/assets/js/base/hocs/with-scroll-to-top/test/index.js
index 6687d83ea1c..1ceabcb59a6 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/hocs/with-scroll-to-top/test/index.js
+++ b/plugins/woocommerce/client/blocks/assets/js/base/hocs/with-scroll-to-top/test/index.js
@@ -1,55 +1,35 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render, screen } from '@testing-library/react';
/**
* Internal dependencies
*/
import withScrollToTop from '../index';
-const TestComponent = withScrollToTop( ( props ) => (
- <span { ...props }>
- <button />
- </span>
-) );
-
const focusedMock = jest.fn();
const scrollIntoViewMock = jest.fn();
-const mockedButton = {
- focus: focusedMock,
- scrollIntoView: scrollIntoViewMock,
-};
-const render = ( { inView } ) => {
- const getBoundingClientRect = () => ( {
+let scrollToTop;
+const TestComponent = withScrollToTop( ( props ) => {
+ scrollToTop = props.scrollToTop;
+ return (
+ <span>
+ <button />
+ </span>
+ );
+} );
+
+const setup = ( { inView } ) => {
+ render( <TestComponent /> );
+ const button = screen.getByRole( 'button' );
+ button.focus = focusedMock;
+ button.scrollIntoView = scrollIntoViewMock;
+ button.getBoundingClientRect = () => ( {
bottom: inView ? 0 : -10,
} );
- return TestRenderer.create( <TestComponent />, {
- createNodeMock: ( element ) => {
- if ( element.type === 'button' ) {
- return {
- ...mockedButton,
- getBoundingClientRect,
- };
- }
- if ( element.type === 'div' ) {
- return {
- getBoundingClientRect,
- parentElement: {
- querySelectorAll: () => [
- { ...mockedButton, getBoundingClientRect },
- ],
- },
- scrollIntoView: scrollIntoViewMock,
- };
- }
- return null;
- },
- } );
+ scrollToTop( { focusableSelector: 'button' } );
};
describe( 'withScrollToTop Component', () => {
@@ -60,11 +40,7 @@ describe( 'withScrollToTop Component', () => {
describe( 'if component is not in view', () => {
beforeEach( () => {
- const renderer = render( { inView: false } );
- const props = renderer.root.findByType( 'span' ).props;
- props.scrollToTop( {
- focusableSelector: 'button',
- } );
+ setup( { inView: false } );
} );
it( 'scrolls to top of the component when scrollToTop is called', () => {
@@ -78,11 +54,7 @@ describe( 'withScrollToTop Component', () => {
describe( 'if component is in view', () => {
beforeEach( () => {
- const renderer = render( { inView: true } );
- const props = renderer.root.findByType( 'span' ).props;
- props.scrollToTop( {
- focusableSelector: 'button',
- } );
+ setup( { inView: true } );
} );
it( "doesn't scroll to top of the component when scrollToTop is called", () => {
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-previous.jsx b/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-previous.jsx
index c1db5f40599..dd4f4a232cd 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-previous.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-previous.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
/**
* Internal dependencies
@@ -12,87 +9,35 @@ import TestRenderer, { act } from 'react-test-renderer';
import { usePrevious } from '../use-previous';
describe( 'usePrevious', () => {
- const TestComponent = ( { testValue, validation } ) => {
- const previousValue = usePrevious( testValue, validation );
- return (
- <div
- data-testValue={ testValue }
- data-previousValue={ previousValue }
- />
+ const renderUsePrevious = ( testValue, validation ) =>
+ renderHook(
+ ( props ) => usePrevious( props.testValue, props.validation ),
+ { initialProps: { testValue, validation } }
);
- };
-
- let renderer;
- beforeEach( () => ( renderer = null ) );
it( 'should be undefined at first pass', () => {
- act( () => {
- renderer = TestRenderer.create( <TestComponent testValue={ 1 } /> );
- } );
- const testValue =
- renderer.root.findByType( 'div' ).props[ 'data-testValue' ];
- const testPreviousValue =
- renderer.root.findByType( 'div' ).props[ 'data-previousValue' ];
+ const { result } = renderUsePrevious( 1 );
- expect( testValue ).toBe( 1 );
- expect( testPreviousValue ).toBe( undefined );
+ expect( result.current ).toBe( undefined );
} );
it( 'test new and previous value', () => {
- let testValue;
- let testPreviousValue;
- act( () => {
- renderer = TestRenderer.create( <TestComponent testValue={ 1 } /> );
- } );
+ const { result, rerender } = renderUsePrevious( 1 );
- act( () => {
- renderer.update( <TestComponent testValue={ 2 } /> );
- } );
- testValue = renderer.root.findByType( 'div' ).props[ 'data-testValue' ];
- testPreviousValue =
- renderer.root.findByType( 'div' ).props[ 'data-previousValue' ];
- expect( testValue ).toBe( 2 );
- expect( testPreviousValue ).toBe( 1 );
+ rerender( { testValue: 2 } );
+ expect( result.current ).toBe( 1 );
- act( () => {
- renderer.update( <TestComponent testValue={ 3 } /> );
- } );
- testValue = renderer.root.findByType( 'div' ).props[ 'data-testValue' ];
- testPreviousValue =
- renderer.root.findByType( 'div' ).props[ 'data-previousValue' ];
- expect( testValue ).toBe( 3 );
- expect( testPreviousValue ).toBe( 2 );
+ rerender( { testValue: 3 } );
+ expect( result.current ).toBe( 2 );
} );
it( 'should not update value if validation fails', () => {
- let testValue;
- let testPreviousValue;
- act( () => {
- renderer = TestRenderer.create(
- <TestComponent testValue={ 1 } validation={ Number.isFinite } />
- );
- } );
+ const { result, rerender } = renderUsePrevious( 1, Number.isFinite );
- act( () => {
- renderer.update(
- <TestComponent testValue="abc" validation={ Number.isFinite } />
- );
- } );
- testValue = renderer.root.findByType( 'div' ).props[ 'data-testValue' ];
- testPreviousValue =
- renderer.root.findByType( 'div' ).props[ 'data-previousValue' ];
- expect( testValue ).toBe( 'abc' );
- expect( testPreviousValue ).toBe( 1 );
+ rerender( { testValue: 'abc', validation: Number.isFinite } );
+ expect( result.current ).toBe( 1 );
- act( () => {
- renderer.update(
- <TestComponent testValue={ 3 } validation={ Number.isFinite } />
- );
- } );
- testValue = renderer.root.findByType( 'div' ).props[ 'data-testValue' ];
- testPreviousValue =
- renderer.root.findByType( 'div' ).props[ 'data-previousValue' ];
- expect( testValue ).toBe( 3 );
- expect( testPreviousValue ).toBe( 1 );
+ rerender( { testValue: 3, validation: Number.isFinite } );
+ expect( result.current ).toBe( 1 );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-shallow-equal.jsx b/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-shallow-equal.jsx
index 687b6b1c6b5..64c40d0e41f 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-shallow-equal.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/base/hooks/test/use-shallow-equal.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
/**
* Internal dependencies
@@ -12,12 +9,11 @@ import TestRenderer, { act } from 'react-test-renderer';
import { useShallowEqual } from '../use-shallow-equal';
describe( 'useShallowEqual', () => {
- const TestComponent = ( { testValue } ) => {
- const newValue = useShallowEqual( testValue );
- return <div data-newValue={ newValue } />;
- };
- let renderer;
- beforeEach( () => ( renderer = null ) );
+ const renderShallowEqual = ( testValue ) =>
+ renderHook( ( props ) => useShallowEqual( props.testValue ), {
+ initialProps: { testValue },
+ } );
+
it.each`
testValueA | aType | testValueB | bType
${ { a: 'b', foo: 'bar' } } | ${ 'object' } | ${ { foo: 'bar', a: 'b' } } | ${ 'object' }
@@ -28,22 +24,11 @@ describe( 'useShallowEqual', () => {
`(
'$testValueA ($aType) and $testValueB ($bType) are expected to be equal',
( { testValueA, testValueB } ) => {
- let testPropValue;
- act( () => {
- renderer = TestRenderer.create(
- <TestComponent testValue={ testValueA } />
- );
- } );
- testPropValue =
- renderer.root.findByType( 'div' ).props[ 'data-newValue' ];
- expect( testPropValue ).toBe( testValueA );
+ const { result, rerender } = renderShallowEqual( testValueA );
+ expect( result.current ).toBe( testValueA );
// do update
- act( () => {
- renderer.update( <TestComponent testValue={ testValueB } /> );
- } );
- testPropValue =
- renderer.root.findByType( 'div' ).props[ 'data-newValue' ];
- expect( testPropValue ).toBe( testValueA );
+ rerender( { testValue: testValueB } );
+ expect( result.current ).toBe( testValueA );
}
);
@@ -58,22 +43,11 @@ describe( 'useShallowEqual', () => {
`(
'$testValueA ($aType) and $testValueB ($bType) are expected to not be equal',
( { testValueA, testValueB } ) => {
- let testPropValue;
- act( () => {
- renderer = TestRenderer.create(
- <TestComponent testValue={ testValueA } />
- );
- } );
- testPropValue =
- renderer.root.findByType( 'div' ).props[ 'data-newValue' ];
- expect( testPropValue ).toBe( testValueA );
+ const { result, rerender } = renderShallowEqual( testValueA );
+ expect( result.current ).toBe( testValueA );
// do update
- act( () => {
- renderer.update( <TestComponent testValue={ testValueB } /> );
- } );
- testPropValue =
- renderer.root.findByType( 'div' ).props[ 'data-newValue' ];
- expect( testPropValue ).toBe( testValueB );
+ rerender( { testValue: testValueB } );
+ expect( result.current ).toBe( testValueB );
}
);
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/price-filter/test/use-price-constraints.jsx b/plugins/woocommerce/client/blocks/assets/js/blocks/price-filter/test/use-price-constraints.jsx
index f5d2b10965a..6fd3083cb58 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/price-filter/test/use-price-constraints.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/price-filter/test/use-price-constraints.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { renderHook } from '@testing-library/react';
/**
* Internal dependencies
@@ -13,77 +10,62 @@ import { usePriceConstraint } from '../use-price-constraints';
import { ROUND_UP, ROUND_DOWN } from '../constants';
describe( 'usePriceConstraints', () => {
- const TestComponent = ( { price } ) => {
- const maxPriceConstraint = usePriceConstraint( price, 2, ROUND_UP );
- const minPriceConstraint = usePriceConstraint( price, 2, ROUND_DOWN );
- return (
- <div
- data-minPriceConstraint={ minPriceConstraint }
- data-maxPriceConstraint={ maxPriceConstraint }
- />
+ const renderPriceConstraints = ( price ) =>
+ renderHook(
+ ( { price: currentPrice } ) => ( {
+ max: usePriceConstraint( currentPrice, 2, ROUND_UP ),
+ min: usePriceConstraint( currentPrice, 2, ROUND_DOWN ),
+ } ),
+ { initialProps: { price } }
);
- };
it( 'max price constraint should be updated when new price is set', () => {
- const renderer = TestRenderer.create(
- <TestComponent price={ 1000 } />
- );
- const container = renderer.root.findByType( 'div' );
+ const { result, rerender } = renderPriceConstraints( 1000 );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 1000 );
+ expect( result.current.max ).toBe( 1000 );
- renderer.update( <TestComponent price={ 2000 } /> );
+ rerender( { price: 2000 } );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 2000 );
+ expect( result.current.max ).toBe( 2000 );
} );
it( 'min price constraint should be updated when new price is set', () => {
- const renderer = TestRenderer.create(
- <TestComponent price={ 1000 } />
- );
- const container = renderer.root.findByType( 'div' );
+ const { result, rerender } = renderPriceConstraints( 1000 );
- expect( container.props[ 'data-minPriceConstraint' ] ).toBe( 1000 );
+ expect( result.current.min ).toBe( 1000 );
- renderer.update( <TestComponent price={ 2000 } /> );
+ rerender( { price: 2000 } );
- expect( container.props[ 'data-minPriceConstraint' ] ).toBe( 2000 );
+ expect( result.current.min ).toBe( 2000 );
} );
it( 'previous price constraint should be preserved when new price is not an infinite number', () => {
- const renderer = TestRenderer.create(
- <TestComponent price={ 1000 } />
- );
- const container = renderer.root.findByType( 'div' );
+ const { result, rerender } = renderPriceConstraints( 1000 );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 1000 );
+ expect( result.current.max ).toBe( 1000 );
- renderer.update( <TestComponent price={ Infinity } /> );
+ rerender( { price: Infinity } );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 1000 );
+ expect( result.current.max ).toBe( 1000 );
} );
it( 'max price constraint should be higher if the price is decimal', () => {
- const renderer = TestRenderer.create(
- <TestComponent price={ 1099 } />
- );
- const container = renderer.root.findByType( 'div' );
+ const { result, rerender } = renderPriceConstraints( 1099 );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 1100 );
+ expect( result.current.max ).toBe( 1100 );
- renderer.update( <TestComponent price={ 1999 } /> );
+ rerender( { price: 1999 } );
- expect( container.props[ 'data-maxPriceConstraint' ] ).toBe( 2000 );
+ expect( result.current.max ).toBe( 2000 );
} );
it( 'min price constraint should be lower if the price is decimal', () => {
- const renderer = TestRenderer.create( <TestComponent price={ 999 } /> );
- const container = renderer.root.findByType( 'div' );
+ const { result, rerender } = renderPriceConstraints( 999 );
- expect( container.props[ 'data-minPriceConstraint' ] ).toBe( 900 );
+ expect( result.current.min ).toBe( 900 );
- renderer.update( <TestComponent price={ 1999 } /> );
+ rerender( { price: 1999 } );
- expect( container.props[ 'data-minPriceConstraint' ] ).toBe( 1900 );
+ expect( result.current.min ).toBe( 1900 );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-category.jsx b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-category.jsx
index ca85d49be66..dd0720dcf8b 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-category.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-category.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
import * as mockUtils from '@woocommerce/editor-components/utils';
/**
@@ -23,30 +20,41 @@ jest.mock( '../../base/utils/errors', () => ( {
const mockCategory = { name: 'Clothing' };
const attributes = { categoryId: 1 };
-const TestComponent = withCategory( ( props ) => {
- return (
- <div
- data-error={ props.error }
- data-getCategory={ props.getCategory }
- data-isLoading={ props.isLoading }
- data-category={ props.category }
- />
- );
+
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
} );
-const render = () => {
- return TestRenderer.create( <TestComponent attributes={ attributes } /> );
+const TestComponent = withCategory( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
};
describe( 'withCategory Component', () => {
- let renderer;
+ let renderResult;
+ const renderComponent = ( props = { attributes } ) =>
+ settle( () => {
+ renderResult = render( <TestComponent { ...props } /> );
+ } );
+
afterEach( () => {
mockUtils.getCategory.mockReset();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
describe( 'lifecycle events', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getCategory.mockImplementation( () => Promise.resolve() );
- renderer = render();
+ await renderComponent();
} );
it( 'getCategory is called on mount with passed in category id', () => {
@@ -56,10 +64,14 @@ describe( 'withCategory Component', () => {
expect( getCategory ).toHaveBeenCalledTimes( 1 );
} );
- it( 'getCategory is called on component update', () => {
+ it( 'getCategory is called on component update', async () => {
const { getCategory } = mockUtils;
const newAttributes = { ...attributes, categoryId: 2 };
- renderer.update( <TestComponent attributes={ newAttributes } /> );
+ await settle( () =>
+ renderResult.rerender(
+ <TestComponent attributes={ newAttributes } />
+ )
+ );
expect( getCategory ).toHaveBeenNthCalledWith(
2,
@@ -68,31 +80,28 @@ describe( 'withCategory Component', () => {
expect( getCategory ).toHaveBeenCalledTimes( 2 );
} );
- it( 'getCategory is hooked to the prop', () => {
+ it( 'getCategory is hooked to the prop', async () => {
const { getCategory } = mockUtils;
- const props = renderer.root.findByType( 'div' ).props;
- props[ 'data-getCategory' ]();
+ await settle( () => lastProps.getCategory() );
expect( getCategory ).toHaveBeenCalledTimes( 2 );
} );
} );
describe( 'when the API returns category data', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getCategory.mockImplementation( ( categoryId ) =>
Promise.resolve( { ...mockCategory, id: categoryId } )
);
- renderer = render();
+ await renderComponent();
} );
it( 'sets the category props', () => {
- const props = renderer.root.findByType( 'div' ).props;
-
- expect( props[ 'data-error' ] ).toBeNull();
- expect( typeof props[ 'data-getCategory' ] ).toBe( 'function' );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-category' ] ).toEqual( {
+ expect( lastProps.error ).toBeNull();
+ expect( typeof lastProps.getCategory ).toBe( 'function' );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.category ).toEqual( {
...mockCategory,
id: attributes.categoryId,
} );
@@ -101,31 +110,25 @@ describe( 'withCategory Component', () => {
describe( 'when the API returns an error', () => {
const error = { message: 'There was an error.' };
- const getCategoryPromise = Promise.reject( error );
const formattedError = { message: 'There was an error.', type: 'api' };
- beforeEach( () => {
- mockUtils.getCategory.mockImplementation(
- () => getCategoryPromise
+ beforeEach( async () => {
+ mockUtils.getCategory.mockImplementation( () =>
+ Promise.reject( error )
);
- mockBaseUtils.formatError.mockImplementation(
- () => formattedError
- );
- renderer = render();
+ mockBaseUtils.formatError.mockImplementation( () => formattedError );
+ await renderComponent();
} );
- test( 'sets the error prop', async () => {
- await expect( () => getCategoryPromise() ).toThrow();
-
+ test( 'sets the error prop', () => {
const { formatError } = mockBaseUtils;
- const props = renderer.root.findByType( 'div' ).props;
expect( formatError ).toHaveBeenCalledWith( error );
expect( formatError ).toHaveBeenCalledTimes( 1 );
- expect( props[ 'data-error' ] ).toEqual( formattedError );
- expect( typeof props[ 'data-getCategory' ] ).toBe( 'function' );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-category' ] ).toBeNull();
+ expect( lastProps.error ).toEqual( formattedError );
+ expect( typeof lastProps.getCategory ).toBe( 'function' );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.category ).toBeNull();
} );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product-variations.jsx b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product-variations.jsx
index 0ba3fd4a868..14d5473b622 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product-variations.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product-variations.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
import * as mockUtils from '@woocommerce/editor-components/utils';
/**
@@ -29,35 +26,44 @@ const mockVariations = [
{ id: 3, name: 'Blue' },
{ id: 4, name: 'Red' },
];
-const TestComponent = withProductVariations( ( props ) => {
- return (
- <div
- data-error={ props.error }
- data-expandedProduct={ props.expandedProduct }
- data-isLoading={ props.isLoading }
- data-variations={ props.variations }
- data-variationsLoading={ props.variationsLoading }
- data-onLoadMoreVariations={ props.onLoadMoreVariations }
- data-totalVariations={ props.totalVariations }
- />
- );
+
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
} );
-const render = () => {
- return TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ mockProducts }
- selected={ [ 1 ] }
- showVariations={ true }
- />
- );
+const TestComponent = withProductVariations( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
};
describe( 'withProductVariations Component', () => {
- let renderer;
+ let renderResult;
+ const renderComponent = ( props ) =>
+ settle( () => {
+ renderResult = render(
+ <TestComponent
+ error={ null }
+ isLoading={ false }
+ products={ mockProducts }
+ selected={ [ 1 ] }
+ showVariations={ true }
+ { ...props }
+ />
+ );
+ } );
+
afterEach( () => {
mockUtils.getProductVariationsWithTotal.mockReset();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
describe( 'lifecycle events', () => {
@@ -70,8 +76,8 @@ describe( 'withProductVariations Component', () => {
);
} );
- it( 'getProductVariationsWithTotal is called on mount', () => {
- renderer = render();
+ it( 'getProductVariationsWithTotal is called on mount', async () => {
+ await renderComponent();
const { getProductVariationsWithTotal } = mockUtils;
expect( getProductVariationsWithTotal ).toHaveBeenCalledWith( 1, {
@@ -80,26 +86,25 @@ describe( 'withProductVariations Component', () => {
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 1 );
} );
- it( 'getProductVariationsWithTotal is called on component update', () => {
- renderer = TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ mockProducts }
- />
- );
+ it( 'getProductVariationsWithTotal is called on component update', async () => {
+ await renderComponent( {
+ selected: undefined,
+ showVariations: undefined,
+ } );
const { getProductVariationsWithTotal } = mockUtils;
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 0 );
- renderer.update(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ mockProducts }
- selected={ [ 1 ] }
- showVariations={ true }
- />
+ await settle( () =>
+ renderResult.rerender(
+ <TestComponent
+ error={ null }
+ isLoading={ false }
+ products={ mockProducts }
+ selected={ [ 1 ] }
+ showVariations={ true }
+ />
+ )
);
expect( getProductVariationsWithTotal ).toHaveBeenCalledWith( 1, {
@@ -108,31 +113,15 @@ describe( 'withProductVariations Component', () => {
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 1 );
} );
- it( 'getProductVariationsWithTotal is not called if selected product has no variations', () => {
- TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ mockProducts }
- selected={ [ 2 ] }
- showVariations={ true }
- />
- );
+ it( 'getProductVariationsWithTotal is not called if selected product has no variations', async () => {
+ await renderComponent( { selected: [ 2 ] } );
const { getProductVariationsWithTotal } = mockUtils;
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 0 );
} );
- it( 'getProductVariationsWithTotal is called if selected product is a variation', () => {
- TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ mockProducts }
- selected={ [ 3 ] }
- showVariations={ true }
- />
- );
+ it( 'getProductVariationsWithTotal is called if selected product is a variation', async () => {
+ await renderComponent( { selected: [ 3 ] } );
const { getProductVariationsWithTotal } = mockUtils;
expect( getProductVariationsWithTotal ).toHaveBeenCalledWith( 1, {
@@ -143,18 +132,17 @@ describe( 'withProductVariations Component', () => {
} );
describe( 'when the API returns variations data', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getProductVariationsWithTotal.mockImplementation( () =>
Promise.resolve( {
variations: mockVariations,
total: mockVariations.length,
} )
);
- renderer = render();
+ await renderComponent();
} );
- it( 'sets the variations props', async () => {
- const props = renderer.root.findByType( 'div' ).props;
+ it( 'sets the variations props', () => {
const expectedVariations = {
1: [
{ id: 3, name: 'Blue', parent: 1 },
@@ -162,40 +150,34 @@ describe( 'withProductVariations Component', () => {
],
};
- expect( props[ 'data-error' ] ).toBeNull();
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-variations' ] ).toEqual( expectedVariations );
+ expect( lastProps.error ).toBeNull();
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.variations ).toEqual( expectedVariations );
} );
} );
describe( 'when the API returns an error', () => {
const error = { message: 'There was an error.' };
- const getProductVariationsWithTotalPromise = Promise.reject( error );
const formattedError = { message: 'There was an error.', type: 'api' };
- beforeEach( () => {
- mockUtils.getProductVariationsWithTotal.mockImplementation(
- () => getProductVariationsWithTotalPromise
+ beforeEach( async () => {
+ mockUtils.getProductVariationsWithTotal.mockImplementation( () =>
+ Promise.reject( error )
);
mockBaseUtils.formatError.mockImplementation(
() => formattedError
);
- renderer = render();
+ await renderComponent();
} );
- test( 'sets the error prop', async () => {
- await TestRenderer.act( async () => {
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
-
+ test( 'sets the error prop', () => {
const { formatError } = mockBaseUtils;
- const props = renderer.root.findByType( 'div' ).props;
expect( formatError ).toHaveBeenCalledWith( error );
expect( formatError ).toHaveBeenCalledTimes( 1 );
- expect( props[ 'data-error' ] ).toEqual( formattedError );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-variations' ] ).toEqual( { 1: null } );
+ expect( lastProps.error ).toEqual( formattedError );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.variations ).toEqual( { 1: null } );
} );
} );
@@ -233,21 +215,8 @@ describe( 'withProductVariations Component', () => {
} );
it( 'loads the first 25 variations by default and provides onLoadMoreVariations', async () => {
- renderer = TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ productWithManyVariations }
- selected={ [ 1 ] }
- showVariations={ true }
- />
- );
+ await renderComponent( { products: productWithManyVariations } );
- await TestRenderer.act( async () => {
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
-
- const props = renderer.root.findByType( 'div' ).props;
const { getProductVariationsWithTotal } = mockUtils;
// Should have been called once with offset 0
@@ -257,57 +226,34 @@ describe( 'withProductVariations Component', () => {
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 1 );
// Should have first 25 variations
- expect( props[ 'data-variations' ][ 1 ] ).toHaveLength( 25 );
- expect( props[ 'data-variations' ][ 1 ][ 0 ] ).toEqual( {
+ expect( lastProps.variations[ 1 ] ).toHaveLength( 25 );
+ expect( lastProps.variations[ 1 ][ 0 ] ).toEqual( {
id: 1,
name: 'Variation 1',
parent: 1,
} );
- expect( props[ 'data-variations' ][ 1 ][ 24 ] ).toEqual( {
+ expect( lastProps.variations[ 1 ][ 24 ] ).toEqual( {
id: 25,
name: 'Variation 25',
parent: 1,
} );
// Should have total variations count
- expect( props[ 'data-totalVariations' ][ 1 ] ).toBe(
- totalVariations
- );
+ expect( lastProps.totalVariations[ 1 ] ).toBe( totalVariations );
// Should provide onLoadMoreVariations function
- expect( typeof props[ 'data-onLoadMoreVariations' ] ).toBe(
- 'function'
- );
+ expect( typeof lastProps.onLoadMoreVariations ).toBe( 'function' );
} );
it( 'loads the next 25 variations when onLoadMoreVariations is called', async () => {
- renderer = TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ productWithManyVariations }
- selected={ [ 1 ] }
- showVariations={ true }
- />
- );
-
- // Wait for initial load
- await TestRenderer.act( async () => {
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
-
- let props = renderer.root.findByType( 'div' ).props;
+ await renderComponent( { products: productWithManyVariations } );
// Verify initial 25 variations are loaded
- expect( props[ 'data-variations' ][ 1 ] ).toHaveLength( 25 );
+ expect( lastProps.variations[ 1 ] ).toHaveLength( 25 );
// Call onLoadMoreVariations to load next batch
- await TestRenderer.act( async () => {
- props[ 'data-onLoadMoreVariations' ]();
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
+ await settle( () => lastProps.onLoadMoreVariations() );
- props = renderer.root.findByType( 'div' ).props;
const { getProductVariationsWithTotal } = mockUtils;
// Should have been called again with offset 25
@@ -317,13 +263,13 @@ describe( 'withProductVariations Component', () => {
expect( getProductVariationsWithTotal ).toHaveBeenCalledTimes( 2 );
// Should now have 50 variations (25 + 25)
- expect( props[ 'data-variations' ][ 1 ] ).toHaveLength( 50 );
- expect( props[ 'data-variations' ][ 1 ][ 25 ] ).toEqual( {
+ expect( lastProps.variations[ 1 ] ).toHaveLength( 50 );
+ expect( lastProps.variations[ 1 ][ 25 ] ).toEqual( {
id: 26,
name: 'Variation 26',
parent: 1,
} );
- expect( props[ 'data-variations' ][ 1 ][ 49 ] ).toEqual( {
+ expect( lastProps.variations[ 1 ][ 49 ] ).toEqual( {
id: 50,
name: 'Variation 50',
parent: 1,
@@ -331,38 +277,14 @@ describe( 'withProductVariations Component', () => {
} );
it( 'loads all variations when onLoadMoreVariations is called multiple times', async () => {
- renderer = TestRenderer.create(
- <TestComponent
- error={ null }
- isLoading={ false }
- products={ productWithManyVariations }
- selected={ [ 1 ] }
- showVariations={ true }
- />
- );
-
- // Wait for initial load
- await TestRenderer.act( async () => {
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
-
- let props = renderer.root.findByType( 'div' ).props;
+ await renderComponent( { products: productWithManyVariations } );
// Load second batch
- await TestRenderer.act( async () => {
- props[ 'data-onLoadMoreVariations' ]();
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
-
- props = renderer.root.findByType( 'div' ).props;
+ await settle( () => lastProps.onLoadMoreVariations() );
// Load third batch (final 10 variations)
- await TestRenderer.act( async () => {
- props[ 'data-onLoadMoreVariations' ]();
- await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
- } );
+ await settle( () => lastProps.onLoadMoreVariations() );
- props = renderer.root.findByType( 'div' ).props;
const { getProductVariationsWithTotal } = mockUtils;
// Should have been called 3 times total
@@ -376,8 +298,8 @@ describe( 'withProductVariations Component', () => {
);
// Should now have all 60 variations
- expect( props[ 'data-variations' ][ 1 ] ).toHaveLength( 60 );
- expect( props[ 'data-variations' ][ 1 ][ 59 ] ).toEqual( {
+ expect( lastProps.variations[ 1 ] ).toHaveLength( 60 );
+ expect( lastProps.variations[ 1 ][ 59 ] ).toEqual( {
id: 60,
name: 'Variation 60',
parent: 1,
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product.jsx b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product.jsx
index 4319cb15013..02bbfb7e254 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-product.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
import * as mockUtils from '@woocommerce/editor-components/utils';
/**
@@ -23,30 +20,41 @@ jest.mock( '../../base/utils/errors', () => ( {
const mockProduct = { name: 'T-Shirt' };
const attributes = { productId: 1 };
-const TestComponent = withProduct( ( props ) => {
- return (
- <div
- data-error={ props.error }
- data-getProduct={ props.getProduct }
- data-isLoading={ props.isLoading }
- data-product={ props.product }
- />
- );
+
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
} );
-const render = () => {
- return TestRenderer.create( <TestComponent attributes={ attributes } /> );
+const TestComponent = withProduct( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
};
describe( 'withProduct Component', () => {
- let renderer;
+ let renderResult;
+ const renderComponent = ( props = { attributes } ) =>
+ settle( () => {
+ renderResult = render( <TestComponent { ...props } /> );
+ } );
+
afterEach( () => {
mockUtils.getProduct.mockReset();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
describe( 'lifecycle events', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getProduct.mockImplementation( () => Promise.resolve() );
- renderer = render();
+ await renderComponent();
} );
it( 'getProduct is called on mount with passed in product id', () => {
@@ -56,10 +64,14 @@ describe( 'withProduct Component', () => {
expect( getProduct ).toHaveBeenCalledTimes( 1 );
} );
- it( 'getProduct is called on component update', () => {
+ it( 'getProduct is called on component update', async () => {
const { getProduct } = mockUtils;
const newAttributes = { ...attributes, productId: 2 };
- renderer.update( <TestComponent attributes={ newAttributes } /> );
+ await settle( () =>
+ renderResult.rerender(
+ <TestComponent attributes={ newAttributes } />
+ )
+ );
expect( getProduct ).toHaveBeenNthCalledWith(
2,
@@ -68,31 +80,28 @@ describe( 'withProduct Component', () => {
expect( getProduct ).toHaveBeenCalledTimes( 2 );
} );
- it( 'getProduct is hooked to the prop', () => {
+ it( 'getProduct is hooked to the prop', async () => {
const { getProduct } = mockUtils;
- const props = renderer.root.findByType( 'div' ).props;
- props[ 'data-getProduct' ]();
+ await settle( () => lastProps.getProduct() );
expect( getProduct ).toHaveBeenCalledTimes( 2 );
} );
} );
describe( 'when the API returns product data', () => {
- beforeEach( () => {
+ beforeEach( async () => {
mockUtils.getProduct.mockImplementation( ( productId ) =>
Promise.resolve( { ...mockProduct, id: productId } )
);
- renderer = render();
+ await renderComponent();
} );
it( 'sets the product props', () => {
- const props = renderer.root.findByType( 'div' ).props;
-
- expect( props[ 'data-error' ] ).toBeNull();
- expect( typeof props[ 'data-getProduct' ] ).toBe( 'function' );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-product' ] ).toEqual( {
+ expect( lastProps.error ).toBeNull();
+ expect( typeof lastProps.getProduct ).toBe( 'function' );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.product ).toEqual( {
...mockProduct,
id: attributes.productId,
} );
@@ -101,29 +110,25 @@ describe( 'withProduct Component', () => {
describe( 'when the API returns an error', () => {
const error = { message: 'There was an error.' };
- const getProductPromise = Promise.reject( error );
const formattedError = { message: 'There was an error.', type: 'api' };
- beforeEach( () => {
- mockUtils.getProduct.mockImplementation( () => getProductPromise );
- mockBaseUtils.formatError.mockImplementation(
- () => formattedError
+ beforeEach( async () => {
+ mockUtils.getProduct.mockImplementation( () =>
+ Promise.reject( error )
);
- renderer = render();
+ mockBaseUtils.formatError.mockImplementation( () => formattedError );
+ await renderComponent();
} );
- test( 'sets the error prop', async () => {
- await expect( () => getProductPromise() ).toThrow();
-
+ test( 'sets the error prop', () => {
const { formatError } = mockBaseUtils;
- const props = renderer.root.findByType( 'div' ).props;
expect( formatError ).toHaveBeenCalledWith( error );
expect( formatError ).toHaveBeenCalledTimes( 1 );
- expect( props[ 'data-error' ] ).toEqual( formattedError );
- expect( typeof props[ 'data-getProduct' ] ).toBe( 'function' );
- expect( props[ 'data-isLoading' ] ).toBe( false );
- expect( props[ 'data-product' ] ).toBeNull();
+ expect( lastProps.error ).toEqual( formattedError );
+ expect( typeof lastProps.getProduct ).toBe( 'function' );
+ expect( lastProps.isLoading ).toBe( false );
+ expect( lastProps.product ).toBeNull();
} );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-categories.jsx b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-categories.jsx
index 37efc9f4a98..ee20dc52c3a 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-categories.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-categories.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
import * as mockUtils from '@woocommerce/editor-components/utils';
/**
@@ -20,36 +17,42 @@ mockUtils.getCategories = jest.fn().mockImplementation( () =>
] )
);
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
+} );
+const TestComponent = withSearchedCategories( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
+};
+
describe( 'withSearchedCategories Component', () => {
afterEach( () => {
mockUtils.getCategories.mockClear();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
- const TestComponent = withSearchedCategories(
- ( { selected, categories, isLoading, onSearch } ) => {
- return (
- <div
- data-categories={ categories }
- data-selected={ selected }
- data-isLoading={ isLoading }
- data-onSearch={ onSearch }
- />
- );
- }
- );
+
describe( 'lifecycle tests', () => {
const selected = [ 10 ];
- let props, renderer;
- act( () => {
- renderer = TestRenderer.create(
- <TestComponent selected={ selected } />
+ beforeEach( async () => {
+ await settle( () =>
+ render( <TestComponent selected={ selected } /> )
);
} );
it( 'has expected values for props', () => {
- props = renderer.root.findByType( 'div' ).props;
- expect( props[ 'data-selected' ] ).toEqual( selected );
- expect( props[ 'data-categories' ] ).toEqual( [
+ expect( lastProps.selected ).toEqual( selected );
+ expect( lastProps.categories ).toEqual( [
{ id: 1, name: 'Clothing' },
{ id: 2, name: 'Food' },
] );
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-products.jsx b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-products.jsx
index a8b156fd3ff..0cd382a97af 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-products.jsx
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-searched-products.jsx
@@ -1,10 +1,7 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer, { act } from 'react-test-renderer';
+import { render, act } from '@testing-library/react';
import * as mockUtils from '@woocommerce/editor-components/utils';
import { useDebouncedCallback } from 'use-debounce';
@@ -39,49 +36,55 @@ mockUtils.getProducts = jest.fn().mockImplementation( () =>
] )
);
+// Capture the props the HOC injects into the wrapped component.
+let lastProps;
+const CapturedComponent = jest.fn( ( props ) => {
+ lastProps = props;
+ return null;
+} );
+const TestComponent = withSearchedProducts( CapturedComponent );
+
+// Run an interaction and flush the async state updates it triggers inside
+// `act`, so React's async fetch-then-setState work does not leak past the test.
+const settle = async ( fn ) => {
+ await act( async () => {
+ fn();
+ await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
+ } );
+};
+
describe( 'withSearchedProducts Component', () => {
const { getProducts } = mockUtils;
afterEach( () => {
useDebouncedCallback.mockClear();
mockUtils.getProducts.mockClear();
+ CapturedComponent.mockClear();
+ lastProps = undefined;
} );
- const TestComponent = withSearchedProducts(
- ( { selected, products, isLoading, onSearch } ) => {
- return (
- <div
- data-products={ products }
- data-selected={ selected }
- data-isLoading={ isLoading }
- data-onSearch={ onSearch }
- />
- );
- }
- );
+
describe( 'lifecycle tests', () => {
const selected = [ 10 ];
- let props, renderer;
- act( () => {
- renderer = TestRenderer.create(
- <TestComponent selected={ selected } />
+ beforeEach( async () => {
+ await settle( () =>
+ render( <TestComponent selected={ selected } /> )
);
} );
it( 'has expected values for props', () => {
- props = renderer.root.findByType( 'div' ).props;
- expect( props[ 'data-selected' ] ).toEqual( selected );
- expect( props[ 'data-products' ] ).toEqual( [
+ expect( lastProps.selected ).toEqual( selected );
+ expect( lastProps.products ).toEqual( [
{ id: 10, name: 'foo', parent: 0 },
{ id: 20, name: 'bar', parent: 0 },
] );
} );
it( 'debounce and getProducts is called on search event', async () => {
- props = renderer.root.findByType( 'div' ).props;
+ // Ignore the getProducts call triggered on mount so the assertion
+ // measures only the call made in response to the search event.
+ getProducts.mockClear();
- act( () => {
- props[ 'data-onSearch' ]();
- } );
+ await settle( () => lastProps.onSearch() );
expect( useDebouncedCallback ).toHaveBeenCalled();
expect( getProducts ).toHaveBeenCalledTimes( 1 );
diff --git a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-transform-single-select-to-multiple-select.js b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-transform-single-select-to-multiple-select.js
index 8f571477dc3..64d96aaa0ae 100644
--- a/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-transform-single-select-to-multiple-select.js
+++ b/plugins/woocommerce/client/blocks/assets/js/hocs/test/with-transform-single-select-to-multiple-select.js
@@ -1,37 +1,35 @@
-// We need to disable the following eslint check as it's only applicable
-// to testing-library/react not `react-test-renderer` used here
-/* eslint-disable testing-library/await-async-query */
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render } from '@testing-library/react';
/**
* Internal dependencies
*/
import withTransformSingleSelectToMultipleSelect from '../with-transform-single-select-to-multiple-select';
-const TestComponent = withTransformSingleSelectToMultipleSelect( ( props ) => {
- return <div selected={ props.selected } />;
-} );
+const InnerComponent = jest.fn( () => null );
+const TestComponent =
+ withTransformSingleSelectToMultipleSelect( InnerComponent );
+
+const getReceivedProps = () =>
+ InnerComponent.mock.calls[ InnerComponent.mock.calls.length - 1 ][ 0 ];
describe( 'withTransformSingleSelectToMultipleSelect Component', () => {
+ beforeEach( () => {
+ InnerComponent.mockClear();
+ } );
+
describe( 'when the API returns an error', () => {
it( 'converts the selected value into an array', () => {
const selected = 123;
- const renderer = TestRenderer.create(
- <TestComponent selected={ selected } />
- );
- const props = renderer.root.findByType( 'div' ).props;
- expect( props.selected ).toEqual( [ selected ] );
+ render( <TestComponent selected={ selected } /> );
+ expect( getReceivedProps().selected ).toEqual( [ selected ] );
} );
it( 'passes an empty array as the selected prop if selected was null', () => {
- const renderer = TestRenderer.create(
- <TestComponent selected={ null } />
- );
- const props = renderer.root.findByType( 'div' ).props;
- expect( props.selected ).toEqual( [] );
+ render( <TestComponent selected={ null } /> );
+ expect( getReceivedProps().selected ).toEqual( [] );
} );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/package.json b/plugins/woocommerce/client/blocks/package.json
index 87be32ac489..9a1798e41b4 100644
--- a/plugins/woocommerce/client/blocks/package.json
+++ b/plugins/woocommerce/client/blocks/package.json
@@ -210,7 +210,6 @@
"progress-bar-webpack-plugin": "2.1.x",
"react-docgen": "5.4.3",
"react-docgen-typescript-plugin": "^1.0.5",
- "react-test-renderer": "18.3.x",
"redux": "4.2.1",
"request-promise": "4.2.6",
"rimraf": "5.0.5",
diff --git a/plugins/woocommerce/client/blocks/packages/components/chip/test/__snapshots__/index.js.snap b/plugins/woocommerce/client/blocks/packages/components/chip/test/__snapshots__/index.js.snap
index a2336c981e2..d761af527bd 100644
--- a/plugins/woocommerce/client/blocks/packages/components/chip/test/__snapshots__/index.js.snap
+++ b/plugins/woocommerce/client/blocks/packages/components/chip/test/__snapshots__/index.js.snap
@@ -1,312 +1,319 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Chip should render children nodes 1`] = `
-<li
- className="wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
+<div>
+ <li
+ class="wc-block-components-chip wc-block-components-chip--radius-small"
>
- Test
- </span>
- Lorem Ipsum
-</li>
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
+ >
+ Test
+ </span>
+ Lorem Ipsum
+ </li>
+</div>
`;
exports[`Chip should render defined radius 1`] = `
-<li
- className="wc-block-components-chip wc-block-components-chip--radius-large"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
+<div>
+ <li
+ class="wc-block-components-chip wc-block-components-chip--radius-large"
>
- Test
- </span>
-</li>
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
+ >
+ Test
+ </span>
+ </li>
+</div>
`;
exports[`Chip should render nodes as the text 1`] = `
-<li
- className="wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
+<div>
+ <li
+ class="wc-block-components-chip wc-block-components-chip--radius-small"
>
- <h1>
- Test
- </h1>
- </span>
-</li>
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
+ >
+ <h1>
+ Test
+ </h1>
+ </span>
+ </li>
+</div>
`;
exports[`Chip should render screen reader text 1`] = `
-<li
- className="wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={true}
- className="wc-block-components-chip__text"
- >
- Test
- </span>
- <span
- className="screen-reader-text"
+<div>
+ <li
+ class="wc-block-components-chip wc-block-components-chip--radius-small"
>
- Test 2
- </span>
-</li>
+ <span
+ aria-hidden="true"
+ class="wc-block-components-chip__text"
+ >
+ Test
+ </span>
+ <span
+ class="screen-reader-text"
+ >
+ Test 2
+ </span>
+ </li>
+</div>
`;
exports[`Chip should render text 1`] = `
-<li
- className="wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
+<div>
+ <li
+ class="wc-block-components-chip wc-block-components-chip--radius-small"
>
- Test
- </span>
-</li>
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
+ >
+ Test
+ </span>
+ </li>
+</div>
`;
exports[`Chip with custom wrapper should render a chip made up of a div instead of a li 1`] = `
-<div
- className="wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
+<div>
+ <div
+ class="wc-block-components-chip wc-block-components-chip--radius-small"
>
- Test
- </span>
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
+ >
+ Test
+ </span>
+ </div>
</div>
`;
exports[`RemovableChip should render custom aria label 1`] = `
-<li
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
- >
- <h1>
- Test
- </h1>
- </span>
- <button
- aria-label="Aria test"
- className="wc-block-components-chip__remove"
- disabled={false}
- onClick={[Function]}
- onKeyDown={[Function]}
+<div>
+ <li
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </button>
-</li>
+ <h1>
+ Test
+ </h1>
+ </span>
+ <button
+ aria-label="Aria test"
+ class="wc-block-components-chip__remove"
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </button>
+ </li>
+</div>
`;
exports[`RemovableChip should render default aria label if text is a node 1`] = `
-<li
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={true}
- className="wc-block-components-chip__text"
- >
- <h1>
- Test
- </h1>
- </span>
- <span
- className="screen-reader-text"
+<div>
+ <li
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- Test 2
- </span>
- <button
- aria-label="Remove "Test 2""
- className="wc-block-components-chip__remove"
- disabled={false}
- onClick={[Function]}
- onKeyDown={[Function]}
- >
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="true"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </button>
-</li>
+ <h1>
+ Test
+ </h1>
+ </span>
+ <span
+ class="screen-reader-text"
+ >
+ Test 2
+ </span>
+ <button
+ aria-label="Remove "Test 2""
+ class="wc-block-components-chip__remove"
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </button>
+ </li>
+</div>
`;
exports[`RemovableChip should render screen reader text aria label 1`] = `
-<li
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={true}
- className="wc-block-components-chip__text"
- >
- Test
- </span>
- <span
- className="screen-reader-text"
- >
- Test 2
- </span>
- <button
- aria-label="Remove "Test 2""
- className="wc-block-components-chip__remove"
- disabled={false}
- onClick={[Function]}
- onKeyDown={[Function]}
+<div>
+ <li
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="true"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </button>
-</li>
+ Test
+ </span>
+ <span
+ class="screen-reader-text"
+ >
+ Test 2
+ </span>
+ <button
+ aria-label="Remove "Test 2""
+ class="wc-block-components-chip__remove"
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </button>
+ </li>
+</div>
`;
exports[`RemovableChip should render text and the remove button 1`] = `
-<li
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
- >
- Test
- </span>
- <button
- aria-label="Remove "Test""
- className="wc-block-components-chip__remove"
- disabled={false}
- onClick={[Function]}
- onKeyDown={[Function]}
+<div>
+ <li
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </button>
-</li>
+ Test
+ </span>
+ <button
+ aria-label="Remove "Test""
+ class="wc-block-components-chip__remove"
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </button>
+ </li>
+</div>
`;
exports[`RemovableChip should render with disabled remove button 1`] = `
-<li
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
- >
- Test
- </span>
- <button
- aria-label="Remove "Test""
- className="wc-block-components-chip__remove"
- disabled={true}
- onClick={[Function]}
- onKeyDown={[Function]}
+<div>
+ <li
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </button>
-</li>
+ Test
+ </span>
+ <button
+ aria-label="Remove "Test""
+ class="wc-block-components-chip__remove"
+ disabled=""
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </button>
+ </li>
+</div>
`;
exports[`RemovableChip with removeOnAnyClick should be a button when removeOnAnyClick is set to true 1`] = `
-<button
- aria-label="Remove "Test""
- className="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
- disabled={false}
- onClick={[Function]}
- onKeyDown={[Function]}
->
- <span
- aria-hidden={false}
- className="wc-block-components-chip__text"
- >
- Test
- </span>
- <span
- aria-hidden={true}
- className="wc-block-components-chip__remove"
+<div>
+ <button
+ aria-label="Remove "Test""
+ class="is-removable wc-block-components-chip wc-block-components-chip--radius-small"
>
- <svg
- aria-hidden={true}
- className="wc-block-components-chip__remove-icon"
- focusable={false}
- height={16}
- role="img"
- viewBox="0 0 24 24"
- width={16}
- xmlns="http://www.w3.org/2000/svg"
+ <span
+ aria-hidden="false"
+ class="wc-block-components-chip__text"
>
- <path
- d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
- />
- </svg>
- </span>
-</button>
+ Test
+ </span>
+ <span
+ aria-hidden="true"
+ class="wc-block-components-chip__remove"
+ >
+ <svg
+ aria-hidden="true"
+ class="wc-block-components-chip__remove-icon"
+ focusable="false"
+ height="16"
+ role="img"
+ viewBox="0 0 24 24"
+ width="16"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
+ />
+ </svg>
+ </span>
+ </button>
+</div>
`;
diff --git a/plugins/woocommerce/client/blocks/packages/components/chip/test/index.js b/plugins/woocommerce/client/blocks/packages/components/chip/test/index.js
index f666b1ab1ff..f95c8ff347d 100644
--- a/plugins/woocommerce/client/blocks/packages/components/chip/test/index.js
+++ b/plugins/woocommerce/client/blocks/packages/components/chip/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render } from '@testing-library/react';
/**
* Internal dependencies
@@ -10,100 +10,92 @@ import { Chip, RemovableChip } from '..';
describe( 'Chip', () => {
test( 'should render text', () => {
- const component = TestRenderer.create( <Chip text="Test" /> );
+ const { container } = render( <Chip text="Test" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render nodes as the text', () => {
- const component = TestRenderer.create(
- <Chip text={ <h1>Test</h1> } />
- );
+ const { container } = render( <Chip text={ <h1>Test</h1> } /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render defined radius', () => {
- const component = TestRenderer.create(
- <Chip text="Test" radius="large" />
- );
+ const { container } = render( <Chip text="Test" radius="large" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render screen reader text', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<Chip text="Test" screenReaderText="Test 2" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render children nodes', () => {
- const component = TestRenderer.create(
- <Chip text="Test">Lorem Ipsum</Chip>
- );
+ const { container } = render( <Chip text="Test">Lorem Ipsum</Chip> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
describe( 'with custom wrapper', () => {
test( 'should render a chip made up of a div instead of a li', () => {
- const component = TestRenderer.create(
- <Chip text="Test" element="div" />
- );
+ const { container } = render( <Chip text="Test" element="div" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
} );
describe( 'RemovableChip', () => {
test( 'should render text and the remove button', () => {
- const component = TestRenderer.create( <RemovableChip text="Test" /> );
+ const { container } = render( <RemovableChip text="Test" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render with disabled remove button', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<RemovableChip text="Test" disabled={ true } />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render custom aria label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<RemovableChip text={ <h1>Test</h1> } ariaLabel="Aria test" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render default aria label if text is a node', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<RemovableChip text={ <h1>Test</h1> } screenReaderText="Test 2" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render screen reader text aria label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<RemovableChip text="Test" screenReaderText="Test 2" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
describe( 'with removeOnAnyClick', () => {
test( 'should be a button when removeOnAnyClick is set to true', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<RemovableChip text="Test" removeOnAnyClick={ true } />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
} );
diff --git a/plugins/woocommerce/client/blocks/packages/components/label/test/__snapshots__/index.js.snap b/plugins/woocommerce/client/blocks/packages/components/label/test/__snapshots__/index.js.snap
index 48dccc73894..d3e50b43aa7 100644
--- a/plugins/woocommerce/client/blocks/packages/components/label/test/__snapshots__/index.js.snap
+++ b/plugins/woocommerce/client/blocks/packages/components/label/test/__snapshots__/index.js.snap
@@ -1,62 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Label with wrapperElement should render both label and screen reader label 1`] = `
-<label
- className="foo-bar"
- data-foo="bar"
->
- <span
- aria-hidden="true"
- >
- Lorem
- </span>
- <span
- className="screen-reader-text"
+<div>
+ <label
+ class="foo-bar"
+ data-foo="bar"
>
- Ipsum
- </span>
-</label>
+ <span
+ aria-hidden="true"
+ >
+ Lorem
+ </span>
+ <span
+ class="screen-reader-text"
+ >
+ Ipsum
+ </span>
+ </label>
+</div>
`;
exports[`Label with wrapperElement should render only the label 1`] = `
-<label
- className="foo-bar"
- data-foo="bar"
->
- Lorem
-</label>
+<div>
+ <label
+ class="foo-bar"
+ data-foo="bar"
+ >
+ Lorem
+ </label>
+</div>
`;
exports[`Label with wrapperElement should render only the screen reader label 1`] = `
-<label
- className="foo-bar screen-reader-text"
- data-foo="bar"
->
- Ipsum
-</label>
+<div>
+ <label
+ class="foo-bar screen-reader-text"
+ data-foo="bar"
+ >
+ Ipsum
+ </label>
+</div>
`;
exports[`Label without wrapperElement should render both label and screen reader label 1`] = `
-[
+<div>
<span
aria-hidden="true"
>
Lorem
- </span>,
+ </span>
<span
- className="screen-reader-text"
+ class="screen-reader-text"
>
Ipsum
- </span>,
-]
+ </span>
+</div>
`;
-exports[`Label without wrapperElement should render only the label 1`] = `"Lorem"`;
+exports[`Label without wrapperElement should render only the label 1`] = `
+<div>
+ Lorem
+</div>
+`;
exports[`Label without wrapperElement should render only the screen reader label 1`] = `
-<span
- className="screen-reader-text"
->
- Ipsum
-</span>
+<div>
+ <span
+ class="screen-reader-text"
+ >
+ Ipsum
+ </span>
+</div>
`;
diff --git a/plugins/woocommerce/client/blocks/packages/components/label/test/index.js b/plugins/woocommerce/client/blocks/packages/components/label/test/index.js
index 1ce67de5fa4..56e8b651997 100644
--- a/plugins/woocommerce/client/blocks/packages/components/label/test/index.js
+++ b/plugins/woocommerce/client/blocks/packages/components/label/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import TestRenderer from 'react-test-renderer';
+import { render } from '@testing-library/react';
/**
* Internal dependencies
@@ -11,31 +11,29 @@ import Label from '../';
describe( 'Label', () => {
describe( 'without wrapperElement', () => {
test( 'should render both label and screen reader label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<Label label="Lorem" screenReaderLabel="Ipsum" />
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render only the label', () => {
- const component = TestRenderer.create( <Label label="Lorem" /> );
+ const { container } = render( <Label label="Lorem" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render only the screen reader label', () => {
- const component = TestRenderer.create(
- <Label screenReaderLabel="Ipsum" />
- );
+ const { container } = render( <Label screenReaderLabel="Ipsum" /> );
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
describe( 'with wrapperElement', () => {
test( 'should render both label and screen reader label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<Label
label="Lorem"
screenReaderLabel="Ipsum"
@@ -47,11 +45,11 @@ describe( 'Label', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render only the label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<Label
label="Lorem"
wrapperElement="label"
@@ -62,11 +60,11 @@ describe( 'Label', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
test( 'should render only the screen reader label', () => {
- const component = TestRenderer.create(
+ const { container } = render(
<Label
screenReaderLabel="Ipsum"
wrapperElement="label"
@@ -77,7 +75,7 @@ describe( 'Label', () => {
/>
);
- expect( component.toJSON() ).toMatchSnapshot();
+ expect( container ).toMatchSnapshot();
} );
} );
} );
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2c4ce65320c..9c3d6a4b3ce 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3285,9 +3285,6 @@ importers:
react-refresh:
specifier: ^0.14.0
version: 0.14.2
- react-test-renderer:
- specifier: 18.3.x
- version: 18.3.1(react@18.3.1)
readline-sync:
specifier: ^1.4.10
version: 1.4.10
@@ -3853,9 +3850,6 @@ importers:
react-docgen-typescript-plugin:
specifier: ^1.0.5
version: 1.0.8(typescript@5.7.3)(webpack@5.97.1)
- react-test-renderer:
- specifier: 18.3.x
- version: 18.3.1(react@18.3.1)
redux:
specifier: 4.2.1
version: 4.2.1