Update blocks JS tests to React 18 (#47383)

This commit is contained in:
Sam Seay 2024-05-15 17:33:36 +08:00 committed by GitHub
parent 02c640480d
commit 3ef7a01840
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 2829 additions and 81507 deletions

View File

@ -72,8 +72,8 @@
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"@types/react": "^17.0.71", "@types/react": "^17.0.71",
"react": "^17.0.2", "react-resize-aware": "3.1.1",
"react-resize-aware": "3.1.1" "@automattic/tour-kit>@wordpress/element": "4.4.1"
} }
} }
} }

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Update the Blocks JS tests to React 18

View File

@ -79,6 +79,7 @@
"@babel/runtime": "^7.23.5", "@babel/runtime": "^7.23.5",
"@testing-library/react": "12.1.3", "@testing-library/react": "12.1.3",
"@testing-library/react-hooks": "7.0.2", "@testing-library/react-hooks": "7.0.2",
"react-test-renderer": "17.0.2",
"@types/jest": "^27.5.2", "@types/jest": "^27.5.2",
"@types/lodash": "^4.14.202", "@types/lodash": "^4.14.202",
"@types/md5": "^2.3.5", "@types/md5": "^2.3.5",

View File

@ -121,6 +121,7 @@
"@testing-library/react": "12.1.3", "@testing-library/react": "12.1.3",
"@testing-library/react-hooks": "7.0.2", "@testing-library/react-hooks": "7.0.2",
"@testing-library/user-event": "13.5.0", "@testing-library/user-event": "13.5.0",
"react-test-renderer": "17.0.2",
"@types/cookie": "^0.4.1", "@types/cookie": "^0.4.1",
"@types/dompurify": "^2.4.0", "@types/dompurify": "^2.4.0",
"@types/expect-puppeteer": "^4.4.7", "@types/expect-puppeteer": "^4.4.7",

View File

@ -1,7 +1,7 @@
/** /**
* External dependencies * External dependencies
*/ */
import { render, screen } from '@testing-library/react'; import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import { CheckoutProvider } from '@woocommerce/base-context'; import { CheckoutProvider } from '@woocommerce/base-context';
import { useCheckoutAddress } from '@woocommerce/base-context/hooks'; import { useCheckoutAddress } from '@woocommerce/base-context/hooks';
@ -21,11 +21,18 @@ jest.mock( '@wordpress/element', () => {
}; };
} ); } );
const renderInCheckoutProvider = ( ui, options = {} ) => { const renderInCheckoutProvider = ( ui, options = { legacyRoot: true } ) => {
const Wrapper = ( { children } ) => { const Wrapper = ( { children } ) => {
return <CheckoutProvider>{ children }</CheckoutProvider>; return <CheckoutProvider>{ children }</CheckoutProvider>;
}; };
return render( ui, { wrapper: Wrapper, ...options } ); 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;
}; };
// Countries used in testing addresses must be in the wcSettings global. // Countries used in testing addresses must be in the wcSettings global.
@ -63,29 +70,34 @@ const inputAddress = async ( {
postcode = null, postcode = null,
} ) => { } ) => {
if ( country ) { if ( country ) {
const countryInput = screen.getByLabelText( countryRegExp ); const countryInput = screen.queryByRole( 'combobox', {
userEvent.type( countryInput, country + '{arrowdown}{enter}' ); name: countryRegExp,
} );
await userEvent.type( countryInput, country + '{arrowdown}{enter}' );
} }
if ( city ) { if ( city ) {
const cityInput = screen.getByLabelText( cityRegExp ); const cityInput = screen.getByLabelText( cityRegExp );
userEvent.type( cityInput, city ); await userEvent.type( cityInput, city );
} }
if ( state ) { if ( state ) {
const stateButton = screen.queryByRole( 'combobox', { const stateButton = screen.queryByRole( 'combobox', {
name: stateRegExp, name: stateRegExp,
} ); } );
// State input might be a select or a text input. // State input might be a select or a text input.
if ( stateButton ) { if ( stateButton ) {
userEvent.click( stateButton ); await userEvent.click( stateButton );
userEvent.click( screen.getByRole( 'option', { name: state } ) ); await userEvent.click(
screen.getByRole( 'option', { name: state } )
);
} else { } else {
const stateInput = screen.getByLabelText( stateRegExp ); const stateInput = screen.getByLabelText( stateRegExp );
userEvent.type( stateInput, state ); await userEvent.type( stateInput, state );
} }
} }
if ( postcode ) { if ( postcode ) {
const postcodeInput = screen.getByLabelText( postalCodeRegExp ); const postcodeInput = screen.getByLabelText( postalCodeRegExp );
userEvent.type( postcodeInput, postcode ); await userEvent.type( postcodeInput, postcode );
} }
}; };
@ -114,7 +126,7 @@ describe( 'Form Component', () => {
); );
}; };
it( 'updates context value when interacting with form elements', () => { it( 'updates context value when interacting with form elements', async () => {
renderInCheckoutProvider( renderInCheckoutProvider(
<> <>
<WrappedAddressForm type="shipping" /> <WrappedAddressForm type="shipping" />
@ -122,9 +134,11 @@ describe( 'Form Component', () => {
</> </>
); );
inputAddress( primaryAddress ); await act( async () => {
await inputAddress( primaryAddress );
} );
expect( screen.getByText( /country/ ) ).toHaveTextContent( expect( screen.getByText( /country:/ ) ).toHaveTextContent(
`country: ${ primaryAddress.countryKey }` `country: ${ primaryAddress.countryKey }`
); );
expect( screen.getByText( /city/ ) ).toHaveTextContent( expect( screen.getByText( /city/ ) ).toHaveTextContent(
@ -138,38 +152,54 @@ describe( 'Form Component', () => {
); );
} ); } );
it( 'input fields update when changing the country', () => { it( 'input fields update when changing the country', async () => {
renderInCheckoutProvider( <WrappedAddressForm type="shipping" /> ); renderInCheckoutProvider( <WrappedAddressForm type="shipping" /> );
inputAddress( primaryAddress ); await act( async () => {
await inputAddress( primaryAddress );
} );
// Verify correct labels are used. // Verify correct labels are used.
expect( screen.getByLabelText( /City/ ) ).toBeInTheDocument(); expect( screen.getByLabelText( /City/ ) ).toBeInTheDocument();
expect( screen.getByLabelText( /County/ ) ).toBeInTheDocument(); expect( screen.getByLabelText( /County/ ) ).toBeInTheDocument();
expect( screen.getByLabelText( /Postcode/ ) ).toBeInTheDocument(); expect( screen.getByLabelText( /Postcode/ ) ).toBeInTheDocument();
inputAddress( secondaryAddress ); await act( async () => {
await inputAddress( secondaryAddress );
} );
// Verify state input has been removed. // Verify state input has been removed.
expect( screen.queryByText( stateRegExp ) ).not.toBeInTheDocument(); expect( screen.queryByText( stateRegExp ) ).not.toBeInTheDocument();
inputAddress( tertiaryAddress ); await act( async () => {
await inputAddress( tertiaryAddress );
} );
// Verify postal code input label changed. // Verify postal code input label changed.
expect( screen.getByLabelText( /Postal code/ ) ).toBeInTheDocument(); expect( screen.getByLabelText( /Postal code/ ) ).toBeInTheDocument();
} ); } );
it( 'input values are reset after changing the country', () => { it( 'input values are reset after changing the country', async () => {
renderInCheckoutProvider( <WrappedAddressForm type="shipping" /> ); renderInCheckoutProvider( <WrappedAddressForm type="shipping" /> );
inputAddress( secondaryAddress ); await act( async () => {
await inputAddress( secondaryAddress );
} );
// Only update `country` to verify other values are reset. // Only update `country` to verify other values are reset.
inputAddress( { country: primaryAddress.country } ); await act( async () => {
await inputAddress( { country: primaryAddress.country } );
} );
expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' ); expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' );
// Repeat the test with an address which has a select for the state. // Repeat the test with an address which has a select for the state.
inputAddress( tertiaryAddress ); await act( async () => {
inputAddress( { country: primaryAddress.country } ); await inputAddress( tertiaryAddress );
} );
await act( async () => {
await inputAddress( { country: primaryAddress.country } );
} );
expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' ); expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' );
} ); } );
} ); } );

View File

@ -102,7 +102,7 @@ describe( 'LocalPickupSelect', () => {
expect( screen.getByText( 'Package 1' ) ).toBeInTheDocument(); expect( screen.getByText( 'Package 1' ) ).toBeInTheDocument();
} ); } );
it( 'Calls the correct functions when changing selected option', () => { it( 'Calls the correct functions when changing selected option', async () => {
const setSelectedOption = jest.fn(); const setSelectedOption = jest.fn();
const onSelectRate = jest.fn(); const onSelectRate = jest.fn();
render( render(
@ -111,10 +111,10 @@ describe( 'LocalPickupSelect', () => {
onSelectRateOverride={ onSelectRate } onSelectRateOverride={ onSelectRate }
/> />
); );
userEvent.click( screen.getByText( 'Store 2' ) ); await userEvent.click( screen.getByText( 'Store 2' ) );
expect( setSelectedOption ).toHaveBeenLastCalledWith( '2' ); expect( setSelectedOption ).toHaveBeenLastCalledWith( '2' );
expect( onSelectRate ).toHaveBeenLastCalledWith( '2' ); expect( onSelectRate ).toHaveBeenLastCalledWith( '2' );
userEvent.click( screen.getByText( 'Store 1' ) ); await userEvent.click( screen.getByText( 'Store 1' ) );
expect( setSelectedOption ).toHaveBeenLastCalledWith( '1' ); expect( setSelectedOption ).toHaveBeenLastCalledWith( '1' );
expect( onSelectRate ).toHaveBeenLastCalledWith( '1' ); expect( onSelectRate ).toHaveBeenLastCalledWith( '1' );
} ); } );

View File

@ -66,7 +66,6 @@ exports[`ProductDetails should render details 1`] = `
<li <li
className="" className=""
> >
<span <span
className="wc-block-components-product-details__value" className="wc-block-components-product-details__value"
> >

View File

@ -12,12 +12,15 @@ import { VALIDATION_STORE_KEY } from '@woocommerce/block-data';
import { TotalsCoupon } from '..'; import { TotalsCoupon } from '..';
describe( 'TotalsCoupon', () => { describe( 'TotalsCoupon', () => {
it( "Shows a validation error when one is in the wc/store/validation data store and doesn't show one when there isn't", () => { it( "Shows a validation error when one is in the wc/store/validation data store and doesn't show one when there isn't", async () => {
const user = userEvent.setup();
const { rerender } = render( <TotalsCoupon instanceId={ 'coupon' } /> ); const { rerender } = render( <TotalsCoupon instanceId={ 'coupon' } /> );
const openCouponFormButton = screen.getByText( 'Add a coupon' ); const openCouponFormButton = screen.getByText( 'Add a coupon' );
expect( openCouponFormButton ).toBeInTheDocument(); expect( openCouponFormButton ).toBeInTheDocument();
userEvent.click( openCouponFormButton ); await act( async () => {
await user.click( openCouponFormButton );
} );
expect( expect(
screen.queryByText( 'Invalid coupon code' ) screen.queryByText( 'Invalid coupon code' )
).not.toBeInTheDocument(); ).not.toBeInTheDocument();

View File

@ -1,7 +1,8 @@
/** /**
* External dependencies * External dependencies
*/ */
import { render, fireEvent, findByText } from '@testing-library/react'; import { render, findByText, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
/** /**
* Internal dependencies * Internal dependencies
@ -49,7 +50,7 @@ describe( 'NoticeBanner', () => {
expect( summaryElement ).toBeInTheDocument(); expect( summaryElement ).toBeInTheDocument();
} ); } );
test( 'can be dismissed when isDismissible prop is true', () => { test( 'can be dismissed when isDismissible prop is true', async () => {
const onRemoveMock = jest.fn(); const onRemoveMock = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<NoticeBanner <NoticeBanner
@ -61,11 +62,13 @@ describe( 'NoticeBanner', () => {
</NoticeBanner> </NoticeBanner>
); );
const closeButton = getByRole( 'button' ); const closeButton = getByRole( 'button' );
fireEvent.click( closeButton ); await act( async () => {
await userEvent.click( closeButton );
} );
expect( onRemoveMock ).toHaveBeenCalled(); expect( onRemoveMock ).toHaveBeenCalled();
} ); } );
test( 'calls onRemove function when the notice is dismissed', () => { test( 'calls onRemove function when the notice is dismissed', async () => {
const onRemoveMock = jest.fn(); const onRemoveMock = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<NoticeBanner status="info" isDismissible onRemove={ onRemoveMock }> <NoticeBanner status="info" isDismissible onRemove={ onRemoveMock }>
@ -73,7 +76,9 @@ describe( 'NoticeBanner', () => {
</NoticeBanner> </NoticeBanner>
); );
const closeButton = getByRole( 'button' ); const closeButton = getByRole( 'button' );
fireEvent.click( closeButton ); await act( async () => {
await userEvent.click( closeButton );
} );
expect( onRemoveMock ).toHaveBeenCalled(); expect( onRemoveMock ).toHaveBeenCalled();
} ); } );

View File

@ -3,7 +3,8 @@
*/ */
import { useCartEventsContext } from '@woocommerce/base-context'; import { useCartEventsContext } from '@woocommerce/base-context';
import { useEffect } from '@wordpress/element'; import { useEffect } from '@wordpress/element';
import { render, screen, waitFor } from '@testing-library/react'; import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
/** /**
* Internal dependencies * Internal dependencies
@ -13,13 +14,15 @@ import Block from '../../../../../../blocks/cart/inner-blocks/proceed-to-checkou
describe( 'CartEventsProvider', () => { describe( 'CartEventsProvider', () => {
it( 'allows observers to unsubscribe', async () => { it( 'allows observers to unsubscribe', async () => {
const user = userEvent.setup();
const mockObserver = jest.fn().mockReturnValue( { type: 'error' } ); const mockObserver = jest.fn().mockReturnValue( { type: 'error' } );
const MockObserverComponent = () => { const MockObserverComponent = () => {
const { onProceedToCheckout } = useCartEventsContext(); const { onProceedToCheckout } = useCartEventsContext();
useEffect( () => { useEffect( () => {
const unsubscribe = onProceedToCheckout( () => { const unsubscribe = onProceedToCheckout( () => {
mockObserver();
unsubscribe(); unsubscribe();
mockObserver();
} ); } );
}, [ onProceedToCheckout ] ); }, [ onProceedToCheckout ] );
return <div>Mock observer</div>; return <div>Mock observer</div>;
@ -33,6 +36,7 @@ describe( 'CartEventsProvider', () => {
</div> </div>
</CartEventsProvider> </CartEventsProvider>
); );
// TODO: Fix a recent deprecation of showSpinner prop of Button called in this component. // TODO: Fix a recent deprecation of showSpinner prop of Button called in this component.
expect( console ).toHaveWarned(); expect( console ).toHaveWarned();
@ -42,9 +46,14 @@ describe( 'CartEventsProvider', () => {
// Forcibly set the button URL to # to prevent JSDOM error: `["Error: Not implemented: navigation (except hash changes)` // Forcibly set the button URL to # to prevent JSDOM error: `["Error: Not implemented: navigation (except hash changes)`
button.parentElement?.removeAttribute( 'href' ); button.parentElement?.removeAttribute( 'href' );
// Click twice. The observer should unsubscribe after the first click. await act( async () => {
button.click(); await user.click( button );
button.click(); } );
await act( async () => {
await user.click( button );
} );
await waitFor( () => { await waitFor( () => {
expect( mockObserver ).toHaveBeenCalledTimes( 1 ); expect( mockObserver ).toHaveBeenCalledTimes( 1 );
} ); } );

View File

@ -106,7 +106,14 @@ const setup = ( params: SetupParams ) => {
results: stubCollectionData(), results: stubCollectionData(),
isLoading: false, isLoading: false,
} ); } );
const utils = render( <AttributeFilterBlock attributes={ attributes } /> ); const utils = render( <AttributeFilterBlock attributes={ attributes } />, {
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 applyButton = screen.getByRole( 'button', { name: /apply/i } ); const applyButton = screen.getByRole( 'button', { name: /apply/i } );
const smallAttributeCheckbox = screen.getByRole( 'checkbox', { const smallAttributeCheckbox = screen.getByRole( 'checkbox', {
name: /small/i, name: /small/i,
@ -154,10 +161,10 @@ describe( 'Filter by Attribute block', () => {
expect( applyButton ).toBeDisabled(); expect( applyButton ).toBeDisabled();
} ); } );
test( 'should enable Apply button when filter attributes are changed', () => { test( 'should enable Apply button when filter attributes are changed', async () => {
const { applyButton, smallAttributeCheckbox } = const { applyButton, smallAttributeCheckbox } =
setupWithoutSelectedFilterAttributes(); setupWithoutSelectedFilterAttributes();
userEvent.click( smallAttributeCheckbox ); await userEvent.click( smallAttributeCheckbox );
expect( applyButton ).not.toBeDisabled(); expect( applyButton ).not.toBeDisabled();
} ); } );
@ -170,21 +177,21 @@ describe( 'Filter by Attribute block', () => {
expect( applyButton ).toBeDisabled(); expect( applyButton ).toBeDisabled();
} ); } );
test( 'should enable Apply button when filter attributes are changed', () => { test( 'should enable Apply button when filter attributes are changed', async () => {
const { applyButton, smallAttributeCheckbox } = const { applyButton, smallAttributeCheckbox } =
setupWithSelectedFilterAttributes(); setupWithSelectedFilterAttributes();
userEvent.click( smallAttributeCheckbox ); await userEvent.click( smallAttributeCheckbox );
expect( applyButton ).not.toBeDisabled(); expect( applyButton ).not.toBeDisabled();
} ); } );
test( 'should disable Apply button when deselecting the same previously selected attribute', () => { test( 'should disable Apply button when deselecting the same previously selected attribute', async () => {
const { applyButton, smallAttributeCheckbox } = const { applyButton, smallAttributeCheckbox } =
setupWithSelectedFilterAttributes( { filterSize: 'small' } ); setupWithSelectedFilterAttributes( { filterSize: 'small' } );
userEvent.click( smallAttributeCheckbox ); await userEvent.click( smallAttributeCheckbox );
expect( applyButton ).not.toBeDisabled(); expect( applyButton ).not.toBeDisabled();
userEvent.click( smallAttributeCheckbox ); await userEvent.click( smallAttributeCheckbox );
expect( applyButton ).toBeDisabled(); expect( applyButton ).toBeDisabled();
} ); } );
} ); } );

View File

@ -133,6 +133,8 @@ describe( 'PaymentMethods', () => {
} ); } );
test( 'selecting new payment method', async () => { test( 'selecting new payment method', async () => {
const user = userEvent.setup();
const ShowActivePaymentMethod = () => { const ShowActivePaymentMethod = () => {
const { activePaymentMethod, activeSavedToken } = const { activePaymentMethod, activeSavedToken } =
wpDataFunctions.useSelect( ( select ) => { wpDataFunctions.useSelect( ( select ) => {
@ -192,7 +194,9 @@ describe( 'PaymentMethods', () => {
expect( savedToken ).toBeNull(); expect( savedToken ).toBeNull();
} ); } );
userEvent.click( screen.getByText( 'Select new payment' ) ); await act( async () => {
await user.click( screen.getByText( 'Select new payment' ) );
} );
await waitFor( () => { await waitFor( () => {
const activePaymentMethod = screen.queryByText( const activePaymentMethod = screen.queryByText(

View File

@ -231,6 +231,13 @@ describe( 'Testing cart', () => {
} ); } );
expect( quantityInput.value ).toBe( '5' ); expect( quantityInput.value ).toBe( '5' );
// React Transition Group uses deprecated findDOMNode, so we need to suppress the warning. This will have to be fixed in React 19.
expect( console ).toHaveErroredWith(
`Warning: findDOMNode is deprecated and will be removed in the next major release. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-find-node%s`,
// The stack trace
expect.any( String )
);
} ); } );
it( 'does not show the remove item button when a filter prevents this', async () => { it( 'does not show the remove item button when a filter prevents this', async () => {

View File

@ -5,6 +5,7 @@ import {
render, render,
findByLabelText, findByLabelText,
queryByLabelText, queryByLabelText,
act,
} from '@testing-library/react'; } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
@ -60,6 +61,7 @@ describe( 'FrontendBlock', () => {
} ); } );
it( 'Clears any validation errors when the checkbox is checked', async () => { it( 'Clears any validation errors when the checkbox is checked', async () => {
const user = userEvent.setup();
const { container } = render( const { container } = render(
<FrontendBlock <FrontendBlock
checkbox={ true } checkbox={ true }
@ -70,7 +72,9 @@ describe( 'FrontendBlock', () => {
container, container,
'I agree to the terms and conditions' 'I agree to the terms and conditions'
); );
userEvent.click( checkbox ); await act( async () => {
await user.click( checkbox );
} );
expect( actionCreators.clearValidationError ).toHaveBeenLastCalledWith( expect( actionCreators.clearValidationError ).toHaveBeenLastCalledWith(
expect.stringMatching( /terms-and-conditions-\d/ ) expect.stringMatching( /terms-and-conditions-\d/ )
); );

View File

@ -8,6 +8,7 @@ import {
fireEvent, fireEvent,
findByPlaceholderText, findByPlaceholderText,
queryByPlaceholderText, queryByPlaceholderText,
act,
} from '@testing-library/react'; } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
@ -18,6 +19,8 @@ import OrderNotes from '../index';
describe( 'Checkout order notes', () => { describe( 'Checkout order notes', () => {
it( 'Shows a textarea when the checkbox to add order notes is toggled', async () => { it( 'Shows a textarea when the checkbox to add order notes is toggled', async () => {
const user = userEvent.setup();
const { container } = render( const { container } = render(
<OrderNotes <OrderNotes
disabled={ false } disabled={ false }
@ -31,7 +34,10 @@ describe( 'Checkout order notes', () => {
'Add a note to your order' 'Add a note to your order'
); );
await userEvent.click( checkbox ); await act( async () => {
await user.click( checkbox );
} );
const textarea = await findByPlaceholderText( const textarea = await findByPlaceholderText(
container, container,
'Enter a note' 'Enter a note'
@ -59,6 +65,7 @@ describe( 'Checkout order notes', () => {
} ); } );
it( 'Retains the order note when toggling the textarea on and off', async () => { it( 'Retains the order note when toggling the textarea on and off', async () => {
const user = userEvent.setup();
const onChange = jest.fn(); const onChange = jest.fn();
const { container, rerender } = render( const { container, rerender } = render(
<OrderNotes <OrderNotes
@ -74,7 +81,9 @@ describe( 'Checkout order notes', () => {
'Add a note to your order' 'Add a note to your order'
); );
await userEvent.click( checkbox ); await act( async () => {
await user.click( checkbox );
} );
// The onChange handler should not have been called because the value is the same as what was stored // The onChange handler should not have been called because the value is the same as what was stored
expect( onChange ).not.toHaveBeenCalled(); expect( onChange ).not.toHaveBeenCalled();
@ -83,7 +92,10 @@ describe( 'Checkout order notes', () => {
container, container,
'Enter a note' 'Enter a note'
); );
fireEvent.change( textarea, { target: { value: 'Test message' } } ); // eslint-disable-next-line testing-library/no-unnecessary-act -- Act warnings still happen without wrapping in act.
await act( async () => {
fireEvent.change( textarea, { target: { value: 'Test message' } } );
} );
expect( onChange ).toHaveBeenLastCalledWith( 'Test message' ); expect( onChange ).toHaveBeenLastCalledWith( 'Test message' );
// Rerender here with the new value to simulate the onChange updating the value // Rerender here with the new value to simulate the onChange updating the value
@ -97,7 +109,10 @@ describe( 'Checkout order notes', () => {
); );
// Toggle off. // Toggle off.
await userEvent.click( checkbox ); await act( async () => {
await user.click( checkbox );
} );
expect( onChange ).toHaveBeenLastCalledWith( '' ); expect( onChange ).toHaveBeenLastCalledWith( '' );
// Rerender here with an empty value to simulate the onChange updating the value // Rerender here with an empty value to simulate the onChange updating the value
@ -111,7 +126,9 @@ describe( 'Checkout order notes', () => {
); );
// Toggle back on. // Toggle back on.
await userEvent.click( checkbox ); await act( async () => {
await user.click( checkbox );
} );
expect( onChange ).toHaveBeenLastCalledWith( 'Test message' ); expect( onChange ).toHaveBeenLastCalledWith( 'Test message' );
} ); } );
} ); } );

View File

@ -100,21 +100,35 @@ describe( 'Testing Mini-Cart', () => {
} ); } );
it( 'opens Mini-Cart drawer when clicking on button', async () => { it( 'opens Mini-Cart drawer when clicking on button', async () => {
const user = userEvent.setup();
render( <MiniCartBlock /> ); render( <MiniCartBlock /> );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() ); await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
userEvent.click( screen.getByLabelText( /items/i ) ); await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
await waitFor( () => await waitFor( () =>
expect( screen.getByText( /your cart/i ) ).toBeInTheDocument() 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 () => { it( 'closes the drawer when clicking on the close button', async () => {
const user = userEvent.setup();
render( <MiniCartBlock /> ); render( <MiniCartBlock /> );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() ); await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
// Open drawer. // Open drawer.
userEvent.click( screen.getByLabelText( /items/i ) ); await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
// Close drawer. // Close drawer.
let closeButton = null; let closeButton = null;
@ -122,7 +136,9 @@ describe( 'Testing Mini-Cart', () => {
closeButton = screen.getByLabelText( /close/i ); closeButton = screen.getByLabelText( /close/i );
} ); } );
if ( closeButton ) { if ( closeButton ) {
userEvent.click( closeButton ); await act( async () => {
await user.click( closeButton );
} );
} }
await waitFor( () => { await waitFor( () => {
@ -130,16 +146,34 @@ describe( 'Testing Mini-Cart', () => {
screen.queryByText( /your cart/i ) screen.queryByText( /your cart/i )
).not.toBeInTheDocument(); ).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 () => { it( 'renders empty cart if there are no items in the cart', async () => {
const user = userEvent.setup();
mockEmptyCart(); mockEmptyCart();
render( <MiniCartBlock /> ); render( <MiniCartBlock /> );
await waitFor( () => expect( fetchMock ).toHaveBeenCalled() ); await waitFor( () => expect( fetchMock ).toHaveBeenCalled() );
userEvent.click( screen.getByLabelText( /items/i ) );
await act( async () => {
await user.click( screen.getByLabelText( /items/i ) );
} );
expect( fetchMock ).toHaveBeenCalledTimes( 1 ); 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 () => { it( 'updates contents when removed from cart event is triggered', async () => {

View File

@ -2,7 +2,7 @@
* External dependencies * External dependencies
*/ */
import React from '@wordpress/element'; import React from '@wordpress/element';
import { act, render, screen, waitFor, within } from '@testing-library/react'; import { render, screen, waitFor, within } from '@testing-library/react';
import * as hooks from '@woocommerce/base-context/hooks'; import * as hooks from '@woocommerce/base-context/hooks';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
@ -78,7 +78,14 @@ const setup = ( params: SetupParams ) => {
} ); } );
const { container, ...utils } = render( const { container, ...utils } = render(
<RatingFilterBlock attributes={ attributes } /> <RatingFilterBlock attributes={ attributes } />,
{ 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 ); const getList = () => container.querySelector( selectors.list );
@ -210,7 +217,7 @@ describe( 'Filter by Rating block', () => {
expect( getRating5Chips() ).toBeNull(); expect( getRating5Chips() ).toBeNull();
} ); } );
test( 'replaces chosen option when another one is clicked', () => { test( 'replaces chosen option when another one is clicked', async () => {
const ratingParam = '2'; const ratingParam = '2';
const { const {
getDropdown, getDropdown,
@ -225,21 +232,21 @@ describe( 'Filter by Rating block', () => {
const dropdown = getDropdown(); const dropdown = getDropdown();
if ( dropdown ) { if ( dropdown ) {
userEvent.click( dropdown ); await userEvent.click( dropdown );
acceptErrorWithDuplicatedKeys(); acceptErrorWithDuplicatedKeys();
} }
const rating4Suggestion = getRating4Suggestion(); const rating4Suggestion = getRating4Suggestion();
if ( rating4Suggestion ) { if ( rating4Suggestion ) {
userEvent.click( rating4Suggestion ); await userEvent.click( rating4Suggestion );
} }
expect( getRating2Chips() ).toBeNull(); expect( getRating2Chips() ).toBeNull();
expect( getRating4Chips() ).toBeInTheDocument(); expect( getRating4Chips() ).toBeInTheDocument();
} ); } );
test( 'removes the option when the X button is clicked', () => { test( 'removes the option when the X button is clicked', async () => {
const ratingParam = '4'; const ratingParam = '4';
const { const {
getRating2Chips, getRating2Chips,
@ -257,9 +264,7 @@ describe( 'Filter by Rating block', () => {
); );
if ( removeRating4Button ) { if ( removeRating4Button ) {
act( () => { await userEvent.click( removeRating4Button );
userEvent.click( removeRating4Button );
} );
acceptErrorWithDuplicatedKeys(); acceptErrorWithDuplicatedKeys();
} }
@ -286,7 +291,7 @@ describe( 'Filter by Rating block', () => {
expect( getRating5Chips() ).toBeNull(); expect( getRating5Chips() ).toBeNull();
} ); } );
test( 'adds chosen option to another one that is clicked', () => { test( 'adds chosen option to another one that is clicked', async () => {
const ratingParam = '2'; const ratingParam = '2';
const { const {
getDropdown, getDropdown,
@ -304,14 +309,14 @@ describe( 'Filter by Rating block', () => {
const dropdown = getDropdown(); const dropdown = getDropdown();
if ( dropdown ) { if ( dropdown ) {
userEvent.click( dropdown ); await userEvent.click( dropdown );
acceptErrorWithDuplicatedKeys(); acceptErrorWithDuplicatedKeys();
} }
const rating4Suggestion = getRating4Suggestion(); const rating4Suggestion = getRating4Suggestion();
if ( rating4Suggestion ) { if ( rating4Suggestion ) {
userEvent.click( rating4Suggestion ); await userEvent.click( rating4Suggestion );
} }
expect( getRating2Chips() ).toBeInTheDocument(); expect( getRating2Chips() ).toBeInTheDocument();
@ -321,7 +326,7 @@ describe( 'Filter by Rating block', () => {
const rating5Suggestion = getRating5Suggestion(); const rating5Suggestion = getRating5Suggestion();
if ( rating5Suggestion ) { if ( rating5Suggestion ) {
userEvent.click( rating5Suggestion ); await userEvent.click( rating5Suggestion );
} }
expect( getRating2Chips() ).toBeInTheDocument(); expect( getRating2Chips() ).toBeInTheDocument();
@ -329,7 +334,7 @@ describe( 'Filter by Rating block', () => {
expect( getRating5Chips() ).toBeInTheDocument(); expect( getRating5Chips() ).toBeInTheDocument();
} ); } );
test( 'removes the option when the X button is clicked', () => { test( 'removes the option when the X button is clicked', async () => {
const ratingParam = '2,4,5'; const ratingParam = '2,4,5';
const { const {
getRating2Chips, getRating2Chips,
@ -347,9 +352,7 @@ describe( 'Filter by Rating block', () => {
); );
if ( removeRating4Button ) { if ( removeRating4Button ) {
act( () => { await userEvent.click( removeRating4Button );
userEvent.click( removeRating4Button );
} );
} }
expect( getRating2Chips() ).toBeInTheDocument(); expect( getRating2Chips() ).toBeInTheDocument();
@ -393,7 +396,7 @@ describe( 'Filter by Rating block', () => {
const rating4checkbox = getRating4Checkbox(); const rating4checkbox = getRating4Checkbox();
if ( rating4checkbox ) { if ( rating4checkbox ) {
userEvent.click( rating4checkbox ); await userEvent.click( rating4checkbox );
} }
expect( getRating2Checkbox()?.checked ).toBeFalsy(); expect( getRating2Checkbox()?.checked ).toBeFalsy();
@ -416,7 +419,7 @@ describe( 'Filter by Rating block', () => {
const rating4checkbox = getRating4Checkbox(); const rating4checkbox = getRating4Checkbox();
if ( rating4checkbox ) { if ( rating4checkbox ) {
userEvent.click( rating4checkbox ); await userEvent.click( rating4checkbox );
} }
await waitFor( () => { await waitFor( () => {
@ -462,7 +465,7 @@ describe( 'Filter by Rating block', () => {
const rating5checkbox = getRating5Checkbox(); const rating5checkbox = getRating5Checkbox();
if ( rating5checkbox ) { if ( rating5checkbox ) {
userEvent.click( rating5checkbox ); await userEvent.click( rating5checkbox );
} }
await waitFor( () => { await waitFor( () => {
@ -487,7 +490,7 @@ describe( 'Filter by Rating block', () => {
const rating2checkbox = getRating2Checkbox(); const rating2checkbox = getRating2Checkbox();
if ( rating2checkbox ) { if ( rating2checkbox ) {
userEvent.click( rating2checkbox ); await userEvent.click( rating2checkbox );
} }
await waitFor( () => { await waitFor( () => {

View File

@ -15,7 +15,7 @@ jest.mock( '@woocommerce/settings', () => ( {
/** /**
* External dependencies * External dependencies
*/ */
import { render } from '@testing-library/react'; import { act, render } from '@testing-library/react';
import { getSetting } from '@woocommerce/settings'; import { getSetting } from '@woocommerce/settings';
/** /**
@ -48,7 +48,7 @@ describe( 'ReviewsFrontendBlock', () => {
rating: 1, rating: 1,
}; };
it( 'Does not render when there are no reviews', () => { it( 'Does not render when there are no reviews', async () => {
const { container } = render( const { container } = render(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - withReviews HOC will need refactoring to TS to fix this. // @ts-ignore - withReviews HOC will need refactoring to TS to fix this.
@ -62,8 +62,9 @@ describe( 'ReviewsFrontendBlock', () => {
onChangeOrderby={ jest.fn() } onChangeOrderby={ jest.fn() }
/> />
); );
await act( async () => {
expect( container.firstChild ).toBeNull(); expect( container ).toBeEmptyDOMElement();
} );
} ); } );
it( 'Shows load more button when there are more reviews than displayed.', async () => { it( 'Shows load more button when there are more reviews than displayed.', async () => {

View File

@ -2,7 +2,6 @@
exports[`Filter by Stock block renders the stock filter block 1`] = ` exports[`Filter by Stock block renders the stock filter block 1`] = `
<div> <div>
<div <div
class="wc-block-stock-filter style-list" class="wc-block-stock-filter style-list"
> >
@ -112,7 +111,6 @@ exports[`Filter by Stock block renders the stock filter block 1`] = `
exports[`Filter by Stock block renders the stock filter block with the filter button 1`] = ` exports[`Filter by Stock block renders the stock filter block with the filter button 1`] = `
<div> <div>
<div <div
class="wc-block-stock-filter style-list" class="wc-block-stock-filter style-list"
> >
@ -238,7 +236,6 @@ exports[`Filter by Stock block renders the stock filter block with the filter bu
exports[`Filter by Stock block renders the stock filter block with the product counts 1`] = ` exports[`Filter by Stock block renders the stock filter block with the product counts 1`] = `
<div> <div>
<div <div
class="wc-block-stock-filter style-list" class="wc-block-stock-filter style-list"
> >

View File

@ -87,7 +87,14 @@ const setup = ( params: SetupParams = {} ) => {
}; };
const { container, ...utils } = render( const { container, ...utils } = render(
<Block attributes={ attributes } /> <Block attributes={ attributes } />,
{ 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 ); const getList = () => container.querySelector( selectors.list );
@ -261,7 +268,8 @@ describe( 'Filter by Stock block', () => {
expect( getOnBackorderChips() ).toBeNull(); expect( getOnBackorderChips() ).toBeNull();
} ); } );
test( 'replaces chosen option when another one is clicked', () => { test( 'replaces chosen option when another one is clicked', async () => {
const user = userEvent.setup();
const ratingParam = 'instock'; const ratingParam = 'instock';
const { const {
getDropdown, getDropdown,
@ -276,20 +284,25 @@ describe( 'Filter by Stock block', () => {
const dropdown = getDropdown(); const dropdown = getDropdown();
if ( dropdown ) { if ( dropdown ) {
userEvent.click( dropdown ); await act( async () => {
await user.click( dropdown );
} );
} }
const outOfStockSuggestion = getOutOfStockSuggestion(); const outOfStockSuggestion = getOutOfStockSuggestion();
if ( outOfStockSuggestion ) { if ( outOfStockSuggestion ) {
userEvent.click( outOfStockSuggestion ); await act( async () => {
await user.click( outOfStockSuggestion );
} );
} }
expect( getInStockChips() ).toBeNull(); expect( getInStockChips() ).toBeNull();
expect( getOutOfStockChips() ).toBeInTheDocument(); expect( getOutOfStockChips() ).toBeInTheDocument();
} ); } );
test( 'removes the option when the X button is clicked', () => { test( 'removes the option when the X button is clicked', async () => {
const user = userEvent.setup();
const ratingParam = 'outofstock'; const ratingParam = 'outofstock';
const { const {
getInStockChips, getInStockChips,
@ -298,23 +311,27 @@ describe( 'Filter by Stock block', () => {
getRemoveButtonFromChips, getRemoveButtonFromChips,
} = setupMultipleChoiceDropdown( ratingParam ); } = setupMultipleChoiceDropdown( ratingParam );
expect( getInStockChips() ).toBeNull(); await waitFor( () => {
expect( getOutOfStockChips() ).toBeInTheDocument(); expect( getInStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeNull(); expect( getOutOfStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeNull();
} );
const removeOutOfStockButton = getRemoveButtonFromChips( const removeOutOfStockButton = getRemoveButtonFromChips(
getOutOfStockChips() getOutOfStockChips()
); );
if ( removeOutOfStockButton ) { if ( removeOutOfStockButton ) {
act( () => { act( async () => {
userEvent.click( removeOutOfStockButton ); await user.click( removeOutOfStockButton );
} ); } );
} }
expect( getInStockChips() ).toBeNull(); await waitFor( () => {
expect( getOutOfStockChips() ).toBeNull(); expect( getInStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeNull(); expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeNull();
} );
} ); } );
} ); } );
@ -336,6 +353,7 @@ describe( 'Filter by Stock block', () => {
} ); } );
test( 'adds chosen option to another one that is clicked', async () => { test( 'adds chosen option to another one that is clicked', async () => {
const user = userEvent.setup();
const ratingParam = 'onbackorder'; const ratingParam = 'onbackorder';
const { const {
getDropdown, getDropdown,
@ -346,20 +364,25 @@ describe( 'Filter by Stock block', () => {
getOutOfStockSuggestion, getOutOfStockSuggestion,
} = setupMultipleChoiceDropdown( ratingParam ); } = setupMultipleChoiceDropdown( ratingParam );
expect( getInStockChips() ).toBeNull(); await waitFor( () => {
expect( getOutOfStockChips() ).toBeNull(); expect( getInStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeInTheDocument(); expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeInTheDocument();
} );
const dropdown = getDropdown(); const dropdown = getDropdown();
if ( dropdown ) { if ( dropdown ) {
userEvent.click( dropdown ); await act( async () => {
await user.click( dropdown );
} );
} }
const inStockSuggestion = getInStockSuggestion(); const inStockSuggestion = getInStockSuggestion();
if ( inStockSuggestion ) { if ( inStockSuggestion ) {
userEvent.click( inStockSuggestion ); await act( async () => {
await user.click( inStockSuggestion );
} );
} }
expect( getInStockChips() ).toBeInTheDocument(); expect( getInStockChips() ).toBeInTheDocument();
@ -368,7 +391,9 @@ describe( 'Filter by Stock block', () => {
const freshDropdown = getDropdown(); const freshDropdown = getDropdown();
if ( freshDropdown ) { if ( freshDropdown ) {
userEvent.click( freshDropdown ); await act( async () => {
await user.click( freshDropdown );
} );
} }
const outOfStockSuggestion = getOutOfStockSuggestion(); const outOfStockSuggestion = getOutOfStockSuggestion();
@ -384,7 +409,8 @@ describe( 'Filter by Stock block', () => {
} ); } );
} ); } );
test( 'removes the option when the X button is clicked', () => { test( 'removes the option when the X button is clicked', async () => {
const user = userEvent.setup();
const ratingParam = 'instock,outofstock,onbackorder'; const ratingParam = 'instock,outofstock,onbackorder';
const { const {
getInStockChips, getInStockChips,
@ -393,23 +419,27 @@ describe( 'Filter by Stock block', () => {
getRemoveButtonFromChips, getRemoveButtonFromChips,
} = setupMultipleChoiceDropdown( ratingParam ); } = setupMultipleChoiceDropdown( ratingParam );
expect( getInStockChips() ).toBeInTheDocument(); await waitFor( () => {
expect( getOutOfStockChips() ).toBeInTheDocument(); expect( getInStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeInTheDocument(); expect( getOutOfStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeInTheDocument();
} );
const removeOutOfStockButton = getRemoveButtonFromChips( const removeOutOfStockButton = getRemoveButtonFromChips(
getOutOfStockChips() getOutOfStockChips()
); );
if ( removeOutOfStockButton ) { if ( removeOutOfStockButton ) {
act( () => { act( async () => {
userEvent.click( removeOutOfStockButton ); await user.click( removeOutOfStockButton );
} ); } );
} }
expect( getInStockChips() ).toBeInTheDocument(); await waitFor( () => {
expect( getOutOfStockChips() ).toBeNull(); expect( getInStockChips() ).toBeInTheDocument();
expect( getOnBackorderChips() ).toBeInTheDocument(); expect( getOutOfStockChips() ).toBeNull();
expect( getOnBackorderChips() ).toBeInTheDocument();
} );
} ); } );
} ); } );
@ -434,6 +464,7 @@ describe( 'Filter by Stock block', () => {
} ); } );
test( 'replaces chosen option when another one is clicked', async () => { test( 'replaces chosen option when another one is clicked', async () => {
const user = userEvent.setup();
const ratingParam = 'outofstock'; const ratingParam = 'outofstock';
const { const {
getInStockCheckbox, getInStockCheckbox,
@ -448,7 +479,9 @@ describe( 'Filter by Stock block', () => {
const onBackorderCheckbox = getOnBackorderCheckbox(); const onBackorderCheckbox = getOnBackorderCheckbox();
if ( onBackorderCheckbox ) { if ( onBackorderCheckbox ) {
userEvent.click( onBackorderCheckbox ); await act( async () => {
await user.click( onBackorderCheckbox );
} );
} }
expect( getInStockCheckbox()?.checked ).toBeFalsy(); expect( getInStockCheckbox()?.checked ).toBeFalsy();

View File

@ -3712,7 +3712,6 @@ Object {
<strong> <strong>
berry berry
</strong> </strong>
</label> </label>
</div> </div>
</div> </div>
@ -3748,7 +3747,6 @@ Object {
<strong> <strong>
berry berry
</strong> </strong>
</label> </label>
</div> </div>
</div> </div>
@ -3830,7 +3828,6 @@ Object {
<strong> <strong>
berry berry
</strong> </strong>
</label> </label>
</div> </div>
</div> </div>
@ -3866,7 +3863,6 @@ Object {
<strong> <strong>
berry berry
</strong> </strong>
</label> </label>
</div> </div>
</div> </div>

View File

@ -99,8 +99,8 @@ const getAlias = ( options = {} ) => {
__dirname, __dirname,
`../assets/js/templates/` `../assets/js/templates/`
), ),
'react/jsx-dev-runtime': require.resolve( 'react/jsx-dev-runtime.js' ), 'react/jsx-dev-runtime': require.resolve( 'react/jsx-dev-runtime' ),
'react/jsx-runtime': require.resolve( 'react/jsx-runtime.js' ), 'react/jsx-runtime': require.resolve( 'react/jsx-runtime' ),
}; };
}; };

File diff suppressed because it is too large Load Diff

View File

@ -137,10 +137,9 @@
"@storybook/react": "7.5.2", "@storybook/react": "7.5.2",
"@storybook/react-webpack5": "^7.6.4", "@storybook/react-webpack5": "^7.6.4",
"@testing-library/dom": "9.3.3", "@testing-library/dom": "9.3.3",
"@testing-library/jest-dom": "5.16.5", "@testing-library/jest-dom": "6.4.5",
"@testing-library/react": "12.1.5", "@testing-library/react": "15.0.7",
"@testing-library/react-hooks": "7.0.2", "@testing-library/user-event": "14.5.2",
"@testing-library/user-event": "13.5.0",
"@types/classnames": "2.3.0", "@types/classnames": "2.3.0",
"@types/dinero.js": "1.9.0", "@types/dinero.js": "1.9.0",
"@types/dompurify": "2.3.4", "@types/dompurify": "2.3.4",
@ -252,7 +251,7 @@
"puppeteer": "17.1.3", "puppeteer": "17.1.3",
"react-docgen": "5.4.3", "react-docgen": "5.4.3",
"react-docgen-typescript-plugin": "^1.0.5", "react-docgen-typescript-plugin": "^1.0.5",
"react-test-renderer": "17.0.2", "react-test-renderer": "18.3.1",
"redux": "4.2.1", "redux": "4.2.1",
"request-promise": "4.2.6", "request-promise": "4.2.6",
"rimraf": "5.0.5", "rimraf": "5.0.5",
@ -319,8 +318,8 @@
"wordpress-components": "npm:@wordpress/components@14.2.0" "wordpress-components": "npm:@wordpress/components@14.2.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^17.0.0", "react": "^18.3.0",
"react-dom": "^17.0.0" "react-dom": "^18.3.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"ndb": "1.1.5" "ndb": "1.1.5"

View File

@ -1,7 +1,3 @@
/**
* External dependencies
*/
import { renderHook } from '@testing-library/react-hooks';
/** /**
* Internal dependencies * Internal dependencies
*/ */
@ -19,6 +15,7 @@ jest.mock( '@woocommerce/settings', () => {
describe( 'Checkout registry (as admin user)', () => { describe( 'Checkout registry (as admin user)', () => {
test( 'should throw if the filter throws and user is an admin', () => { test( 'should throw if the filter throws and user is an admin', () => {
expect.assertions( 1 );
const filterName = 'ErrorTestFilter'; const filterName = 'ErrorTestFilter';
const value = 'Hello World'; const value = 'Hello World';
registerCheckoutFilters( filterName, { registerCheckoutFilters( filterName, {
@ -27,30 +24,35 @@ describe( 'Checkout registry (as admin user)', () => {
}, },
} ); } );
const { result } = renderHook( () => try {
applyCheckoutFilter( { applyCheckoutFilter( {
filterName, filterName,
defaultValue: value, defaultValue: value,
} ) } );
); } catch ( e ) {
expect( result.error ).toEqual( Error( 'test error' ) ); // eslint-disable-next-line -- The toThrow helper does not stop wordpress/jest-console from erroring.
expect( e.message ).toBe( 'test error' );
}
} ); } );
test( 'should throw if validation throws and user is an admin', () => { test( 'should throw if validation throws and user is an admin', () => {
expect.assertions( 1 );
const filterName = 'ValidationTestFilter'; const filterName = 'ValidationTestFilter';
const value = 'Hello World'; const value = 'Hello World';
registerCheckoutFilters( filterName, { registerCheckoutFilters( filterName, {
[ filterName ]: ( val ) => val, [ filterName ]: ( val ) => val,
} ); } );
const { result } = renderHook( () => try {
applyCheckoutFilter( { applyCheckoutFilter( {
filterName, filterName,
defaultValue: value, defaultValue: value,
validation: () => { validation: () => {
throw Error( 'validation error' ); throw Error( 'validation error' );
}, },
} ) } );
); } catch ( e ) {
expect( result.error ).toEqual( Error( 'validation error' ) ); // eslint-disable-next-line -- The toThrow helper does not stop wordpress/jest-console from erroring.
expect( e.message ).toBe( 'validation error' );
}
} ); } );
} ); } );

View File

@ -1,7 +1,7 @@
/** /**
* External dependencies * External dependencies
*/ */
import { renderHook } from '@testing-library/react-hooks'; import { renderHook } from '@testing-library/react';
/** /**
* Internal dependencies * Internal dependencies
*/ */

View File

@ -23,6 +23,8 @@ jest.mock( '@wordpress/data', () => ( {
describe( 'ValidatedTextInput', () => { describe( 'ValidatedTextInput', () => {
it( 'Removes related validation error on change', async () => { it( 'Removes related validation error on change', async () => {
const user = userEvent.setup();
render( render(
<ValidatedTextInput <ValidatedTextInput
instanceId={ '0' } instanceId={ '0' }
@ -46,9 +48,14 @@ describe( 'ValidatedTextInput', () => {
await expect( await expect(
select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' ) select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
).not.toBe( undefined ); ).not.toBe( undefined );
const textInputElement = await screen.getByLabelText( 'Test Input' ); const textInputElement = await screen.getByLabelText( 'Test Input' );
await userEvent.type( textInputElement, 'New value' );
await expect( await act( async () => {
await user.type( textInputElement, 'New value' );
} );
expect(
select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' ) select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
).toBe( undefined ); ).toBe( undefined );
} ); } );
@ -75,7 +82,11 @@ describe( 'ValidatedTextInput', () => {
select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' ) select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' )
).not.toBe( undefined ); ).not.toBe( undefined );
const textInputElement = await screen.getByLabelText( 'Test Input' ); const textInputElement = await screen.getByLabelText( 'Test Input' );
await userEvent.type( textInputElement, 'New value' );
await act( async () => {
await userEvent.type( textInputElement, 'New value' );
} );
await expect( await expect(
select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' ) select( VALIDATION_STORE_KEY ).getValidationError( 'textinput-1' )
).toBe( undefined ); ).toBe( undefined );
@ -129,6 +140,7 @@ describe( 'ValidatedTextInput', () => {
await expect( errorMessageElement ).toBeInTheDocument(); await expect( errorMessageElement ).toBeInTheDocument();
} ); } );
it( 'Runs custom validation on the input', async () => { it( 'Runs custom validation on the input', async () => {
const user = userEvent.setup();
const TestComponent = () => { const TestComponent = () => {
const [ inputValue, setInputValue ] = useState( 'Test' ); const [ inputValue, setInputValue ] = useState( 'Test' );
return ( return (
@ -147,17 +159,26 @@ describe( 'ValidatedTextInput', () => {
render( <TestComponent /> ); render( <TestComponent /> );
const textInputElement = await screen.getByLabelText( 'Test Input' ); const textInputElement = await screen.getByLabelText( 'Test Input' );
await userEvent.type( textInputElement, 'Invalid Value' ); await act( async () => {
await user.type( textInputElement, 'Invalid Value' );
} );
await expect( await expect(
select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' ) select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
).not.toBe( undefined ); ).not.toBe( undefined );
await userEvent.type( textInputElement, '{selectall}{del}Valid Value' );
await act( async () => {
await user.clear( textInputElement );
await user.type( textInputElement, 'Valid Value' );
} );
await expect( textInputElement.value ).toBe( 'Valid Value' ); await expect( textInputElement.value ).toBe( 'Valid Value' );
await expect( await expect(
select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' ) select( VALIDATION_STORE_KEY ).getValidationError( 'test-input' )
).toBe( undefined ); ).toBe( undefined );
} ); } );
it( 'Shows a custom error message for an invalid required input', async () => { it( 'Shows a custom error message for an invalid required input', async () => {
const user = userEvent.setup();
const TestComponent = () => { const TestComponent = () => {
const [ inputValue, setInputValue ] = useState( '' ); const [ inputValue, setInputValue ] = useState( '' );
return ( return (
@ -173,9 +194,13 @@ describe( 'ValidatedTextInput', () => {
}; };
render( <TestComponent /> ); render( <TestComponent /> );
const textInputElement = await screen.getByLabelText( 'Test Input' ); const textInputElement = await screen.getByLabelText( 'Test Input' );
await userEvent.type( textInputElement, 'test' );
await userEvent.type( textInputElement, '{selectall}{del}' ); await act( async () => {
await textInputElement.blur(); await user.type( textInputElement, 'test' );
await user.clear( textInputElement );
await textInputElement.blur();
} );
await expect( await expect(
screen.queryByText( 'Please enter a valid test input' ) screen.queryByText( 'Please enter a valid test input' )
).not.toBeNull(); ).not.toBeNull();

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Update the Blocks JS tests to React 18

File diff suppressed because it is too large Load Diff