From ff92692ecc4225d2884e6205c506fc37c4868c74 Mon Sep 17 00:00:00 2001 From: Taha Paksu <3295+tpaksu@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:13:14 +0100 Subject: [PATCH] Convert shopper checkout purchase with UPE tests to Playwright (#10203) --- ...shopper-checkout-purchase-with-upe-methods | 4 + tests/e2e-pw/config/default.ts | 40 +++- ...checkout-purchase-with-upe-methods.spec.ts | 113 ++++++++++ .../shopper-myaccount-saved-cards.spec.ts | 199 ++++++++++++++++++ ...-subscriptions-purchase-free-trial.spec.ts | 31 ++- tests/e2e-pw/utils/merchant.ts | 17 +- tests/e2e-pw/utils/shopper-navigation.ts | 8 +- tests/e2e-pw/utils/shopper.ts | 100 ++++++++- ...checkout-purchase-with-upe-methods.spec.js | 170 --------------- ...payment-methods-add-delete-success.spec.js | 72 ------- ...r-myaccount-save-card-and-checkout.spec.js | 75 ------- 11 files changed, 495 insertions(+), 334 deletions(-) create mode 100644 changelog/dev-10064-playwright-migration-shopper-checkout-purchase-with-upe-methods create mode 100644 tests/e2e-pw/specs/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts create mode 100644 tests/e2e-pw/specs/shopper/shopper-myaccount-saved-cards.spec.ts delete mode 100644 tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js delete mode 100644 tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-delete-success.spec.js delete mode 100644 tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js diff --git a/changelog/dev-10064-playwright-migration-shopper-checkout-purchase-with-upe-methods b/changelog/dev-10064-playwright-migration-shopper-checkout-purchase-with-upe-methods new file mode 100644 index 00000000000..f8f20e10237 --- /dev/null +++ b/changelog/dev-10064-playwright-migration-shopper-checkout-purchase-with-upe-methods @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Convert shopper checkout with UPE methods E2E test to Playwright, split saving card tests to separate file diff --git a/tests/e2e-pw/config/default.ts b/tests/e2e-pw/config/default.ts index d370c84d25f..8094ff25eb8 100644 --- a/tests/e2e-pw/config/default.ts +++ b/tests/e2e-pw/config/default.ts @@ -74,6 +74,35 @@ export const config = { email: 'e2e-wcpay-customer@woo.com', }, }, + 'upe-customer': { + billing: { + be: { + firstname: 'I am', + lastname: 'Customer', + company: 'Automattic', + country: 'Belgium', + addressfirstline: 'Rue de l’Étuve, 1000', + addresssecondline: 'billing-be', + city: 'Bruxelles', + postcode: '1000', + phone: '123456789', + email: 'e2e-wcpay-customer@woocommerce.com', + }, + de: { + firstname: 'I am', + lastname: 'Customer', + company: 'Automattic', + country: 'Germany', + addressfirstline: 'Petuelring 130', + addresssecondline: 'billing-de', + city: 'München', + postcode: '80809', + state: 'DE-BY', + phone: '123456789', + email: 'e2e-wcpay-customer@woocommerce.com', + }, + }, + }, 'subscriptions-customer': { billing: { firstname: 'I am', @@ -125,11 +154,11 @@ export const config = { basic3: { number: '378282246310005', expires: { - month: '11', + month: '12', year: '45', }, cvc: '1234', - label: 'Amex ending in 0005', + label: 'American Express ending in 0005', }, '3ds': { number: '4000002760003184', @@ -272,4 +301,9 @@ export const config = { }, }; -export type CustomerAddress = typeof config.addresses.customer.billing; +export type CustomerAddress = Omit< + typeof config.addresses.customer.billing, + 'state' +> & { + state?: string; +}; diff --git a/tests/e2e-pw/specs/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts b/tests/e2e-pw/specs/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts new file mode 100644 index 00000000000..117e5742537 --- /dev/null +++ b/tests/e2e-pw/specs/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts @@ -0,0 +1,113 @@ +/** + * External dependencies + */ +import test, { Page, expect } from '@playwright/test'; + +/** + * Internal dependencies + */ +import { + activateMulticurrency, + addCurrency, + deactivateMulticurrency, + disablePaymentMethods, + enablePaymentMethods, + restoreCurrencies, +} from '../../utils/merchant'; +import { getShopper, getMerchant } from '../../utils/helpers'; +import { + disableCardTestingProtection, + enableCardTestingProtection, +} from '../../utils/devtools'; +import { + addToCartFromShopPage, + changeAccountCurrency, + emptyCart, + expectFraudPreventionToken, + fillBillingAddress, + focusPlaceOrderButton, + placeOrder, +} from '../../utils/shopper'; +import { config } from '../../config/default'; +import { goToCheckout, goToShop } from '../../utils/shopper-navigation'; + +test.describe( 'Enable UPE with deferred intent creation', () => { + let wasMultiCurrencyEnabled = false; + let merchantPage: Page, shopperPage: Page; + test.beforeAll( async ( { browser } ) => { + // Open browsers. + merchantPage = ( await getMerchant( browser ) ).merchantPage; + shopperPage = ( await getShopper( browser ) ).shopperPage; + + // Prepare merchant side of tests. + wasMultiCurrencyEnabled = await activateMulticurrency( merchantPage ); + await addCurrency( merchantPage, 'EUR' ); + await enablePaymentMethods( merchantPage, [ 'bancontact' ] ); + // Prepare shopper side of tests. + await changeAccountCurrency( + shopperPage, + config.addresses.customer.billing, + 'EUR' + ); + await emptyCart( shopperPage ); + } ); + + test.afterAll( async () => { + // Restore shopper side of tests. + await emptyCart( shopperPage ); + + // Restore merchant side of tests + await disablePaymentMethods( merchantPage, [ 'bancontact' ] ); + await restoreCurrencies( merchantPage ); + if ( ! wasMultiCurrencyEnabled ) { + await deactivateMulticurrency( merchantPage ); + } + } ); + + const testBancontactOrder = async ( + cardTestingPreventionState: boolean + ) => { + await goToShop( shopperPage ); + await addToCartFromShopPage( shopperPage, 'Beanie' ); + await goToCheckout( shopperPage ); + await fillBillingAddress( + shopperPage, + config.addresses[ 'upe-customer' ].billing.be + ); + await shopperPage.waitForLoadState( 'networkidle' ); + await expectFraudPreventionToken( + shopperPage, + cardTestingPreventionState + ); + await shopperPage.getByText( 'Bancontact' ).click(); + await focusPlaceOrderButton( shopperPage ); + await placeOrder( shopperPage ); + await shopperPage.waitForLoadState( 'networkidle' ); + await shopperPage + .getByRole( 'link', { + name: 'Authorize Test Payment', + } ) + .click(); + await expect( + shopperPage.getByText( 'Order received' ).first() + ).toBeVisible(); + }; + + test.describe( 'Card testing prevention enabled', () => { + test.beforeAll( async () => { + await enableCardTestingProtection( merchantPage ); + } ); + test.afterAll( async () => { + await disableCardTestingProtection( merchantPage ); + } ); + test( 'should successfully place order with Bancontact', async () => { + await testBancontactOrder( true ); + } ); + } ); + + test.describe( 'Card testing prevention disabled', () => { + test( 'should successfully place order with Bancontact', async () => { + await testBancontactOrder( false ); + } ); + } ); +} ); diff --git a/tests/e2e-pw/specs/shopper/shopper-myaccount-saved-cards.spec.ts b/tests/e2e-pw/specs/shopper/shopper-myaccount-saved-cards.spec.ts new file mode 100644 index 00000000000..13aed1d56ad --- /dev/null +++ b/tests/e2e-pw/specs/shopper/shopper-myaccount-saved-cards.spec.ts @@ -0,0 +1,199 @@ +/** + * External dependencies + */ +import test, { Page, expect } from '@playwright/test'; + +/** + * Internal dependencies + */ +import { config } from '../../config/default'; +import { goToMyAccount, goToShop } from '../../utils/shopper-navigation'; +import { getAnonymousShopper } from '../../utils/helpers'; +import { + addSavedCard, + confirmCardAuthentication, + deleteSavedCard, + placeOrder, + placeOrderWithOptions, + selectSavedCardOnCheckout, + setDefaultPaymentMethod, + setupProductCheckout, +} from '../../utils/shopper'; +import RestAPI from '../../utils/rest-api'; + +const cards = { + basic: config.cards.basic, + '3ds': config.cards[ '3ds' ], + '3ds2': config.cards[ '3ds2' ], +} as { [ key: string ]: typeof config.cards.basic }; + +test.describe( 'Shopper can save and delete cards', () => { + let timeAdded: number; + // Use cards different than other tests to prevent conflicts. + const card2 = config.cards.basic3; + let shopperPage: Page = null; + const customerBillingConfig = + config.addresses[ 'subscriptions-customer' ].billing; + + test.beforeAll( async ( { browser }, { project } ) => { + // Delete the user, if present, and create a new one with a new order. + // This is required to avoid running this test on a customer that already has a saved card. + const restApi = new RestAPI( project.use.baseURL ); + await restApi.deleteCustomerByEmailAddress( + customerBillingConfig.email + ); + + shopperPage = ( await getAnonymousShopper( browser ) ).shopperPage; + await placeOrderWithOptions( shopperPage, { + billingAddress: customerBillingConfig, + createAccount: true, + } ); + } ); + + async function waitTwentySecondsSinceLastCardAdded( page: Page ) { + // Make sure that at least 20s had already elapsed since the last card was added. + // Otherwise, you will get the error message, + // "You cannot add a new payment method so soon after the previous one." + // Source: /docker/wordpress/wp-content/plugins/woocommerce/includes/class-wc-form-handler.php#L509-L521 + const timeTestFinished = Date.now(); + const elapsedWaitTime = timeTestFinished - timeAdded; + const remainingWaitTime = + 20000 > elapsedWaitTime ? 20000 - elapsedWaitTime : 0; + + await page.waitForTimeout( remainingWaitTime ); + } + + // No need to run this test for all card types. + test( 'prevents adding another card for 20 seconds after a card is added', async () => { + await goToMyAccount( shopperPage, 'payment-methods' ); + // Take note of the time when we added this card + await addSavedCard( shopperPage, config.cards.basic, 'US', '94110' ); + timeAdded = +Date.now(); + + // Try to add a new card before 20 seconds have passed + await addSavedCard( shopperPage, config.cards.basic2, 'US', '94110' ); + + // Verify that the card was not added + await expect( + shopperPage.getByText( + 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' + ) + ).toBeVisible(); + + await expect( + shopperPage.getByText( 'Payment method successfully added' ) + ).not.toBeVisible(); + + await expect( + shopperPage.getByText( + `${ config.cards.basic2.expires.month }/${ config.cards.basic2.expires.year }` + ) + ).not.toBeVisible(); + + await waitTwentySecondsSinceLastCardAdded( shopperPage ); + // cleanup for the next tests + await goToMyAccount( shopperPage, 'payment-methods' ); + await deleteSavedCard( shopperPage, config.cards.basic ); + } ); + + Object.entries( cards ).forEach( ( [ cardName, card ] ) => { + test.describe( 'Testing card: ' + cardName, () => { + test( `should add the ${ cardName } card as a new payment method`, async () => { + await goToMyAccount( shopperPage, 'payment-methods' ); + await addSavedCard( shopperPage, card, 'US', '94110' ); + // Take note of the time when we added this card + timeAdded = +Date.now(); + + if ( cardName === '3ds' || cardName === '3ds2' ) { + await confirmCardAuthentication( shopperPage ); + } + + await shopperPage.waitForURL( /\/my-account\/payment-methods/, { + waitUntil: 'load', + } ); + + // Verify that the card was added + await expect( + shopperPage.getByText( + 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' + ) + ).not.toBeVisible(); + + await expect( + shopperPage.getByText( 'Payment method successfully added' ) + ).toBeVisible(); + + await expect( + shopperPage.getByText( + `${ card.expires.month }/${ card.expires.year }` + ) + ).toBeVisible(); + + await waitTwentySecondsSinceLastCardAdded( shopperPage ); + } ); + + test( `should be able to purchase with the saved ${ cardName } card`, async () => { + await goToShop( shopperPage ); + await setupProductCheckout( shopperPage ); + await selectSavedCardOnCheckout( shopperPage, card ); + if ( cardName === 'basic' ) { + await placeOrder( shopperPage ); + } else { + await shopperPage + .getByRole( 'button', { name: 'Place order' } ) + .click(); + await confirmCardAuthentication( shopperPage ); + } + + await shopperPage.waitForURL( /\/order-received\//, { + waitUntil: 'load', + } ); + await expect( + shopperPage.getByRole( 'heading', { + name: 'Order received', + } ) + ).toBeVisible(); + } ); + + test( `should be able to set the ${ cardName } card as default payment method`, async () => { + await goToMyAccount( shopperPage, 'payment-methods' ); + await addSavedCard( shopperPage, card2, 'US', '94110' ); + // Take note of the time when we added this card + timeAdded = +Date.now(); + + await expect( + shopperPage.getByText( 'Payment method successfully added' ) + ).toBeVisible(); + await expect( + shopperPage.getByText( + `${ card2.expires.month }/${ card2.expires.year }` + ) + ).toBeVisible(); + await setDefaultPaymentMethod( shopperPage, card2 ); + // Verify that the card was set as default + await expect( + shopperPage.getByText( + 'This payment method was successfully set as your default.' + ) + ).toBeVisible(); + } ); + + test( `should be able to delete ${ cardName } card`, async () => { + await goToMyAccount( shopperPage, 'payment-methods' ); + await deleteSavedCard( shopperPage, card ); + await expect( + shopperPage.getByText( 'Payment method deleted.' ) + ).toBeVisible(); + + await deleteSavedCard( shopperPage, card2 ); + await expect( + shopperPage.getByText( 'Payment method deleted.' ) + ).toBeVisible(); + } ); + + test.afterAll( async () => { + waitTwentySecondsSinceLastCardAdded( shopperPage ); + } ); + } ); + } ); +} ); diff --git a/tests/e2e-pw/specs/shopper/shopper-subscriptions-purchase-free-trial.spec.ts b/tests/e2e-pw/specs/shopper/shopper-subscriptions-purchase-free-trial.spec.ts index 6339ad3a505..fa386aab47f 100644 --- a/tests/e2e-pw/specs/shopper/shopper-subscriptions-purchase-free-trial.spec.ts +++ b/tests/e2e-pw/specs/shopper/shopper-subscriptions-purchase-free-trial.spec.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import test, { expect } from '@playwright/test'; +import test, { Page, expect } from '@playwright/test'; /** * Internal dependencies @@ -20,6 +20,11 @@ import { goToProductPageBySlug, } from '../../utils/shopper-navigation'; import { goToOrder, goToSubscriptions } from '../../utils/merchant-navigation'; +import { + activateMulticurrency, + deactivateMulticurrency, + isMulticurrencyEnabled, +} from '../../utils/merchant'; const nowLocal = new Date(); const nowUTC = new Date( @@ -40,6 +45,25 @@ let orderId: string, subscriptionId: string; describeif( shouldRunSubscriptionsTests )( 'Shopper: Subscriptions - Purchase Free Trial', () => { + let wasMultiCurrencyEnabled = false; + let merchantPage: Page; + + test.beforeAll( async ( { browser } ) => { + merchantPage = ( await getMerchant( browser ) ).merchantPage; + wasMultiCurrencyEnabled = await isMulticurrencyEnabled( + merchantPage + ); + if ( wasMultiCurrencyEnabled ) { + await deactivateMulticurrency( merchantPage ); + } + } ); + + test.afterAll( async () => { + if ( wasMultiCurrencyEnabled ) { + await activateMulticurrency( merchantPage ); + } + } ); + test( 'Merchant should be able to purchase a free trial', async ( { browser, } ) => { @@ -124,10 +148,7 @@ describeif( shouldRunSubscriptionsTests )( .replace( '#', '' ); } ); - test( 'Merchant should be able to create an order with "Setup Intent"', async ( { - browser, - } ) => { - const { merchantPage } = await getMerchant( browser ); + test( 'Merchant should be able to create an order with "Setup Intent"', async () => { await goToOrder( merchantPage, orderId ); await expect( merchantPage.getByText( 'Payment via Credit card /' ) diff --git a/tests/e2e-pw/utils/merchant.ts b/tests/e2e-pw/utils/merchant.ts index 5dd2b866cf7..3ae07e9efe4 100644 --- a/tests/e2e-pw/utils/merchant.ts +++ b/tests/e2e-pw/utils/merchant.ts @@ -275,12 +275,17 @@ export const enablePaymentMethods = async ( paymentMethods: string[] ) => { await navigation.goToWooPaymentsSettings( page ); - + let atLeastOnePaymentMethodEnabled = false; for ( const paymentMethodName of paymentMethods ) { - await page.getByLabel( paymentMethodName ).check(); + if ( ! ( await page.getByLabel( paymentMethodName ).isChecked() ) ) { + await page.getByLabel( paymentMethodName ).check(); + atLeastOnePaymentMethodEnabled = true; + } } - await saveWooPaymentsSettings( page ); + if ( atLeastOnePaymentMethodEnabled ) { + await saveWooPaymentsSettings( page ); + } }; export const disablePaymentMethods = async ( @@ -288,17 +293,21 @@ export const disablePaymentMethods = async ( paymentMethods: string[] ) => { await navigation.goToWooPaymentsSettings( page ); + let atLeastOnePaymentMethodDisabled = false; for ( const paymentMethodName of paymentMethods ) { const checkbox = await page.getByLabel( paymentMethodName ); if ( await checkbox.isChecked() ) { await checkbox.click(); + atLeastOnePaymentMethodDisabled = true; await page.getByRole( 'button', { name: 'Remove' } ).click(); } } - await saveWooPaymentsSettings( page ); + if ( atLeastOnePaymentMethodDisabled ) { + await saveWooPaymentsSettings( page ); + } }; export const ensureOrderIsProcessed = async ( page: Page, orderId: string ) => { diff --git a/tests/e2e-pw/utils/shopper-navigation.ts b/tests/e2e-pw/utils/shopper-navigation.ts index faa8b8f0ea6..db9a607e4c5 100644 --- a/tests/e2e-pw/utils/shopper-navigation.ts +++ b/tests/e2e-pw/utils/shopper-navigation.ts @@ -48,7 +48,11 @@ export const goToOrder = async ( page: Page, orderId: string ) => { } ); }; -export const goToSubscriptions = ( page: Page ) => - page.goto( '/my-account/subscriptions/', { +export const goToMyAccount = async ( page: Page, subPage?: string ) => { + await page.goto( '/my-account/' + ( subPage ?? '' ), { waitUntil: 'load', } ); +}; + +export const goToSubscriptions = async ( page: Page ) => + await goToMyAccount( page, 'subscriptions' ); diff --git a/tests/e2e-pw/utils/shopper.ts b/tests/e2e-pw/utils/shopper.ts index d90ca74682e..bb2b7e6097f 100644 --- a/tests/e2e-pw/utils/shopper.ts +++ b/tests/e2e-pw/utils/shopper.ts @@ -49,7 +49,12 @@ export const fillBillingAddress = async ( .locator( '#billing_address_2' ) .fill( billingAddress.addresssecondline ); await page.locator( '#billing_city' ).fill( billingAddress.city ); - await page.locator( '#billing_state' ).selectOption( billingAddress.state ); + if ( billingAddress.state ) { + // Setting the state is optional, relative to the selected country. E.g Selecting Belgium hides the state input. + await page + .locator( '#billing_state' ) + .selectOption( billingAddress.state ); + } await page.locator( '#billing_postcode' ).fill( billingAddress.postcode ); await page.locator( '#billing_phone' ).fill( billingAddress.phone ); await page.locator( '#billing_email' ).fill( billingAddress.email ); @@ -163,8 +168,9 @@ export const confirmCardAuthentication = async ( name: authorize ? 'Complete' : 'Fail', } ); - // Not ideal, but we need to wait for the loading animation to finish before we can click the button. - await page.waitForTimeout( 1000 ); + await expect( + stripeFrame.locator( '.LightboxModalLoadingIndicator' ) + ).not.toBeVisible(); await button.click(); }; @@ -300,10 +306,17 @@ export const placeOrderWithOptions = async ( options?: { productId?: number; billingAddress?: CustomerAddress; + createAccount?: boolean; } ) => { await addCartProduct( page, options?.productId ); await setupCheckout( page, options?.billingAddress ); + if ( + options?.createAccount && + ( await page.getByLabel( 'Create an account?' ).isVisible() ) + ) { + await page.getByLabel( 'Create an account?' ).check(); + } await selectPaymentMethod( page ); await fillCardDetails( page, config.cards.basic ); await focusPlaceOrderButton( page ); @@ -361,3 +374,84 @@ export const emptyCart = async ( page: Page ) => { 'Your cart is currently empty.' ); }; + +export const changeAccountCurrency = async ( + page: Page, + customerDetails: any, + currency: string +) => { + await navigation.goToMyAccount( page, 'edit-account' ); + await page.getByLabel( 'First name *' ).fill( customerDetails.firstname ); + await page.getByLabel( 'Last name *' ).fill( customerDetails.lastname ); + await page.getByLabel( 'Default currency' ).selectOption( currency ); + await page.getByRole( 'button', { name: 'Save changes' } ).click(); + await expect( + page.getByText( 'Account details changed successfully.' ) + ).toBeVisible(); +}; + +export const addSavedCard = async ( + page: Page, + card: typeof config.cards.basic, + country: string, + zipCode?: string +) => { + await page.getByRole( 'link', { name: 'Add payment method' } ).click(); + await page.waitForLoadState( 'networkidle' ); + await page.getByText( 'Credit card / debit card' ).click(); + const frameHandle = page.getByTitle( 'Secure payment input frame' ); + const stripeFrame = frameHandle.contentFrame(); + + if ( ! stripeFrame ) return; + + await stripeFrame + .getByPlaceholder( '1234 1234 1234 1234' ) + .fill( card.number ); + + await stripeFrame + .getByPlaceholder( 'MM / YY' ) + .fill( card.expires.month + card.expires.year ); + + await stripeFrame.getByPlaceholder( 'CVC' ).fill( card.cvc ); + await stripeFrame + .getByRole( 'combobox', { name: 'country' } ) + .selectOption( country ); + const zip = stripeFrame.getByLabel( 'ZIP Code' ); + if ( zip ) await zip.fill( zipCode ?? '90210' ); + + await page.getByRole( 'button', { name: 'Add payment method' } ).click(); +}; + +export const deleteSavedCard = async ( + page: Page, + card: typeof config.cards.basic +) => { + await page + .getByRole( 'row', { name: card.label } ) + .first() + .getByRole( 'link', { name: 'Delete' } ) + .click(); + await page.waitForTimeout( 1000 ); + await expect( page.getByText( 'Payment method deleted.' ) ).toBeVisible(); +}; + +export const selectSavedCardOnCheckout = async ( + page: Page, + card: typeof config.cards.basic +) => + await page + .getByText( + `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` + ) + .click(); + +export const setDefaultPaymentMethod = async ( + page: Page, + card: typeof config.cards.basic +) => { + await page + .getByRole( 'row', { name: card.label } ) + .first() + .getByRole( 'link', { name: 'Make default' } ) + .click(); +}; diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js deleted file mode 100644 index 491fc145ef6..00000000000 --- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -/** - * Internal dependencies - */ -import { merchantWCP, shopperWCP } from '../../../utils/flows'; -import { - setupProductCheckout, - selectOnCheckout, - completeRedirectedPayment, -} from '../../../utils/payments'; -const { shopper, merchant } = require( '@woocommerce/e2e-utils' ); - -const UPE_METHOD_CHECKBOXES = [ - "//label[contains(text(), 'Bancontact')]/preceding-sibling::span/input[@type='checkbox']", -]; -const card = config.get( 'cards.basic' ); -const card2 = config.get( 'cards.basic2' ); -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; - -const cardTestingPreventionStates = [ - { cardTestingPreventionEnabled: false }, - { cardTestingPreventionEnabled: true }, -]; - -describe.each( cardTestingPreventionStates )( - 'Enabled UPE with deferred intent creation', - ( { cardTestingPreventionEnabled } ) => { - let wasMulticurrencyEnabled; - - beforeAll( async () => { - await merchant.login(); - wasMulticurrencyEnabled = await merchantWCP.activateMulticurrency(); - await merchantWCP.addCurrency( 'EUR' ); - await merchantWCP.enablePaymentMethod( UPE_METHOD_CHECKBOXES ); - if ( cardTestingPreventionEnabled ) { - await merchantWCP.enableCardTestingProtection(); - } - await merchant.logout(); - await shopper.login(); - await shopperWCP.changeAccountCurrencyTo( - config.get( 'addresses.upe-customer.billing.de' ), - 'EUR' - ); - await shopperWCP.emptyCart(); - } ); - - afterAll( async () => { - await shopperWCP.emptyCart(); - await shopperWCP.logout(); - await merchant.login(); - await merchantWCP.disablePaymentMethod( UPE_METHOD_CHECKBOXES ); - if ( cardTestingPreventionEnabled ) { - await merchantWCP.disableCardTestingProtection(); - } - if ( ! wasMulticurrencyEnabled ) { - await merchantWCP.deactivateMulticurrency(); - } - await merchant.logout(); - } ); - - describe( 'Enabled UPE with deferred intent creation', () => { - it( `should successfully place order with Bancontact, carding prevention: ${ cardTestingPreventionEnabled }`, async () => { - await setupProductCheckout( - config.get( 'addresses.upe-customer.billing.be' ) - ); - await page.waitForTimeout( 1000 ); - if ( cardTestingPreventionEnabled ) { - const token = await page.evaluate( () => { - return window.wcpayFraudPreventionToken; - } ); - expect( token ).not.toBeUndefined(); - } - await selectOnCheckout( 'bancontact', page ); - await shopper.placeOrder(); - await completeRedirectedPayment( page, 'success' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - await expect( page ).toMatchTextContent( 'Order received' ); - } ); - } ); - - // No need to run these tests for card testing prevention checks. - if ( ! cardTestingPreventionEnabled ) { - describe( 'My Account', () => { - let timeAdded; - - it( 'should add the card as a new payment method', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic', card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatchTextContent( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatchTextContent( - 'Payment method successfully added' - ); - await expect( page ).toMatchTextContent( - `${ card.expires.month }/${ card.expires.year }` - ); - await waitTwentySecondsSinceLastCardAdded(); - } ); - - it( 'should be able to set payment method as default', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic2', card2 ); - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatchTextContent( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatchTextContent( - 'Payment method successfully added' - ); - await expect( page ).toMatchTextContent( - `${ card2.expires.month }/${ card2.expires.year }` - ); - await shopperWCP.setDefaultPaymentMethod( card2.label ); - // Verify that the card was set as default - await expect( page ).toMatchTextContent( - 'This payment method was successfully set as your default.' - ); - } ); - - it( 'should be able to delete cards', async () => { - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatchTextContent( - 'Payment method deleted.' - ); - - await shopperWCP.deleteSavedPaymentMethod( card2.label ); - await expect( page ).toMatchTextContent( - 'Payment method deleted.' - ); - } ); - - afterAll( async () => { - await waitTwentySecondsSinceLastCardAdded(); - } ); - - async function waitTwentySecondsSinceLastCardAdded() { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - - elapsedWaitTime - : 0; - - await new Promise( ( r ) => - setTimeout( r, remainingWaitTime ) - ); - } - } ); - } - } -); diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-delete-success.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-delete-success.spec.js deleted file mode 100644 index 750232ac3d8..00000000000 --- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-delete-success.spec.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -const { shopper } = require( '@woocommerce/e2e-utils' ); - -/** - * Internal dependencies - */ -import { shopperWCP } from '../../../utils/flows'; - -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; -const cards = Object.entries( config.get( 'cards' ) ); -const validCards = cards.filter( ( [ cardType ] ) => - [ 'basic', '3ds', '3ds2' ].includes( cardType ) -); - -describe( 'Payment Methods', () => { - beforeAll( async () => { - await shopper.login(); - await shopperWCP.goToPaymentMethods(); - } ); - - afterAll( async () => { - await shopperWCP.logout(); - } ); - - describe.each( validCards )( 'when using a %s card', ( cardType, card ) => { - const { label } = card; - const { month, year } = card.expires; - let timeAdded; - - it( 'should add the card as a new payment method', async () => { - await shopperWCP.addNewPaymentMethod( cardType, card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatchTextContent( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatchTextContent( - 'Payment method successfully added' - ); - await expect( page ).toMatchTextContent( label ); - await expect( page ).toMatchTextContent( `${ month }/${ year }` ); - } ); - - it( 'should be able to delete the card', async () => { - await shopperWCP.deleteSavedPaymentMethod( label ); - await expect( page ).toMatchTextContent( - 'Payment method deleted.' - ); - } ); - - afterAll( async () => { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - elapsedWaitTime - : 0; - - await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js deleted file mode 100644 index 9ce09f10616..00000000000 --- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -const { shopper } = require( '@woocommerce/e2e-utils' ); - -/** - * Internal dependencies - */ -import { shopperWCP } from '../../../utils/flows'; -import { - confirmCardAuthentication, - setupProductCheckout, -} from '../../../utils/payments'; - -const cards = [ - [ 'basic', config.get( 'cards.basic' ) ], - [ '3DS2', config.get( 'cards.3ds2' ) ], -]; - -describe( 'Saved cards ', () => { - describe.each( cards )( - 'when using a %s card added through my account', - ( cardType, card ) => { - beforeAll( async () => { - await shopper.login(); - } ); - - afterAll( async () => { - await shopperWCP.logout(); - } ); - - it( 'should save the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( cardType, card ); - await expect( page ).toMatchTextContent( - 'Payment method successfully added' - ); - await expect( page ).toMatchTextContent( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - - if ( cardType === 'basic' ) { - await shopper.placeOrder(); - } else { - await expect( page ).toClick( '#place_order' ); - await confirmCardAuthentication( page ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - } - - await expect( page ).toMatchTextContent( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatchTextContent( - 'Payment method deleted' - ); - } ); - } - ); -} );