From 711733a2d488f6d4a1d18633fbff33cd52ae000b Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Tue, 30 Jan 2024 10:57:12 +0530 Subject: [PATCH] Add initial cash app pay E2E tests. --- tests/e2e/specs/d1.cash-app-pay.spec.js | 340 ++++++++++++++++++++++++ tests/e2e/utils/helper.js | 128 +++++++++ 2 files changed, 468 insertions(+) create mode 100644 tests/e2e/specs/d1.cash-app-pay.spec.js diff --git a/tests/e2e/specs/d1.cash-app-pay.spec.js b/tests/e2e/specs/d1.cash-app-pay.spec.js new file mode 100644 index 00000000..b65a4e7c --- /dev/null +++ b/tests/e2e/specs/d1.cash-app-pay.spec.js @@ -0,0 +1,340 @@ +import { test, expect, devices, chromium } from '@playwright/test'; +import { + createProduct, + doSquareRefund, + doesProductExist, + fillAddressFields, + gotoOrderEditPage, + placeCashAppPayOrder, + saveCashAppPaySettings, + selectPaymentMethod, + visitCheckout, + waitForUnBlock, +} from '../utils/helper'; +const iPhone = devices['iPhone 14 Pro Max']; + +test.describe('Cash App Pay Tests', () => { + test.beforeAll('Setup', async ({ baseURL }) => { + const browser = await chromium.launch(); + const page = await browser.newPage(); + + // Create a product if it doesn't exist. + if (!(await doesProductExist(baseURL, 'simple-product'))) { + await createProduct(page, { + name: 'Simple Product', + regularPrice: '14.99', + sku: 'simple-product', + }); + + await expect( + await page.getByText('Product published') + ).toBeVisible(); + } + await browser.close(); + }); + + test('Store owner can see Cash App Pay in payment methods list - @foundational', async ({ + page, + }) => { + await page.goto('/wp-admin/admin.php?page=wc-settings&tab=checkout'); + const creditCard = await page.locator( + 'table.wc_gateways tr[data-gateway_id="square_cash_app_pay"]' + ); + await expect(creditCard).toBeVisible(); + await expect(creditCard.locator('td.name a')).toContainText( + 'Cash App Pay (Square)' + ); + }); + + test('Store owner can configure Cash App Pay payment gateway - @foundational', async ({ + page, + }) => { + await saveCashAppPaySettings(page, { + enabled: false, + }); + + await page.goto('/product/simple-product'); + await page.locator('.single_add_to_cart_button').click(); + + // Confirm that the Cash App Pay is not visible on checkout page. + await visitCheckout(page, false); + await fillAddressFields(page, false); + await expect( + await page.locator( + 'ul.wc_payment_methods li.payment_method_square_cash_app_pay' + ) + ).not.toBeVisible(); + // Confirm that the Cash App Pay is not visible on block-checkout page. + await visitCheckout(page, true); + await expect( + await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ) + ).not.toBeVisible(); + + const cashAppTitle = 'Cash App Pay TEST'; + const cashAppDescription = 'Cash App Pay TEST Description'; + await saveCashAppPaySettings(page, { + enabled: true, + title: cashAppTitle, + description: cashAppDescription, + }); + + // Confirm that the Cash App Pay is visible on checkout page. + await visitCheckout(page, false); + const paymentMethod = await page.locator( + 'ul.wc_payment_methods li.payment_method_square_cash_app_pay' + ); + await expect(paymentMethod).toBeVisible(); + await selectPaymentMethod(page, 'square_cash_app_pay', false); + await expect(paymentMethod.locator('label').first()).toContainText( + cashAppTitle + ); + await expect( + paymentMethod + .locator('.payment_method_square_cash_app_pay p', { + hasText: cashAppDescription, + }) + .first() + ).toBeVisible(); + + // Confirm that the Cash App Pay is visible on block-checkout page. + await visitCheckout(page, true); + const cashAppMethod = await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ); + await expect(cashAppMethod).toBeVisible(); + await expect(cashAppMethod).toContainText(cashAppTitle); + await selectPaymentMethod(page, 'square_cash_app_pay', true); + await expect( + page + .locator( + '.wc-block-components-radio-control-accordion-content p', + { + hasText: cashAppDescription, + } + ) + .first() + ).toBeVisible(); + }); + + test('Store owner can configure Cash App Pay Button Appearance - @foundational', async ({ + page, + }) => { + await saveCashAppPaySettings(page, { + enabled: true, + buttonTheme: 'light', + buttonShape: 'round', + }); + + // Confirm button styles on checkout page. + await visitCheckout(page, false); + const paymentMethod = await page.locator( + 'ul.wc_payment_methods li.payment_method_square_cash_app_pay' + ); + await expect(paymentMethod).toBeVisible(); + await selectPaymentMethod(page, 'square_cash_app_pay', false); + const cashAppPayButton = await page + .locator('#wc-square-cash-app') + .getByTestId('cap-btn'); + await expect(cashAppPayButton).toBeVisible(); + await expect(cashAppPayButton).toHaveClass(/rounded-3xl/); + await expect(cashAppPayButton).toHaveClass(/bg-white/); + + // Confirm button styles on block-checkout page. + await visitCheckout(page, true); + const cashAppMethod = await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ); + await expect(cashAppMethod).toBeVisible(); + await selectPaymentMethod(page, 'square_cash_app_pay', true); + const cashAppButton = await page + .locator('#wc-square-cash-app-pay') + .getByTestId('cap-btn'); + await expect(cashAppButton).toBeVisible(); + await expect(cashAppButton).toHaveClass(/rounded-3xl/); + await expect(cashAppButton).toHaveClass(/bg-white/); + + await saveCashAppPaySettings(page, { + enabled: true, + buttonTheme: 'dark', + buttonShape: 'semiround', + }); + + // Confirm button styles on checkout page. + await visitCheckout(page, false); + const payMethod = await page.locator( + 'ul.wc_payment_methods li.payment_method_square_cash_app_pay' + ); + await expect(payMethod).toBeVisible(); + await selectPaymentMethod(page, 'square_cash_app_pay', false); + const button = await page + .locator('#wc-square-cash-app') + .getByTestId('cap-btn'); + await expect(button).toBeVisible(); + await expect(button).toHaveClass(/rounded-md/); + await expect(button).toHaveClass(/bg-black/); + + // Confirm button styles on block-checkout page. + await visitCheckout(page, true); + const blockPayMethod = await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ); + await expect(blockPayMethod).toBeVisible(); + await selectPaymentMethod(page, 'square_cash_app_pay', true); + const buttonBlock = await page + .locator('#wc-square-cash-app-pay') + .getByTestId('cap-btn'); + await expect(buttonBlock).toBeVisible(); + await expect(buttonBlock).toHaveClass(/rounded-md/); + await expect(buttonBlock).toHaveClass(/bg-black/); + }); + + test('Cash App Pay should be only available for US based sellers - @foundational', async ({ + page, + }) => { + await page.goto('/wp-admin/admin.php?page=wc-settings&tab=general'); + await page + .locator('select[name="woocommerce_default_country"]') + .selectOption('IN:GJ'); + await page.locator('.woocommerce-save-button').click(); + + await expect( + page + .locator('.notice.notice-error p', { + hasText: /Cash App Pay/, + }) + .first() + ).toContainText( + 'Your base country is IN, but Cash App Pay can’t accept transactions from merchants outside of US.' + ); + + // Confirm that the Cash App Pay is not visible on block-checkout page. + await visitCheckout(page, true); + await expect( + await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ) + ).not.toBeVisible(); + + await page.goto('/wp-admin/admin.php?page=wc-settings&tab=general'); + await page + .locator('select[name="woocommerce_default_country"]') + .selectOption('US:CA'); + await page.locator('.woocommerce-save-button').click(); + }); + + test('Cash App Pay should be only available for US based buyers - @foundational', async ({ + page, + }) => { + // Confirm that the Cash App Pay is not visible on checkout page. + await visitCheckout(page, false); + await fillAddressFields(page, false); + + // non-US buyer. + await page.locator('#billing_country').selectOption('IN'); + await page.locator('#billing_country').blur(); + await waitForUnBlock(page); + const payMethod = await page.locator( + 'ul.wc_payment_methods li.payment_method_square_cash_app_pay' + ); + await expect(payMethod).not.toBeVisible(); + + // US based buyer. + await fillAddressFields(page, false); + await expect(payMethod).toBeVisible(); + + // Confirm that the Cash App Pay is not visible on block-checkout page. + await visitCheckout(page, true); + await fillAddressFields(page, true); + await page.locator('#billing-country').locator('input').fill('India'); + await page.waitForTimeout(1500); + const blockPayMethod = await page.locator( + 'label[for="radio-control-wc-payment-method-options-square_cash_app_pay"]' + ); + await expect(blockPayMethod).not.toBeVisible(); + + // US based buyer. + await fillAddressFields(page, true); + await expect(blockPayMethod).toBeVisible(); + }); + + const isBlockCheckout = [true, false]; + + for (const isBlock of isBlockCheckout) { + const title = isBlock ? '[Block]:' : '[non-Block]:'; + + test( + title + 'Customers can pay using Cash App Pay - @foundational', + async ({ browser }) => { + const context = await browser.newContext({ + ...iPhone, + }); + const page = await context.newPage(); + await page.goto('/product/simple-product'); + await page.locator('.single_add_to_cart_button').click(); + await visitCheckout(page, isBlock); + await fillAddressFields(page, isBlock); + await selectPaymentMethod(page, 'square_cash_app_pay', isBlock); + const orderId = await placeCashAppPayOrder(page, isBlock); + + await gotoOrderEditPage(page, orderId); + await expect(page.locator('#order_status')).toHaveValue( + 'wc-processing' + ); + await expect( + page.getByText( + 'Cash App Pay (Square) Test Charge Approved for an amount of' + ) + ).toBeVisible(); + } + ); + } + + test('Store owners can fully refund Cash App Pay orders - @foundational', async ({ + browser, + }) => { + const isBlock = true; + const context = await browser.newContext({ + ...iPhone, + }); + const page = await context.newPage(); + await page.goto('/product/simple-product'); + page.on('dialog', dialog => dialog.accept()); + await page.locator('.single_add_to_cart_button').click(); + await visitCheckout(page, isBlock); + await fillAddressFields(page, isBlock); + await selectPaymentMethod(page, 'square_cash_app_pay', isBlock); + const orderId = await placeCashAppPayOrder(page, isBlock); + await gotoOrderEditPage(page, orderId); + await doSquareRefund( page, '14.99' ); + await expect( page.locator( '#order_status' ) ).toHaveValue( 'wc-refunded' ); + await expect( await page.getByText( 'Cash App Pay (Square) Refund in the amount of $14.99 approved' ) ).toBeVisible(); + await expect( await page.getByText( 'Cash App Pay (Square) Order completely refunded.' ) ).toBeVisible(); + }); + + test('Store owners can partially refund Cash App Pay orders - @foundational', async ({ + browser, + }) => { + const isBlock = true; + const context = await browser.newContext({ + ...iPhone, + }); + const page = await context.newPage(); + await page.goto('/product/simple-product'); + page.on('dialog', dialog => dialog.accept()); + await page.locator('.single_add_to_cart_button').click(); + await visitCheckout(page, isBlock); + await fillAddressFields(page, isBlock); + await selectPaymentMethod(page, 'square_cash_app_pay', isBlock); + const orderId = await placeCashAppPayOrder(page, isBlock); + await gotoOrderEditPage(page, orderId); + await doSquareRefund( page, '1' ); + await expect( await page.getByText( 'Cash App Pay (Square) Refund in the amount of $1.00 approved' ) ).toBeVisible(); + await expect( page.locator( '#order_status' ) ).toHaveValue( 'wc-processing' ); + + await doSquareRefund( page, '13.99' ); + await expect( page.locator( '#order_status' ) ).toHaveValue( 'wc-refunded' ); + await expect( await page.getByText( 'Cash App Pay (Square) Order completely refunded.' ) ).toBeVisible(); + }); +}); diff --git a/tests/e2e/utils/helper.js b/tests/e2e/utils/helper.js index 2a746080..40d185b0 100644 --- a/tests/e2e/utils/helper.js +++ b/tests/e2e/utils/helper.js @@ -331,3 +331,131 @@ export async function deleteAllProducts( page, permanent = true ) { await page.locator( '#delete_all' ).first().click(); } } + + +/** + * Save Cash App Pay payment settings + * + * @param {Page} page Playwright page object + * @param {Object} options Cash App Pay payment settings + */ +export async function saveCashAppPaySettings(page, options) { + const settings = { + enabled: true, + title: 'Cash App Pay', + description: 'Pay securely using Cash App Pay.', + debugMode: 'off', + buttonTheme: 'dark', + buttonShape: 'semiround', + ...options, + }; + + await page.goto( + '/wp-admin/admin.php?page=wc-settings&tab=checkout§ion=square_cash_app_pay' + ); + + // Enable/Disable + if (!settings.enabled) { + await page.locator('#woocommerce_square_cash_app_pay_enabled').uncheck(); + } else { + await page.locator('#woocommerce_square_cash_app_pay_enabled').check(); + } + + // Title and Description + await page + .locator('#woocommerce_square_cash_app_pay_title') + .fill(settings.title); + await page + .locator('#woocommerce_square_cash_app_pay_description') + .fill(settings.description); + + // Debug Mode and Environment + await page + .locator('#woocommerce_square_cash_app_pay_debug_mode') + .selectOption(settings.debugMode); + + // Button customization + await page + .locator('#woocommerce_square_cash_app_pay_button_theme') + .selectOption(settings.buttonTheme); + await page + .locator('#woocommerce_square_cash_app_pay_button_shape') + .selectOption(settings.buttonShape); + + await page.getByRole('button', { name: 'Save changes' }).click(); + await expect(page.locator('#message.updated.inline').last()).toContainText( + 'Your settings have been saved.' + ); +} + +/** + * Select payment method + * + * @param {Page} page Playwright page object + * @param {string} paymentMethod Payment method name + * @param {boolean} isBlockCheckout Is block checkout? + */ +export async function selectPaymentMethod( + page, + paymentMethod, + isBlockCheckout +) { + if (isBlockCheckout) { + await page + .locator( + `label[for="radio-control-wc-payment-method-options-${paymentMethod}"]` + ) + .click(); + await expect( + page.locator('.wc-block-components-loading-mask') + ).not.toBeVisible(); + return; + } + // Wait for overlay to disappear + await page + .locator('.blockUI.blockOverlay') + .last() + .waitFor({ state: 'detached' }); + + // Wait for payment method to appear + const payMethod = await page + .locator( + `ul.wc_payment_methods li.payment_method_${paymentMethod} label` + ) + .first(); + await expect(payMethod).toBeVisible(); + + // Select payment method + await page + .locator(`label[for="payment_method_${paymentMethod}"]`) + .waitFor(); + await payMethod.click(); +} + +/** + * Pay using Cash App Pay + * + * @param {Object} page Playwright page object. + * @param {Boolean} isBlock Indicates if is block checkout. + */ +export async function placeCashAppPayOrder( page, isBlock = true ) { + // Wait for overlay to disappear + await waitForUnBlock(page); + if ( isBlock ) { + await page.locator('#wc-square-cash-app-pay').getByTestId('cap-btn').click(); + } else { + await page.locator('#wc-square-cash-app').getByTestId('cap-btn').click(); + } + await page.waitForLoadState('networkidle'); + await page.getByRole('button', { name: 'Approve' }).click(); + await page.waitForLoadState('networkidle'); + await page.getByRole('button', { name: 'Done' }).click(); + await page.waitForLoadState('networkidle'); + await expect( + await page.locator( '.entry-title' ) + ).toHaveText( 'Order received' ); + const orderId = await page + .locator( '.woocommerce-order-overview__order strong' ) + .innerText(); + return orderId; +}