From c792e429b12363f7d2764b8e1472bf74da700fbf Mon Sep 17 00:00:00 2001 From: Eason Su Date: Wed, 13 Dec 2023 16:06:13 +0800 Subject: [PATCH 1/8] Change the onboarding to require a connected Google Ads account and make its setup card always visible. --- js/src/hooks/useGoogleAdsAccount.js | 11 ++++++++++ .../setup-paid-ads/paid-ads-setup-sections.js | 22 +++++++++---------- .../setup-paid-ads/setup-paid-ads.js | 15 ++++++++----- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/js/src/hooks/useGoogleAdsAccount.js b/js/src/hooks/useGoogleAdsAccount.js index 9760ce87c8..16db5002f1 100644 --- a/js/src/hooks/useGoogleAdsAccount.js +++ b/js/src/hooks/useGoogleAdsAccount.js @@ -9,6 +9,7 @@ import { useCallback } from '@wordpress/element'; */ import { STORE_KEY } from '.~/data/constants'; import { useAppDispatch } from '.~/data'; +import { GOOGLE_ADS_ACCOUNT_STATUS } from '.~/constants'; import useGoogleAccount from './useGoogleAccount'; const googleAdsAccountSelector = 'getGoogleAdsAccount'; @@ -36,6 +37,15 @@ const useGoogleAdsAccount = () => { googleAdsAccountSelector ); + // The "incomplete" status means there is a connected account but billing is not yet set + // so it's considered as `true`. + // The main reason for not using a naming like `isGoogleAdsConnected` here is to make + // a slight distinction from the "connected" status. + const hasGoogleAdsConnection = [ + GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED, + GOOGLE_ADS_ACCOUNT_STATUS.INCOMPLETE, + ].includes( acc?.status ); + return { googleAdsAccount: acc, isResolving: isResolvingGoogleAdsAccount, @@ -43,6 +53,7 @@ const useGoogleAdsAccount = () => { hasFinishedResolution: selector.hasFinishedResolution( googleAdsAccountSelector ), + hasGoogleAdsConnection, }; }, [ google, isResolving, refetchGoogleAdsAccount ] diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-setup-sections.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-setup-sections.js index f29fa2ff7a..86c3739bf7 100644 --- a/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-setup-sections.js +++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-setup-sections.js @@ -11,16 +11,14 @@ import { Form } from '@woocommerce/components'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useTargetAudienceFinalCountryCodes from '.~/hooks/useTargetAudienceFinalCountryCodes'; import useGoogleAdsAccountBillingStatus from '.~/hooks/useGoogleAdsAccountBillingStatus'; -import GoogleAdsAccountSection from './google-ads-account-section'; import AudienceSection from '.~/components/paid-ads/audience-section'; import BudgetSection from '.~/components/paid-ads/budget-section'; import BillingCard from '.~/components/paid-ads/billing-card'; +import SpinnerCard from '.~/components/spinner-card'; +import Section from '.~/wcdl/section'; import validateCampaign from '.~/components/paid-ads/validateCampaign'; import clientSession from './clientSession'; -import { - GOOGLE_ADS_ACCOUNT_STATUS, - GOOGLE_ADS_BILLING_STATUS, -} from '.~/constants'; +import { GOOGLE_ADS_BILLING_STATUS } from '.~/constants'; /** * @typedef { import(".~/data/actions").CountryCode } CountryCode @@ -77,7 +75,7 @@ function resolveInitialPaidAds( paidAds, targetAudience ) { * @param {(onStatesReceived: PaidAdsData)=>void} props.onStatesReceived Callback to receive the data for setting up paid ads when initial and also when the audience, budget, and billing are updated. */ export default function PaidAdsSetupSections( { onStatesReceived } ) { - const { googleAdsAccount } = useGoogleAdsAccount(); + const { hasGoogleAdsConnection } = useGoogleAdsAccount(); const { data: targetAudience } = useTargetAudienceFinalCountryCodes(); const { billingStatus } = useGoogleAdsAccountBillingStatus(); @@ -135,7 +133,11 @@ export default function PaidAdsSetupSections( { onStatesReceived } ) { }, [ targetAudience ] ); if ( ! targetAudience || ! billingStatus ) { - return ; + return ( +
+ +
+ ); } const initialValues = { @@ -153,16 +155,12 @@ export default function PaidAdsSetupSections( { onStatesReceived } ) { > { ( formProps ) => { const { countryCodes } = formProps.values; - const disabledAudience = ! [ - GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED, - GOOGLE_ADS_ACCOUNT_STATUS.INCOMPLETE, - ].includes( googleAdsAccount?.status ); + const disabledAudience = ! hasGoogleAdsConnection; const disabledBudget = disabledAudience || countryCodes.length === 0; return ( <> - clientSession.getShowPaidAdsSetup( false ) @@ -123,31 +126,32 @@ export default function SetupPaidAds() { function createSkipButton( text ) { const eventProps = { opened_paid_ads_setup: 'no', - google_ads_account_status: 'unknown', + google_ads_account_status: googleAdsAccount?.status, billing_method_status: 'unknown', campaign_form_validation: 'unknown', }; if ( showPaidAdsSetup ) { const selector = select( STORE_KEY ); - const account = selector.getGoogleAdsAccount(); const billing = selector.getGoogleAdsAccountBillingStatus(); merge( eventProps, { opened_paid_ads_setup: 'yes', - google_ads_account_status: account?.status, billing_method_status: billing?.status, campaign_form_validation: paidAds.isValid ? 'valid' : 'invalid', } ); } + const disabledSkip = + completing === ACTION_COMPLETE || ! hasGoogleAdsConnection; + return ( + Date: Wed, 13 Dec 2023 16:08:18 +0800 Subject: [PATCH 2/8] Hide the content about the ad budget in the Boost card before a Google Ads account is connected. --- .../campaign-preview/mockup-search.js | 2 +- .../paid-ads-features-section.js | 41 +++++++++++-------- .../setup-paid-ads/setup-paid-ads.js | 5 ++- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/js/src/components/paid-ads/campaign-preview/mockup-search.js b/js/src/components/paid-ads/campaign-preview/mockup-search.js index bdf2b04d2b..fb1e013439 100644 --- a/js/src/components/paid-ads/campaign-preview/mockup-search.js +++ b/js/src/components/paid-ads/campaign-preview/mockup-search.js @@ -48,7 +48,7 @@ export default function MockupSearch( { product } ) { - +
diff --git a/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-features-section.js b/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-features-section.js index 14099026e6..fe3330df4c 100644 --- a/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-features-section.js +++ b/js/src/setup-mc/setup-stepper/setup-paid-ads/paid-ads-features-section.js @@ -15,7 +15,7 @@ import AppDocumentationLink from '.~/components/app-documentation-link'; import CampaignPreview from '.~/components/paid-ads/campaign-preview'; import './paid-ads-features-section.scss'; -function FeatureList() { +function FeatureList( { hideBudgetContent } ) { const featuresItems = [ { Icon: GridiconCheckmark, @@ -24,22 +24,27 @@ function FeatureList() { 'google-listings-and-ads' ), }, - { - Icon: GridiconCheckmark, - content: __( - 'Set a daily budget, and only pay when someone clicks.', - 'google-listings-and-ads' - ), - }, - { - Icon: GridiconGift, - content: __( - 'Claim $500 in ads credit when you spend your first $500 with Google Ads. Terms and conditions apply.', - 'google-listings-and-ads' - ), - }, ]; + if ( ! hideBudgetContent ) { + featuresItems.push( + { + Icon: GridiconCheckmark, + content: __( + 'Set a daily budget, and only pay when someone clicks.', + 'google-listings-and-ads' + ), + }, + { + Icon: GridiconGift, + content: __( + 'Claim $500 in ads credit when you spend your first $500 with Google Ads. Terms and conditions apply.', + 'google-listings-and-ads' + ), + } + ); + } + return (
{ featuresItems.map( ( { Icon, content }, idx ) => ( @@ -61,11 +66,13 @@ function FeatureList() { * for the next actions: skip or continue the paid ads setup. * * @param {Object} props React props. + * @param {boolean} props.hideBudgetContent Whether to hide the content about the ad budget. * @param {boolean} props.hideFooterButtons Whether to hide the buttons at the card footer. * @param {JSX.Element} props.skipButton Button to skip paid ads setup. * @param {JSX.Element} props.continueButton Button to continue paid ads setup. */ export default function PaidAdsFeaturesSection( { + hideBudgetContent, hideFooterButtons, skipButton, continueButton, @@ -120,7 +127,9 @@ export default function PaidAdsFeaturesSection( { 'google-listings-and-ads' ) }
- + { __( 'Source: Google Internal Data, July 2020', 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 42ac698057..b576527af8 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 @@ -174,7 +174,10 @@ export default function SetupPaidAds() { Date: Wed, 13 Dec 2023 16:13:21 +0800 Subject: [PATCH 3/8] Update tracking README. --- src/Tracking/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Tracking/README.md b/src/Tracking/README.md index b8104759e5..2be5fc3674 100644 --- a/src/Tracking/README.md +++ b/src/Tracking/README.md @@ -571,7 +571,7 @@ A modal is open - [`ReviewRequest`](../../js/src/product-feed/review-request/index.js#L31) with `context: REQUEST_REVIEW` - [`SubmissionSuccessGuide`](../../js/src/product-feed/submission-success-guide/index.js#L155) with `context: GUIDE_NAMES.SUBMISSION_SUCCESS` -### [`gla_onboarding_complete_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L47) +### [`gla_onboarding_complete_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L49) Clicking on the skip paid ads button to complete the onboarding flow. The 'unknown' value of properties may means: - the paid ads setup is not opened @@ -581,13 +581,13 @@ Clicking on the skip paid ads button to complete the onboarding flow. | name | type | description | | ---- | ---- | ----------- | `opened_paid_ads_setup` | `string` | Whether the paid ads setup is opened, e.g. 'yes', 'no' -`google_ads_account_status` | `string` | The connection status of merchant's Google Ads addcount, e.g. 'unknown', 'connected', 'disconnected', 'incomplete' +`google_ads_account_status` | `string` | The connection status of merchant's Google Ads addcount, e.g. 'connected', 'disconnected', 'incomplete' `billing_method_status` | `string` | aaa, The status of billing method of merchant's Google Ads addcount e.g. 'unknown', 'pending', 'approved', 'cancelled' `campaign_form_validation` | `string` | Whether the entered paid campaign form data are valid, e.g. 'unknown', 'valid', 'invalid' #### Emitters -- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L69) +- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L71) -### [`gla_onboarding_complete_with_paid_ads_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L39) +### [`gla_onboarding_complete_with_paid_ads_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L41) Clicking on the "Complete setup" button to complete the onboarding flow with paid ads. #### Properties | name | type | description | @@ -595,12 +595,12 @@ Clicking on the "Complete setup" button to complete the onboarding flow with pai `budget` | `number` | The budget for the campaign `audiences` | `string` | The targeted audiences for the campaign #### Emitters -- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L69) +- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L71) -### [`gla_onboarding_open_paid_ads_setup_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L33) +### [`gla_onboarding_open_paid_ads_setup_button_click`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L35) Clicking on the "Create a paid ad campaign" button to open the paid ads setup in the onboarding flow. #### Emitters -- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L69) +- [`exports`](../../js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js#L71) ### [`gla_paid_campaign_step`](../../js/src/utils/recordEvent.js#L122) Triggered when moving to another step during creating/editing a campaign. From ab228ba476f78d15be661086c35410cef5ebc49c Mon Sep 17 00:00:00 2001 From: martynmjones Date: Tue, 5 Dec 2023 19:08:48 +0000 Subject: [PATCH 4/8] Update budget recommendation text --- tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js | 2 +- tests/e2e/utils/pages/setup-ads/setup-budget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js b/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js index cbea1c7d23..8e0e64b5b5 100644 --- a/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js +++ b/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js @@ -360,7 +360,7 @@ test.describe( 'Set up Ads account', () => { test( 'Budget Recommendation', async () => { await expect( - page.getByText( 'set a daily budget of 5 to 15 USD' ) + page.getByText( 'set a daily budget of 15 USD' ) ).toBeVisible(); } ); } ); diff --git a/tests/e2e/utils/pages/setup-ads/setup-budget.js b/tests/e2e/utils/pages/setup-ads/setup-budget.js index 54ec0ab8eb..355aae1029 100644 --- a/tests/e2e/utils/pages/setup-ads/setup-budget.js +++ b/tests/e2e/utils/pages/setup-ads/setup-budget.js @@ -92,7 +92,7 @@ export default class SetupBudget extends MockRequests { * @return {string} The budget recommendation range. */ extractBudgetRecommendationRange( text ) { - const match = text.match( /set a daily budget of (\d+ to \d+)/ ); + const match = text.match( /set a daily budget of (\d+)/ ); if ( match ) { return match[ 1 ]; } From ea809f5597e8a5a6b06c8ec41360e006e283d6d9 Mon Sep 17 00:00:00 2001 From: Eason Su Date: Thu, 14 Dec 2023 16:48:29 +0800 Subject: [PATCH 5/8] Fix the budget recommendation E2E tests for PR #2153 after cherry-picking PR #2174. Ref: - https://github.com/woocommerce/google-listings-and-ads/pull/2153 - https://github.com/woocommerce/google-listings-and-ads/pull/2174#pullrequestreview-1771727538 --- .../add-paid-campaigns/add-paid-campaigns.test.js | 10 ---------- .../specs/setup-mc/step-4-complete-campaign.test.js | 8 ++++---- tests/e2e/utils/mock-requests.js | 13 ------------- tests/e2e/utils/pages/setup-ads/setup-budget.js | 6 +++--- 4 files changed, 7 insertions(+), 30 deletions(-) diff --git a/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js b/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js index 8e0e64b5b5..a7b1cd56b1 100644 --- a/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js +++ b/tests/e2e/specs/add-paid-campaigns/add-paid-campaigns.test.js @@ -248,16 +248,6 @@ test.describe( 'Set up Ads account', () => { test.describe( 'Create your paid campaign', () => { test.beforeAll( async () => { setupBudgetPage = new SetupBudgetPage( page ); - await setupBudgetPage.fulfillBudgetRecommendation( { - currency: 'USD', - recommendations: [ - { - country: 'US', - daily_budget_low: 5, - daily_budget_high: 15, - }, - ], - } ); } ); test( 'Continue to create paid campaign', async () => { 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 c34ac1a1c4..0046273e56 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 @@ -423,13 +423,13 @@ test.describe( 'Complete your campaign', () => { await expect( treeSelectMenu ).not.toBeVisible(); } ); - test( 'should see the budget recommendation range changed, and see the budget recommendation request is triggered when changing the ads audience', async () => { + test( 'should see the budget recommendation value changed, and see the budget recommendation request is triggered when changing the ads audience', async () => { let textContent = await setupBudgetPage .getBudgetRecommendationTextRow() .textContent(); const textBeforeRemoveCountry = - setupBudgetPage.extractBudgetRecommendationRange( + setupBudgetPage.extractBudgetRecommendationValue( textContent ); @@ -438,7 +438,7 @@ test.describe( 'Complete your campaign', () => { await removeCountryFromSearchBox( page, - 'United States (US)' + 'United Kingdom (UK)' ); await responsePromise; @@ -448,7 +448,7 @@ test.describe( 'Complete your campaign', () => { .textContent(); const textAfterRemoveCountry = - setupBudgetPage.extractBudgetRecommendationRange( + setupBudgetPage.extractBudgetRecommendationValue( textContent ); diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 09a61c4c48..73d2e601bd 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -222,19 +222,6 @@ export default class MockRequests { await this.fulfillRequest( /\/wc\/gla\/ads\/accounts\b/, payload ); } - /** - * Fulfill the Budget Recommendation request. - * - * @param {Object} payload - * @return {Promise} - */ - async fulfillBudgetRecommendation( payload ) { - await this.fulfillRequest( - /\/wc\/gla\/ads\/campaigns\/budget-recommendation\b/, - payload - ); - } - /** * Fulfill the Sync Settings Connection request. * diff --git a/tests/e2e/utils/pages/setup-ads/setup-budget.js b/tests/e2e/utils/pages/setup-ads/setup-budget.js index 355aae1029..dca6843f64 100644 --- a/tests/e2e/utils/pages/setup-ads/setup-budget.js +++ b/tests/e2e/utils/pages/setup-ads/setup-budget.js @@ -85,13 +85,13 @@ export default class SetupBudget extends MockRequests { } /** - * Extract budget recommendation range. + * Extract budget recommendation value. * * @param {string} text * - * @return {string} The budget recommendation range. + * @return {string} The budget recommendation value. */ - extractBudgetRecommendationRange( text ) { + extractBudgetRecommendationValue( text ) { const match = text.match( /set a daily budget of (\d+)/ ); if ( match ) { return match[ 1 ]; From 27f7c0558032573078715aacb83f37954f56d37e Mon Sep 17 00:00:00 2001 From: Eason Su Date: Thu, 14 Dec 2023 18:14:52 +0800 Subject: [PATCH 6/8] Add more utils to mock requests for E2E tests. --- tests/e2e/utils/mock-requests.js | 36 ++++++++++++++++ .../pages/setup-ads/setup-ads-accounts.js | 43 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 73d2e601bd..5ee29a943a 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -296,6 +296,42 @@ export default class MockRequests { ); } + /** + * Fulfill the MC account issues request. + * + * @param {Object} payload + * @return {Promise} + */ + async fulfillAccountIssuesRequest( payload ) { + await this.fulfillRequest( + /\/wc\/gla\/mc\/issues\/account\b/, + payload + ); + } + + /** + * Fulfill the MC product issues request. + * + * @param {Object} payload + * @return {Promise} + */ + async fulfillProductIssuesRequest( payload ) { + await this.fulfillRequest( + /\/wc\/gla\/mc\/issues\/product\b/, + payload + ); + } + + /** + * Fulfill the MC review request. + * + * @param {Object} payload + * @return {Promise} + */ + async fulfillMCReview( payload ) { + await this.fulfillRequest( /\/wc\/gla\/mc\/review\b/, payload ); + } + /** * Fulfill product statistics request. * diff --git a/tests/e2e/utils/pages/setup-ads/setup-ads-accounts.js b/tests/e2e/utils/pages/setup-ads/setup-ads-accounts.js index 5e18565506..fb41f64dcd 100644 --- a/tests/e2e/utils/pages/setup-ads/setup-ads-accounts.js +++ b/tests/e2e/utils/pages/setup-ads/setup-ads-accounts.js @@ -117,6 +117,49 @@ export default class SetupAdsAccount extends MockRequests { await this.getAdsAccountSelect().selectOption( accountNumber ); } + /** + * Mock Google Ads account as not yet connected. + * + * @return {Promise} + */ + async mockAdsAccountDisconnected() { + await this.fulfillAdsConnection( { + id: 0, + currency: null, + symbol: 'NT$', + status: 'disconnected', + } ); + } + + /** + * Mock Google Ads account as connected but its billing setup is incomplete. + * + * @return {Promise} + */ + async mockAdsAccountIncomplete() { + await this.fulfillAdsConnection( { + id: 12345, + currency: 'TWD', + symbol: 'NT$', + status: 'incomplete', + } ); + } + + /** + * Mock Google Ads account as connected. + * + * @param {number} [id=12345] + * @return {Promise} + */ + async mockAdsAccountConnected( id = 12345 ) { + await this.fulfillAdsConnection( { + id, + currency: 'TWD', + symbol: 'NT$', + status: 'connected', + } ); + } + /** * Mock the Ads accounts response. * From b4421aa97fea4d383fb59321d81c7c68daee309f Mon Sep 17 00:00:00 2001 From: Eason Su Date: Thu, 14 Dec 2023 18:18:19 +0800 Subject: [PATCH 7/8] Adjust E2E tests to reflect the change of requiring Google Ads connection in step 4 of the onboarding. --- .../setup-mc/step-4-complete-campaign.test.js | 347 +++++++++++------- .../setup-mc/step-4-complete-campaign.js | 12 +- 2 files changed, 225 insertions(+), 134 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 0046273e56..4f9594f7f2 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 @@ -61,6 +61,12 @@ test.describe( 'Complete your campaign', () => { // Mock Merchant Center as connected completeCampaign.mockMCConnected(), + // Mock Google Ads as not yet connected. + setupAdsAccountPage.mockAdsAccountDisconnected(), + + // Mock there is no existing Google Ads account. + setupAdsAccountPage.mockAdsAccountsResponse( [] ), + // Mock MC step as paid_ads completeCampaign.mockMCSetup( 'incomplete', 'paid_ads' ), @@ -79,6 +85,40 @@ test.describe( 'Complete your campaign', () => { completeCampaign.fulfillSyncableProductsCountRequest( { count: 1024, } ), + + // The following mocks are requests will happen after completing the onboarding + completeCampaign.mockSuccessfulSettingsSyncRequest(), + + completeCampaign.fulfillProductStatisticsRequest( { + timestamp: 1695011644, + statistics: { + active: 0, + expiring: 0, + pending: 0, + disapproved: 0, + not_synced: 1137, + }, + scheduled_sync: 1, + } ), + + completeCampaign.fulfillAccountIssuesRequest( { + issues: [], + page: 1, + total: 0, + } ), + + completeCampaign.fulfillProductIssuesRequest( { + issues: [], + page: 1, + total: 0, + } ), + + completeCampaign.fulfillMCReview( { + cooldown: 0, + issues: [], + reviewEligibleRegions: [], + status: 'ONBOARDING', + } ), ] ); await completeCampaign.goto(); @@ -127,124 +167,63 @@ test.describe( 'Complete your campaign', () => { } ); } ); - test.describe( 'Click "Skip this step for now"', () => { - test.beforeAll( async () => { - await Promise.all( [ - // Mock settings sync request - completeCampaign.mockSuccessfulSettingsSyncRequest(), - - // Mock product statistics request - completeCampaign.fulfillProductStatisticsRequest( { - timestamp: 1695011644, - statistics: { - active: 0, - expiring: 0, - pending: 0, - disapproved: 0, - not_synced: 1137, - }, - scheduled_sync: 1, - } ), - ] ); - 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 Listings & Ads!', - } ); - await expect( setupSuccessModal ).toBeVisible(); - } ); - - test( 'should see the url contains product-feed', async () => { - expect( page.url() ).toMatch( /path=%2Fgoogle%2Fproduct-feed/ ); - } ); - } ); - - test.describe( 'Set up paid ads', () => { - test.beforeAll( async () => { - await Promise.all( [ - // Mock settings sync request - completeCampaign.mockSuccessfulSettingsSyncRequest(), - - // Mock product statistics request - completeCampaign.fulfillProductStatisticsRequest( { - timestamp: 1695011644, - statistics: { - active: 0, - expiring: 0, - pending: 0, - disapproved: 0, - not_synced: 1137, - }, - scheduled_sync: 1, - } ), - ] ); - await completeCampaign.goto(); - } ); - - test( 'should see the "Create a paid ad campaign" button is enabled', async () => { - const button = completeCampaign.getCreatePaidAdButton(); - await expect( button ).toBeVisible(); - await expect( button ).toBeEnabled(); - } ); - - test.describe( 'Click "Create a paid ad campaign" button', () => { - test.beforeAll( async () => { - await completeCampaign.clickCreatePaidAdButton(); - await setupAdsAccountPage.mockAdsAccountsResponse( [] ); + test.describe( 'Google Ads', () => { + test.describe( 'Google Ads section', () => { + test.beforeEach( async () => { + await completeCampaign.goto(); } ); - test( 'should see "Complete setup" button is disabled', async () => { - const completeSetupButton = - completeCampaign.getCompleteSetupButton(); - await expect( completeSetupButton ).toBeVisible(); - await expect( completeSetupButton ).toBeDisabled(); + test( 'should see Google Ads section', async () => { + const section = completeCampaign.getAdsAccountSection(); + await expect( section ).toBeVisible(); } ); - test( 'should see "Skip paid ads creation" button is enabled', async () => { - const skipPaidAdsCreationButton = - completeCampaign.getSkipPaidAdsCreationButton(); - await expect( skipPaidAdsCreationButton ).toBeVisible(); - await expect( skipPaidAdsCreationButton ).toBeEnabled(); - } ); - - test( 'should see "Google Ads" section is enabled', async () => { - const googleAdsSection = - completeCampaign.getAdsAccountSection(); - await expect( googleAdsSection ).toBeVisible(); + test( 'should only see non-budget related items and no footer buttons in the Features section when not yet connected', async () => { + const section = completeCampaign.getPaidAdsFeaturesSection(); + const items = section.locator( + '.gla-paid-ads-features-section__feature-list > div' + ); + await expect( items ).toHaveCount( 1 ); + await expect( items ).toContainText( 'Promote your products' ); - // Cannot use toBeEnabled() because
is not a native control element - // such as