[e2e tests] Fix flakiness and refactor create-order spec (#51292)
This commit is contained in:
parent
0e2258b57d
commit
0c8a8bd6cf
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
const { test, expect } = require( '@playwright/test' );
|
||||
const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
|
||||
const { test: baseTest, expect } = require( '../../fixtures/fixtures' );
|
||||
const { random } = require( '../../utils/helpers' );
|
||||
|
||||
const simpleProductName = 'Add new order simple product';
|
||||
const variableProductName = 'Add new order variable product';
|
||||
const externalProductName = 'Add new order external product';
|
||||
const groupedProductName = 'Add new order grouped product';
|
||||
const taxClasses = [
|
||||
{
|
||||
name: 'Tax Class Simple',
|
||||
|
@ -37,52 +33,110 @@ const taxRates = [
|
|||
},
|
||||
];
|
||||
const taxTotals = [ '10.00', '20.00', '240.00' ];
|
||||
let simpleProductId,
|
||||
variableProductId,
|
||||
externalProductId,
|
||||
subProductAId,
|
||||
subProductBId,
|
||||
groupedProductId,
|
||||
customerId,
|
||||
orderId;
|
||||
|
||||
test.describe(
|
||||
'WooCommerce Orders > Add new order',
|
||||
{ tag: [ '@services', '@hpos' ] },
|
||||
() => {
|
||||
test.use( { storageState: process.env.ADMINSTATE } );
|
||||
async function getOrderIdFromPage( page ) {
|
||||
// get order ID from the page
|
||||
const orderText = await page
|
||||
.locator( 'h2.woocommerce-order-data__heading' )
|
||||
.textContent();
|
||||
const parts = orderText.match( /([0-9])\w+/ );
|
||||
return parts[ 0 ];
|
||||
}
|
||||
|
||||
test.beforeAll( async ( { baseURL } ) => {
|
||||
const api = new wcApi( {
|
||||
url: baseURL,
|
||||
consumerKey: process.env.CONSUMER_KEY,
|
||||
consumerSecret: process.env.CONSUMER_SECRET,
|
||||
version: 'wc/v3',
|
||||
} );
|
||||
// enable taxes on the account
|
||||
await api.put( 'settings/general/woocommerce_calc_taxes', {
|
||||
value: 'yes',
|
||||
} );
|
||||
// add tax classes
|
||||
for ( const taxClass of taxClasses ) {
|
||||
await api.post( 'taxes/classes', taxClass );
|
||||
async function addProductToOrder( page, product, quantity ) {
|
||||
await page.getByRole( 'button', { name: 'Add item(s)' } ).click();
|
||||
await page.getByRole( 'button', { name: 'Add product(s)' } ).click();
|
||||
await page.getByText( 'Search for a product…' ).click();
|
||||
await page.locator( 'span > .select2-search__field' ).fill( product.name );
|
||||
await page.getByRole( 'option', { name: product.name } ).first().click();
|
||||
await page
|
||||
.locator( 'tr' )
|
||||
.filter( { hasText: product.name } )
|
||||
.getByPlaceholder( '1' )
|
||||
.fill( quantity.toString() );
|
||||
await page.locator( '#btn-ok' ).click();
|
||||
}
|
||||
|
||||
const test = baseTest.extend( {
|
||||
storageState: process.env.ADMINSTATE,
|
||||
order: async ( { api }, use ) => {
|
||||
const order = {};
|
||||
|
||||
await use( order );
|
||||
|
||||
if ( order.id ) {
|
||||
await api.delete( `orders/${ order.id }`, { force: true } );
|
||||
}
|
||||
// attach rates to the classes
|
||||
for ( let i = 0; i < taxRates.length; i++ ) {
|
||||
await api.post( 'taxes', taxRates[ i ] );
|
||||
}
|
||||
// create simple product
|
||||
},
|
||||
|
||||
customer: async ( { api }, use ) => {
|
||||
let customer = {};
|
||||
const username = `sideshowbob_${ random() }`;
|
||||
|
||||
await api
|
||||
.post( 'customers', {
|
||||
email: `${ username }@example.com`,
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
username,
|
||||
billing: {
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
company: 'Die Bart Die',
|
||||
address_1: '123 Fake St',
|
||||
address_2: '',
|
||||
city: 'Springfield',
|
||||
state: 'FL',
|
||||
postcode: '12345',
|
||||
country: 'US',
|
||||
email: `${ username }@example.com`,
|
||||
phone: '555-555-5556',
|
||||
},
|
||||
shipping: {
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
company: 'Die Bart Die',
|
||||
address_1: '321 Fake St',
|
||||
address_2: '',
|
||||
city: 'Springfield',
|
||||
state: 'FL',
|
||||
postcode: '12345',
|
||||
country: 'US',
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
customer = response.data;
|
||||
} );
|
||||
|
||||
await use( customer );
|
||||
|
||||
// Cleanup
|
||||
await api.delete( `customers/${ customer.id }`, { force: true } );
|
||||
},
|
||||
|
||||
simpleProduct: async ( { api }, use ) => {
|
||||
let product = {};
|
||||
|
||||
await api
|
||||
.post( 'products', {
|
||||
name: simpleProductName,
|
||||
name: `Product simple ${ random() }`,
|
||||
type: 'simple',
|
||||
regular_price: '100',
|
||||
tax_class: 'Tax Class Simple',
|
||||
} )
|
||||
.then( ( resp ) => {
|
||||
simpleProductId = resp.data.id;
|
||||
.then( ( response ) => {
|
||||
product = response.data;
|
||||
} );
|
||||
// create variable product
|
||||
|
||||
await use( product );
|
||||
|
||||
// Cleanup
|
||||
await api.delete( `products/${ product.id }`, { force: true } );
|
||||
},
|
||||
|
||||
variableProduct: async ( { api }, use ) => {
|
||||
let product = {};
|
||||
|
||||
const variations = [
|
||||
{
|
||||
regular_price: '100',
|
||||
|
@ -113,25 +167,36 @@ test.describe(
|
|||
tax_class: 'Tax Class Variable',
|
||||
},
|
||||
];
|
||||
|
||||
await api
|
||||
.post( 'products', {
|
||||
name: variableProductName,
|
||||
name: `Product variable ${ random() }`,
|
||||
type: 'variable',
|
||||
tax_class: 'Tax Class Variable',
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
variableProductId = response.data.id;
|
||||
product = response.data;
|
||||
} );
|
||||
|
||||
for ( const key in variations ) {
|
||||
api.post(
|
||||
`products/${ variableProductId }/variations`,
|
||||
`products/${ product.id }/variations`,
|
||||
variations[ key ]
|
||||
);
|
||||
}
|
||||
} );
|
||||
// create external product
|
||||
|
||||
await use( product );
|
||||
|
||||
// Cleanup
|
||||
await api.delete( `products/${ product.id }`, { force: true } );
|
||||
},
|
||||
|
||||
externalProduct: async ( { api }, use ) => {
|
||||
let product = {};
|
||||
|
||||
await api
|
||||
.post( 'products', {
|
||||
name: externalProductName,
|
||||
name: `Product external ${ random() }`,
|
||||
regular_price: '800',
|
||||
tax_class: 'Tax Class External',
|
||||
external_url: 'https://wordpress.org/plugins/woocommerce',
|
||||
|
@ -139,9 +204,20 @@ test.describe(
|
|||
button_text: 'Buy now',
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
externalProductId = response.data.id;
|
||||
product = response.data;
|
||||
} );
|
||||
// create grouped product
|
||||
|
||||
await use( product );
|
||||
|
||||
// Cleanup
|
||||
await api.delete( `products/${ product.id }`, { force: true } );
|
||||
},
|
||||
|
||||
groupedProduct: async ( { api }, use ) => {
|
||||
let product = {};
|
||||
let subProductAId;
|
||||
let subProductBId;
|
||||
|
||||
await api
|
||||
.post( 'products', {
|
||||
name: 'Add-on A',
|
||||
|
@ -160,82 +236,42 @@ test.describe(
|
|||
} );
|
||||
await api
|
||||
.post( 'products', {
|
||||
name: groupedProductName,
|
||||
name: `Product grouped ${ random() }`,
|
||||
regular_price: '29.99',
|
||||
grouped_products: [ subProductAId, subProductBId ],
|
||||
type: 'grouped',
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
groupedProductId = response.data.id;
|
||||
} );
|
||||
// create a customer
|
||||
await api
|
||||
.post( 'customers', {
|
||||
email: 'sideshowbob@example.com',
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
username: 'sideshowbob',
|
||||
billing: {
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
company: 'Die Bart Die',
|
||||
address_1: '123 Fake St',
|
||||
address_2: '',
|
||||
city: 'Springfield',
|
||||
state: 'FL',
|
||||
postcode: '12345',
|
||||
country: 'US',
|
||||
email: 'sideshowbob@example.com',
|
||||
phone: '555-555-5556',
|
||||
},
|
||||
shipping: {
|
||||
first_name: 'Sideshow',
|
||||
last_name: 'Bob',
|
||||
company: 'Die Bart Die',
|
||||
address_1: '321 Fake St',
|
||||
address_2: '',
|
||||
city: 'Springfield',
|
||||
state: 'FL',
|
||||
postcode: '12345',
|
||||
country: 'US',
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
customerId = response.data.id;
|
||||
} );
|
||||
product = response.data;
|
||||
} );
|
||||
|
||||
test.afterEach( async ( { baseURL } ) => {
|
||||
const api = new wcApi( {
|
||||
url: baseURL,
|
||||
consumerKey: process.env.CONSUMER_KEY,
|
||||
consumerSecret: process.env.CONSUMER_SECRET,
|
||||
version: 'wc/v3',
|
||||
await use( product );
|
||||
|
||||
// Cleanup
|
||||
await api.delete( `products/${ product.id }`, { force: true } );
|
||||
},
|
||||
} );
|
||||
|
||||
test.describe(
|
||||
'WooCommerce Orders > Add new order',
|
||||
{ tag: [ '@services', '@hpos' ] },
|
||||
() => {
|
||||
test.beforeAll( async ( { api } ) => {
|
||||
// enable taxes on the account
|
||||
await api.put( 'settings/general/woocommerce_calc_taxes', {
|
||||
value: 'yes',
|
||||
} );
|
||||
// clean up order after each test
|
||||
if ( orderId && orderId !== '' ) {
|
||||
await api.delete( `orders/${ orderId }`, { force: true } );
|
||||
// add tax classes
|
||||
for ( const taxClass of taxClasses ) {
|
||||
await api.post( 'taxes/classes', taxClass );
|
||||
}
|
||||
// attach rates to the classes
|
||||
for ( let i = 0; i < taxRates.length; i++ ) {
|
||||
await api.post( 'taxes', taxRates[ i ] );
|
||||
}
|
||||
} );
|
||||
|
||||
test.afterAll( async ( { baseURL } ) => {
|
||||
const api = new wcApi( {
|
||||
url: baseURL,
|
||||
consumerKey: process.env.CONSUMER_KEY,
|
||||
consumerSecret: process.env.CONSUMER_SECRET,
|
||||
version: 'wc/v3',
|
||||
} );
|
||||
// cleans up all products after run
|
||||
await api.post( 'products/batch', {
|
||||
delete: [
|
||||
simpleProductId,
|
||||
variableProductId,
|
||||
externalProductId,
|
||||
subProductAId,
|
||||
subProductBId,
|
||||
groupedProductId,
|
||||
],
|
||||
} );
|
||||
test.afterAll( async ( { api } ) => {
|
||||
// clean up tax classes and rates
|
||||
for ( const { slug } of taxClasses ) {
|
||||
await api
|
||||
|
@ -258,19 +294,15 @@ test.describe(
|
|||
await api.put( 'settings/general/woocommerce_calc_taxes', {
|
||||
value: 'no',
|
||||
} );
|
||||
// clean up customer
|
||||
await api.delete( `customers/${ customerId }`, { force: true } );
|
||||
} );
|
||||
|
||||
test( 'can create a simple guest order', async ( { page } ) => {
|
||||
test( 'can create a simple guest order', async ( {
|
||||
page,
|
||||
simpleProduct,
|
||||
order,
|
||||
} ) => {
|
||||
await page.goto( 'wp-admin/admin.php?page=wc-orders&action=new' );
|
||||
|
||||
// get order ID from the page
|
||||
const orderText = await page
|
||||
.locator( 'h2.woocommerce-order-data__heading' )
|
||||
.textContent();
|
||||
orderId = orderText.match( /([0-9])\w+/ );
|
||||
orderId = orderId[ 0 ].toString();
|
||||
order.id = await getOrderIdFromPage( page );
|
||||
|
||||
await page
|
||||
.locator( '#order_status' )
|
||||
|
@ -334,22 +366,7 @@ test.describe(
|
|||
.fill( 'Only asked for a slushie' );
|
||||
|
||||
// Add a product
|
||||
await page.getByRole( 'button', { name: 'Add item(s)' } ).click();
|
||||
await page
|
||||
.getByRole( 'button', { name: 'Add product(s)' } )
|
||||
.click();
|
||||
await page.getByText( 'Search for a product…' ).click();
|
||||
await page
|
||||
.locator( 'span > .select2-search__field' )
|
||||
.fill( 'Simple' );
|
||||
await page
|
||||
.getByRole( 'option', { name: simpleProductName } )
|
||||
.click();
|
||||
await page
|
||||
.getByRole( 'row', { name: '×Add new order simple product' } )
|
||||
.getByPlaceholder( '1' )
|
||||
.fill( '2' );
|
||||
await page.locator( '#btn-ok' ).click();
|
||||
await addProductToOrder( page, simpleProduct, 2 );
|
||||
|
||||
// Create the order
|
||||
await page.getByRole( 'button', { name: 'Create' } ).click();
|
||||
|
@ -375,40 +392,26 @@ test.describe(
|
|||
|
||||
test( 'can create an order for an existing customer', async ( {
|
||||
page,
|
||||
simpleProduct,
|
||||
customer,
|
||||
order,
|
||||
} ) => {
|
||||
await page.goto( 'wp-admin/admin.php?page=wc-orders&action=new' );
|
||||
|
||||
// get order ID from the page
|
||||
const orderText = await page
|
||||
.locator( 'h2.woocommerce-order-data__heading' )
|
||||
.textContent();
|
||||
orderId = orderText.match( /([0-9])\w+/ );
|
||||
orderId = orderId[ 0 ].toString();
|
||||
order.id = await getOrderIdFromPage( page );
|
||||
|
||||
// Select customer
|
||||
await page.getByText( 'Guest' ).click();
|
||||
await page
|
||||
.locator( 'input[aria-owns="select2-customer_user-results"]' )
|
||||
.fill( 'sideshowbob@' );
|
||||
await page.getByRole( 'option', { name: 'Sideshow Bob' } ).click();
|
||||
.fill( customer.username );
|
||||
await page
|
||||
.getByRole( 'option', {
|
||||
name: `${ customer.first_name } ${ customer.last_name }`,
|
||||
} )
|
||||
.click();
|
||||
|
||||
// Add a product
|
||||
await page.getByRole( 'button', { name: 'Add item(s)' } ).click();
|
||||
await page
|
||||
.getByRole( 'button', { name: 'Add product(s)' } )
|
||||
.click();
|
||||
await page.getByText( 'Search for a product…' ).click();
|
||||
await page
|
||||
.locator( 'span > .select2-search__field' )
|
||||
.fill( 'Simple' );
|
||||
await page
|
||||
.getByRole( 'option', { name: simpleProductName } )
|
||||
.click();
|
||||
await page
|
||||
.getByRole( 'row', { name: '×Add new order simple product' } )
|
||||
.getByPlaceholder( '1' )
|
||||
.fill( '2' );
|
||||
await page.locator( '#btn-ok' ).click();
|
||||
await addProductToOrder( page, simpleProduct, 2 );
|
||||
|
||||
// Create the order
|
||||
await page.getByRole( 'button', { name: 'Create' } ).click();
|
||||
|
@ -431,12 +434,14 @@ test.describe(
|
|||
// View customer profile
|
||||
await page.getByRole( 'link', { name: 'Profile →' } ).click();
|
||||
await expect(
|
||||
page.getByRole( 'heading', { name: 'Edit User sideshowbob' } )
|
||||
page.getByRole( 'heading', {
|
||||
name: `Edit User ${ customer.username }`,
|
||||
} )
|
||||
).toBeVisible();
|
||||
|
||||
// Go back to the order
|
||||
await page.goto(
|
||||
`wp-admin/admin.php?page=wc-orders&action=edit&id=${ orderId }`
|
||||
`wp-admin/admin.php?page=wc-orders&action=edit&id=${ order.id }`
|
||||
);
|
||||
await page
|
||||
.getByRole( 'link', {
|
||||
|
@ -449,17 +454,12 @@ test.describe(
|
|||
await expect( page.getByRole( 'row' ) ).toHaveCount( 3 ); // 1 order and header and footer rows
|
||||
} );
|
||||
|
||||
test( 'can create new order', async ( { page } ) => {
|
||||
test( 'can create new order', async ( { page, order } ) => {
|
||||
await page.goto( 'wp-admin/admin.php?page=wc-orders&action=new' );
|
||||
await expect(
|
||||
page.locator( 'h1.wp-heading-inline' )
|
||||
).toContainText( 'Add new order' );
|
||||
// get order ID from the page
|
||||
const orderText = await page
|
||||
.locator( 'h2.woocommerce-order-data__heading' )
|
||||
.textContent();
|
||||
orderId = orderText.match( /([0-9])\w+/ );
|
||||
orderId = orderId[ 0 ].toString();
|
||||
order.id = await getOrderIdFromPage( page );
|
||||
|
||||
await page
|
||||
.locator( '#order_status' )
|
||||
|
@ -488,74 +488,51 @@ test.describe(
|
|||
|
||||
test( 'can create new complex order with multiple product types & tax classes', async ( {
|
||||
page,
|
||||
simpleProduct,
|
||||
variableProduct,
|
||||
externalProduct,
|
||||
groupedProduct,
|
||||
order,
|
||||
} ) => {
|
||||
orderId = '';
|
||||
await page.goto( 'wp-admin/admin.php?page=wc-orders&action=new' );
|
||||
order.id = await getOrderIdFromPage( page );
|
||||
|
||||
// open modal for adding line items
|
||||
await page.locator( 'button.add-line-item' ).click();
|
||||
await page.locator( 'button.add-order-item' ).click();
|
||||
|
||||
// search for each product to add
|
||||
await page.locator( 'text=Search for a product…' ).click();
|
||||
for ( const product of [
|
||||
simpleProduct,
|
||||
variableProduct,
|
||||
groupedProduct,
|
||||
externalProduct,
|
||||
] ) {
|
||||
await page.getByText( 'Search for a product…' ).click();
|
||||
await page
|
||||
.locator( '.select2-search--dropdown' )
|
||||
.getByRole( 'combobox' )
|
||||
.pressSequentially( simpleProductName );
|
||||
.locator( 'span > .select2-search__field' )
|
||||
.fill( product.name );
|
||||
await page
|
||||
.locator(
|
||||
'li.select2-results__option.select2-results__option--highlighted'
|
||||
)
|
||||
.click();
|
||||
|
||||
await page.locator( 'text=Search for a product…' ).click();
|
||||
await page
|
||||
.locator( '.select2-search--dropdown' )
|
||||
.getByRole( 'combobox' )
|
||||
.pressSequentially( variableProductName );
|
||||
await page
|
||||
.locator(
|
||||
'li.select2-results__option.select2-results__option--highlighted'
|
||||
)
|
||||
.click();
|
||||
|
||||
await page.locator( 'text=Search for a product…' ).click();
|
||||
await page
|
||||
.locator( '.select2-search--dropdown' )
|
||||
.getByRole( 'combobox' )
|
||||
.type( groupedProductName );
|
||||
await page
|
||||
.locator(
|
||||
'li.select2-results__option.select2-results__option--highlighted'
|
||||
)
|
||||
.click();
|
||||
|
||||
await page.locator( 'text=Search for a product…' ).click();
|
||||
await page
|
||||
.locator( '.select2-search--dropdown' )
|
||||
.getByRole( 'combobox' )
|
||||
.type( externalProductName );
|
||||
await page
|
||||
.locator(
|
||||
'li.select2-results__option.select2-results__option--highlighted'
|
||||
)
|
||||
.getByRole( 'option', { name: product.name } )
|
||||
.first()
|
||||
.click();
|
||||
}
|
||||
|
||||
await page.locator( 'button#btn-ok' ).click();
|
||||
|
||||
// assert that products added
|
||||
await expect(
|
||||
page.locator( 'td.name > a >> nth=0' )
|
||||
).toContainText( simpleProductName );
|
||||
).toContainText( simpleProduct.name );
|
||||
await expect(
|
||||
page.locator( 'td.name > a >> nth=1' )
|
||||
).toContainText( variableProductName );
|
||||
).toContainText( variableProduct.name );
|
||||
await expect(
|
||||
page.locator( 'td.name > a >> nth=2' )
|
||||
).toContainText( groupedProductName );
|
||||
).toContainText( groupedProduct.name );
|
||||
await expect(
|
||||
page.locator( 'td.name > a >> nth=3' )
|
||||
).toContainText( externalProductName );
|
||||
).toContainText( externalProduct.name );
|
||||
|
||||
// Recalculate taxes
|
||||
page.on( 'dialog', ( dialog ) => dialog.accept() );
|
||||
|
|
Loading…
Reference in New Issue