Skip to content

Commit

Permalink
Merge pull request #2034 from woocommerce/release/2.5.1
Browse files Browse the repository at this point in the history
release 2.5.1
  • Loading branch information
martynmjones authored Aug 1, 2023
2 parents c641f14 + d321bb5 commit fa2a652
Show file tree
Hide file tree
Showing 68 changed files with 2,505 additions and 356 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/php-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
wp-version: ${{ needs.GetMatrix.outputs.latest-wp-version }}
- php: 8.1
wp-version: ${{ needs.GetMatrix.outputs.latest-wp-version }}
- php: 8.2
wp-version: ${{ needs.GetMatrix.outputs.latest-wp-version }}

steps:
- name: Checkout repository
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/post-release-automerge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: 'Merge the release to develop'
run-name: Merge the released `${{ github.head_ref }}` from `trunk` to `develop`

# **What it does**: Merges trunk to develop after `release/*` is merged to `trunk`.
# **Why we have it**: To automate the release process and follow git-flow.

on:
pull_request:
types:
- closed
branches:
- trunk

jobs:
automerge_trunk:
name: Automerge released trunk
runs-on: ubuntu-latest
steps:
- uses: woocommerce/grow/automerge-released-trunk@actions-v1
12 changes: 12 additions & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"phpVersion": "8.0",
"plugins": [
"https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip",
"https://github.com/WP-API/Basic-Auth/archive/master.zip",
"."
],
"lifecycleScripts": {
"afterStart": "./tests/e2e/bin/test-env-setup.sh",
"afterClean": "./tests/e2e/bin/test-env-setup.sh"
}
}
8 changes: 8 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
*** WooCommerce Google Listings and Ads Changelog ***

= 2.5.1 - 2023-08-01 =
* Dev - Setup wp-env for E2E tests.
* Dev - automate merging trunk to develop after a release.
* Fix - Fix support for "add_to_cart" event in Products (Beta) block.
* Fix - Prevent PHP 8.2 deprecation messages.
* Tweak - Ability to filter products for syncing via `gla_filter_product_query_args` apply_filters hook.
* Update - Show validation errors on steps 2 and 3 of the onboarding flow when unable to continue.

= 2.5.0 - 2023-07-18 =
* Tweak - Add Tip with information with Campaign assets are imported.
* Tweak - Provide more detailed error reasons when unable to complete site verification for the Google Merchant Center account being connected in the onboarding flow.
Expand Down
4 changes: 2 additions & 2 deletions google-listings-and-ads.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: Google Listings and Ads
* Plugin URL: https://wordpress.org/plugins/google-listings-and-ads/
* Description: Native integration with Google that allows merchants to easily display their products across Google’s network.
* Version: 2.5.0
* Version: 2.5.1
* Author: WooCommerce
* Author URI: https://woocommerce.com/
* Text Domain: google-listings-and-ads
Expand All @@ -30,7 +30,7 @@

defined( 'ABSPATH' ) || exit;

define( 'WC_GLA_VERSION', '2.5.0' ); // WRCS: DEFINED_VERSION.
define( 'WC_GLA_VERSION', '2.5.1' ); // WRCS: DEFINED_VERSION.
define( 'WC_GLA_MIN_PHP_VER', '7.4' );
define( 'WC_GLA_MIN_WC_VER', '6.9' );

Expand Down
4 changes: 4 additions & 0 deletions js/src/components/adaptive-form/adaptive-form-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import { createContext, useContext } from '@wordpress/element';
* @property {boolean} isSubmitting `true` if the form is currently being submitted.
* @property {boolean} isSubmitted Set to `true` after the form is submitted. Initial value and during submission are set to `false`.
* @property { HTMLElement | null} submitter Set to the element triggering the `handleSubmit` callback until the processing of `onSubmit` is completed. `null` otherwise.
* @property {number} validationRequestCount The current validation request count.
* @property {boolean} requestedShowValidation Whether have requested verification. It will be reset to false after calling hideValidation.
* @property {() => void} showValidation Increase the validation request count by 1.
* @property {() => void} hideValidation Reset the validation request count to 0.
*/

/**
Expand Down
13 changes: 13 additions & 0 deletions js/src/components/adaptive-form/adaptive-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ function AdaptiveForm( { onSubmit, extendAdapter, children, ...props }, ref ) {

const isMounted = useIsMounted();

// Add states for form user sides to determine whether to show validation results.
const [ validationRequestCount, setValidationRequestCount ] = useState( 0 );
const showValidation = useCallback( () => {
setValidationRequestCount( ( count ) => count + 1 );
}, [] );
const hideValidation = useCallback( () => {
setValidationRequestCount( 0 );
}, [] );

// Add `isSubmitting` and `isSubmitted` states for facilitating across multiple layers of
// component controlling, such as disabling inputs or buttons.
const [ submission, setSubmission ] = useState( null );
Expand Down Expand Up @@ -208,6 +217,10 @@ function AdaptiveForm( { onSubmit, extendAdapter, children, ...props }, ref ) {
isSubmitting,
isSubmitted,
submitter: adapterRef.current.submitter,
validationRequestCount,
requestedShowValidation: validationRequestCount > 0,
showValidation,
hideValidation,
};

if ( typeof extendAdapter === 'function' ) {
Expand Down
199 changes: 199 additions & 0 deletions js/src/components/adaptive-form/adaptive-form.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* External dependencies
*/
import '@testing-library/jest-dom';
import { screen, render, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
*/
import AdaptiveForm from './adaptive-form';

const alwaysValid = () => ( {} );

const delayOneSecond = () => new Promise( ( r ) => setTimeout( r, 1000 ) );

describe( 'AdaptiveForm', () => {
it( 'Should have `formContext.adapter` with functions and initial states', () => {
const children = jest.fn();

render(
<AdaptiveForm validate={ alwaysValid }>{ children }</AdaptiveForm>
);

const formContextSchema = expect.objectContaining( {
adapter: expect.objectContaining( {
isSubmitting: false,
isSubmitted: false,
submitter: null,
validationRequestCount: 0,
requestedShowValidation: false,
showValidation: expect.any( Function ),
hideValidation: expect.any( Function ),
} ),
} );

expect( children ).toHaveBeenLastCalledWith( formContextSchema );
} );

it( 'Should provide `isSubmitting` and `isSubmitted` states via adapter', async () => {
const inspect = jest.fn();

render(
<AdaptiveForm validate={ alwaysValid } onSubmit={ delayOneSecond }>
{ ( formContext ) => {
const { isSubmitting, isSubmitted } = formContext.adapter;
inspect( isSubmitting, isSubmitted );

return <button onClick={ formContext.handleSubmit } />;
} }
</AdaptiveForm>
);

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

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

expect( inspect ).toHaveBeenLastCalledWith( true, false );

await act( async () => {
jest.runOnlyPendingTimers();
} );

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

it( 'Should be able to signal failed submission to reset `isSubmitting` and `isSubmitted` states', async () => {
const inspect = jest.fn();

const onSubmit = ( values, enhancer ) => {
enhancer.signalFailedSubmission();
return delayOneSecond();
};

render(
<AdaptiveForm validate={ alwaysValid } onSubmit={ onSubmit }>
{ ( formContext ) => {
const { isSubmitting, isSubmitted } = formContext.adapter;
inspect( isSubmitting, isSubmitted );

return <button onClick={ formContext.handleSubmit } />;
} }
</AdaptiveForm>
);

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

expect( inspect ).toHaveBeenLastCalledWith( true, false );

await act( async () => {
jest.runOnlyPendingTimers();
} );

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

it( 'Should provide the element triggering the form submission via `submitter` until the processing is completed', async () => {
const inspectOnSubmit = jest.fn();
const inspectSubmitter = jest.fn();

render(
<AdaptiveForm validate={ alwaysValid } onSubmit={ inspectOnSubmit }>
{ ( formContext ) => {
inspectSubmitter( formContext.adapter.submitter );

return (
<>
<button onClick={ formContext.handleSubmit }>
A
</button>

<button onClick={ formContext.handleSubmit }>
B
</button>
</>
);
} }
</AdaptiveForm>
);

const [ buttonA, buttonB ] = screen.getAllByRole( 'button' );

expect( inspectOnSubmit ).toHaveBeenCalledTimes( 0 );

await act( async () => {
return userEvent.click( buttonA );
} );

expect( inspectSubmitter ).toHaveBeenCalledWith( buttonA );
expect( inspectSubmitter ).toHaveBeenLastCalledWith( null );
expect( inspectOnSubmit ).toHaveBeenCalledTimes( 1 );
expect( inspectOnSubmit ).toHaveBeenLastCalledWith(
{},
expect.objectContaining( { submitter: buttonA } )
);

inspectSubmitter.mockClear();

await act( async () => {
return userEvent.click( buttonB );
} );

expect( inspectSubmitter ).toHaveBeenCalledWith( buttonB );
expect( inspectSubmitter ).toHaveBeenLastCalledWith( null );
expect( inspectOnSubmit ).toHaveBeenCalledTimes( 2 );
expect( inspectOnSubmit ).toHaveBeenLastCalledWith(
{},
expect.objectContaining( { submitter: buttonB } )
);
} );

it( 'Should be able to accumulate and reset the validation request count and requested state', async () => {
const inspect = jest.fn();

render(
<AdaptiveForm validate={ alwaysValid }>
{ ( { adapter } ) => {
inspect(
adapter.requestedShowValidation,
adapter.validationRequestCount
);

return (
<>
<button onClick={ adapter.showValidation }>
request
</button>

<button onClick={ adapter.hideValidation }>
reset
</button>
</>
);
} }
</AdaptiveForm>
);

const requestButton = screen.getByRole( 'button', { name: 'request' } );
const resetButton = screen.getByRole( 'button', { name: 'reset' } );

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

await userEvent.click( requestButton );

expect( inspect ).toHaveBeenLastCalledWith( true, 1 );

await userEvent.click( requestButton );

expect( inspect ).toHaveBeenLastCalledWith( true, 2 );

await userEvent.click( resetButton );

expect( inspect ).toHaveBeenLastCalledWith( false, 0 );
} );
} );
17 changes: 17 additions & 0 deletions js/src/components/app-input-number-control/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import { useReducer } from '@wordpress/element';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -36,6 +41,17 @@ const AppInputNumberControl = ( props ) => {
const numberSettings = useStoreNumberSettings( settings );
const numberFormat = useNumberFormat( settings );

// The `InputControl` in `@wordpress/components` doesn't take into account the context
// in which the `value` of a controlled component is updated via `onBlur`, resulting in
// the incoming `value` prop may not syncing to the <input> element's display value.
// Therefore, an updater of `useReducer` is used to make the value synchronized via the
// onChange callback.
//
// Ref:
// - https://github.com/WordPress/gutenberg/blob/%40wordpress/components%4019.17.0/packages/components/src/input-control/index.tsx#L59-L62
// - https://github.com/WordPress/gutenberg/blob/%40wordpress/components%4019.17.0/packages/components/src/input-control/utils.ts#L71-L108
const [ , forceUpdate ] = useReducer( ( x ) => x + 1, 0 );

/**
* Value to be displayed to the user in the UI.
*/
Expand Down Expand Up @@ -74,6 +90,7 @@ const AppInputNumberControl = ( props ) => {
const handleChange = ( val ) => {
const numberValue = getNumberFromString( val );
onChange( numberValue );
forceUpdate();
};

const handleBlur = ( e ) => {
Expand Down
Loading

0 comments on commit fa2a652

Please sign in to comment.