diff --git a/tests/e2e-jest/specs/merchant/checkout-terms.test.js b/tests/e2e-jest/specs/merchant/checkout-terms.test.js deleted file mode 100644 index 0b92e0828ec..00000000000 --- a/tests/e2e-jest/specs/merchant/checkout-terms.test.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * External dependencies - */ -import { merchant, setCheckbox, unsetCheckbox } from '@woocommerce/e2e-utils'; -import { - visitBlockPage, - selectBlockByName, - saveOrPublish, -} from '@woocommerce/blocks-test-utils'; - -/** - * Internal dependencies - */ -import { openSettingsSidebar } from '../../utils'; -import { - shopper, - preventCompatibilityNotice, - reactivateCompatibilityNotice, -} from '../../../utils'; -import { - BASE_URL, - BILLING_DETAILS, - SIMPLE_VIRTUAL_PRODUCT_NAME, -} from '../../../utils/constants'; - -if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { - // eslint-disable-next-line jest/no-focused-tests, jest/expect-expect - test.only( `Skipping checkout tests`, () => {} ); -} - -describe( 'Merchant → Checkout → Can adjust T&S and Privacy Policy options', () => { - beforeAll( async () => { - await shopper.goToShop(); - await page.goto( `${ BASE_URL }/?setup_terms_and_privacy` ); - // eslint-disable-next-line jest/no-standalone-expect - await expect( page ).toMatch( 'Terms & Privacy pages set up.' ); - await shopper.block.emptyCart(); - } ); - - afterAll( async () => { - await shopper.block.emptyCart(); - await page.goto( `${ BASE_URL }/?teardown_terms_and_privacy` ); - // eslint-disable-next-line jest/no-standalone-expect - await expect( page ).toMatch( 'Terms & Privacy pages teared down.' ); - } ); - - it( 'Merchant can see T&S and Privacy Policy links without checkbox', async () => { - await shopper.goToShop(); - await shopper.addToCartFromShopPage( SIMPLE_VIRTUAL_PRODUCT_NAME ); - await shopper.block.goToCheckout(); - await expect( page ).toMatch( - 'By proceeding with your purchase you agree to our Terms and Conditions and Privacy Policy' - ); - await shopper.block.fillInCheckoutWithTestData(); - await shopper.block.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'Merchant can see T&S and Privacy Policy links with checkbox', async () => { - // Activate checkboxes for T&S and Privacy Policy links. - await preventCompatibilityNotice(); - await merchant.login(); - await visitBlockPage( 'Checkout Block' ); - await openSettingsSidebar(); - await selectBlockByName( 'woocommerce/checkout-terms-block' ); - const [ termsCheckboxLabel ] = await page.$x( - `//label[contains(text(), "Require checkbox") and contains(@class, "components-toggle-control__label")]` - ); - const termsCheckboxId = await page.evaluate( - ( label ) => `#${ label.getAttribute( 'for' ) }`, - termsCheckboxLabel - ); - await setCheckbox( termsCheckboxId ); - await saveOrPublish(); - await shopper.goToShop(); - await shopper.addToCartFromShopPage( SIMPLE_VIRTUAL_PRODUCT_NAME ); - await shopper.block.goToCheckout(); - await shopper.block.fillBillingDetails( BILLING_DETAILS ); - - // Wait for the "Place Order" button to avoid flakey tests. - await page.waitForSelector( - '.wc-block-components-checkout-place-order-button:not([disabled])' - ); - - // Placing an order now, must lead to an error. - await page.click( '.wc-block-components-checkout-place-order-button' ); - - const termsCheckbox = await page.$( - '.wp-block-woocommerce-checkout-terms-block div' - ); - const termsCheckboxClassList = ( - await ( await termsCheckbox.getProperty( 'className' ) ).jsonValue() - ).split( ' ' ); - expect( termsCheckboxClassList ).toContain( 'has-error' ); - await setCheckbox( '#terms-and-conditions' ); - - // Placing an order now, must succeed. - await shopper.block.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // Deactivate checkboxes for T&S and Privacy Policy links. - await visitBlockPage( 'Checkout Block' ); - await openSettingsSidebar(); - await selectBlockByName( 'woocommerce/checkout-terms-block' ); - await unsetCheckbox( termsCheckboxId ); - await saveOrPublish(); - await merchant.logout(); - await reactivateCompatibilityNotice(); - } ); -} ); diff --git a/tests/e2e/tests/checkout/checkout-block.merchant.block_theme.spec.ts b/tests/e2e/tests/checkout/checkout-block.merchant.block_theme.spec.ts index 15e36c50865..1b63b3d728a 100644 --- a/tests/e2e/tests/checkout/checkout-block.merchant.block_theme.spec.ts +++ b/tests/e2e/tests/checkout/checkout-block.merchant.block_theme.spec.ts @@ -2,8 +2,20 @@ * External dependencies */ import { BlockData } from '@woocommerce/e2e-types'; -import { test, expect } from '@woocommerce/e2e-playwright-utils'; +import { test as base, expect } from '@woocommerce/e2e-playwright-utils'; +/** + * Internal dependencies + */ +import { CheckoutPage } from './checkout.page'; +import { REGULAR_PRICED_PRODUCT_NAME } from './constants'; + +declare global { + interface Window { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + wcSettings: { storePages: any }; + } +} const blockData: BlockData = { name: 'Checkout', slug: 'woocommerce/checkout', @@ -16,11 +28,157 @@ const blockData: BlockData = { frontend: {}, }, }; - +const test = base.extend< { checkoutPageObject: CheckoutPage } >( { + checkoutPageObject: async ( { page }, use ) => { + const pageObject = new CheckoutPage( { + page, + } ); + await use( pageObject ); + }, +} ); test.describe( 'Merchant → Checkout', () => { // `as string` is safe here because we know the variable is a string, it is defined above. const blockSelectorInEditor = blockData.selectors.editor.block as string; + test.describe( 'Can adjust T&S and Privacy Policy options', () => { + test.beforeAll( async ( { browser } ) => { + const page = await browser.newPage(); + await page.goto( + `${ process.env.WORDPRESS_BASE_URL }/?setup_terms_and_privacy` + ); + await expect( + page.getByText( 'Terms & Privacy pages set up.' ) + ).toBeVisible(); + await page.close(); + } ); + + test.afterAll( async ( { browser } ) => { + const page = await browser.newPage(); + await page.goto( + `${ process.env.WORDPRESS_BASE_URL }/?teardown_terms_and_privacy` + ); + await expect( + page.getByText( 'Terms & Privacy pages teared down.' ) + ).toBeVisible(); + await page.close(); + } ); + + test( 'Merchant can see T&S and Privacy Policy links without checkbox', async ( { + frontendUtils, + checkoutPageObject, + } ) => { + await frontendUtils.goToShop(); + await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME ); + await frontendUtils.goToCheckout(); + await expect( + frontendUtils.page.getByText( + 'By proceeding with your purchase you agree to our Terms and Conditions and Privacy Policy' + ) + ).toBeVisible(); + + const termsAndConditions = frontendUtils.page + .getByRole( 'link' ) + .getByText( 'Terms and Conditions' ) + .first(); + const privacyPolicy = frontendUtils.page + .getByRole( 'link' ) + .getByText( 'Privacy Policy' ) + .first(); + + const { termsPageUrl, privacyPageUrl } = + await frontendUtils.page.evaluate( () => { + return { + termsPageUrl: + window.wcSettings.storePages.terms.permalink, + privacyPageUrl: + window.wcSettings.storePages.privacy.permalink, + }; + } ); + await expect( termsAndConditions ).toHaveAttribute( + 'href', + termsPageUrl + ); + await expect( privacyPolicy ).toHaveAttribute( + 'href', + privacyPageUrl + ); + await checkoutPageObject.fillInCheckoutWithTestData(); + await checkoutPageObject.placeOrder(); + await expect( + frontendUtils.page.getByText( + 'Thank you. Your order has been received.' + ) + ).toBeVisible(); + } ); + test( 'Merchant can see T&S and Privacy Policy links with checkbox', async ( { + frontendUtils, + checkoutPageObject, + editorUtils, + admin, + editor, + } ) => { + await admin.visitSiteEditor( { + postId: 'woocommerce/woocommerce//page-checkout', + postType: 'wp_template', + } ); + await editorUtils.enterEditMode(); + await editor.openDocumentSettingsSidebar(); + await editor.selectBlocks( + blockSelectorInEditor + + ' [data-type="woocommerce/checkout-terms-block"]' + ); + let requireTermsCheckbox = editor.page.getByRole( 'checkbox', { + name: 'Require checkbox', + exact: true, + } ); + await requireTermsCheckbox.check(); + await editor.saveSiteEditorEntities(); + await frontendUtils.goToShop(); + await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME ); + await frontendUtils.goToCheckout(); + await checkoutPageObject.fillInCheckoutWithTestData(); + await checkoutPageObject.placeOrder( false ); + + const checkboxWithError = frontendUtils.page.getByLabel( + 'You must accept our Terms and Conditions and Privacy Policy to continue with your purchase.' + ); + await expect( checkboxWithError ).toHaveAttribute( + 'aria-invalid', + 'true' + ); + + await frontendUtils.page + .getByLabel( + 'You must accept our Terms and Conditions and Privacy Policy to continue with your purchase.' + ) + .check(); + + await checkoutPageObject.placeOrder(); + await expect( + frontendUtils.page.getByText( + 'Thank you. Your order has been received' + ) + ).toBeVisible(); + + await admin.visitSiteEditor( { + postId: 'woocommerce/woocommerce//page-checkout', + postType: 'wp_template', + } ); + await editorUtils.enterEditMode(); + await editor.openDocumentSettingsSidebar(); + await editor.selectBlocks( + blockSelectorInEditor + + ' [data-type="woocommerce/checkout-terms-block"]' + ); + requireTermsCheckbox = editor.page.getByRole( 'checkbox', { + name: 'Require checkbox', + exact: true, + } ); + await requireTermsCheckbox.uncheck(); + await editor.saveSiteEditorEntities(); + } ); + } ); + test.describe( 'in page editor', () => { test.beforeEach( async ( { editorUtils, admin, editor } ) => { await admin.visitSiteEditor( { diff --git a/tests/e2e/tests/checkout/checkout.page.ts b/tests/e2e/tests/checkout/checkout.page.ts index ba9a0ca545e..e58e26675f0 100644 --- a/tests/e2e/tests/checkout/checkout.page.ts +++ b/tests/e2e/tests/checkout/checkout.page.ts @@ -78,9 +78,17 @@ export class CheckoutPage { await this.page.evaluate( 'document.activeElement.blur()' ); } - async placeOrder() { + /** + * Place order and wait for redirect to order received page. + * + * @param waitForRedirect If false, then the method will not wait for the redirect to order received page. Useful + * when testing for errors on the checkout page. + */ + async placeOrder( waitForRedirect = true ) { await this.page.getByText( 'Place Order', { exact: true } ).click(); - await this.page.waitForURL( /order-received/ ); + if ( waitForRedirect ) { + await this.page.waitForURL( /order-received/ ); + } } async verifyAddressDetails(