From c035bdcd0de3db73e64b174dc78b0cb3893a476c Mon Sep 17 00:00:00 2001
From: asvinb
Date: Thu, 22 Aug 2024 19:59:53 +0400
Subject: [PATCH 01/10] Add SkipPaidAdsConfirmationModal component.
---
.../setup-stepper/setup-paid-ads/constants.js | 2 +
.../setup-paid-ads/setup-paid-ads.js | 31 +++++-
.../skip-paid-ads-confirmation-modal.js | 100 ++++++++++++++++++
3 files changed, 129 insertions(+), 4 deletions(-)
create mode 100644 js/src/setup-mc/setup-stepper/setup-paid-ads/constants.js
create mode 100644 js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/constants.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/constants.js
new file mode 100644
index 0000000000..05f0b5bb55
--- /dev/null
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/constants.js
@@ -0,0 +1,2 @@
+export const ACTION_COMPLETE = 'complete-ads';
+export const ACTION_SKIP = 'skip-ads';
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index f5dd0f9a07..9e49450fe5 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -22,13 +22,12 @@ import FaqsSection from '.~/components/paid-ads/faqs-section';
import AppButton from '.~/components/app-button';
import PaidAdsFeaturesSection from './paid-ads-features-section';
import PaidAdsSetupSections from './paid-ads-setup-sections';
+import SkipPaidAdsConfirmationModal from './skip-paid-ads-confirmation-modal';
import { getProductFeedUrl } from '.~/utils/urls';
import clientSession from './clientSession';
import { API_NAMESPACE, STORE_KEY } from '.~/data/constants';
import { GUIDE_NAMES } from '.~/constants';
-
-const ACTION_COMPLETE = 'complete-ads';
-const ACTION_SKIP = 'skip-ads';
+import { ACTION_COMPLETE, ACTION_SKIP } from './constants';
/**
* Clicking on the "Create a paid ad campaign" button to open the paid ads setup in the onboarding flow.
@@ -76,6 +75,10 @@ export default function SetupPaidAds() {
);
const [ paidAds, setPaidAds ] = useState( {} );
const [ completing, setCompleting ] = useState( null );
+ const [
+ showSkipPaidAdsConfirmationModal,
+ setShowSkipPaidAdsConfirmationModal,
+ ] = useState( false );
const handleContinuePaidAdsSetupClick = () => {
setShowPaidAdsSetup( true );
@@ -117,6 +120,14 @@ export default function SetupPaidAds() {
await finishOnboardingSetup( event, onBeforeFinish );
};
+ const handleSkipModal = () => {
+ setShowSkipPaidAdsConfirmationModal( true );
+ };
+
+ const handleCancelSkipConfirmationClick = () => {
+ setShowSkipPaidAdsConfirmationModal( false );
+ };
+
// The status check of Google Ads account connection is included in `paidAds.isReady`,
// because when there is no connected account, it will disable the budget section and set the `amount` to `undefined`.
const disabledComplete = completing === ACTION_SKIP || ! paidAds.isReady;
@@ -150,7 +161,10 @@ export default function SetupPaidAds() {
text={ text }
loading={ completing === ACTION_SKIP }
disabled={ disabledSkip }
- onClick={ finishOnboardingSetup }
+ onClick={
+ // Show the skip modal only for the "Skip this step for now" button only.
+ showPaidAdsSetup ? finishOnboardingSetup : handleSkipModal
+ }
eventName="gla_onboarding_complete_button_click"
eventProps={ eventProps }
/>
@@ -194,6 +208,15 @@ export default function SetupPaidAds() {
) }
+
+ { showSkipPaidAdsConfirmationModal && (
+
+ ) }
+
{ createSkipButton(
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
new file mode 100644
index 0000000000..49b78a1fca
--- /dev/null
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -0,0 +1,100 @@
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { createInterpolateElement } from '@wordpress/element';
+import { noop } from 'lodash';
+
+/**
+ * Internal dependencies
+ */
+import AppModal from '.~/components/app-modal';
+import AppButton from '.~/components/app-button';
+import AppDocumentationLink from '.~/components/app-documentation-link';
+import { ACTION_COMPLETE } from './constants';
+
+/**
+ * Triggered when the request review is successful
+ *
+ * @event gla_request_review_success
+ */
+
+/**
+ * Triggered when the request review fails
+ *
+ * @event gla_request_review_failure
+ */
+
+/**
+ * Renders a modal dialog that confirms whether the user wants to skip setting up paid ads.
+ * It provides information about the benefits of enabling Performance Max and includes a link to learn more.
+ *
+ * @param {Object} props React props.
+ * @param {Function} props.onRequestClose Function to be called when the modal should be closed. Defaults to a no-op function.
+ * @param {Function} props.onSkipConfirmation Function to be called when the user confirms skipping the paid ads setup. Defaults to a no-op function.
+ * @param {boolean} [props.isProcessing=false] Indicates whether a process is currently running (e.g., the confirmation is being processed). If true, the confirmation button will show a loading state.
+ */
+const SkipPaidAdsConfirmationModal = ( {
+ onRequestClose = noop,
+ onSkipConfirmation = noop,
+ isProcessing = false,
+} ) => {
+ const handleSkipConfirmationClick = ( event ) => {
+ onSkipConfirmation( event );
+ };
+
+ return (
+
+ { __( 'No', 'google-listings-and-ads' ) }
+ ,
+
+ { __( 'Yes', 'google-listings-and-ads' ) }
+ ,
+ ] }
+ onRequestClose={ onRequestClose }
+ >
+
+ { __(
+ 'Enabling Performance Max is highly recommended to drive more sales and reach new audiences across Google channels like Search, YouTube and Discover.',
+ 'google-listings-and-ads'
+ ) }
+
+
+ { __(
+ 'Performance Max uses the best of Google’s AI to show the most impactful ads for your products at the right time and place. Google will use your product data to create ads for this campaign.',
+ 'google-listings-and-ads'
+ ) }
+
+
+ { createInterpolateElement(
+ __(
+ ' Learn more about Performance Max.',
+ 'google-listings-and-ads'
+ ),
+ {
+ Link: (
+
+ ),
+ }
+ ) }
+
+
+ );
+};
+
+export default SkipPaidAdsConfirmationModal;
From 0bea89e8a7d6808fd749b83b78f2cef04c36238e Mon Sep 17 00:00:00 2001
From: asvinb
Date: Thu, 22 Aug 2024 20:21:02 +0400
Subject: [PATCH 02/10] Use correct function to complete onboarding.
---
.../setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js | 2 +-
.../setup-paid-ads/skip-paid-ads-confirmation-modal.js | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index 9e49450fe5..ef9b726474 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -212,7 +212,7 @@ export default function SetupPaidAds() {
{ showSkipPaidAdsConfirmationModal && (
) }
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index 49b78a1fca..ab985b5883 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -11,7 +11,7 @@ import { noop } from 'lodash';
import AppModal from '.~/components/app-modal';
import AppButton from '.~/components/app-button';
import AppDocumentationLink from '.~/components/app-documentation-link';
-import { ACTION_COMPLETE } from './constants';
+import { ACTION_SKIP } from './constants';
/**
* Triggered when the request review is successful
@@ -53,10 +53,11 @@ const SkipPaidAdsConfirmationModal = ( {
,
{ __( 'Yes', 'google-listings-and-ads' ) }
@@ -86,6 +87,7 @@ const SkipPaidAdsConfirmationModal = ( {
Link: (
From 4d81a640311f3dfc2fb10a942f5d04c1e3655969 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Thu, 22 Aug 2024 20:41:06 +0400
Subject: [PATCH 03/10] Rename functions.
---
.../setup-paid-ads/setup-paid-ads.js | 11 +++++++----
.../skip-paid-ads-confirmation-modal.js | 17 ++++-------------
2 files changed, 11 insertions(+), 17 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index ef9b726474..fc2dc7c689 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -120,11 +120,11 @@ export default function SetupPaidAds() {
await finishOnboardingSetup( event, onBeforeFinish );
};
- const handleSkipModal = () => {
+ const handleShowSkipPaidAdsConfirmationModal = () => {
setShowSkipPaidAdsConfirmationModal( true );
};
- const handleCancelSkipConfirmationClick = () => {
+ const handleCancelSkipPaidAdsClick = () => {
setShowSkipPaidAdsConfirmationModal( false );
};
@@ -163,8 +163,11 @@ export default function SetupPaidAds() {
disabled={ disabledSkip }
onClick={
// Show the skip modal only for the "Skip this step for now" button only.
- showPaidAdsSetup ? finishOnboardingSetup : handleSkipModal
+ showPaidAdsSetup
+ ? finishOnboardingSetup
+ : handleShowSkipPaidAdsConfirmationModal
}
+ // TODO: might want to review eventName and eventProps
eventName="gla_onboarding_complete_button_click"
eventProps={ eventProps }
/>
@@ -211,7 +214,7 @@ export default function SetupPaidAds() {
{ showSkipPaidAdsConfirmationModal && (
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index ab985b5883..f33be59052 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -14,15 +14,10 @@ import AppDocumentationLink from '.~/components/app-documentation-link';
import { ACTION_SKIP } from './constants';
/**
- * Triggered when the request review is successful
+ * Triggered when the skip button is clicked
+ * // TODO: to review
*
- * @event gla_request_review_success
- */
-
-/**
- * Triggered when the request review fails
- *
- * @event gla_request_review_failure
+ * @event gla_skip_paid_ads_modal_confirm_button_click
*/
/**
@@ -39,10 +34,6 @@ const SkipPaidAdsConfirmationModal = ( {
onSkipConfirmation = noop,
isProcessing = false,
} ) => {
- const handleSkipConfirmationClick = ( event ) => {
- onSkipConfirmation( event );
- };
-
return (
Date: Fri, 23 Aug 2024 17:31:20 +0400
Subject: [PATCH 04/10] Update e2e tests.
---
.../setup-mc/step-4-complete-campaign.test.js | 90 ++++++++++++-------
.../setup-mc/step-4-complete-campaign.js | 68 ++++++++++++++
2 files changed, 126 insertions(+), 32 deletions(-)
diff --git a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
index 53b2a4a497..1ce3808c0d 100644
--- a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
+++ b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
@@ -370,41 +370,72 @@ test.describe( 'Complete your campaign', () => {
await completeCampaign.clickCompleteSetupButton();
await requestsPromises;
- const setupSuccessModal = page
- .locator( '.components-modal__content' )
- .filter( {
- hasText:
- 'You’ve successfully set up Google for WooCommerce!',
- } );
+ const setupSuccessModal =
+ completeCampaign.getSetupSuccessModal();
await expect( setupSuccessModal ).toBeVisible();
} );
} );
} );
} );
- test.describe( 'Complete onboarding by "Skip this step for now"', () => {
- test.beforeAll( async () => {
- // Reset the showing status for the "Set up paid ads" section.
- await page.evaluate( () => window.sessionStorage.clear() );
- await setupAdsAccountPage.mockAdsAccountIncomplete();
- await completeCampaign.goto();
- await completeCampaign.clickSkipStepButton();
- } );
+ test.describe(
+ 'Ask user for confirmation when clicking "Skip this step for now"',
+ () => {
+ test.describe( 'User skips paid ads creation', () => {
+ test.beforeAll( async () => {
+ // Reset the showing status for the "Set up paid ads" section.
+ await page.evaluate( () => window.sessionStorage.clear() );
+ await setupAdsAccountPage.mockAdsAccountIncomplete();
+ await completeCampaign.goto();
+ await completeCampaign.clickSkipStepButton();
+ } );
- test( 'should see the setup success modal', async () => {
- const setupSuccessModal = page
- .locator( '.components-modal__content' )
- .filter( {
- hasText:
- 'You’ve successfully set up Google for WooCommerce!',
+ test( 'should see the modal', async () => {
+ const skipPaidAdsModal =
+ completeCampaign.getSkipPaidAdsCreationModal();
+ await expect( skipPaidAdsModal ).toBeVisible();
} );
- await expect( setupSuccessModal ).toBeVisible();
- } );
- test( 'should see the url contains product-feed', async () => {
- expect( page.url() ).toMatch( /path=%2Fgoogle%2Fproduct-feed/ );
- } );
- } );
+ test( 'should see the url contains product-feed if the user skips', async () => {
+ await completeCampaign.clickYesButton();
+ await page.waitForURL( /path=%2Fgoogle%2Fproduct-feed/ );
+ expect( page.url() ).toMatch(
+ /path=%2Fgoogle%2Fproduct-feed/
+ );
+ } );
+
+ test( 'should see the setup success modal', async () => {
+ const setupSuccessModal =
+ completeCampaign.getSetupSuccessModal();
+ await expect( setupSuccessModal ).toBeVisible();
+ } );
+ } );
+
+ test.describe( 'User does not skip paid ads creation', () => {
+ test.beforeAll( async () => {
+ // Reset the showing status for the "Set up paid ads" section.
+ await page.evaluate( () => window.sessionStorage.clear() );
+ await setupAdsAccountPage.mockAdsAccountIncomplete();
+ await completeCampaign.goto();
+ await completeCampaign.clickSkipStepButton();
+ } );
+
+ test( 'should no longer see the confirmation modal', async () => {
+ await completeCampaign.clickNoButton();
+
+ const skipPaidAdsModal =
+ completeCampaign.getSkipPaidAdsCreationModal();
+ await expect( skipPaidAdsModal ).not.toBeVisible();
+ } );
+
+ test( 'user should stay on the same page', async () => {
+ await expect( page.url() ).toMatch(
+ /path=%2Fgoogle%2Fsetup-mc&google-mc=connected/
+ );
+ } );
+ } );
+ }
+ );
test.describe( 'Complete onboarding by "Skip paid ads creation"', () => {
test.beforeAll( async () => {
@@ -415,12 +446,7 @@ test.describe( 'Complete your campaign', () => {
} );
test( 'should also see the setup success modal', async () => {
- const setupSuccessModal = page
- .locator( '.components-modal__content' )
- .filter( {
- hasText:
- 'You’ve successfully set up Google for WooCommerce!',
- } );
+ const setupSuccessModal = completeCampaign.getSetupSuccessModal();
await expect( setupSuccessModal ).toBeVisible();
} );
diff --git a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
index 6fc934fa88..1662ad3006 100644
--- a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
+++ b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
@@ -179,4 +179,72 @@ export default class CompleteCampaign extends MockRequests {
mcSettingsSyncRequestPromise,
] );
}
+
+ /**
+ * Retrieves the "Yes" button from the skip paid ads creation modal.
+ *
+ * @return {import('@playwright/test').Locator} Locator for the "Yes" button.
+ */
+ getYesButton() {
+ return this.page.getByRole( 'button', {
+ name: 'Yes',
+ exact: true,
+ } );
+ }
+
+ /**
+ * Clicks the "Yes" button in the skip paid ads creation modal.
+ *
+ * @return {Promise} Resolves when the click action is completed and the page has loaded.
+ */
+ async clickYesButton() {
+ const button = this.getYesButton();
+ await button.click();
+ await this.page.waitForLoadState( LOAD_STATE.DOM_CONTENT_LOADED );
+ }
+
+ /**
+ * Retrieves the "No" button from the skip paid ads creation modal.
+ *
+ * @return {import('@playwright/test').Locator} Locator for the "No" button.
+ */
+ getNoButton() {
+ return this.page.getByRole( 'button', {
+ name: 'No',
+ exact: true,
+ } );
+ }
+
+ /**
+ * Clicks the "No" button in the skip paid ads creation modal.
+ *
+ * @return {Promise} Resolves when the click action is completed and the page has loaded.
+ */
+ async clickNoButton() {
+ const button = this.getNoButton();
+ await button.click();
+ await this.page.waitForLoadState( LOAD_STATE.DOM_CONTENT_LOADED );
+ }
+
+ /**
+ * Retrieves the skip paid ads creation modal element.
+ *
+ * @return {import('@playwright/test').Locator} Locator for the modal containing the text "Skip setting up ads?".
+ */
+ getSkipPaidAdsCreationModal() {
+ return this.page.locator( '.components-modal__content' ).filter( {
+ hasText: 'Skip setting up ads?',
+ } );
+ }
+
+ /**
+ * Retrieves the setup success modal element.
+ *
+ * @return {import('@playwright/test').Locator} Locator for the modal containing the text "You’ve successfully set up Google for WooCommerce!".
+ */
+ getSetupSuccessModal() {
+ return this.page.locator( '.components-modal__content' ).filter( {
+ hasText: 'You’ve successfully set up Google for WooCommerce!',
+ } );
+ }
}
From 2180c5f7b789dc27046f5f9f450c346cc6cc2fc8 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Wed, 28 Aug 2024 17:00:04 +0400
Subject: [PATCH 05/10] Address code review feedback.
---
.../setup-paid-ads/setup-paid-ads.js | 12 ++--
.../skip-paid-ads-confirmation-modal.js | 43 ++++++++++--
.../setup-mc/step-4-complete-campaign.test.js | 67 ++++++++++---------
.../setup-mc/step-4-complete-campaign.js | 28 ++++----
4 files changed, 90 insertions(+), 60 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index fc2dc7c689..8950163fb7 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -161,13 +161,9 @@ export default function SetupPaidAds() {
text={ text }
loading={ completing === ACTION_SKIP }
disabled={ disabledSkip }
- onClick={
- // Show the skip modal only for the "Skip this step for now" button only.
- showPaidAdsSetup
- ? finishOnboardingSetup
- : handleShowSkipPaidAdsConfirmationModal
- }
- // TODO: might want to review eventName and eventProps
+ onClick={ handleShowSkipPaidAdsConfirmationModal }
+ // TODO: Review eventName and eventProps
+ // The same eventName and eventProps has been copied over to the "Confirm" button in the SkipPaidAdsConfirmationModal component.
eventName="gla_onboarding_complete_button_click"
eventProps={ eventProps }
/>
@@ -217,6 +213,8 @@ export default function SetupPaidAds() {
onRequestClose={ handleCancelSkipPaidAdsClick }
onSkipConfirmation={ finishOnboardingSetup }
isProcessing={ !! completing }
+ showPaidAdsSetup={ showPaidAdsSetup }
+ paidAds={ paidAds }
/>
) }
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index f33be59052..9f750727d8 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -2,8 +2,9 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
+import { select } from '@wordpress/data';
import { createInterpolateElement } from '@wordpress/element';
-import { noop } from 'lodash';
+import { noop, merge } from 'lodash';
/**
* Internal dependencies
@@ -11,13 +12,15 @@ import { noop } from 'lodash';
import AppModal from '.~/components/app-modal';
import AppButton from '.~/components/app-button';
import AppDocumentationLink from '.~/components/app-documentation-link';
+import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import { ACTION_SKIP } from './constants';
+import { STORE_KEY } from '.~/data/constants';
/**
* Triggered when the skip button is clicked
* // TODO: to review
*
- * @event gla_skip_paid_ads_modal_confirm_button_click
+ * @event gla_onboarding_complete_button_click
*/
/**
@@ -28,30 +31,56 @@ import { ACTION_SKIP } from './constants';
* @param {Function} props.onRequestClose Function to be called when the modal should be closed. Defaults to a no-op function.
* @param {Function} props.onSkipConfirmation Function to be called when the user confirms skipping the paid ads setup. Defaults to a no-op function.
* @param {boolean} [props.isProcessing=false] Indicates whether a process is currently running (e.g., the confirmation is being processed). If true, the confirmation button will show a loading state.
+ * @param {boolean} [props.showPaidAdsSetup=false] Indicates whether the paid ads setup is currently shown. If true, additional event properties will be included in the eventProps.
+ * @param {Object} [props.paidAds={}] The paid ads data, including the campaign form data and validation status.
*/
const SkipPaidAdsConfirmationModal = ( {
onRequestClose = noop,
onSkipConfirmation = noop,
isProcessing = false,
+ showPaidAdsSetup = false,
+ paidAds = {},
} ) => {
+ const { googleAdsAccount } = useGoogleAdsAccount();
+
+ const eventProps = {
+ opened_paid_ads_setup: 'no',
+ google_ads_account_status: googleAdsAccount?.status,
+ billing_method_status: 'unknown',
+ campaign_form_validation: 'unknown',
+ };
+
+ // TODO: Review once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged
+ if ( showPaidAdsSetup ) {
+ const selector = select( STORE_KEY );
+ const billing = selector.getGoogleAdsAccountBillingStatus();
+
+ merge( eventProps, {
+ opened_paid_ads_setup: 'yes',
+ billing_method_status: billing?.status,
+ campaign_form_validation: paidAds.isValid ? 'valid' : 'invalid',
+ } );
+ }
+
return (
- { __( 'No', 'google-listings-and-ads' ) }
+
+ { __( 'Cancel', 'google-listings-and-ads' ) }
,
- { __( 'Yes', 'google-listings-and-ads' ) }
+ { __( 'Complete setup', 'google-listings-and-ads' ) }
,
] }
onRequestClose={ onRequestClose }
diff --git a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
index 1ce3808c0d..b66d190466 100644
--- a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
+++ b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
@@ -397,7 +397,7 @@ test.describe( 'Complete your campaign', () => {
} );
test( 'should see the url contains product-feed if the user skips', async () => {
- await completeCampaign.clickYesButton();
+ await completeCampaign.clickCompleteSetupButton();
await page.waitForURL( /path=%2Fgoogle%2Fproduct-feed/ );
expect( page.url() ).toMatch(
/path=%2Fgoogle%2Fproduct-feed/
@@ -409,6 +409,23 @@ test.describe( 'Complete your campaign', () => {
completeCampaign.getSetupSuccessModal();
await expect( setupSuccessModal ).toBeVisible();
} );
+
+ test( 'should see buttons on Dashboard for Google Ads onboarding', async () => {
+ await page.keyboard.press( 'Escape' );
+ await page
+ .getByRole( 'tab', { name: 'Dashboard' } )
+ .click();
+
+ const buttons = page.getByRole( 'button', {
+ name: 'Add paid campaign',
+ } );
+
+ await expect( buttons ).toHaveCount( 2 );
+ for ( const button of await buttons.all() ) {
+ await expect( button ).toBeVisible();
+ await expect( button ).toBeEnabled();
+ }
+ } );
} );
test.describe( 'User does not skip paid ads creation', () => {
@@ -421,7 +438,7 @@ test.describe( 'Complete your campaign', () => {
} );
test( 'should no longer see the confirmation modal', async () => {
- await completeCampaign.clickNoButton();
+ await completeCampaign.clickCancelModalButton();
const skipPaidAdsModal =
completeCampaign.getSkipPaidAdsCreationModal();
@@ -437,36 +454,22 @@ test.describe( 'Complete your campaign', () => {
}
);
- test.describe( 'Complete onboarding by "Skip paid ads creation"', () => {
- test.beforeAll( async () => {
- await setupAdsAccountPage.mockAdsAccountIncomplete();
- await completeCampaign.goto();
- await completeCampaign.clickCreatePaidAdButton();
- await completeCampaign.clickSkipPaidAdsCreationButon();
- } );
-
- test( 'should also see the setup success modal', async () => {
- const setupSuccessModal = completeCampaign.getSetupSuccessModal();
- await expect( setupSuccessModal ).toBeVisible();
- } );
-
- test( 'should also see the url contains product-feed', async () => {
- expect( page.url() ).toMatch( /path=%2Fgoogle%2Fproduct-feed/ );
- } );
-
- test( 'should see buttons on Dashboard for Google Ads onboarding', async () => {
- await page.keyboard.press( 'Escape' );
- await page.getByRole( 'tab', { name: 'Dashboard' } ).click();
-
- const buttons = page.getByRole( 'button', {
- name: 'Add paid campaign',
+ // TODO: Should no longer be needed once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged.
+ test.describe(
+ 'Ask user for confirmation when clicking the "Skip paid ads creation"',
+ () => {
+ test.beforeAll( async () => {
+ await setupAdsAccountPage.mockAdsAccountIncomplete();
+ await completeCampaign.goto();
+ await completeCampaign.clickCreatePaidAdButton();
+ await completeCampaign.clickSkipPaidAdsCreationButon();
} );
- await expect( buttons ).toHaveCount( 2 );
- for ( const button of await buttons.all() ) {
- await expect( button ).toBeVisible();
- await expect( button ).toBeEnabled();
- }
- } );
- } );
+ test( 'should see the confirmation modal', async () => {
+ const skipPaidAdsModal =
+ completeCampaign.getSkipPaidAdsCreationModal();
+ await expect( skipPaidAdsModal ).toBeVisible();
+ } );
+ }
+ );
} );
diff --git a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
index 1662ad3006..53b3374c78 100644
--- a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
+++ b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
@@ -181,47 +181,47 @@ export default class CompleteCampaign extends MockRequests {
}
/**
- * Retrieves the "Yes" button from the skip paid ads creation modal.
+ * Retrieves the "Complete setup" button from the skip paid ads creation modal.
*
- * @return {import('@playwright/test').Locator} Locator for the "Yes" button.
+ * @return {import('@playwright/test').Locator} Locator for the "Complete setup" button.
*/
- getYesButton() {
+ getCompleteSetuModalButton() {
return this.page.getByRole( 'button', {
- name: 'Yes',
+ name: 'Complete setup',
exact: true,
} );
}
/**
- * Clicks the "Yes" button in the skip paid ads creation modal.
+ * Clicks the "Complete setup" button in the skip paid ads creation modal.
*
* @return {Promise} Resolves when the click action is completed and the page has loaded.
*/
- async clickYesButton() {
- const button = this.getYesButton();
+ async clickCompleteSetupModalButton() {
+ const button = this.getCompleteSetuModalButton();
await button.click();
await this.page.waitForLoadState( LOAD_STATE.DOM_CONTENT_LOADED );
}
/**
- * Retrieves the "No" button from the skip paid ads creation modal.
+ * Retrieves the "Cancel" button from the skip paid ads creation modal.
*
- * @return {import('@playwright/test').Locator} Locator for the "No" button.
+ * @return {import('@playwright/test').Locator} Locator for the "Cancel" button.
*/
- getNoButton() {
+ getCancelModalButton() {
return this.page.getByRole( 'button', {
- name: 'No',
+ name: 'Cancel',
exact: true,
} );
}
/**
- * Clicks the "No" button in the skip paid ads creation modal.
+ * Clicks the "Cancel" button in the skip paid ads creation modal.
*
* @return {Promise} Resolves when the click action is completed and the page has loaded.
*/
- async clickNoButton() {
- const button = this.getNoButton();
+ async clickCancelModalButton() {
+ const button = this.getCancelModalButton();
await button.click();
await this.page.waitForLoadState( LOAD_STATE.DOM_CONTENT_LOADED );
}
From bdb300f16ce1b74d76974a404a51738c5f812099 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Mon, 2 Sep 2024 12:47:34 +0400
Subject: [PATCH 06/10] Update label.
---
.../setup-paid-ads/skip-paid-ads-confirmation-modal.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index 9f750727d8..e9d62623a1 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -80,7 +80,10 @@ const SkipPaidAdsConfirmationModal = ( {
eventProps={ eventProps }
isPrimary
>
- { __( 'Complete setup', 'google-listings-and-ads' ) }
+ { __(
+ 'Complete setup without setting up ads',
+ 'google-listings-and-ads'
+ ) }
,
] }
onRequestClose={ onRequestClose }
From afc0554a4892d38f5dd0dab9c49674efec7fb512 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Wed, 4 Sep 2024 19:09:02 +0400
Subject: [PATCH 07/10] Address CR feedback.
---
.../setup-paid-ads/setup-paid-ads.js | 41 +++++-----
.../skip-paid-ads-confirmation-modal.js | 75 +++++--------------
2 files changed, 40 insertions(+), 76 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index 8950163fb7..711a68ed9e 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -28,6 +28,7 @@ import clientSession from './clientSession';
import { API_NAMESPACE, STORE_KEY } from '.~/data/constants';
import { GUIDE_NAMES } from '.~/constants';
import { ACTION_COMPLETE, ACTION_SKIP } from './constants';
+import { recordGlaEvent } from '.~/utils/tracks';
/**
* Clicking on the "Create a paid ad campaign" button to open the paid ads setup in the onboarding flow.
@@ -120,19 +121,9 @@ export default function SetupPaidAds() {
await finishOnboardingSetup( event, onBeforeFinish );
};
- const handleShowSkipPaidAdsConfirmationModal = () => {
- setShowSkipPaidAdsConfirmationModal( true );
- };
-
- const handleCancelSkipPaidAdsClick = () => {
+ const handleSkipCreatePaidAds = async ( event ) => {
setShowSkipPaidAdsConfirmationModal( false );
- };
-
- // The status check of Google Ads account connection is included in `paidAds.isReady`,
- // because when there is no connected account, it will disable the budget section and set the `amount` to `undefined`.
- const disabledComplete = completing === ACTION_SKIP || ! paidAds.isReady;
- function createSkipButton( text ) {
const eventProps = {
opened_paid_ads_setup: 'no',
google_ads_account_status: googleAdsAccount?.status,
@@ -140,6 +131,7 @@ export default function SetupPaidAds() {
campaign_form_validation: 'unknown',
};
+ // TODO: Review once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged
if ( showPaidAdsSetup ) {
const selector = select( STORE_KEY );
const billing = selector.getGoogleAdsAccountBillingStatus();
@@ -151,6 +143,24 @@ export default function SetupPaidAds() {
} );
}
+ recordGlaEvent( 'gla_onboarding_complete_button_click', eventProps );
+
+ await finishOnboardingSetup( event );
+ };
+
+ const handleShowSkipPaidAdsConfirmationModal = () => {
+ setShowSkipPaidAdsConfirmationModal( true );
+ };
+
+ const handleCancelSkipPaidAdsClick = () => {
+ setShowSkipPaidAdsConfirmationModal( false );
+ };
+
+ // The status check of Google Ads account connection is included in `paidAds.isReady`,
+ // because when there is no connected account, it will disable the budget section and set the `amount` to `undefined`.
+ const disabledComplete = completing === ACTION_SKIP || ! paidAds.isReady;
+
+ function createSkipButton( text ) {
const disabledSkip =
completing === ACTION_COMPLETE || ! hasGoogleAdsConnection;
@@ -162,10 +172,6 @@ export default function SetupPaidAds() {
loading={ completing === ACTION_SKIP }
disabled={ disabledSkip }
onClick={ handleShowSkipPaidAdsConfirmationModal }
- // TODO: Review eventName and eventProps
- // The same eventName and eventProps has been copied over to the "Confirm" button in the SkipPaidAdsConfirmationModal component.
- eventName="gla_onboarding_complete_button_click"
- eventProps={ eventProps }
/>
);
}
@@ -211,10 +217,7 @@ export default function SetupPaidAds() {
{ showSkipPaidAdsConfirmationModal && (
) }
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index e9d62623a1..ee63053399 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -2,9 +2,6 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
-import { select } from '@wordpress/data';
-import { createInterpolateElement } from '@wordpress/element';
-import { noop, merge } from 'lodash';
/**
* Internal dependencies
@@ -12,9 +9,7 @@ import { noop, merge } from 'lodash';
import AppModal from '.~/components/app-modal';
import AppButton from '.~/components/app-button';
import AppDocumentationLink from '.~/components/app-documentation-link';
-import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import { ACTION_SKIP } from './constants';
-import { STORE_KEY } from '.~/data/constants';
/**
* Triggered when the skip button is clicked
@@ -23,48 +18,24 @@ import { STORE_KEY } from '.~/data/constants';
* @event gla_onboarding_complete_button_click
*/
+/**
+ * @fires gla_documentation_link_click with `{ context: 'skip-paid-ads-modal', link_id: 'paid-ads-with-performance-max-campaigns-learn-more', href: 'https://support.google.com/google-ads/answer/10724817' }`
+ */
+
/**
* Renders a modal dialog that confirms whether the user wants to skip setting up paid ads.
* It provides information about the benefits of enabling Performance Max and includes a link to learn more.
*
* @param {Object} props React props.
- * @param {Function} props.onRequestClose Function to be called when the modal should be closed. Defaults to a no-op function.
- * @param {Function} props.onSkipConfirmation Function to be called when the user confirms skipping the paid ads setup. Defaults to a no-op function.
- * @param {boolean} [props.isProcessing=false] Indicates whether a process is currently running (e.g., the confirmation is being processed). If true, the confirmation button will show a loading state.
- * @param {boolean} [props.showPaidAdsSetup=false] Indicates whether the paid ads setup is currently shown. If true, additional event properties will be included in the eventProps.
- * @param {Object} [props.paidAds={}] The paid ads data, including the campaign form data and validation status.
+ * @param {Function} props.onRequestClose Function to be called when the modal should be closed.
+ * @param {Function} props.onSkipCreatePaidAds Function to be called when the user confirms skipping the paid ads setup.
*/
const SkipPaidAdsConfirmationModal = ( {
- onRequestClose = noop,
- onSkipConfirmation = noop,
- isProcessing = false,
- showPaidAdsSetup = false,
- paidAds = {},
+ onRequestClose,
+ onSkipCreatePaidAds,
} ) => {
- const { googleAdsAccount } = useGoogleAdsAccount();
-
- const eventProps = {
- opened_paid_ads_setup: 'no',
- google_ads_account_status: googleAdsAccount?.status,
- billing_method_status: 'unknown',
- campaign_form_validation: 'unknown',
- };
-
- // TODO: Review once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged
- if ( showPaidAdsSetup ) {
- const selector = select( STORE_KEY );
- const billing = selector.getGoogleAdsAccountBillingStatus();
-
- merge( eventProps, {
- opened_paid_ads_setup: 'yes',
- billing_method_status: billing?.status,
- campaign_form_validation: paidAds.isValid ? 'valid' : 'invalid',
- } );
- }
-
return (
@@ -72,12 +43,8 @@ const SkipPaidAdsConfirmationModal = ( {
,
{ __(
@@ -101,22 +68,16 @@ const SkipPaidAdsConfirmationModal = ( {
) }
- { createInterpolateElement(
- __(
- ' Learn more about Performance Max.',
+
+ { __(
+ 'Learn more about Performance Max.',
'google-listings-and-ads'
- ),
- {
- Link: (
-
- ),
- }
- ) }
+ ) }
+
);
From 7c4df64b4a65798817ffeb5eded5517aaf03a110 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Wed, 4 Sep 2024 19:11:43 +0400
Subject: [PATCH 08/10] Remove comment. :
---
.../setup-paid-ads/skip-paid-ads-confirmation-modal.js | 7 -------
1 file changed, 7 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
index ee63053399..18de3c6583 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/skip-paid-ads-confirmation-modal.js
@@ -11,13 +11,6 @@ import AppButton from '.~/components/app-button';
import AppDocumentationLink from '.~/components/app-documentation-link';
import { ACTION_SKIP } from './constants';
-/**
- * Triggered when the skip button is clicked
- * // TODO: to review
- *
- * @event gla_onboarding_complete_button_click
- */
-
/**
* @fires gla_documentation_link_click with `{ context: 'skip-paid-ads-modal', link_id: 'paid-ads-with-performance-max-campaigns-learn-more', href: 'https://support.google.com/google-ads/answer/10724817' }`
*/
From b884b97cc593f28900450637b01efffe56a64a7a Mon Sep 17 00:00:00 2001
From: asvinb
Date: Wed, 4 Sep 2024 19:28:20 +0400
Subject: [PATCH 09/10] Fix E2E tests.
---
tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js | 2 +-
.../e2e/utils/pages/setup-mc/step-4-complete-campaign.js | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
index b66d190466..4765c6e3b8 100644
--- a/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
+++ b/tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
@@ -397,7 +397,7 @@ test.describe( 'Complete your campaign', () => {
} );
test( 'should see the url contains product-feed if the user skips', async () => {
- await completeCampaign.clickCompleteSetupButton();
+ await completeCampaign.clickCompleteSetupModalButton();
await page.waitForURL( /path=%2Fgoogle%2Fproduct-feed/ );
expect( page.url() ).toMatch(
/path=%2Fgoogle%2Fproduct-feed/
diff --git a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
index 53b3374c78..b6827c68aa 100644
--- a/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
+++ b/tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js
@@ -181,19 +181,19 @@ export default class CompleteCampaign extends MockRequests {
}
/**
- * Retrieves the "Complete setup" button from the skip paid ads creation modal.
+ * Retrieves the "Complete setup without setting up ads" button from the skip paid ads creation modal.
*
- * @return {import('@playwright/test').Locator} Locator for the "Complete setup" button.
+ * @return {import('@playwright/test').Locator} Locator for the "Complete setup without setting up ads" button.
*/
getCompleteSetuModalButton() {
return this.page.getByRole( 'button', {
- name: 'Complete setup',
+ name: 'Complete setup without setting up ads',
exact: true,
} );
}
/**
- * Clicks the "Complete setup" button in the skip paid ads creation modal.
+ * Clicks the "Complete setup without setting up ads" button in the skip paid ads creation modal.
*
* @return {Promise} Resolves when the click action is completed and the page has loaded.
*/
From 5ec87d6449440bf43be5895d3b291490e0aabea2 Mon Sep 17 00:00:00 2001
From: asvinb
Date: Thu, 5 Sep 2024 16:53:45 +0400
Subject: [PATCH 10/10] Fix unecessary page wait.
---
js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js | 1 -
tests/e2e/utils/pages/setup-mc/step-4-complete-campaign.js | 3 +--
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
index 711a68ed9e..e2b7881c75 100644
--- a/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
+++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
@@ -167,7 +167,6 @@ export default function SetupPaidAds() {
return (
} Resolves when the click action is completed and the page has loaded.
+ * @return {Promise} Resolves when the click action is completed.
*/
async clickCancelModalButton() {
const button = this.getCancelModalButton();
await button.click();
- await this.page.waitForLoadState( LOAD_STATE.DOM_CONTENT_LOADED );
}
/**