Skip to content

Commit

Permalink
Merge pull request #2039 from woocommerce/fix/wp-6-3-compatibility
Browse files Browse the repository at this point in the history
WP 6.3 Compatibility: Fix the errors of "setImmediate is not defined"
  • Loading branch information
eason9487 authored Aug 4, 2023
2 parents f61075c + 7ebf4c1 commit 0dffc53
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 3 deletions.
4 changes: 2 additions & 2 deletions js/src/components/adaptive-form/adaptive-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,12 @@ function AdaptiveForm( { onSubmit, extendAdapter, children, ...props }, ref ) {
// Related to WC 6.9. Only one delegate can be consumed at a time in this render prop to
// ensure the updating states will always be the latest when calling.
if ( batchQueue.length ) {
// Use `setImmediate` to avoid the warning of request state updates while rendering.
// Use `setTimeout` to avoid the warning of request state updates while rendering.
// Mutating a React hook state is an anti-pattern in most cases. Here is done intentionally
// because it's necessary to ensure this component will be triggered re-rendering through
// `setBatchQueue`, but also to avoid calling `setBatchQueue` here and triggering additional
// rendering again.
setImmediate( () => setDelegation( batchQueue.shift() ) );
setTimeout( () => setDelegation( batchQueue.shift() ) );
}

/* === Start of enhancement-related codes === */
Expand Down
109 changes: 109 additions & 0 deletions js/src/components/adaptive-form/adaptive-form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,113 @@ describe( 'AdaptiveForm', () => {

expect( inspect ).toHaveBeenLastCalledWith( false, 0 );
} );

describe( 'Compatibility patches', () => {
it( 'Should update all changes to values for the synchronous multiple calls to `setValue`', async () => {
render(
<AdaptiveForm
initialValues={ {
firstName: 'Foo',
lastName: 'Bar',
email: '(empty)',
} }
validate={ alwaysValid }
>
{ ( { setValue, values } ) => {
return (
<>
<button
onClick={ () => {
setValue( 'firstName', 'Hey' );
setValue( 'lastName', 'Howdy' );
setValue( 'email', 'hi[at]greetings' );
} }
/>
<article>
{ `${ values.firstName } ${ values.lastName } ${ values.email }` }
</article>
</>
);
} }
</AdaptiveForm>
);

const article = screen.getByRole( 'article' );

expect( article.textContent ).toBe( 'Foo Bar (empty)' );

await act( async () => {
await userEvent.click( screen.getByRole( 'button' ) );
jest.runAllTimers();
} );

expect( article.textContent ).toBe( 'Hey Howdy hi[at]greetings' );
} );

it( 'Should call back to `onChange` for the changed value only', async () => {
const onChange = jest.fn();

render(
<AdaptiveForm
onChange={ onChange }
initialValues={ {
firstName: '',
lastName: '',
agreedTerms: false,
} }
validate={ alwaysValid }
>
{ ( { setValue, getInputProps } ) => {
return (
<>
<button
onClick={ () => {
setValue( 'firstName', 'Hey' );
} }
/>
<input
type="text"
{ ...getInputProps( 'lastName' ) }
/>
<input
type="checkbox"
{ ...getInputProps( 'agreedTerms' ) }
/>
</>
);
} }
</AdaptiveForm>
);

await act( async () => {
await userEvent.click( screen.getByRole( 'button' ) );
jest.runAllTimers();
} );

expect( onChange ).toHaveBeenCalledTimes( 1 );
expect( onChange ).toHaveBeenLastCalledWith(
{ name: 'firstName', value: 'Hey' },
expect.any( Object ),
true
);

await userEvent.type( screen.getByRole( 'textbox' ), 'a' );

expect( onChange ).toHaveBeenCalledTimes( 2 );
expect( onChange ).toHaveBeenLastCalledWith(
{ name: 'lastName', value: 'a' },
expect.any( Object ),
true
);

await userEvent.click( screen.getByRole( 'checkbox' ) );

expect( onChange ).toHaveBeenCalledTimes( 3 );
expect( onChange ).toHaveBeenLastCalledWith(
{ name: 'agreedTerms', value: true },
expect.any( Object ),
true
);
} );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ export default function useCroppedImageSelector( {
// since `toolbar` will be triggered the refresh event at the end, so this function
// must be called after that.
if ( this === frame ) {
setImmediate( handleSelectionToggle );
setTimeout( handleSelectionToggle );
return;
}

Expand Down

0 comments on commit 0dffc53

Please sign in to comment.