Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Playwright E2E tests: Multiple signed in roles (#10561)
Browse files Browse the repository at this point in the history
* Convert checkout place order E2E tests to Playwright

* Add "gotoMyAccount" method

* Create login/logout utility functions

* Use the existing "customer" test data

* Complete the place order test cases

* Fix "My Account" page title

* Fix rebase

* Reset My account page title

* Check for heading instead of the page title

* Check for heading in login/logout functions

* Fix all failing tests

* Add guest/customer/admin roles

* Update the auth setup

* Register the auth setup within Playwright

* Update testing cases

* Add generated auth files to .gitignore

* Tidy up comments

Co-authored-by: Thomas Roberts <[email protected]>

* Remove unnecessary comment

Co-authored-by: Thomas Roberts <[email protected]>

* Update comments

Co-authored-by: Thomas Roberts <[email protected]>

* Remove unnecessary comment

Co-authored-by: Thomas Roberts <[email protected]>

* Update comment for Guest case

Co-authored-by: Thomas Roberts <[email protected]>

* Remove confusing comment

* Remove another unnecessary comment

* Remove unnecessary Playwright project dependency

* Tidy up the file structure and constants

* Fix mixed up test descriptions

* Remove commented code

Co-authored-by: Thomas Roberts <[email protected]>

* Remove unnecessary function from frontend-utils

* Refactor testing cases

* Rename testing file

* Delete unused testing file

* Ensure we're logged out before trying to log in as a user

* Log out before each authentication setup step

* Ensure tests requiring admin are logged in

* Log in as admin during block theme setup

* Fix Playwright strict mode violation

* Run Multiple sign-in roles to the global-setup phase

In this step of the Playwright's setup, we can add the multiple sign-in
roles and keeping the admin logged by default.
This fixes the issue of failing tests `logged out` error.

* Remove unnecessary login as admin

* Remove "auth.setup" dependency since the logic lives in the global setup instead

* Remove unnecessary login as admin from test files

The admin profile is set by default

---------

Co-authored-by: Thomas Roberts <[email protected]>
Co-authored-by: Thomas Roberts <[email protected]>
  • Loading branch information
3 people authored Dec 8, 2023
1 parent cddc17c commit d976360
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ tests/cli/vendor
**/e2e/artifacts/
/artifacts/
/playwright-report/
**/e2e/.auth

# Logs
/logs
Expand Down
25 changes: 0 additions & 25 deletions tests/e2e-jest/specs/shopper/cart-checkout/checkout.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,31 +333,6 @@ describe( 'Shopper → Checkout', () => {
} );
} );

describe( 'Place Order', () => {
it( 'Guest user can place order', async () => {
if ( await shopper.isLoggedIn() ) {
await shopper.logout();
}
await shopper.block.goToShop();
await shopper.addToCartFromShopPage( SIMPLE_VIRTUAL_PRODUCT_NAME );
await shopper.block.goToCheckout();
await shopper.block.fillBillingDetails( BILLING_DETAILS );
await shopper.block.placeOrder();
await expect( page ).toMatch( 'Your order has been received.' );
} );

it( 'Logged in user can place an order', async () => {
await shopper.login();
await shopper.block.goToShop();
await shopper.addToCartFromShopPage( SIMPLE_VIRTUAL_PRODUCT_NAME );
await shopper.block.goToCheckout();
await shopper.block.fillBillingDetails( BILLING_DETAILS );
await shopper.block.placeOrder();
await expect( page ).toMatch( 'Your order has been received.' );
await shopper.logout();
} );
} );

describe.skip( `Shipping`, () => {
afterEach( async () => {
await merchant.login();
Expand Down
99 changes: 98 additions & 1 deletion tests/e2e/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
*/
import { FullConfig, chromium, request } from '@playwright/test';
import { RequestUtils } from '@wordpress/e2e-test-utils-playwright';
import { expect } from '@woocommerce/e2e-playwright-utils';
import fs from 'fs';
import { cli } from '@woocommerce/e2e-utils';
import {
cli,
adminFile,
customerFile,
guestFile,
} from '@woocommerce/e2e-utils';

/**
* Internal dependencies
Expand Down Expand Up @@ -79,6 +85,94 @@ const loginAsCustomer = async ( config: FullConfig ) => {
await browser.close();
};

const authenticateAsAdmin = async ( config: FullConfig ) => {
const { baseURL, userAgent } = config.projects[ 0 ].use;

// Specify user agent when running against an external test site to avoid getting HTTP 406 NOT ACCEPTABLE errors.
const contextOptions = { baseURL, userAgent };
// Create browser, browserContext, and page for admin users
const browser = await chromium.launch();
const context = await browser.newContext( contextOptions );
const page = await context.newPage();
await page.goto( '/my-account' );
await page.getByLabel( 'Username or email address' ).fill( admin.username );
await page.getByLabel( 'Password' ).fill( admin.password );
await page.getByRole( 'button', { name: 'Log in' } ).click();
// Sometimes login flow sets cookies in the process of several redirects.
// Wait for the final URL to ensure that the cookies are actually set.
await page.waitForURL( '/my-account/' );

await expect(
page
.getByRole( 'list' )
.filter( {
hasText:
'Dashboard Orders Downloads Addresses Account details Log out',
} )
.getByRole( 'link', { name: 'Log out' } )
).toBeVisible();

await page.context().storageState( { path: adminFile } );

await context.close();
await browser.close();
};

const authenticateAsCustomer = async ( config: FullConfig ) => {
const { baseURL, userAgent } = config.projects[ 0 ].use;

// Specify user agent when running against an external test site to avoid getting HTTP 406 NOT ACCEPTABLE errors.
const contextOptions = { baseURL, userAgent };
// Create browser, browserContext, and page for customer users
const browser = await chromium.launch();
const context = await browser.newContext( contextOptions );
const page = await context.newPage();
await page.goto( '/my-account' );
await page
.getByLabel( 'Username or email address' )
.fill( customer.username );
await page.getByLabel( 'Password' ).fill( customer.password );
await page.getByRole( 'button', { name: 'Log in' } ).click();
// Sometimes login flow sets cookies in the process of several redirects.
// Wait for the final URL to ensure that the cookies are actually set.
await page.waitForURL( '/my-account/' );

await expect(
page
.getByRole( 'list' )
.filter( {
hasText:
'Dashboard Orders Downloads Addresses Account details Log out',
} )
.getByRole( 'link', { name: 'Log out' } )
).toBeVisible();

await page.context().storageState( { path: customerFile } );

await context.close();
await browser.close();
};

const visitAsGuest = async ( config: FullConfig ) => {
const { baseURL, userAgent } = config.projects[ 0 ].use;

// Specify user agent when running against an external test site to avoid getting HTTP 406 NOT ACCEPTABLE errors.
const contextOptions = { baseURL, userAgent };
// Create browser, browserContext, and page for customer and admin users
const browser = await chromium.launch();
const context = await browser.newContext( contextOptions );
const page = await context.newPage();
await page.goto( '/my-account' );
await expect(
page.getByLabel( 'Username or email address' )
).toBeVisible();

await page.context().storageState( { path: guestFile } );

await context.close();
await browser.close();
};

const prepareAttributes = async ( config: FullConfig ) => {
const { baseURL, userAgent } = config.projects[ 0 ].use;

Expand Down Expand Up @@ -145,6 +239,9 @@ async function globalSetup( config: FullConfig ) {

await prepareAttributes( config );
await loginAsCustomer( config );
await authenticateAsAdmin( config );
await authenticateAsCustomer( config );
await visitAsGuest( config );
}

export default globalSetup;
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
* External dependencies
*/
import { test as base, expect } from '@woocommerce/e2e-playwright-utils';
import { customerFile, guestFile } from '@woocommerce/e2e-utils';

/**
* Internal dependencies
*/
import { CheckoutPage } from './checkout.page';
import {
FREE_SHIPPING_NAME,
FREE_SHIPPING_PRICE,
SIMPLE_PHYSICAL_PRODUCT_NAME,
FLAT_RATE_SHIPPING_NAME,
FLAT_RATE_SHIPPING_PRICE,
} from './constants';

const test = base.extend< { pageObject: CheckoutPage } >( {
pageObject: async ( { page }, use ) => {
Expand All @@ -18,14 +26,7 @@ const test = base.extend< { pageObject: CheckoutPage } >( {
} );

test.describe( 'Shopper → Checkout block → Shipping', () => {
const FREE_SHIPPING_NAME = 'Free shipping';
const FREE_SHIPPING_PRICE = '$0.00';
const FLAT_RATE_SHIPPING_NAME = 'Flat rate shipping';
const FLAT_RATE_SHIPPING_PRICE = '$10.00';

test.use( {
storageState: process.env.CUSTOMERSTATE,
} );
test.use( { storageState: customerFile } );

test( 'Shopper can choose free shipping, flat rate shipping, and can have different billing and shipping addresses', async ( {
pageObject,
Expand Down Expand Up @@ -96,3 +97,31 @@ test.describe( 'Shopper → Checkout block → Shipping', () => {
await pageObject.verifyAddressDetails( 'shipping' );
} );
} );

// We only check if guest user can place an order because we already checked if logged in user can
// place an order in the previous test
test.describe( 'Shopper → Checkout block → Place Order', () => {
test.use( { storageState: guestFile } );

test( 'Guest user can place order', async ( {
pageObject,
frontendUtils,
page,
} ) => {
await frontendUtils.emptyCart();
await frontendUtils.goToShop();
await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
await frontendUtils.goToCheckout();
await expect(
await pageObject.selectAndVerifyShippingOption(
FREE_SHIPPING_NAME,
FREE_SHIPPING_PRICE
)
).toBe( true );
await pageObject.fillInCheckoutWithTestData();
await pageObject.placeOrder();
await expect(
page.getByText( 'Your order has been received.' )
).toBeVisible();
} );
} );
2 changes: 1 addition & 1 deletion tests/e2e/tests/checkout/checkout.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export class CheckoutPage {
shippingName: string,
shippingPrice: string
) {
const shipping = this.page.getByLabel( shippingName );
const shipping = this.page.getByLabel( shippingName ).first();
await expect( shipping ).toBeVisible();
if (
! ( await this.isShippingRateSelected(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import { BlockData } from '@woocommerce/e2e-types';
import { test, expect } from '@woocommerce/e2e-playwright-utils';
import { BASE_URL, cli } from '@woocommerce/e2e-utils';

/**
* Internal dependencies
*/

const blockData: BlockData< {
urlSearchParamWhenFilterIsApplied: string;
endpointAPI: string;
Expand Down
5 changes: 5 additions & 0 deletions tests/e2e/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ export const STORAGE_STATE_PATH = path.join(
process.cwd(),
'artifacts/storage-states/admin.json'
);

// User roles file paths
export const adminFile = '.auth/admin.json';
export const customerFile = '.auth/customer.json';
export const guestFile = '.auth/guest.json';
6 changes: 6 additions & 0 deletions tests/e2e/utils/frontend/frontend-utils.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,10 @@ export class FrontendUtils {
await locator.press( 'End' );
await locator.press( 'Shift+Home' );
}

async gotoMyAccount() {
await this.page.goto( '/my-account', {
waitUntil: 'commit',
} );
}
}

0 comments on commit d976360

Please sign in to comment.