diff --git a/plugins/woocommerce/changelog/fix-improve-flaky-e2e-tests b/plugins/woocommerce/changelog/fix-improve-flaky-e2e-tests new file mode 100644 index 00000000000..19bb845475c --- /dev/null +++ b/plugins/woocommerce/changelog/fix-improve-flaky-e2e-tests @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix a couple of flaky e2e tests diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js index 9cfe7a7d075..99f9534d39b 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js @@ -22,6 +22,10 @@ test.describe( 'Cart & Checkout Restricted Coupons', () => { await api.put( 'settings/general/woocommerce_currency', { value: 'USD', } ); + // enable COD + await api.put( 'payment_gateways/cod', { + enabled: true, + } ); // add categories await api .post( 'products/categories', { @@ -154,6 +158,10 @@ test.describe( 'Cart & Checkout Restricted Coupons', () => { force: true, } ); await api.post( 'coupons/batch', { delete: [ ...couponBatchId ] } ); + + await api.put( 'payment_gateways/cod', { + enabled: false, + } ); } ); test( 'expired coupon cannot be used', async ( { page, context } ) => { diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout.spec.js index 160117b24b7..67ca22f5f91 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/checkout.spec.js @@ -298,115 +298,153 @@ test.describe( 'Checkout page', () => { } ); test( 'allows guest customer to place an order', async ( { page } ) => { - await addProductsToCart( page, simpleProductName, '2' ); + await test.step( 'Add 2 products to the cart', async () => { + await addProductsToCart( page, simpleProductName, '2' ); + } ); - await page.goto( '/checkout/' ); - await expect( page.locator( 'strong.product-quantity' ) ).toContainText( - '2' - ); - let totalPrice = await page - .getByRole( 'row', { name: 'Total' } ) - .last() - .locator( 'td' ) - .textContent(); - totalPrice = Number( totalPrice.replace( /\$([\d.]+).*/, '$1' ) ); - await expect( totalPrice ).toBeGreaterThanOrEqual( - Number( twoProductPrice ) - ); + await test.step( 'Go to checkout and confirm that products and totals are as expected', async () => { + await page.goto( '/checkout/' ); + await expect( + page.locator( 'strong.product-quantity' ) + ).toContainText( '2' ); + let totalPrice = await page + .getByRole( 'row', { name: 'Total' } ) + .last() + .locator( 'td' ) + .textContent(); + totalPrice = Number( totalPrice.replace( /\$([\d.]+).*/, '$1' ) ); + await expect( totalPrice ).toBeGreaterThanOrEqual( + Number( twoProductPrice ) + ); // account for taxes or shipping that may be present + } ); - await page.locator( '#billing_first_name' ).fill( 'Lisa' ); - await page.locator( '#billing_last_name' ).fill( 'Simpson' ); - await page - .locator( '#billing_address_1' ) - .fill( '123 Evergreen Terrace' ); - await page.locator( '#billing_city' ).fill( 'Springfield' ); - await page.locator( '#billing_state' ).selectOption( 'OR' ); - await page.locator( '#billing_postcode' ).fill( '97403' ); - await page.locator( '#billing_phone' ).fill( '555 555-5555' ); - await page.locator( '#billing_email' ).fill( guestEmail ); + await test.step( 'Complete the checkout form', async () => { + await page + .getByRole( 'textbox', { name: 'First name *' } ) + .fill( 'Lisa' ); + await page + .getByRole( 'textbox', { name: 'Last name *' } ) + .fill( 'Simpson' ); + await page + .getByRole( 'textbox', { name: 'Street address *' } ) + .fill( '123 Evergreen Terrace' ); + await page + .getByRole( 'textbox', { name: 'Town / City *' } ) + .fill( 'Springfield' ); + await page.locator( '#billing_state' ).selectOption( 'OR' ); + await page + .getByRole( 'textbox', { name: 'ZIP Code *' } ) + .fill( '97403' ); + await page.getByLabel( 'Phone *' ).fill( '555 555-5555' ); + await page.getByLabel( 'Email address *' ).fill( guestEmail ); - await page.locator( 'text=Cash on delivery' ).click(); - await expect( page.locator( 'div.payment_method_cod' ) ).toBeVisible(); + await page.getByText( 'Cash on delivery' ).click(); - await page.locator( 'text=Place order' ).click(); + await page.getByRole( 'button', { name: 'Place order' } ).click(); + } ); - await expect( - page.getByRole( 'heading', { name: 'Order received' } ) - ).toBeVisible(); + await test.step( 'Load the order confirmation page, extract order number', async () => { + await expect( + page.getByRole( 'heading', { name: 'Order received' } ) + ).toBeVisible(); - // get order ID from the page - const orderReceivedText = await page - .locator( '.woocommerce-order-overview__order.order' ) - .textContent(); - guestOrderId = await orderReceivedText.split( /(\s+)/ )[ 6 ].toString(); + // get order ID from the page + const orderReceivedText = await page + .locator( '.woocommerce-order-overview__order.order' ) + .textContent(); + guestOrderId = await orderReceivedText + .split( /(\s+)/ )[ 6 ] + .toString(); + } ); - // Let's simulate a new browser context (by dropping all cookies), and reload the page. This approximates a - // scenario where the server can no longer identify the shopper. However, so long as we are within the 10 minute - // grace period following initial order placement, the 'order received' page should still be rendered. - await page.context().clearCookies(); - await page.reload(); - await expect( - page.getByRole( 'heading', { name: 'Order received' } ) - ).toBeVisible(); + await test.step( 'Simulate cookies cleared, but within 10 minute grace period', async () => { + // Let's simulate a new browser context (by dropping all cookies), and reload the page. This approximates a + // scenario where the server can no longer identify the shopper. However, so long as we are within the 10 minute + // grace period following initial order placement, the 'order received' page should still be rendered. + await page.context().clearCookies(); + await page.reload(); + await expect( + page.getByRole( 'heading', { name: 'Order received' } ) + ).toBeVisible(); + } ); - // Let's simulate a scenario where the 10 minute grace period has expired. This time, we expect the shopper to - // be presented with a request to verify their email address. - await setFilterValue( - page, - 'woocommerce_order_email_verification_grace_period', - 0 - ); - await page.reload(); - await expect( - page.locator( 'form.woocommerce-verify-email p:nth-child(3)' ) - ).toContainText( /verify the email address associated with the order/ ); + await test.step( 'Simulate cookies cleared, outside 10 minute window', async () => { + // Let's simulate a scenario where the 10 minute grace period has expired. This time, we expect the shopper to + // be presented with a request to verify their email address. + await setFilterValue( + page, + 'woocommerce_order_email_verification_grace_period', + 0 + ); + await page.waitForTimeout( 2000 ); // needs some time before reload for change to take effect. + await page.reload( { waitForLoadState: 'networkidle' } ); + await expect( + page.getByRole( 'button', { name: 'Verify' } ) + ).toBeVisible(); + await expect( page.getByLabel( 'Email address *' ) ).toBeVisible(); + await expect( + page.locator( 'form.woocommerce-verify-email p:nth-child(3)' ) + ).toContainText( + /verify the email address associated with the order/ + ); + } ); - // Supplying an email address other than the actual order billing email address will take them back to the same - // page with an error message. - await page.fill( '#email', 'incorrect@email.address' ); - await page.locator( 'form.woocommerce-verify-email button' ).click(); - await expect( - page.locator( 'form.woocommerce-verify-email p:nth-child(4)' ) - ).toContainText( /verify the email address associated with the order/ ); - await expect( page.locator( '.is-error' ) ).toContainText( - /We were unable to verify the email address you provided/ - ); + await test.step( 'Supply incorrect email address for the order, error', async () => { + // Supplying an email address other than the actual order billing email address will take them back to the same + // page with an error message. + await page + .getByLabel( 'Email address *' ) + .fill( 'incorrect@email.address' ); + await page.getByRole( 'button', { name: 'Verify' } ).click(); + await expect( + page.locator( 'form.woocommerce-verify-email p:nth-child(4)' ) + ).toContainText( + /verify the email address associated with the order/ + ); + await expect( page.getByRole( 'alert' ) ).toContainText( + /We were unable to verify the email address you provided/ + ); + } ); - // However if they supply the *correct* billing email address, they should see the order received page again. - await page.fill( '#email', guestEmail ); - await page.locator( 'form.woocommerce-verify-email button' ).click(); - await expect( - page.getByRole( 'heading', { name: 'Order received' } ) - ).toBeVisible(); + await test.step( 'Supply the correct email address for the order, display order confirmation', async () => { + // However if they supply the *correct* billing email address, they should see the order received page again. + await page.getByLabel( 'Email address *' ).fill( guestEmail ); + await page.getByRole( 'button', { name: 'Verify' } ).click(); + await expect( + page.getByRole( 'heading', { name: 'Order received' } ) + ).toBeVisible(); + } ); - await page.goto( 'wp-login.php' ); - await page.locator( 'input[name="log"]' ).fill( admin.username ); - await page.locator( 'input[name="pwd"]' ).fill( admin.password ); - await page.locator( 'text=Log In' ).click(); + await test.step( 'Confirm order details on the backend (as a merchant)', async () => { + await page.goto( 'wp-login.php' ); + await page.locator( 'input[name="log"]' ).fill( admin.username ); + await page.locator( 'input[name="pwd"]' ).fill( admin.password ); + await page.locator( 'text=Log In' ).click(); - // load the order placed as a guest - await page.goto( - `wp-admin/post.php?post=${ guestOrderId }&action=edit` - ); + // load the order placed as a guest + await page.goto( + `wp-admin/post.php?post=${ guestOrderId }&action=edit` + ); - await expect( - page.getByRole( 'heading', { - name: `Order #${ guestOrderId } details`, - } ) - ).toBeVisible(); - await expect( page.locator( '.wc-order-item-name' ) ).toContainText( - simpleProductName - ); - await expect( page.locator( 'td.quantity >> nth=0' ) ).toContainText( - '2' - ); - await expect( page.locator( 'td.item_cost >> nth=0' ) ).toContainText( - singleProductPrice - ); - await expect( page.locator( 'td.line_cost >> nth=0' ) ).toContainText( - twoProductPrice - ); - await clearFilters( page ); + await expect( + page.getByRole( 'heading', { + name: `Order #${ guestOrderId } details`, + } ) + ).toBeVisible(); + await expect( page.locator( '.wc-order-item-name' ) ).toContainText( + simpleProductName + ); + await expect( + page.locator( 'td.quantity >> nth=0' ) + ).toContainText( '2' ); + await expect( + page.locator( 'td.item_cost >> nth=0' ) + ).toContainText( singleProductPrice ); + await expect( + page.locator( 'td.line_cost >> nth=0' ) + ).toContainText( twoProductPrice ); + await clearFilters( page ); + } ); } ); test( 'allows existing customer to place order', async ( { page } ) => {