[E2E] Refactor blocks global setup (#44843)
This commit is contained in:
parent
56e6772af5
commit
8b4bacc2bf
|
@ -1,247 +1,88 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { FullConfig, chromium, request } from '@playwright/test';
|
import { chromium, request } from '@playwright/test';
|
||||||
import { RequestUtils } from '@wordpress/e2e-test-utils-playwright';
|
import { RequestUtils } from '@wordpress/e2e-test-utils-playwright';
|
||||||
import { expect } from '@woocommerce/e2e-playwright-utils';
|
import { BASE_URL, adminFile, cli, customerFile } from '@woocommerce/e2e-utils';
|
||||||
import fs from 'fs';
|
|
||||||
import {
|
|
||||||
cli,
|
|
||||||
adminFile,
|
|
||||||
customerFile,
|
|
||||||
guestFile,
|
|
||||||
} from '@woocommerce/e2e-utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { customer, admin } from './test-data/data/data';
|
import { customer, admin } from './test-data/data/data';
|
||||||
|
|
||||||
const loginAsCustomer = async ( config: FullConfig ) => {
|
const prepareAttributes = async () => {
|
||||||
const { stateDir, baseURL, userAgent } = config.projects[ 0 ].use;
|
|
||||||
|
|
||||||
// used throughout tests for authentication
|
|
||||||
process.env.CUSTOMERSTATE = `${ stateDir }customerState.json`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.unlinkSync( process.env.CUSTOMERSTATE );
|
|
||||||
console.log( 'Customer state file deleted successfully.' );
|
|
||||||
} catch ( err ) {
|
|
||||||
if ( err.code === 'ENOENT' ) {
|
|
||||||
console.log( 'Customer state file does not exist.' );
|
|
||||||
} else {
|
|
||||||
console.log( 'Customer state file could not be deleted: ' + err );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let customerLoggedIn = false;
|
|
||||||
|
|
||||||
// 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 browser = await chromium.launch();
|
||||||
const customerContext = await browser.newContext( contextOptions );
|
const context = await browser.newContext( {
|
||||||
const customerPage = await customerContext.newPage();
|
baseURL: BASE_URL,
|
||||||
|
storageState: adminFile,
|
||||||
|
} );
|
||||||
|
|
||||||
// Sign in as customer user and save state
|
|
||||||
const customerRetries = 5;
|
|
||||||
for ( let i = 0; i < customerRetries; i++ ) {
|
|
||||||
try {
|
|
||||||
await customerPage.goto( `/wp-admin`, {
|
|
||||||
waitUntil: 'commit',
|
|
||||||
} );
|
|
||||||
await customerPage.fill( 'input[name="log"]', customer.username );
|
|
||||||
await customerPage.fill( 'input[name="pwd"]', customer.password );
|
|
||||||
await customerPage.click( 'text=Log In' );
|
|
||||||
|
|
||||||
await customerPage.goto( `/my-account`, {
|
|
||||||
waitUntil: 'commit',
|
|
||||||
} );
|
|
||||||
|
|
||||||
await customerPage
|
|
||||||
.context()
|
|
||||||
.storageState( { path: process.env.CUSTOMERSTATE } );
|
|
||||||
console.log( 'Logged-in as customer successfully.' );
|
|
||||||
customerLoggedIn = true;
|
|
||||||
break;
|
|
||||||
} catch ( e ) {
|
|
||||||
console.log(
|
|
||||||
`Customer log-in failed. Retrying... ${ i }/${ customerRetries }`
|
|
||||||
);
|
|
||||||
console.log( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! customerLoggedIn ) {
|
|
||||||
console.error(
|
|
||||||
'Cannot proceed e2e test, as customer login failed. Please check if the test site has been setup correctly.'
|
|
||||||
);
|
|
||||||
process.exit( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
await customerContext.close();
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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();
|
const page = await context.newPage();
|
||||||
|
|
||||||
await page.goto( `/wp-admin`, { waitUntil: 'commit' } );
|
// Intercept the dialog event. This is needed because when the regenerate
|
||||||
await page.fill( 'input[name="log"]', admin.username );
|
// button is clicked, a dialog is shown.
|
||||||
await page.fill( 'input[name="pwd"]', admin.password );
|
|
||||||
await page.click( 'text=Log In' );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Intercept the dialog event.
|
|
||||||
* This is needed because when the regenerate
|
|
||||||
* button is clicked, a dialog is shown.
|
|
||||||
*/
|
|
||||||
page.on( 'dialog', async ( dialog ) => {
|
page.on( 'dialog', async ( dialog ) => {
|
||||||
await dialog.accept();
|
await dialog.accept();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
await page.goto( '/wp-admin/admin.php?page=wc-status&tab=tools', {
|
await page.goto( '/wp-admin/admin.php?page=wc-status&tab=tools' );
|
||||||
waitUntil: 'commit',
|
|
||||||
} );
|
|
||||||
|
|
||||||
await page.click( '.regenerate_product_attributes_lookup_table input' );
|
// Attributes regeneration should be doable via a CLI command, e.g.:
|
||||||
|
// "wp wc tool run regenerate_product_attributes_lookup_table --user=1"
|
||||||
|
// It doesn't seem to be working correctly ATM so we need to do it via
|
||||||
|
// browser actions.
|
||||||
|
// See: https://github.com/woocommerce/woocommerce/issues/32831
|
||||||
|
await page
|
||||||
|
.getByRole( 'row', {
|
||||||
|
name: /Regenerate the product attributes lookup table/,
|
||||||
|
} )
|
||||||
|
.getByRole( 'button' )
|
||||||
|
.click();
|
||||||
|
|
||||||
await context.close();
|
await context.close();
|
||||||
await browser.close();
|
await browser.close();
|
||||||
|
|
||||||
/*
|
// Note that the two commands below are intentionally duplicated as we need
|
||||||
* Note that the two commands below are intentionally
|
// to run the cron task twice as we need to process more than 1 batch of
|
||||||
* duplicated as we need to run the cron task twice as
|
// items.
|
||||||
* we need to process more than 1 batch of items.
|
const cronTask = `npm run wp-env run tests-cli -- wp action-scheduler run --hooks="woocommerce_run_product_attribute_lookup_regeneration_callback"`;
|
||||||
*/
|
await cli( cronTask );
|
||||||
await cli(
|
await cli( cronTask );
|
||||||
`npm run wp-env run tests-cli -- wp action-scheduler run --hooks="woocommerce_run_product_attribute_lookup_regeneration_callback"`
|
|
||||||
);
|
|
||||||
|
|
||||||
await cli(
|
|
||||||
`npm run wp-env run tests-cli -- wp action-scheduler run --hooks="woocommerce_run_product_attribute_lookup_regeneration_callback"`
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function globalSetup( config: FullConfig ) {
|
async function globalSetup() {
|
||||||
const { storageState, baseURL } = config.projects[ 0 ].use;
|
const timers = {
|
||||||
const storageStatePath =
|
total: '└ Total time',
|
||||||
typeof storageState === 'string' ? storageState : '';
|
authentication: '├ Authentication time',
|
||||||
|
attributes: '├ Attributes preparation time',
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log( 'Running global setup...' );
|
||||||
|
console.time( timers.total );
|
||||||
|
|
||||||
const requestContext = await request.newContext( {
|
const requestContext = await request.newContext( {
|
||||||
baseURL: baseURL ?? '',
|
baseURL: BASE_URL,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const requestUtils = new RequestUtils( requestContext, {
|
console.time( timers.authentication );
|
||||||
storageStatePath,
|
await new RequestUtils( requestContext, {
|
||||||
} );
|
user: admin,
|
||||||
|
storageStatePath: adminFile,
|
||||||
|
} ).setupRest();
|
||||||
|
await new RequestUtils( requestContext, {
|
||||||
|
user: customer,
|
||||||
|
storageStatePath: customerFile,
|
||||||
|
} ).setupRest();
|
||||||
|
console.timeEnd( timers.authentication );
|
||||||
|
|
||||||
|
console.time( timers.attributes );
|
||||||
|
await prepareAttributes();
|
||||||
|
console.timeEnd( timers.attributes );
|
||||||
|
|
||||||
await requestUtils.setupRest();
|
|
||||||
await requestContext.dispose();
|
await requestContext.dispose();
|
||||||
|
console.timeEnd( timers.total );
|
||||||
await prepareAttributes( config );
|
|
||||||
await loginAsCustomer( config );
|
|
||||||
await authenticateAsAdmin( config );
|
|
||||||
await authenticateAsCustomer( config );
|
|
||||||
await visitAsGuest( config );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default globalSetup;
|
export default globalSetup;
|
||||||
|
|
|
@ -10,12 +10,19 @@ export const BLOCK_THEME_NAME = 'Twenty Twenty-Four';
|
||||||
export const CLASSIC_THEME_SLUG = 'storefront';
|
export const CLASSIC_THEME_SLUG = 'storefront';
|
||||||
export const CLASSIC_THEME_NAME = 'Storefront';
|
export const CLASSIC_THEME_NAME = 'Storefront';
|
||||||
export const BASE_URL = 'http://localhost:8889';
|
export const BASE_URL = 'http://localhost:8889';
|
||||||
export const STORAGE_STATE_PATH = path.join(
|
|
||||||
process.cwd(),
|
|
||||||
'artifacts/storage-states/admin.json'
|
|
||||||
);
|
|
||||||
|
|
||||||
// User roles file paths
|
export const WP_ARTIFACTS_PATH =
|
||||||
export const adminFile = '.auth/admin.json';
|
process.env.WP_ARTIFACTS_PATH ||
|
||||||
export const customerFile = '.auth/customer.json';
|
path.join( process.cwd(), 'tests/e2e/artifacts' );
|
||||||
export const guestFile = '.auth/guest.json';
|
|
||||||
|
export const STORAGE_STATE_PATH =
|
||||||
|
process.env.STORAGE_STATE_PATH ||
|
||||||
|
path.join( WP_ARTIFACTS_PATH, 'storage-states/admin.json' );
|
||||||
|
|
||||||
|
// User roles storage states
|
||||||
|
export const adminFile = STORAGE_STATE_PATH;
|
||||||
|
export const customerFile = path.join(
|
||||||
|
path.dirname( STORAGE_STATE_PATH ),
|
||||||
|
'customer.json'
|
||||||
|
);
|
||||||
|
export const guestFile = { cookies: [], origins: [] };
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: tweak
|
||||||
|
|
||||||
|
Streamline and improve execution time of the `woocommerce-blocks` global E2E setup.
|
Loading…
Reference in New Issue