diff --git a/plugins/woocommerce-blocks/assets/js/atomic/utils/render-parent-block.tsx b/plugins/woocommerce-blocks/assets/js/atomic/utils/render-parent-block.tsx
index 913371d0983..24b6c1bd296 100644
--- a/plugins/woocommerce-blocks/assets/js/atomic/utils/render-parent-block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/atomic/utils/render-parent-block.tsx
@@ -15,6 +15,7 @@ import {
hasInnerBlocks,
} from '@woocommerce/blocks-checkout';
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary';
+import type { ReactRootWithContainer } from '@woocommerce/base-utils';
/**
* This file contains logic used on the frontend to convert DOM elements (saved by the block editor) to React
@@ -294,7 +295,7 @@ export const renderParentBlock = ( {
selector: string;
// Function to generate the props object for the block.
getProps: ( el: Element, i: number ) => Record< string, unknown >;
-} ): void => {
+} ): ReactRootWithContainer[] => {
/**
* In addition to getProps, we need to render and return the children. This adds children to props.
*/
@@ -310,7 +311,7 @@ export const renderParentBlock = ( {
/**
* The only difference between using renderParentBlock and renderFrontend is that here we provide children.
*/
- renderFrontend( {
+ return renderFrontend( {
Block,
selector,
getProps: getPropsWithChildren,
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/form/test/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/form/test/index.js
index 3b802cdb8dd..9151c6e39e7 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/form/test/index.js
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/form/test/index.js
@@ -21,16 +21,11 @@ jest.mock( '@wordpress/element', () => {
};
} );
-const renderInCheckoutProvider = ( ui, options = { legacyRoot: true } ) => {
+const renderInCheckoutProvider = ( ui, options = {} ) => {
const Wrapper = ( { children } ) => {
return { children };
};
const result = render( ui, { wrapper: Wrapper, ...options } );
- // We need to switch to React 17 rendering to allow these tests to keep passing, but as a result the React
- // rendering error will be shown.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot`
- );
return result;
};
@@ -129,7 +124,7 @@ describe( 'Form Component', () => {
);
};
- it( 'updates context value when interacting with form elements', async () => {
+ test( 'updates context value when interacting with form elements', async () => {
renderInCheckoutProvider(
<>
@@ -155,7 +150,7 @@ describe( 'Form Component', () => {
);
} );
- it( 'input fields update when changing the country', async () => {
+ test( 'input fields update when changing the country', async () => {
renderInCheckoutProvider( );
await act( async () => {
@@ -182,7 +177,7 @@ describe( 'Form Component', () => {
expect( screen.getByLabelText( /Postal code/ ) ).toBeInTheDocument();
} );
- it( 'input values are reset after changing the country', async () => {
+ test( 'input values are reset after changing the country', async () => {
renderInCheckoutProvider( );
// First enter an address with no state, but fill the city.
diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/render-frontend.tsx b/plugins/woocommerce-blocks/assets/js/base/utils/render-frontend.tsx
index 4867fd9815f..0a1739a5407 100644
--- a/plugins/woocommerce-blocks/assets/js/base/utils/render-frontend.tsx
+++ b/plugins/woocommerce-blocks/assets/js/base/utils/render-frontend.tsx
@@ -1,8 +1,9 @@
/**
* External dependencies
*/
-import { render, Suspense } from '@wordpress/element';
+import { createRoot, useEffect, Suspense } from '@wordpress/element';
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary';
+import type { Root } from 'react-dom/client';
// Some blocks take care of rendering their inner blocks automatically. For
// example, the empty cart. In those cases, we don't want to trigger the render
@@ -27,6 +28,11 @@ export type GetPropsFn<
TAttributes extends Record< string, unknown >
> = ( el: HTMLElement, i: number ) => BlockProps< TProps, TAttributes >;
+export type ReactRootWithContainer = {
+ container: HTMLElement;
+ root: Root;
+};
+
interface RenderBlockParams<
TProps extends Record< string, unknown >,
TAttributes extends Record< string, unknown >
@@ -55,20 +61,32 @@ export const renderBlock = <
attributes = {} as TAttributes,
props = {} as BlockProps< TProps, TAttributes >,
errorBoundaryProps = {},
-}: RenderBlockParams< TProps, TAttributes > ): void => {
- render(
-
- }>
- { Block && }
-
- ,
- container,
- () => {
+}: RenderBlockParams< TProps, TAttributes > ): Root => {
+ const BlockWrapper = () => {
+ useEffect( () => {
if ( container.classList ) {
container.classList.remove( 'is-loading' );
}
- }
- );
+ }, [] );
+
+ return (
+
+ Loading...
+ }
+ >
+ { Block && (
+
+ ) }
+
+
+ );
+ };
+
+ const root = createRoot( container );
+ root.render( );
+ return root;
};
interface RenderBlockInContainersParams<
@@ -99,10 +117,14 @@ const renderBlockInContainers = <
containers,
getProps = () => ( {} as BlockProps< TProps, TAttributes > ),
getErrorBoundaryProps = () => ( {} ),
-}: RenderBlockInContainersParams< TProps, TAttributes > ): void => {
+}: RenderBlockInContainersParams<
+ TProps,
+ TAttributes
+> ): ReactRootWithContainer[] => {
if ( containers.length === 0 ) {
- return;
+ return [];
}
+ const roots: ReactRootWithContainer[] = [];
// Use Array.forEach for IE11 compatibility.
Array.prototype.forEach.call( containers, ( el, i ) => {
@@ -114,14 +136,19 @@ const renderBlockInContainers = <
...( props.attributes || {} ),
};
- renderBlock( {
- Block,
+ roots.push( {
container: el,
- props,
- attributes,
- errorBoundaryProps,
+ root: renderBlock( {
+ Block,
+ container: el,
+ props,
+ attributes,
+ errorBoundaryProps,
+ } ),
} );
} );
+
+ return roots;
};
// Given an element and a list of wrappers, check if the element is inside at
@@ -157,7 +184,10 @@ const renderBlockOutsideWrappers = <
getErrorBoundaryProps,
selector,
wrappers,
-}: RenderBlockOutsideWrappersParams< TProps, TAttributes > ): void => {
+}: RenderBlockOutsideWrappersParams<
+ TProps,
+ TAttributes
+> ): ReactRootWithContainer[] => {
const containers = document.body.querySelectorAll( selector );
// Filter out blocks inside the wrappers.
if ( wrappers && wrappers.length > 0 ) {
@@ -165,7 +195,8 @@ const renderBlockOutsideWrappers = <
return ! isElementInsideWrappers( el, wrappers );
} );
}
- renderBlockInContainers( {
+
+ return renderBlockInContainers( {
Block,
containers,
getProps,
@@ -234,20 +265,21 @@ export const renderFrontend = <
props:
| RenderBlockOutsideWrappersParams< TProps, TAttributes >
| RenderBlockInsideWrapperParams< TProps, TAttributes >
-): void => {
+): ReactRootWithContainer[] => {
const wrappersToSkipOnLoad = document.body.querySelectorAll(
selectorsToSkipOnLoad.join( ',' )
);
const { Block, getProps, getErrorBoundaryProps, selector } = props;
- renderBlockOutsideWrappers( {
+ const roots = renderBlockOutsideWrappers( {
Block,
getProps,
getErrorBoundaryProps,
selector,
wrappers: wrappersToSkipOnLoad,
} );
+
// For each wrapper, add an event listener to render the inner blocks when
// `wc-blocks_render_blocks_frontend` event is triggered.
Array.prototype.forEach.call( wrappersToSkipOnLoad, ( wrapper ) => {
@@ -255,6 +287,8 @@ export const renderFrontend = <
renderBlockInsideWrapper( { ...props, wrapper } );
} );
} );
+
+ return roots;
};
export default renderFrontend;
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/attribute-filter/test/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/attribute-filter/test/block.tsx
index ecdc9b111ae..3b1b191e7ff 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/attribute-filter/test/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/attribute-filter/test/block.tsx
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { render, screen } from '@testing-library/react';
+import { act, render, screen } from '@testing-library/react';
import * as hooks from '@woocommerce/base-context/hooks';
import userEvent from '@testing-library/user-event';
@@ -106,14 +106,8 @@ const setup = ( params: SetupParams ) => {
results: stubCollectionData(),
isLoading: false,
} );
- const utils = render( , {
- legacyRoot: true,
- } );
- // We need to switch to React 17 rendering to allow these tests to keep passing, but as a result the React
- // rendering error will be shown.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot`
- );
+ const utils = render( );
+
const applyButton = screen.getByRole( 'button', { name: /apply/i } );
const smallAttributeCheckbox = screen.getByRole( 'checkbox', {
name: /small/i,
@@ -164,8 +158,10 @@ describe( 'Filter by Attribute block', () => {
test( 'should enable Apply button when filter attributes are changed', async () => {
const { applyButton, smallAttributeCheckbox } =
setupWithoutSelectedFilterAttributes();
- await userEvent.click( smallAttributeCheckbox );
+ await act( async () => {
+ await userEvent.click( smallAttributeCheckbox );
+ } );
expect( applyButton ).not.toBeDisabled();
} );
} );
@@ -180,18 +176,25 @@ describe( 'Filter by Attribute block', () => {
test( 'should enable Apply button when filter attributes are changed', async () => {
const { applyButton, smallAttributeCheckbox } =
setupWithSelectedFilterAttributes();
- await userEvent.click( smallAttributeCheckbox );
+ await act( async () => {
+ await userEvent.click( smallAttributeCheckbox );
+ } );
expect( applyButton ).not.toBeDisabled();
} );
test( 'should disable Apply button when deselecting the same previously selected attribute', async () => {
const { applyButton, smallAttributeCheckbox } =
setupWithSelectedFilterAttributes( { filterSize: 'small' } );
- await userEvent.click( smallAttributeCheckbox );
+
+ await act( async () => {
+ await userEvent.click( smallAttributeCheckbox );
+ } );
expect( applyButton ).not.toBeDisabled();
- await userEvent.click( smallAttributeCheckbox );
+ await act( async () => {
+ await userEvent.click( smallAttributeCheckbox );
+ } );
expect( applyButton ).toBeDisabled();
} );
} );
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-pickup-options-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-pickup-options-block/block.tsx
index 916662798cf..9d6984b6984 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-pickup-options-block/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-pickup-options-block/block.tsx
@@ -6,6 +6,7 @@ import {
useState,
useEffect,
useCallback,
+ useMemo,
createInterpolateElement,
} from '@wordpress/element';
import { useShippingData, useStoreCart } from '@woocommerce/base-context/hooks';
@@ -138,10 +139,12 @@ const renderPickupLocation = (
const Block = (): JSX.Element | null => {
const { shippingRates, selectShippingRate } = useShippingData();
- // Get pickup locations from the first shipping package.
- const pickupLocations = ( shippingRates[ 0 ]?.shipping_rates || [] ).filter(
- isPackageRateCollectable
- );
+ // Memoize pickup locations to prevent re-rendering when the shipping rates change.
+ const pickupLocations = useMemo( () => {
+ return ( shippingRates[ 0 ]?.shipping_rates || [] ).filter(
+ isPackageRateCollectable
+ );
+ }, [ shippingRates ] );
const [ selectedOption, setSelectedOption ] = useState< string >(
() => pickupLocations.find( ( rate ) => rate.selected )?.rate_id || ''
@@ -168,13 +171,19 @@ const Block = (): JSX.Element | null => {
renderPickupLocation,
};
- // Update the selected option if there is no rate selected on mount.
useEffect( () => {
- if ( ! selectedOption && pickupLocations[ 0 ] ) {
+ if (
+ ! selectedOption &&
+ pickupLocations[ 0 ] &&
+ selectedOption !== pickupLocations[ 0 ].rate_id
+ ) {
setSelectedOption( pickupLocations[ 0 ].rate_id );
onSelectRate( pickupLocations[ 0 ].rate_id );
}
- }, [ onSelectRate, pickupLocations, selectedOption ] );
+ // Removing onSelectRate as it lead to an infinite loop when only one pickup location is available.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [ pickupLocations, selectedOption ] );
+
const packageCount = getShippingRatesPackageCount( shippingRates );
return (
<>
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
index 13633478b0c..80362a4b009 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
@@ -26,6 +26,7 @@ import type {
} from '@woocommerce/types';
import NoticeBanner from '@woocommerce/base-components/notice-banner';
import type { ReactElement } from 'react';
+import { useMemo } from '@wordpress/element';
/**
* Renders a shipping rate control option.
@@ -73,19 +74,22 @@ const Block = ( { noShippingPlaceholder = null } ): ReactElement | null => {
const { shippingAddress } = useCustomerData();
- const filteredShippingRates = isCollectable
- ? shippingRates.map( ( shippingRatesPackage ) => {
- return {
- ...shippingRatesPackage,
- shipping_rates: shippingRatesPackage.shipping_rates.filter(
- ( shippingRatesPackageRate ) =>
- ! hasCollectableRate(
- shippingRatesPackageRate.method_id
- )
- ),
- };
- } )
- : shippingRates;
+ const filteredShippingRates = useMemo( () => {
+ return isCollectable
+ ? shippingRates.map( ( shippingRatesPackage ) => {
+ return {
+ ...shippingRatesPackage,
+ shipping_rates:
+ shippingRatesPackage.shipping_rates.filter(
+ ( shippingRatesPackageRate ) =>
+ ! hasCollectableRate(
+ shippingRatesPackageRate.method_id
+ )
+ ),
+ };
+ } )
+ : shippingRates;
+ }, [ shippingRates, isCollectable ] );
if ( ! needsShipping ) {
return null;
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.tsx
index 59e33ddcd74..77b4097c39c 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.tsx
@@ -20,15 +20,10 @@ import {
isCartResponseTotals,
isNumber,
} from '@woocommerce/types';
-import {
- unmountComponentAtNode,
- useCallback,
- useEffect,
- useRef,
- useState,
-} from '@wordpress/element';
+import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import { sprintf, _n } from '@wordpress/i18n';
import clsx from 'clsx';
+import type { ReactRootWithContainer } from '@woocommerce/base-utils';
/**
* Internal dependencies
@@ -110,6 +105,8 @@ const MiniCartBlock = ( attributes: Props ): JSX.Element => {
setContentsNode( node );
}, [] );
+ const rootRef = useRef< ReactRootWithContainer[] | null >( null );
+
useEffect( () => {
const body = document.querySelector( 'body' );
if ( body ) {
@@ -134,7 +131,7 @@ const MiniCartBlock = ( attributes: Props ): JSX.Element => {
return;
}
if ( isOpen ) {
- renderParentBlock( {
+ const renderedBlock = renderParentBlock( {
Block: MiniCartContentsBlock,
blockName,
getProps: ( el: Element ) => {
@@ -151,16 +148,25 @@ const MiniCartBlock = ( attributes: Props ): JSX.Element => {
selector: '.wp-block-woocommerce-mini-cart-contents',
blockMap: getRegisteredBlockComponents( blockName ),
} );
+ rootRef.current = renderedBlock;
}
}
return () => {
if ( contentsNode instanceof Element && isOpen ) {
- const container = contentsNode.querySelector(
+ const unmountingContainer = contentsNode.querySelector(
'.wp-block-woocommerce-mini-cart-contents'
);
- if ( container ) {
- unmountComponentAtNode( container );
+
+ if ( unmountingContainer ) {
+ const foundRoot = rootRef?.current?.find(
+ ( { container } ) => unmountingContainer === container
+ );
+ if ( typeof foundRoot?.root?.unmount === 'function' ) {
+ setTimeout( () => {
+ foundRoot.root.unmount();
+ } );
+ }
}
}
};
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/test/block.js b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/test/block.js
index 313a7c3f3af..94a9644b75b 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/test/block.js
+++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/test/block.js
@@ -111,13 +111,6 @@ describe( 'Testing Mini-Cart', () => {
await waitFor( () =>
expect( screen.getByText( /your cart/i ) ).toBeInTheDocument()
);
-
- // The opening of the drawer uses deprecated ReactDOM.render.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
- // The stack trace
- expect.any( String )
- );
} );
it( 'closes the drawer when clicking on the close button', async () => {
@@ -132,9 +125,11 @@ describe( 'Testing Mini-Cart', () => {
// Close drawer.
let closeButton = null;
+
await waitFor( () => {
closeButton = screen.getByLabelText( /close/i );
} );
+
if ( closeButton ) {
await act( async () => {
await user.click( closeButton );
@@ -146,13 +141,6 @@ describe( 'Testing Mini-Cart', () => {
screen.queryByText( /your cart/i )
).not.toBeInTheDocument();
} );
-
- // The opening of the drawer uses deprecated ReactDOM.render.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
- // The stack trace
- expect.any( String )
- );
} );
it( 'renders empty cart if there are no items in the cart', async () => {
@@ -167,13 +155,6 @@ describe( 'Testing Mini-Cart', () => {
} );
expect( fetchMock ).toHaveBeenCalledTimes( 1 );
-
- // The opening of the drawer uses deprecated ReactDOM.render.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot%s`,
- // The stack trace
- expect.any( String )
- );
} );
it( 'updates contents when removed from cart event is triggered', async () => {
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/rating-filter/test/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/rating-filter/test/block.tsx
index 1cfbe910fb7..aad8468ae82 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/rating-filter/test/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/rating-filter/test/block.tsx
@@ -2,7 +2,14 @@
* External dependencies
*/
import React from '@wordpress/element';
-import { render, screen, waitFor, within } from '@testing-library/react';
+import {
+ act,
+ cleanup,
+ render,
+ screen,
+ waitFor,
+ within,
+} from '@testing-library/react';
import * as hooks from '@woocommerce/base-context/hooks';
import userEvent from '@testing-library/user-event';
@@ -59,6 +66,7 @@ const selectors = {
};
const setup = ( params: SetupParams ) => {
+ cleanup();
const url = `http://woo.local/${
params.filterRating ? '?rating_filter=' + params.filterRating : ''
}`;
@@ -78,14 +86,7 @@ const setup = ( params: SetupParams ) => {
} );
const { container, ...utils } = render(
- ,
- { legacyRoot: true }
- );
-
- // We need to switch to React 17 rendering to allow these tests to keep passing, but as a result the React
- // rendering error will be shown.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot`
+
);
const getList = () => container.querySelector( selectors.list );
@@ -203,74 +204,81 @@ describe( 'Filter by Rating block', () => {
describe( 'Single choice Dropdown', () => {
test( 'renders dropdown', () => {
const { getDropdown, getList } = setupSingleChoiceDropdown();
+
expect( getDropdown() ).toBeInTheDocument();
expect( getList() ).toBeNull();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = '2';
- const { getRating2Chips, getRating4Chips, getRating5Chips } =
- setupSingleChoiceDropdown( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = '2';
+ const { getRating2Chips, getRating4Chips, getRating5Chips } =
+ setupSingleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeNull();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeNull();
+ expect( getRating5Chips() ).toBeNull();
+ } );
} );
test( 'replaces chosen option when another one is clicked', async () => {
- const ratingParam = '2';
- const {
- getDropdown,
- getRating2Chips,
- getRating4Chips,
- getRating4Suggestion,
- } = setupSingleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2';
+ const {
+ getDropdown,
+ getRating2Chips,
+ getRating4Chips,
+ getRating4Suggestion,
+ } = setupSingleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeNull();
- const dropdown = getDropdown();
+ const dropdown = getDropdown();
- if ( dropdown ) {
- await userEvent.click( dropdown );
- acceptErrorWithDuplicatedKeys();
- }
+ if ( dropdown ) {
+ await userEvent.click( dropdown );
+ acceptErrorWithDuplicatedKeys();
+ }
- const rating4Suggestion = getRating4Suggestion();
+ const rating4Suggestion = getRating4Suggestion();
- if ( rating4Suggestion ) {
- await userEvent.click( rating4Suggestion );
- }
+ if ( rating4Suggestion ) {
+ await userEvent.click( rating4Suggestion );
+ }
- expect( getRating2Chips() ).toBeNull();
- expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating2Chips() ).toBeNull();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ } );
} );
test( 'removes the option when the X button is clicked', async () => {
- const ratingParam = '4';
- const {
- getRating2Chips,
- getRating4Chips,
- getRating5Chips,
- getRemoveButtonFromChips,
- } = setupMultipleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '4';
+ const {
+ getRating2Chips,
+ getRating4Chips,
+ getRating5Chips,
+ getRemoveButtonFromChips,
+ } = setupMultipleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeNull();
- expect( getRating4Chips() ).toBeInTheDocument();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeNull();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating5Chips() ).toBeNull();
- const removeRating4Button = getRemoveButtonFromChips(
- getRating4Chips()
- );
+ const removeRating4Button = getRemoveButtonFromChips(
+ getRating4Chips()
+ );
- if ( removeRating4Button ) {
- await userEvent.click( removeRating4Button );
- acceptErrorWithDuplicatedKeys();
- }
+ if ( removeRating4Button ) {
+ await userEvent.click( removeRating4Button );
+ acceptErrorWithDuplicatedKeys();
+ }
- expect( getRating2Chips() ).toBeNull();
- expect( getRating4Chips() ).toBeNull();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeNull();
+ expect( getRating4Chips() ).toBeNull();
+ expect( getRating5Chips() ).toBeNull();
+ } );
} );
} );
@@ -281,83 +289,89 @@ describe( 'Filter by Rating block', () => {
expect( getList() ).toBeNull();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = '2,4';
- const { getRating2Chips, getRating4Chips, getRating5Chips } =
- setupMultipleChoiceDropdown( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = '2,4';
+ const { getRating2Chips, getRating4Chips, getRating5Chips } =
+ setupMultipleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeInTheDocument();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating5Chips() ).toBeNull();
+ } );
} );
test( 'adds chosen option to another one that is clicked', async () => {
- const ratingParam = '2';
- const {
- getDropdown,
- getRating2Chips,
- getRating4Chips,
- getRating5Chips,
- getRating4Suggestion,
- getRating5Suggestion,
- } = setupMultipleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2';
+ const {
+ getDropdown,
+ getRating2Chips,
+ getRating4Chips,
+ getRating5Chips,
+ getRating4Suggestion,
+ getRating5Suggestion,
+ } = setupMultipleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeNull();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeNull();
+ expect( getRating5Chips() ).toBeNull();
- const dropdown = getDropdown();
+ const dropdown = getDropdown();
- if ( dropdown ) {
- await userEvent.click( dropdown );
- acceptErrorWithDuplicatedKeys();
- }
+ if ( dropdown ) {
+ await userEvent.click( dropdown );
+ acceptErrorWithDuplicatedKeys();
+ }
- const rating4Suggestion = getRating4Suggestion();
+ const rating4Suggestion = getRating4Suggestion();
- if ( rating4Suggestion ) {
- await userEvent.click( rating4Suggestion );
- }
+ if ( rating4Suggestion ) {
+ await userEvent.click( rating4Suggestion );
+ }
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeInTheDocument();
- expect( getRating5Chips() ).toBeNull();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating5Chips() ).toBeNull();
- const rating5Suggestion = getRating5Suggestion();
+ const rating5Suggestion = getRating5Suggestion();
- if ( rating5Suggestion ) {
- await userEvent.click( rating5Suggestion );
- }
+ if ( rating5Suggestion ) {
+ await userEvent.click( rating5Suggestion );
+ }
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeInTheDocument();
- expect( getRating5Chips() ).toBeInTheDocument();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating5Chips() ).toBeInTheDocument();
+ } );
} );
test( 'removes the option when the X button is clicked', async () => {
- const ratingParam = '2,4,5';
- const {
- getRating2Chips,
- getRating4Chips,
- getRating5Chips,
- getRemoveButtonFromChips,
- } = setupMultipleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2,4,5';
+ const {
+ getRating2Chips,
+ getRating4Chips,
+ getRating5Chips,
+ getRemoveButtonFromChips,
+ } = setupMultipleChoiceDropdown( ratingParam );
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeInTheDocument();
- expect( getRating5Chips() ).toBeInTheDocument();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeInTheDocument();
+ expect( getRating5Chips() ).toBeInTheDocument();
- const removeRating4Button = getRemoveButtonFromChips(
- getRating4Chips()
- );
+ const removeRating4Button = getRemoveButtonFromChips(
+ getRating4Chips()
+ );
- if ( removeRating4Button ) {
- await userEvent.click( removeRating4Button );
- }
+ if ( removeRating4Button ) {
+ await userEvent.click( removeRating4Button );
+ }
- expect( getRating2Chips() ).toBeInTheDocument();
- expect( getRating4Chips() ).toBeNull();
- expect( getRating5Chips() ).toBeInTheDocument();
+ expect( getRating2Chips() ).toBeInTheDocument();
+ expect( getRating4Chips() ).toBeNull();
+ expect( getRating5Chips() ).toBeInTheDocument();
+ } );
} );
} );
@@ -368,61 +382,67 @@ describe( 'Filter by Rating block', () => {
expect( getList() ).toBeInTheDocument();
} );
- test( 'renders checked options based on URL params', () => {
- const ratingParam = '4';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupSingleChoiceList( ratingParam );
+ test( 'renders checked options based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = '4';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupSingleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeFalsy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeFalsy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ } );
} );
test( 'replaces chosen option when another one is clicked', async () => {
- const ratingParam = '2';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupSingleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupSingleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeTruthy();
- expect( getRating4Checkbox()?.checked ).toBeFalsy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeTruthy();
+ expect( getRating4Checkbox()?.checked ).toBeFalsy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
- const rating4checkbox = getRating4Checkbox();
+ const rating4checkbox = getRating4Checkbox();
- if ( rating4checkbox ) {
- await userEvent.click( rating4checkbox );
- }
+ if ( rating4checkbox ) {
+ await act( async () => {
+ await userEvent.click( rating4checkbox );
+ } );
+ }
- expect( getRating2Checkbox()?.checked ).toBeFalsy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeFalsy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ } );
} );
test( 'removes the option when it is clicked again', async () => {
- const ratingParam = '4';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupMultipleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '4';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeFalsy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeFalsy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
- const rating4checkbox = getRating4Checkbox();
+ const rating4checkbox = getRating4Checkbox();
- if ( rating4checkbox ) {
- await userEvent.click( rating4checkbox );
- }
+ if ( rating4checkbox ) {
+ await userEvent.click( rating4checkbox );
+ }
- await waitFor( () => {
expect( getRating2Checkbox()?.checked ).toBeFalsy();
expect( getRating4Checkbox()?.checked ).toBeFalsy();
expect( getRating5Checkbox()?.checked ).toBeFalsy();
@@ -437,38 +457,40 @@ describe( 'Filter by Rating block', () => {
expect( getList() ).toBeInTheDocument();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = '4,5';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupMultipleChoiceList( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = '4,5';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeFalsy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeTruthy();
+ expect( getRating2Checkbox()?.checked ).toBeFalsy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeTruthy();
+ } );
} );
test( 'adds chosen option to another one that is clicked', async () => {
- const ratingParam = '2,4';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupMultipleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2,4';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeTruthy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeTruthy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
- const rating5checkbox = getRating5Checkbox();
+ const rating5checkbox = getRating5Checkbox();
- if ( rating5checkbox ) {
- await userEvent.click( rating5checkbox );
- }
+ if ( rating5checkbox ) {
+ await userEvent.click( rating5checkbox );
+ }
- await waitFor( () => {
expect( getRating2Checkbox()?.checked ).toBeTruthy();
expect( getRating4Checkbox()?.checked ).toBeTruthy();
expect( getRating5Checkbox()?.checked ).toBeTruthy();
@@ -476,24 +498,24 @@ describe( 'Filter by Rating block', () => {
} );
test( 'removes the option when it is clicked again', async () => {
- const ratingParam = '2,4';
- const {
- getRating2Checkbox,
- getRating4Checkbox,
- getRating5Checkbox,
- } = setupMultipleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = '2,4';
+ const {
+ getRating2Checkbox,
+ getRating4Checkbox,
+ getRating5Checkbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getRating2Checkbox()?.checked ).toBeTruthy();
- expect( getRating4Checkbox()?.checked ).toBeTruthy();
- expect( getRating5Checkbox()?.checked ).toBeFalsy();
+ expect( getRating2Checkbox()?.checked ).toBeTruthy();
+ expect( getRating4Checkbox()?.checked ).toBeTruthy();
+ expect( getRating5Checkbox()?.checked ).toBeFalsy();
- const rating2checkbox = getRating2Checkbox();
+ const rating2checkbox = getRating2Checkbox();
- if ( rating2checkbox ) {
- await userEvent.click( rating2checkbox );
- }
+ if ( rating2checkbox ) {
+ await userEvent.click( rating2checkbox );
+ }
- await waitFor( () => {
expect( getRating2Checkbox()?.checked ).toBeFalsy();
expect( getRating4Checkbox()?.checked ).toBeTruthy();
expect( getRating5Checkbox()?.checked ).toBeFalsy();
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/stock-filter/test/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/stock-filter/test/block.tsx
index 358b619b96d..be9786cb8f5 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/stock-filter/test/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/stock-filter/test/block.tsx
@@ -2,7 +2,14 @@
* External dependencies
*/
import React from '@wordpress/element';
-import { act, render, screen, within, waitFor } from '@testing-library/react';
+import {
+ act,
+ cleanup,
+ render,
+ screen,
+ within,
+ waitFor,
+} from '@testing-library/react';
import { default as fetchMock } from 'jest-fetch-mock';
import userEvent from '@testing-library/user-event';
@@ -68,6 +75,7 @@ const selectors = {
};
const setup = ( params: SetupParams = {} ) => {
+ cleanup();
const url = `http://woo.local/${
params.filterStock ? '?filter_stock_status=' + params.filterStock : ''
}`;
@@ -87,14 +95,7 @@ const setup = ( params: SetupParams = {} ) => {
};
const { container, ...utils } = render(
- ,
- { legacyRoot: true }
- );
-
- // We need to switch to React 17 rendering to allow these tests to keep passing, but as a result the React
- // rendering error will be shown.
- expect( console ).toHaveErroredWith(
- `Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot`
+
);
const getList = () => container.querySelector( selectors.list );
@@ -227,7 +228,7 @@ describe( 'Filter by Stock block', () => {
fetchMock.resetMocks();
} );
- it( 'renders the stock filter block', async () => {
+ test( 'renders the stock filter block', async () => {
const { container } = setup( {
showFilterButton: false,
showCounts: false,
@@ -235,7 +236,7 @@ describe( 'Filter by Stock block', () => {
expect( container ).toMatchSnapshot();
} );
- it( 'renders the stock filter block with the filter button', async () => {
+ test( 'renders the stock filter block with the filter button', async () => {
const { container } = setup( {
showFilterButton: true,
showCounts: false,
@@ -243,7 +244,7 @@ describe( 'Filter by Stock block', () => {
expect( container ).toMatchSnapshot();
} );
- it( 'renders the stock filter block with the product counts', async () => {
+ test( 'renders the stock filter block with the product counts', async () => {
const { container } = setup( {
showFilterButton: false,
showCounts: true,
@@ -254,80 +255,86 @@ describe( 'Filter by Stock block', () => {
describe( 'Single choice Dropdown', () => {
test( 'renders dropdown', () => {
const { getDropdown, getList } = setupSingleChoiceDropdown();
+
expect( getDropdown() ).toBeInTheDocument();
expect( getList() ).toBeNull();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = 'instock';
- const { getInStockChips, getOutOfStockChips, getOnBackorderChips } =
- setupSingleChoiceDropdown( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'instock';
+ const {
+ getInStockChips,
+ getOutOfStockChips,
+ getOnBackorderChips,
+ } = setupSingleChoiceDropdown( ratingParam );
- expect( getInStockChips() ).toBeInTheDocument();
- expect( getOutOfStockChips() ).toBeNull();
- expect( getOnBackorderChips() ).toBeNull();
+ expect( getInStockChips() ).toBeInTheDocument();
+ expect( getOutOfStockChips() ).toBeNull();
+ expect( getOnBackorderChips() ).toBeNull();
+ } );
} );
test( 'replaces chosen option when another one is clicked', async () => {
- const user = userEvent.setup();
- const ratingParam = 'instock';
- const {
- getDropdown,
- getInStockChips,
- getOutOfStockChips,
- getOutOfStockSuggestion,
- } = setupSingleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const user = userEvent.setup();
+ const ratingParam = 'instock';
+ const {
+ getDropdown,
+ getInStockChips,
+ getOutOfStockChips,
+ getOutOfStockSuggestion,
+ } = setupSingleChoiceDropdown( ratingParam );
- expect( getInStockChips() ).toBeInTheDocument();
- expect( getOutOfStockChips() ).toBeNull();
+ expect( getInStockChips() ).toBeInTheDocument();
+ expect( getOutOfStockChips() ).toBeNull();
- const dropdown = getDropdown();
+ const dropdown = getDropdown();
- if ( dropdown ) {
- await act( async () => {
- await user.click( dropdown );
- } );
- }
+ if ( dropdown ) {
+ await act( async () => {
+ await user.click( dropdown );
+ } );
+ }
- const outOfStockSuggestion = getOutOfStockSuggestion();
+ const outOfStockSuggestion = getOutOfStockSuggestion();
- if ( outOfStockSuggestion ) {
- await act( async () => {
- await user.click( outOfStockSuggestion );
- } );
- }
+ if ( outOfStockSuggestion ) {
+ await act( async () => {
+ await user.click( outOfStockSuggestion );
+ } );
+ }
- expect( getInStockChips() ).toBeNull();
- expect( getOutOfStockChips() ).toBeInTheDocument();
+ expect( getInStockChips() ).toBeNull();
+ expect( getOutOfStockChips() ).toBeInTheDocument();
+ } );
} );
test( 'removes the option when the X button is clicked', async () => {
- const user = userEvent.setup();
- const ratingParam = 'outofstock';
- const {
- getInStockChips,
- getOutOfStockChips,
- getOnBackorderChips,
- getRemoveButtonFromChips,
- } = setupMultipleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const user = userEvent.setup();
+ const ratingParam = 'outofstock';
+ const {
+ getInStockChips,
+ getOutOfStockChips,
+ getOnBackorderChips,
+ getRemoveButtonFromChips,
+ } = setupMultipleChoiceDropdown( ratingParam );
- await waitFor( () => {
expect( getInStockChips() ).toBeNull();
expect( getOutOfStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeNull();
- } );
- const removeOutOfStockButton = getRemoveButtonFromChips(
- getOutOfStockChips()
- );
+ const removeOutOfStockButton = getRemoveButtonFromChips(
+ getOutOfStockChips()
+ );
- if ( removeOutOfStockButton ) {
- act( async () => {
- await user.click( removeOutOfStockButton );
- } );
- }
+ if ( removeOutOfStockButton ) {
+ await act( async () => {
+ await user.click( removeOutOfStockButton );
+ } );
+ }
- await waitFor( () => {
expect( getInStockChips() ).toBeNull();
expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeNull();
@@ -342,67 +349,65 @@ describe( 'Filter by Stock block', () => {
expect( getList() ).toBeNull();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = 'instock,onbackorder';
- const { getInStockChips, getOutOfStockChips, getOnBackorderChips } =
- setupMultipleChoiceDropdown( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'instock,onbackorder';
+ const {
+ getInStockChips,
+ getOutOfStockChips,
+ getOnBackorderChips,
+ } = setupMultipleChoiceDropdown( ratingParam );
- expect( getInStockChips() ).toBeInTheDocument();
- expect( getOutOfStockChips() ).toBeNull();
- expect( getOnBackorderChips() ).toBeInTheDocument();
- } );
-
- test( 'adds chosen option to another one that is clicked', async () => {
- const user = userEvent.setup();
- const ratingParam = 'onbackorder';
- const {
- getDropdown,
- getInStockChips,
- getOutOfStockChips,
- getOnBackorderChips,
- getInStockSuggestion,
- getOutOfStockSuggestion,
- } = setupMultipleChoiceDropdown( ratingParam );
-
- await waitFor( () => {
- expect( getInStockChips() ).toBeNull();
+ expect( getInStockChips() ).toBeInTheDocument();
expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeInTheDocument();
} );
- const dropdown = getDropdown();
+ } );
- if ( dropdown ) {
- await act( async () => {
+ test( 'adds chosen option to another one that is clicked', async () => {
+ await waitFor( async () => {
+ const user = userEvent.setup();
+ const ratingParam = 'onbackorder';
+ const {
+ getDropdown,
+ getInStockChips,
+ getOutOfStockChips,
+ getOnBackorderChips,
+ getInStockSuggestion,
+ getOutOfStockSuggestion,
+ } = setupMultipleChoiceDropdown( ratingParam );
+
+ expect( getInStockChips() ).toBeNull();
+ expect( getOutOfStockChips() ).toBeNull();
+ expect( getOnBackorderChips() ).toBeInTheDocument();
+
+ const dropdown = getDropdown();
+
+ if ( dropdown ) {
await user.click( dropdown );
- } );
- }
+ }
- const inStockSuggestion = getInStockSuggestion();
+ const inStockSuggestion = getInStockSuggestion();
- if ( inStockSuggestion ) {
- await act( async () => {
+ if ( inStockSuggestion ) {
await user.click( inStockSuggestion );
- } );
- }
+ }
- expect( getInStockChips() ).toBeInTheDocument();
- expect( getOutOfStockChips() ).toBeNull();
- expect( getOnBackorderChips() ).toBeInTheDocument();
+ expect( getInStockChips() ).toBeInTheDocument();
+ expect( getOutOfStockChips() ).toBeNull();
+ expect( getOnBackorderChips() ).toBeInTheDocument();
- const freshDropdown = getDropdown();
- if ( freshDropdown ) {
- await act( async () => {
+ const freshDropdown = getDropdown();
+ if ( freshDropdown ) {
await user.click( freshDropdown );
- } );
- }
+ }
- const outOfStockSuggestion = getOutOfStockSuggestion();
+ const outOfStockSuggestion = getOutOfStockSuggestion();
- if ( outOfStockSuggestion ) {
- userEvent.click( outOfStockSuggestion );
- }
+ if ( outOfStockSuggestion ) {
+ await userEvent.click( outOfStockSuggestion );
+ }
- await waitFor( () => {
expect( getInStockChips() ).toBeInTheDocument();
expect( getOutOfStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeInTheDocument();
@@ -410,32 +415,30 @@ describe( 'Filter by Stock block', () => {
} );
test( 'removes the option when the X button is clicked', async () => {
- const user = userEvent.setup();
- const ratingParam = 'instock,outofstock,onbackorder';
- const {
- getInStockChips,
- getOutOfStockChips,
- getOnBackorderChips,
- getRemoveButtonFromChips,
- } = setupMultipleChoiceDropdown( ratingParam );
+ await waitFor( async () => {
+ const user = userEvent.setup();
+ const ratingParam = 'instock,outofstock,onbackorder';
+ const {
+ getInStockChips,
+ getOutOfStockChips,
+ getOnBackorderChips,
+ getRemoveButtonFromChips,
+ } = setupMultipleChoiceDropdown( ratingParam );
- await waitFor( () => {
expect( getInStockChips() ).toBeInTheDocument();
expect( getOutOfStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeInTheDocument();
- } );
- const removeOutOfStockButton = getRemoveButtonFromChips(
- getOutOfStockChips()
- );
+ const removeOutOfStockButton = getRemoveButtonFromChips(
+ getOutOfStockChips()
+ );
- if ( removeOutOfStockButton ) {
- act( async () => {
- await user.click( removeOutOfStockButton );
- } );
- }
+ if ( removeOutOfStockButton ) {
+ await act( async () => {
+ await user.click( removeOutOfStockButton );
+ } );
+ }
- await waitFor( () => {
expect( getInStockChips() ).toBeInTheDocument();
expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeInTheDocument();
@@ -450,67 +453,73 @@ describe( 'Filter by Stock block', () => {
expect( getList() ).toBeInTheDocument();
} );
- test( 'renders checked options based on URL params', () => {
- const ratingParam = 'instock';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupSingleChoiceList( ratingParam );
+ test( 'renders checked options based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'instock';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupSingleChoiceList( ratingParam );
- expect( getInStockCheckbox()?.checked ).toBeTruthy();
- expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
- expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ expect( getInStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ } );
} );
test( 'replaces chosen option when another one is clicked', async () => {
- const user = userEvent.setup();
- const ratingParam = 'outofstock';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupSingleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const user = userEvent.setup();
+ const ratingParam = 'outofstock';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupSingleChoiceList( ratingParam );
- expect( getInStockCheckbox()?.checked ).toBeFalsy();
- expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
- expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ expect( getInStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
- const onBackorderCheckbox = getOnBackorderCheckbox();
+ const onBackorderCheckbox = getOnBackorderCheckbox();
- if ( onBackorderCheckbox ) {
- await act( async () => {
- await user.click( onBackorderCheckbox );
- } );
- }
+ if ( onBackorderCheckbox ) {
+ await act( async () => {
+ await user.click( onBackorderCheckbox );
+ } );
+ }
- expect( getInStockCheckbox()?.checked ).toBeFalsy();
- expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
- expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
+ expect( getInStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
+ } );
} );
test( 'removes the option when it is clicked again', async () => {
- const ratingParam = 'onbackorder';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupMultipleChoiceList( ratingParam );
+ await waitFor( async () => {
+ const ratingParam = 'onbackorder';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getInStockCheckbox()?.checked ).toBeFalsy();
- expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
- expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
-
- const onBackorderCheckbox = getOnBackorderCheckbox();
-
- if ( onBackorderCheckbox ) {
- userEvent.click( onBackorderCheckbox );
- }
-
- await waitFor( () => {
expect( getInStockCheckbox()?.checked ).toBeFalsy();
expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
- expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
+
+ const onBackorderCheckbox = getOnBackorderCheckbox();
+
+ if ( onBackorderCheckbox ) {
+ userEvent.click( onBackorderCheckbox );
+ }
+
+ await waitFor( () => {
+ expect( getInStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ } );
} );
} );
} );
@@ -522,66 +531,72 @@ describe( 'Filter by Stock block', () => {
expect( getList() ).toBeInTheDocument();
} );
- test( 'renders chips based on URL params', () => {
- const ratingParam = 'instock,onbackorder';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupMultipleChoiceList( ratingParam );
+ test( 'renders chips based on URL params', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'instock,onbackorder';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getInStockCheckbox()?.checked ).toBeTruthy();
- expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
- expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
- } );
-
- test( 'adds chosen option to another one that is clicked', async () => {
- const ratingParam = 'outofstock,onbackorder';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupMultipleChoiceList( ratingParam );
-
- expect( getInStockCheckbox()?.checked ).toBeFalsy();
- expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
- expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
-
- const inStockCheckbox = getInStockCheckbox();
-
- if ( inStockCheckbox ) {
- userEvent.click( inStockCheckbox );
- }
-
- await waitFor( () => {
expect( getInStockCheckbox()?.checked ).toBeTruthy();
- expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeFalsy();
expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
} );
} );
- test( 'removes the option when it is clicked again', async () => {
- const ratingParam = 'instock,outofstock';
- const {
- getInStockCheckbox,
- getOutOfStockCheckbox,
- getOnBackorderCheckbox,
- } = setupMultipleChoiceList( ratingParam );
+ test( 'adds chosen option to another one that is clicked', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'outofstock,onbackorder';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupMultipleChoiceList( ratingParam );
- expect( getInStockCheckbox()?.checked ).toBeTruthy();
- expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
- expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
-
- const inStockCheckbox = getInStockCheckbox();
-
- if ( inStockCheckbox ) {
- userEvent.click( inStockCheckbox );
- }
-
- await waitFor( () => {
expect( getInStockCheckbox()?.checked ).toBeFalsy();
expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
+
+ const inStockCheckbox = getInStockCheckbox();
+
+ if ( inStockCheckbox ) {
+ userEvent.click( inStockCheckbox );
+ }
+
+ await waitFor( () => {
+ expect( getInStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeTruthy();
+ } );
+ } );
+ } );
+
+ test( 'removes the option when it is clicked again', async () => {
+ await waitFor( async () => {
+ const ratingParam = 'instock,outofstock';
+ const {
+ getInStockCheckbox,
+ getOutOfStockCheckbox,
+ getOnBackorderCheckbox,
+ } = setupMultipleChoiceList( ratingParam );
+
+ expect( getInStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+
+ const inStockCheckbox = getInStockCheckbox();
+
+ if ( inStockCheckbox ) {
+ userEvent.click( inStockCheckbox );
+ }
+
+ await waitFor( () => {
+ expect( getInStockCheckbox()?.checked ).toBeFalsy();
+ expect( getOutOfStockCheckbox()?.checked ).toBeTruthy();
+ expect( getOnBackorderCheckbox()?.checked ).toBeFalsy();
+ } );
} );
} );
} );
diff --git a/plugins/woocommerce/changelog/48843-update-48796-use-createRoot-instead-of-render b/plugins/woocommerce/changelog/48843-update-48796-use-createRoot-instead-of-render
new file mode 100644
index 00000000000..c6f497480f0
--- /dev/null
+++ b/plugins/woocommerce/changelog/48843-update-48796-use-createRoot-instead-of-render
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Switch `render()` to `createRoot().render()` to use React 18 features.
\ No newline at end of file
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js
index aeca8fbb71d..62d8d6f2cdc 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js
@@ -137,9 +137,7 @@ test.describe(
await page
.getByRole( 'button', { name: 'Add a coupon' } )
.click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ i ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -182,9 +180,7 @@ test.describe(
await page
.getByRole( 'button', { name: 'Add a coupon' } )
.click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ i ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -224,9 +220,7 @@ test.describe(
} ) => {
// try to add two same coupons and verify the error message
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ 0 ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -236,9 +230,7 @@ test.describe(
)
).toBeVisible();
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ 0 ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -254,9 +246,7 @@ test.describe(
} ) => {
// add coupon with usage limit
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( couponLimitedCode );
+ await page.getByLabel( 'Enter code' ).fill( couponLimitedCode );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout-block-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout-block-coupons.spec.js
index 95bdb3f28f6..6db1b13ff81 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout-block-coupons.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout-block-coupons.spec.js
@@ -138,9 +138,7 @@ test.describe(
await page
.getByRole( 'button', { name: 'Add a coupon' } )
.click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ i ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -183,9 +181,7 @@ test.describe(
await page
.getByRole( 'button', { name: 'Add a coupon' } )
.click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ i ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -225,9 +221,7 @@ test.describe(
} ) => {
// try to add two same coupons and verify the error message
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ 0 ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -237,9 +231,7 @@ test.describe(
)
).toBeVisible();
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( coupons[ 0 ].code );
+ await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
@@ -255,9 +247,7 @@ test.describe(
} ) => {
// add coupon with usage limit
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
- await page
- .locator( '#wc-block-components-totals-coupon__input-0' )
- .fill( couponLimitedCode );
+ await page.getByLabel( 'Enter code' ).fill( couponLimitedCode );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page