From 419cfecb3453af9ed89403a0ae023122dde6f03c Mon Sep 17 00:00:00 2001 From: Rafael Zaleski Date: Wed, 24 Jan 2024 11:11:21 -0300 Subject: [PATCH] Add E2E tests for merchant on-boarding (#7955) Co-authored-by: Brian Borman <68524302+bborman22@users.noreply.github.com> Co-authored-by: Achyuth Ajoy --- .github/actions/e2e/run-log-tests/action.yml | 1 + changelog/e2e-7347-merchant-on-boarding | 4 + .../tasks/add-currencies-task/index.js | 9 +- .../test/__snapshots__/index.test.js.snap | 6 + .../enabled-currencies-list/modal-checkbox.js | 3 +- package.json | 2 +- .../config/jest-puppeteer-headless.config.js | 17 + ...t-admin-multi-currency-on-boarding.spec.js | 362 ++++++++++++++++++ ...erchant-admin-multi-currency-setup.spec.js | 1 + tests/e2e/utils/flows.js | 31 ++ tests/e2e/utils/helpers.js | 18 + 11 files changed, 450 insertions(+), 4 deletions(-) create mode 100644 changelog/e2e-7347-merchant-on-boarding create mode 100644 tests/e2e/config/jest-puppeteer-headless.config.js create mode 100644 tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-on-boarding.spec.js diff --git a/.github/actions/e2e/run-log-tests/action.yml b/.github/actions/e2e/run-log-tests/action.yml index 71e8d883865..142e085d0fe 100644 --- a/.github/actions/e2e/run-log-tests/action.yml +++ b/.github/actions/e2e/run-log-tests/action.yml @@ -39,6 +39,7 @@ runs: with: name: wp(${{ env.E2E_WP_VERSION }})-wc(${{ env.E2E_WC_VERSION }})-${{ env.E2E_GROUP }}-${{ env.E2E_BRANCH }} path: | + screenshots tests/e2e/screenshots tests/e2e/docker/wordpress/wp-content/debug.log ${{ env.E2E_RESULT_FILEPATH }} diff --git a/changelog/e2e-7347-merchant-on-boarding b/changelog/e2e-7347-merchant-on-boarding new file mode 100644 index 00000000000..e1de02a0b10 --- /dev/null +++ b/changelog/e2e-7347-merchant-on-boarding @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +E2E test - Merchant facing multi-currency on-boarding screen. diff --git a/client/multi-currency-setup/tasks/add-currencies-task/index.js b/client/multi-currency-setup/tasks/add-currencies-task/index.js index 335b6b78985..1795edaa6a0 100644 --- a/client/multi-currency-setup/tasks/add-currencies-task/index.js +++ b/client/multi-currency-setup/tasks/add-currencies-task/index.js @@ -173,13 +173,14 @@ const AddCurrenciesTask = () => { ); } ); - const displayCurrencyCheckbox = ( code ) => + const displayCurrencyCheckbox = ( code, testId = '' ) => availableCurrencyCodes.length && ( ); @@ -284,7 +285,11 @@ const AddCurrenciesTask = () => { { visibleRecommendedCurrencyCodes.map( - displayCurrencyCheckbox + ( code ) => + displayCurrencyCheckbox( + code, + 'recommended-currency' + ) ) }
  • { const handleChange = useCallback( ( enabled ) => { @@ -20,7 +21,7 @@ const EnabledCurrenciesModalCheckbox = ( { ); return ( -
  • +
  • `.theme[data-slug="${ themeSlug }"]`; +const ACTIVATE_THEME_BUTTON_SELECTOR = ( themeSlug ) => + `${ THEME_SELECTOR( themeSlug ) } .button.activate`; +const MULTI_CURRENCY_TOGGLE_SELECTOR = "[data-testid='multi-currency-toggle']"; +const RECOMMENDED_CURRENCY_LIST_SELECTOR = + 'li[data-testid="recommended-currency"]'; +const CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR = + 'li.enabled-currency-checkbox:not([data-testid="recommended-currency"])'; +const ENABLED_CURRENCY_LIST_SELECTOR = 'li.enabled-currency-checkbox'; +const GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR = + 'input[data-testid="enable_auto_currency"]'; +const PREVIEW_STORE_BTN_SELECTOR = '.multi-currency-setup-preview-button'; +const PREVIEW_STORE_IFRAME_SELECTOR = + '.multi-currency-store-settings-preview-iframe'; +const SUBMIT_STEP_BTN_SELECTOR = + '.add-currencies-task.is-active .task-collapsible-body.is-active > button.is-primary'; +const STOREFRONT_SWITCH_CHECKBOX_SELECTOR = + 'input[data-testid="enable_storefront_switcher"]'; + +let wasMulticurrencyEnabled; + +const goToThemesPage = async () => { + await page.goto( `${ WP_ADMIN_DASHBOARD }themes.php`, { + waitUntil: 'networkidle0', + } ); +}; + +const activateTheme = async ( themeSlug ) => { + await goToThemesPage(); + + // Check if the theme is already active. + const isActive = await page.evaluate( ( selector ) => { + const themeElement = document.querySelector( selector ); + return themeElement && themeElement.classList.contains( 'active' ); + }, THEME_SELECTOR( themeSlug ) ); + + // Activate the theme if it's not already active. + if ( ! isActive ) { + await page.click( ACTIVATE_THEME_BUTTON_SELECTOR( themeSlug ) ); + await page.waitForNavigation( { waitUntil: 'networkidle0' } ); + } +}; + +const goToOnboardingPage = async () => { + await page.goto( + `${ WP_ADMIN_DASHBOARD }admin.php?page=wc-admin&path=%2Fpayments%2Fmulti-currency-setup`, + { + waitUntil: 'networkidle0', + } + ); + await uiLoaded(); +}; + +const goToNextOnboardingStep = async () => { + await page.click( SUBMIT_STEP_BTN_SELECTOR ); +}; + +describe( 'Merchant On-boarding', () => { + let activeThemeSlug; + + beforeAll( async () => { + await merchant.login(); + // Get initial multi-currency feature status. + await merchantWCP.openWCPSettings(); + await page.waitForSelector( MULTI_CURRENCY_TOGGLE_SELECTOR ); + wasMulticurrencyEnabled = await page.evaluate( ( selector ) => { + const checkbox = document.querySelector( selector ); + return checkbox ? checkbox.checked : false; + }, MULTI_CURRENCY_TOGGLE_SELECTOR ); + await merchantWCP.activateMulticurrency(); + + await goToThemesPage(); + + // Get current theme slug. + activeThemeSlug = await page.evaluate( () => { + const theme = document.querySelector( '.theme.active' ); + return theme ? theme.getAttribute( 'data-slug' ) : ''; + } ); + } ); + + afterAll( async () => { + // Restore original theme. + await activateTheme( activeThemeSlug ); + + // Disable multi-currency if it was not initially enabled. + if ( ! wasMulticurrencyEnabled ) { + await merchant.login(); + await merchantWCP.deactivateMulticurrency(); + } + await merchant.logout(); + } ); + + describe( 'Currency Selection and Management', () => { + beforeAll( async () => { + await merchantWCP.disableAllEnabledCurrencies(); + } ); + + beforeEach( async () => { + await goToOnboardingPage(); + } ); + + it( 'Should disable the submit button when no currencies are selected', async () => { + await takeScreenshot( 'merchant-on-boarding-multicurrency-screen' ); + await setCheckboxState( + `${ ENABLED_CURRENCY_LIST_SELECTOR } .components-checkbox-control__input`, + false + ); + + await page.waitFor( 1000 ); + + const button = await page.$( SUBMIT_STEP_BTN_SELECTOR ); + expect( button ).not.toBeNull(); + + const isDisabled = await page.evaluate( + ( btn ) => btn.disabled, + button + ); + + expect( isDisabled ).toBeTruthy(); + } ); + + it( 'Should allow multiple currencies to be selectable', async () => { + await page.waitForSelector( + CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR, + { + timeout: 3000, + } + ); + + // Ensure the checkbox within the list item is present and not disabled. + const checkbox = await page.$( + `${ CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR } input[type="checkbox"]` + ); + expect( checkbox ).not.toBeNull(); + const isDisabled = await ( + await checkbox.getProperty( 'disabled' ) + ).jsonValue(); + expect( isDisabled ).toBe( false ); + + // Click the checkbox to select the currency and verify it's checked. + await checkbox.click(); + + const isChecked = await ( + await checkbox.getProperty( 'checked' ) + ).jsonValue(); + expect( isChecked ).toBe( true ); + } ); + + it( 'Should exclude already enabled currencies from the currency screen', async () => { + await merchantWCP.addCurrency( 'GBP' ); + + await goToOnboardingPage(); + + await page.waitForSelector( ENABLED_CURRENCY_LIST_SELECTOR, { + timeout: 3000, + } ); + + // Get the list of currencies as text + const currencies = await page.$$eval( + ENABLED_CURRENCY_LIST_SELECTOR, + ( items ) => items.map( ( item ) => item.textContent.trim() ) + ); + + expect( currencies ).not.toContain( 'GBP' ); + + await merchantWCP.removeCurrency( 'GBP' ); + } ); + + it( 'Should display some suggested currencies at the beginning of the list', async () => { + await page.waitForSelector( RECOMMENDED_CURRENCY_LIST_SELECTOR, { + timeout: 3000, + } ); + + // Get the list of recommended currencies + const recommendedCurrencies = await page.$$eval( + RECOMMENDED_CURRENCY_LIST_SELECTOR, + ( items ) => + items.map( ( item ) => ( { + code: item + .querySelector( 'input' ) + .getAttribute( 'code' ), + name: item + .querySelector( + 'span.enabled-currency-checkbox__code' + ) + .textContent.trim(), + } ) ) + ); + + expect( recommendedCurrencies.length ).toBeGreaterThan( 0 ); + } ); + + it( 'Should ensure selected currencies are enabled after submitting the form', async () => { + const testCurrencies = [ 'GBP', 'EUR', 'CAD', 'AUD' ]; + const addCurrenciesContentSelector = + '.add-currencies-task__content'; + const currencyCheckboxSelector = `${ addCurrenciesContentSelector } li input[type="checkbox"]`; + + await page.waitForSelector( addCurrenciesContentSelector, { + timeout: 3000, + } ); + + // Select the currencies + for ( const currency of testCurrencies ) { + await setCheckboxState( + `${ currencyCheckboxSelector }[code="${ currency }"]`, + true + ); + } + + // Submit the form. + await goToNextOnboardingStep(); + + await merchantWCP.openMultiCurrency(); + + // Ensure the currencies are enabled. + for ( const currency of testCurrencies ) { + const selector = `li.enabled-currency.${ currency.toLowerCase() }`; + await page.waitForSelector( selector, { timeout: 10000 } ); + const element = await page.$( selector ); + + expect( element ).not.toBeNull(); + } + } ); + } ); + + describe( 'Geolocation Features', () => { + beforeAll( async () => { + await merchantWCP.disableAllEnabledCurrencies(); + } ); + + beforeEach( async () => { + await goToOnboardingPage(); + } ); + + it( 'Should offer currency switch by geolocation', async () => { + await goToNextOnboardingStep(); + + const checkbox = await page.$( + GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR + ); + + // Check if exists and not disabled. + expect( checkbox ).not.toBeNull(); + const isDisabled = await ( + await checkbox.getProperty( 'disabled' ) + ).jsonValue(); + expect( isDisabled ).toBe( false ); + + // Click the checkbox to select it. + await page.click( GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR ); + + // Check if the checkbox is selected. + const isChecked = await ( + await checkbox.getProperty( 'checked' ) + ).jsonValue(); + expect( isChecked ).toBe( true ); + } ); + + it( 'Should preview currency switch by geolocation correctly with USD and GBP', async () => { + page.setViewport( { width: 1280, height: 1280 } ); // To take a better screenshot of the iframe preview. + + await goToNextOnboardingStep(); + + await takeScreenshot( + 'merchant-on-boarding-multicurrency-screen-2' + ); + + // Enable feature. + await setCheckboxState( + GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR, + true + ); + + // Click preview button. + await page.click( PREVIEW_STORE_BTN_SELECTOR ); + + await page.waitForSelector( PREVIEW_STORE_IFRAME_SELECTOR, { + timeout: 3000, + } ); + + const iframeElement = await page.$( PREVIEW_STORE_IFRAME_SELECTOR ); + const iframe = await iframeElement.contentFrame(); + + await iframe.waitForSelector( '.woocommerce-store-notice', { + timeout: 3000, + } ); + + await takeScreenshot( + 'merchant-on-boarding-multicurrency-geolocation-switcher-preview' + ); + + const noticeText = await iframe.$eval( + '.woocommerce-store-notice', + ( element ) => element.innerText + ); + expect( noticeText ).toContain( + // eslint-disable-next-line max-len + "We noticed you're visiting from United Kingdom (UK). We've updated our prices to Pound sterling for your shopping convenience." + ); + } ); + } ); + + describe( 'Currency Switcher Widget', () => { + it( 'Should offer the currency switcher widget while Storefront theme is active', async () => { + await activateTheme( 'storefront' ); + + await goToOnboardingPage(); + await goToNextOnboardingStep(); + + const checkbox = await page.$( + STOREFRONT_SWITCH_CHECKBOX_SELECTOR + ); + + // Check if exists and not disabled. + expect( checkbox ).not.toBeNull(); + const isDisabled = await ( + await checkbox.getProperty( 'disabled' ) + ).jsonValue(); + expect( isDisabled ).toBe( false ); + + // Click the checkbox to select it. + await page.click( STOREFRONT_SWITCH_CHECKBOX_SELECTOR ); + + // Check if the checkbox is selected. + const isChecked = await ( + await checkbox.getProperty( 'checked' ) + ).jsonValue(); + expect( isChecked ).toBe( true ); + } ); + + it( 'Should not offer the currency switcher widget when an unsupported theme is active', async () => { + await activateTheme( 'twentytwentyfour' ); + + await goToOnboardingPage(); + await goToNextOnboardingStep(); + + const checkbox = await page.$( + STOREFRONT_SWITCH_CHECKBOX_SELECTOR + ); + + expect( checkbox ).toBeNull(); + + await activateTheme( 'storefront' ); + } ); + } ); +} ); diff --git a/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js index 51f7fc9cd67..800ce9d0e8b 100644 --- a/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js +++ b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js @@ -75,6 +75,7 @@ describe( 'Merchant Multi-Currency Settings', () => { beforeAll( async () => { await merchantWCP.activateMulticurrency(); + await merchantWCP.disableAllEnabledCurrencies(); await shopperWCP.goToShopWithCurrency( 'USD' ); await shopperWCP.goToProductPageBySlug( 'beanie' ); diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js index 3399d5b9ffe..af662b55fee 100644 --- a/tests/e2e/utils/flows.js +++ b/tests/e2e/utils/flows.js @@ -513,6 +513,11 @@ export const merchantWCP = { } }, currencyCode ); + await page.waitForSelector( + 'div.wcpay-confirmation-modal__footer button.components-button.is-primary', + { timeout: 3000 } + ); + await page.click( 'div.wcpay-confirmation-modal__footer button.components-button.is-primary', { text: 'Update selected' } @@ -532,6 +537,7 @@ export const merchantWCP = { }, removeCurrency: async ( currencyCode ) => { + await merchantWCP.openMultiCurrency(); const currencyItemSelector = `li.enabled-currency.${ currencyCode.toLowerCase() }`; await page.waitForSelector( currencyItemSelector, { timeout: 10000 } ); await page.click( @@ -732,6 +738,31 @@ export const merchantWCP = { return wasInitiallyEnabled; }, + disableAllEnabledCurrencies: async () => { + await page.goto( WCPAY_MULTI_CURRENCY, { waitUntil: 'networkidle0' } ); + + await page.waitForSelector( '.enabled-currencies-list li', { + timeout: 10000, + } ); + + // Select all delete buttons for enabled currencies. + const deleteButtons = await page.$$( + '.enabled-currency .enabled-currency__action.delete' + ); + + // Loop through each delete button and click it. + for ( const button of deleteButtons ) { + await button.click(); + + await page.waitForSelector( '.components-snackbar', { + text: 'Enabled currencies updated.', + timeout: 10000, + } ); + + await page.waitFor( 1000 ); + } + }, + editCurrency: async ( currencyCode ) => { await merchantWCP.openMultiCurrency(); diff --git a/tests/e2e/utils/helpers.js b/tests/e2e/utils/helpers.js index ca829481a27..2d9b0e0932b 100644 --- a/tests/e2e/utils/helpers.js +++ b/tests/e2e/utils/helpers.js @@ -80,3 +80,21 @@ export const getProductPriceFromProductPage = async () => { return price; }; + +/** + * Sets the state of all checkboxes matching the specified selector. + * + * @param {string} selector The selector to use to find checkboxes. + * @param {boolean} desiredState The desired state of the checkboxes. + */ +export const setCheckboxState = async ( selector, desiredState ) => { + const checkboxes = await page.$$( selector ); + for ( const checkbox of checkboxes ) { + const isChecked = await ( + await checkbox.getProperty( 'checked' ) + ).jsonValue(); + if ( isChecked !== desiredState ) { + await checkbox.click(); + } + } +};