Add new E2E tests to cover Shopper Cart Block (#40522)

* Add new e2e tests to cover shopper cart block first part

* Add changelog

* Add more tests to cover coupons

* Update coupon tests to include discounts

* Split cart block tests and update tests

* Add E2E tests for cart block shipping

* Add tests for shopper cart block calculating tax

* Remove test.skip

* Add a workaround for filling shipping due to issue found

* Improve welcome modal closure

---------

Co-authored-by: Jon Lane <jon.lane@automattic.com>
This commit is contained in:
Veljko V 2023-11-10 20:14:47 +01:00 committed by GitHub
parent 811e0c079b
commit f51995a470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1592 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Adds tests for shopper cart block flows

View File

@ -0,0 +1,328 @@
const { test, expect } = require( '@playwright/test' );
const { admin } = require( '../../test-data/data' );
const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
const firstProductName = 'First Product';
const firstProductPrice = '10.00';
const secondProductName = 'Second Product';
const secondProductPrice = '20.00';
const firstProductWithFlatRate = +firstProductPrice + 5;
const doubleFirstProductWithFlatRate = +firstProductPrice * 2 + 5;
const twoProductsTotal = +firstProductPrice + +secondProductPrice;
const twoProductsWithFlatRate = twoProductsTotal + 5;
const pageTitle = 'Cart Block';
const pageSlug = pageTitle.replace( / /gi, '-' ).toLowerCase();
const shippingZoneNameES = 'Netherlands Free Shipping';
const shippingCountryNL = 'NL';
const shippingZoneNamePT = 'Portugal Flat Local';
const shippingCountryPT = 'PT';
test.describe( 'Cart Block Calculate Shipping', () => {
let product1Id, product2Id, shippingZoneNLId, shippingZonePTId;
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
// make sure the currency is USD
await api.put( 'settings/general/woocommerce_currency', {
value: 'USD',
} );
// add products
await api
.post( 'products', {
name: firstProductName,
type: 'simple',
regular_price: firstProductPrice,
} )
.then( ( response ) => {
product1Id = response.data.id;
} );
await api
.post( 'products', {
name: secondProductName,
type: 'simple',
regular_price: secondProductPrice,
} )
.then( ( response ) => {
product2Id = response.data.id;
} );
// create shipping zones
await api
.post( 'shipping/zones', {
name: shippingZoneNameES,
} )
.then( ( response ) => {
shippingZoneNLId = response.data.id;
} );
await api
.post( 'shipping/zones', {
name: shippingZoneNamePT,
} )
.then( ( response ) => {
shippingZonePTId = response.data.id;
} );
// set shipping zone locations
await api.put( `shipping/zones/${ shippingZoneNLId }/locations`, [
{
code: shippingCountryNL,
},
] );
await api.put( `shipping/zones/${ shippingZonePTId }/locations`, [
{
code: shippingCountryPT,
},
] );
// set shipping zone methods
await api.post( `shipping/zones/${ shippingZoneNLId }/methods`, {
method_id: 'free_shipping',
} );
await api.post( `shipping/zones/${ shippingZonePTId }/methods`, {
method_id: 'flat_rate',
settings: {
cost: '5.00',
},
} );
await api.post( `shipping/zones/${ shippingZonePTId }/methods`, {
method_id: 'local_pickup',
} );
// confirm that we allow shipping to any country
await api.put( 'settings/general/woocommerce_allowed_countries', {
value: 'all',
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.post( 'products/batch', {
delete: [ product1Id, product2Id ],
} );
await api.delete( `shipping/zones/${ shippingZoneNLId }`, {
force: true,
} );
await api.delete( `shipping/zones/${ shippingZonePTId }`, {
force: true,
} );
} );
test.beforeEach( async ( { page, context } ) => {
// Shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
// all tests use the first product
await page.goto( `/shop/?add-to-cart=${ product1Id }` );
await page.waitForLoadState( 'networkidle' );
} );
test( 'create Cart Block page', async ( { page } ) => {
// create a new page with cart block
await page.goto( 'wp-admin/post-new.php?post_type=page' );
await page.waitForLoadState( 'networkidle' );
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();
// close welcome popup if prompted
try {
await page
.getByLabel( 'Close', { exact: true } )
.click( { timeout: 5000 } );
} catch ( error ) {
console.log( "Welcome modal wasn't present, skipping action." );
}
await page
.getByRole( 'textbox', { name: 'Add title' } )
.fill( pageTitle );
await page.getByRole( 'button', { name: 'Add default block' } ).click();
await page
.getByRole( 'document', {
name: 'Empty block; start writing or type forward slash to choose a block',
} )
.fill( '/cart' );
await page.keyboard.press( 'Enter' );
await page
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await page
.getByRole( 'region', { name: 'Editor publish' } )
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await expect(
page.getByText( `${ pageTitle } is now live.` )
).toBeVisible();
} );
test( 'allows customer to calculate Free Shipping in cart block if in Netherlands', async ( {
page,
} ) => {
await page.goto( pageSlug );
// Set shipping country to Netherlands
await page
.locator(
'.wc-block-components-totals-shipping__change-address__link'
)
.click();
await page.getByRole( 'combobox' ).first().fill( 'Netherlands' );
await page.getByLabel( 'Postal code' ).fill( '1011AA' );
await page.getByLabel( 'City' ).fill( 'Amsterdam' );
await page.getByRole( 'button', { name: 'Update' } ).click();
// Verify shipping costs
await expect(
page.getByRole( 'group' ).getByText( 'Free shipping' )
).toBeVisible();
await expect(
page.locator(
'.wc-block-components-radio-control__description > .wc-block-components-formatted-money-amount'
)
).toContainText( '$0.00' );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( firstProductPrice );
} );
test( 'allows customer to calculate Flat rate and Local pickup in cart block if in Portugal', async ( {
page,
} ) => {
await page.goto( pageSlug );
// Set shipping country to Portugal
await page
.locator(
'.wc-block-components-totals-shipping__change-address__link'
)
.click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();
// Verify shipping costs
await expect(
page.getByRole( 'group' ).getByText( 'Flat rate' )
).toBeVisible();
await expect(
page.locator(
'.wc-block-components-totals-shipping > .wc-block-components-totals-item'
)
).toContainText( '$5.00' );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( firstProductWithFlatRate.toString() );
// Set shipping to local pickup instead of flat rate
await page.getByRole( 'group' ).getByText( 'Local pickup' ).click();
// Verify updated shipping costs
await expect(
page.locator(
'.wc-block-components-totals-shipping > .wc-block-components-totals-item'
)
).toContainText( '$0.00' );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( firstProductPrice );
} );
test( 'should show correct total cart block price after updating quantity', async ( {
page,
} ) => {
await page.goto( pageSlug );
// Set shipping country to Portugal
await page
.locator(
'.wc-block-components-totals-shipping__change-address__link'
)
.click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();
// Increase product quantity and verify the updated price
await page
.getByRole( 'button' )
.filter( { hasText: '', exact: true } )
.click();
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( doubleFirstProductWithFlatRate.toString() );
} );
test( 'should show correct total cart block price with 2 different products and flat rate/local pickup', async ( {
page,
} ) => {
await page.goto( `/shop/?add-to-cart=${ product2Id }` );
await page.waitForLoadState( 'networkidle' );
await page.goto( pageSlug );
// Set shipping country to Portugal
await page
.locator(
'.wc-block-components-totals-shipping__change-address__link'
)
.click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();
// Verify shipping costs
await expect(
page.getByRole( 'group' ).getByText( 'Flat rate' )
).toBeVisible();
await expect(
page.locator(
'.wc-block-components-totals-shipping > .wc-block-components-totals-item'
)
).toContainText( '$5.00' );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( twoProductsWithFlatRate.toString() );
// Set shipping to local pickup instead of flat rate
await page.getByRole( 'group' ).getByText( 'Local pickup' ).click();
// Verify updated shipping costs
await expect(
page.locator(
'.wc-block-components-totals-shipping > .wc-block-components-totals-item'
)
).toContainText( '$0.00' );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( twoProductsTotal.toString() );
} );
} );

View File

@ -0,0 +1,768 @@
const { test, expect } = require( '@playwright/test' );
const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
const { admin } = require( '../../test-data/data' );
const productName = 'First Product Cart Block Taxing';
const productPrice = '100.00';
const messyProductPrice = '13.47';
const secondProductName = 'Second Product Cart Block Taxing';
const pageTitle = 'Cart Block';
const pageSlug = pageTitle.replace( / /gi, '-' ).toLowerCase();
let productId,
productId2,
nastyTaxId,
seventeenTaxId,
sixTaxId,
countryTaxId,
stateTaxId,
cityTaxId,
zipTaxId,
shippingTaxId,
shippingZoneId,
shippingMethodId;
test.describe( 'Shopper Cart Block Tax Display', () => {
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'yes',
} );
await api.put( 'settings/tax/woocommerce_tax_round_at_subtotal', {
value: 'no',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'itemized',
} );
await api
.post( 'products', {
name: productName,
type: 'simple',
regular_price: productPrice,
} )
.then( ( response ) => {
productId = response.data.id;
} );
await api
.post( 'taxes', {
country: 'US',
state: '*',
cities: '*',
postcodes: '*',
rate: '25',
name: 'Nasty Tax',
shipping: false,
} )
.then( ( response ) => {
nastyTaxId = response.data.id;
} );
} );
test.beforeEach( async ( { page, context } ) => {
// shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
// all tests use the first product
await page.goto( `/shop/?add-to-cart=${ productId }`, {
waitUntil: 'networkidle',
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'incl',
} );
await api.put( 'settings/tax/woocommerce_price_display_suffix', {
value: '',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'no',
} );
await api.delete( `products/${ productId }`, {
force: true,
} );
await api.delete( `taxes/${ nastyTaxId }`, {
force: true,
} );
} );
test( 'can create Cart Block page', async ( { page } ) => {
// create a new page with cart block
await page.goto( 'wp-admin/post-new.php?post_type=page' );
await page.waitForLoadState( 'networkidle' );
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();
// Close welcome popup if prompted
try {
await page
.getByLabel( 'Close', { exact: true } )
.click( { timeout: 5000 } );
} catch ( error ) {
console.log( "Welcome modal wasn't present, skipping action." );
}
await page
.getByRole( 'textbox', { name: 'Add title' } )
.fill( pageTitle );
await page.getByRole( 'button', { name: 'Add default block' } ).click();
await page
.getByRole( 'document', {
name: 'Empty block; start writing or type forward slash to choose a block',
} )
.fill( '/cart' );
await page.keyboard.press( 'Enter' );
await page
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await page
.getByRole( 'region', { name: 'Editor publish' } )
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await expect(
page.getByText( `${ pageTitle } is now live.` )
).toBeVisible();
} );
test( 'that inclusive tax is displayed properly in Cart Block page', async ( {
page,
} ) => {
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$125.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$125.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item-tax' )
).toHaveText( 'Including $25.00 Nasty Tax' );
} );
test( 'that exclusive tax is displayed properly in Cart Block page', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'excl',
} );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$100.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$125.00' );
await expect(
page.locator( '.wc-block-components-totals-taxes' )
).toContainText( '$25.00' );
} );
} );
test.describe( 'Shopper Cart Block Tax Rounding', () => {
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'yes',
} );
await api
.post( 'products', {
name: productName,
type: 'simple',
regular_price: messyProductPrice,
} )
.then( ( response ) => {
productId = response.data.id;
} );
await api
.post( 'products', {
name: secondProductName,
type: 'simple',
regular_price: messyProductPrice,
} )
.then( ( response ) => {
productId2 = response.data.id;
} );
await api
.post( 'taxes', {
country: 'US',
state: '*',
cities: '*',
postcodes: '*',
rate: '17',
name: 'Seventeen Tax',
shipping: false,
compound: true,
priority: 1,
} )
.then( ( response ) => {
seventeenTaxId = response.data.id;
} );
await api
.post( 'taxes', {
country: 'US',
state: '*',
cities: '*',
postcodes: '*',
rate: '6',
name: 'Six Tax',
shipping: false,
compound: true,
priority: 2,
} )
.then( ( response ) => {
sixTaxId = response.data.id;
} );
} );
test.beforeEach( async ( { page, context } ) => {
// shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
// all tests use the same products
await page.goto( `/shop/?add-to-cart=${ productId }`, {
waitUntil: 'networkidle',
} );
await page.goto( `/shop/?add-to-cart=${ productId2 }`, {
waitUntil: 'networkidle',
} );
await page.goto( `/shop/?add-to-cart=${ productId2 }`, {
waitUntil: 'networkidle',
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'incl',
} );
await api.put( 'settings/tax/woocommerce_tax_round_at_subtotal', {
value: 'no',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'no',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'single',
} );
await api.delete( `products/${ productId }`, {
force: true,
} );
await api.delete( `products/${ productId2 }`, {
force: true,
} );
await api.delete( `taxes/${ seventeenTaxId }`, {
force: true,
} );
await api.delete( `taxes/${ sixTaxId }`, {
force: true,
} );
} );
test( 'that tax rounding is present at subtotal level', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'excl',
} );
await api.put( 'settings/tax/woocommerce_tax_round_at_subtotal', {
value: 'yes',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'single',
} );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$40.41' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$50.12' );
await expect(
page.locator( '.wc-block-components-totals-taxes' )
).toContainText( '$9.71' );
} );
test( 'that tax rounding is off at subtotal level', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'excl',
} );
await api.put( 'settings/tax/woocommerce_tax_round_at_subtotal', {
value: 'no',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'itemized',
} );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$40.41' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$50.12' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$6.87' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$2.84' );
} );
} );
test.describe( 'Shopper Cart Block Tax Levels', () => {
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'yes',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'excl',
} );
// add product
await api
.post( 'products', {
name: productName,
type: 'simple',
regular_price: productPrice,
} )
.then( ( response ) => {
productId = response.data.id;
} );
// create shipping zone
await api
.post( 'shipping/zones', {
name: 'All',
} )
.then( ( response ) => {
shippingZoneId = response.data.id;
} );
// set shipping zone location
await api.put( `shipping/zones/${ shippingZoneId }/locations`, [
{
code: 'US',
},
] );
// set shipping zone method
await api
.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'free_shipping',
} )
.then( ( response ) => {
shippingMethodId = response.data.id;
} );
// confirm that we allow shipping to any country
await api.put( 'settings/general/woocommerce_allowed_countries', {
value: 'all',
} );
await api
.post( 'taxes', {
country: 'US',
state: '*',
cities: '*',
postcodes: '*',
rate: '10',
name: 'Country Tax',
shipping: false,
priority: 1,
} )
.then( ( response ) => {
countryTaxId = response.data.id;
} );
await api
.post( 'taxes', {
country: '*',
state: 'CA',
cities: '*',
postcodes: '*',
rate: '5',
name: 'State Tax',
shipping: false,
priority: 2,
} )
.then( ( response ) => {
stateTaxId = response.data.id;
} );
await api
.post( 'taxes', {
country: '*',
state: '*',
cities: 'Sacramento',
postcodes: '*',
rate: '2.5',
name: 'City Tax',
shipping: false,
priority: 3,
} )
.then( ( response ) => {
cityTaxId = response.data.id;
} );
await api
.post( 'taxes', {
country: '*',
state: '*',
cities: '*',
postcodes: '55555',
rate: '1.25',
name: 'Zip Tax',
shipping: false,
priority: 4,
} )
.then( ( response ) => {
zipTaxId = response.data.id;
} );
} );
test.beforeEach( async ( { page, context } ) => {
// shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
// all tests use the first product
await page.goto( `/shop/?add-to-cart=${ productId }`, {
waitUntil: 'networkidle',
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'single',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'incl',
} );
await api.delete( `products/${ productId }`, {
force: true,
} );
await api.delete( `shipping/zones/${ shippingZoneId }`, {
force: true,
} );
await api.delete( `taxes/${ countryTaxId }`, {
force: true,
} );
await api.delete( `taxes/${ stateTaxId }`, {
force: true,
} );
await api.delete( `taxes/${ cityTaxId }`, {
force: true,
} );
await api.delete( `taxes/${ zipTaxId }`, {
force: true,
} );
} );
test( 'that applying taxes in cart block of 4 different levels calculates properly', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'itemized',
} );
// workaround to fill shipping details since there is an issue with showing
// shipping calculator on the cart block-based experience for logged out user
await page.goto( '/cart/' ); // we will use the old cart for this purpose
await page.locator( '.shipping-calculator-button' ).click();
await page.getByLabel( 'Town / City' ).fill( 'Sacramento' );
await page.getByLabel( 'ZIP Code' ).fill( '55555' );
await page
.getByRole( 'button', { name: 'Update', exact: true } )
.click();
await expect( page.locator( '.woocommerce-info' ) ).toContainText(
'Shipping costs updated.'
);
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$100.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$118.75' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$10.00' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$5.00' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$2.50' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$1.25' );
} );
test( 'that applying taxes in Cart Block of 2 different levels (2 excluded) calculates properly', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_total_display', {
value: 'itemized',
} );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$100.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$115.00' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$10.00' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-taxes-block'
)
).toContainText( '$5.00' );
} );
} );
test.describe( 'Shipping Cart Block Tax', () => {
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'yes',
} );
await api
.post( 'products', {
name: productName,
type: 'simple',
regular_price: productPrice,
} )
.then( ( response ) => {
productId = response.data.id;
} );
await api
.post( 'taxes', {
country: 'US',
state: '*',
cities: '*',
postcodes: '*',
rate: '15',
name: 'Shipping Tax',
shipping: true,
} )
.then( ( response ) => {
shippingTaxId = response.data.id;
} );
await api
.post( 'shipping/zones', {
name: 'All',
} )
.then( ( response ) => {
shippingZoneId = response.data.id;
} );
await api
.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'flat_rate',
} )
.then( ( response ) => {
shippingMethodId = response.data.id;
} );
await api.put(
`shipping/zones/${ shippingZoneId }/methods/${ shippingMethodId }`,
{
settings: {
cost: '20.00',
},
}
);
await api.put( 'payment_gateways/cod', {
enabled: true,
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'incl',
} );
} );
test.beforeEach( async ( { page, context } ) => {
// shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
// all tests use the first product
await page.goto( `/shop/?add-to-cart=${ productId }`, {
waitUntil: 'networkidle',
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/general/woocommerce_calc_taxes', {
value: 'no',
} );
await api.delete( `products/${ productId }`, {
force: true,
} );
await api.delete( `taxes/${ shippingTaxId }`, {
force: true,
} );
await api.put( 'payment_gateways/cod', {
enabled: false,
} );
await api.delete( `shipping/zones/${ shippingZoneId }`, {
force: true,
} );
} );
test( 'that tax is applied in Cart Block to shipping as well as order', async ( {
page,
baseURL,
} ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.put( 'settings/tax/woocommerce_tax_display_cart', {
value: 'incl',
} );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-subtotal-block'
)
).toContainText( '$115.00' );
await expect(
page.locator(
'.wp-block-woocommerce-cart-order-summary-shipping-block'
)
).toContainText( '$23.00' );
await expect(
page.locator( '.wc-block-components-totals-footer-item' )
).toContainText( '$138.00' );
} );
} );

View File

@ -0,0 +1,256 @@
const { test, expect } = require( '@playwright/test' );
const { admin } = require( '../../test-data/data' );
const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
const simpleProductName = 'A Simple Product';
const singleProductFullPrice = '110.00';
const singleProductSalePrice = '55.00';
const coupons = [
{
code: '5fixedcart',
discount_type: 'fixed_cart',
amount: '5.00',
},
{
code: '50percoff',
discount_type: 'percent',
amount: '50',
},
{
code: '10fixedproduct',
discount_type: 'fixed_product',
amount: '10.00',
},
];
const pageTitle = 'Cart Block';
const pageSlug = pageTitle.replace( / /gi, '-' ).toLowerCase();
let product1Id;
test.describe( 'Cart Block Applying Coupons', () => {
const couponBatchId = new Array();
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
// make sure the currency is USD
await api.put( 'settings/general/woocommerce_currency', {
value: 'USD',
} );
// add a product
await api
.post( 'products', {
name: simpleProductName,
type: 'simple',
regular_price: singleProductFullPrice,
sale_price: singleProductSalePrice,
} )
.then( ( response ) => {
product1Id = response.data.id;
} );
// add coupons
await api
.post( 'coupons/batch', {
create: coupons,
} )
.then( ( response ) => {
for ( let i = 0; i < response.data.create.length; i++ ) {
couponBatchId.push( response.data.create[ i ].id );
}
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.post( 'products/batch', {
delete: [ product1Id ],
} );
await api.post( 'coupons/batch', { delete: [ ...couponBatchId ] } );
} );
test.beforeEach( async ( { context } ) => {
// Shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
} );
test( 'can create Cart Block page', async ( { page } ) => {
// create a new page with cart block
await page.goto( 'wp-admin/post-new.php?post_type=page' );
await page.waitForLoadState( 'networkidle' );
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();
// Close welcome popup if prompted
try {
await page
.getByLabel( 'Close', { exact: true } )
.click( { timeout: 5000 } );
} catch ( error ) {
console.log( "Welcome modal wasn't present, skipping action." );
}
await page
.getByRole( 'textbox', { name: 'Add title' } )
.fill( pageTitle );
await page.getByRole( 'button', { name: 'Add default block' } ).click();
await page
.getByRole( 'document', {
name: 'Empty block; start writing or type forward slash to choose a block',
} )
.fill( '/cart' );
await page.keyboard.press( 'Enter' );
await page
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await page
.getByRole( 'region', { name: 'Editor publish' } )
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await expect(
page.getByText( `${ pageTitle } is now live.` )
).toBeVisible();
} );
test( 'allows cart block to apply coupon of any type', async ( {
page,
} ) => {
const totals = [ '$50.00', '$27.50', '$45.00' ];
// add product to cart block
await page.goto( `/shop/?add-to-cart=${ product1Id }` );
await page.waitForLoadState( 'networkidle' );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
// apply all coupon types
for ( let i = 0; i < coupons.length; i++ ) {
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
await page
.locator( '#wc-block-components-totals-coupon__input-0' )
.fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
.locator( '.wc-block-components-notice-banner__content' )
.getByText(
`Coupon code "${ coupons[ i ].code }" has been applied to your cart.`
)
).toBeVisible();
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toHaveText( totals[ i ] );
await page
.getByLabel( `Remove coupon "${ coupons[ i ].code }"` )
.click();
await expect(
page
.locator( '.wc-block-components-notice-banner__content' )
.getByText(
`Coupon code "${ coupons[ i ].code }" has been removed from your cart.`
)
).toBeVisible();
}
} );
test( 'allows cart block to apply multiple coupons', async ( { page } ) => {
const totals = [ '$50.00', '$22.50', '$12.50' ];
const totalsReverse = [ '$17.50', '$45.00', '$55.00' ];
const discounts = [ '-$5.00', '-$32.50', '-$42.50' ];
// add product to cart block
await page.goto( `/shop/?add-to-cart=${ product1Id }` );
await page.waitForLoadState( 'networkidle' );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
// add all coupons and verify prices
for ( let i = 0; i < coupons.length; i++ ) {
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
await page
.locator( '#wc-block-components-totals-coupon__input-0' )
.fill( coupons[ i ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
.locator( '.wc-block-components-notice-banner__content' )
.getByText(
`Coupon code "${ coupons[ i ].code }" has been applied to your cart.`
)
).toBeVisible();
await expect(
page.locator(
'.wc-block-components-totals-discount > .wc-block-components-totals-item__value'
)
).toHaveText( discounts[ i ] );
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toHaveText( totals[ i ] );
}
for ( let i = 0; i < coupons.length; i++ ) {
await page
.getByLabel( `Remove coupon "${ coupons[ i ].code }"` )
.click();
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toHaveText( totalsReverse[ i ] );
}
} );
test( 'prevents cart block applying same coupon twice', async ( {
page,
} ) => {
// add product to cart block
await page.goto( `/shop/?add-to-cart=${ product1Id }` );
await page.waitForLoadState( 'networkidle' );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
// try to add two same coupons and verify the error message
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
await page
.locator( '#wc-block-components-totals-coupon__input-0' )
.fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
.locator( '.wc-block-components-notice-banner__content' )
.getByText(
`Coupon code "${ coupons[ 0 ].code }" has been applied to your cart.`
)
).toBeVisible();
await page.getByRole( 'button', { name: 'Add a coupon' } ).click();
await page
.locator( '#wc-block-components-totals-coupon__input-0' )
.fill( coupons[ 0 ].code );
await page.getByText( 'Apply', { exact: true } ).click();
await expect(
page
.getByRole( 'alert' )
.getByText(
`Coupon code "${ coupons[ 0 ].code }" has already been applied.`
)
).toBeVisible();
} );
} );

View File

@ -0,0 +1,236 @@
const { test, expect } = require( '@playwright/test' );
const { admin } = require( '../../test-data/data' );
const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
const simpleProductName = 'Single Simple Product';
const simpleProductDesc = 'Lorem ipsum dolor sit amet.';
const singleProductFullPrice = '110.00';
const singleProductSalePrice = '55.00';
const firstCrossSellProductPrice = '25.00';
const secondCrossSellProductPrice = '15.00';
const doubleProductsPrice = +singleProductSalePrice * 2;
const singleProductWithCrossSellProducts =
+singleProductFullPrice +
+firstCrossSellProductPrice +
+secondCrossSellProductPrice;
const pageTitle = 'Cart Block';
const pageSlug = pageTitle.replace( / /gi, '-' ).toLowerCase();
let product1Id, product2Id, product3Id;
test.describe( 'Cart Block page', () => {
test.beforeAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
// make sure the currency is USD
await api.put( 'settings/general/woocommerce_currency', {
value: 'USD',
} );
// add 3 products
await api
.post( 'products', {
name: `${ simpleProductName } Cross-Sell 1`,
type: 'simple',
regular_price: firstCrossSellProductPrice,
} )
.then( ( response ) => {
product2Id = response.data.id;
} );
await api
.post( 'products', {
name: `${ simpleProductName } Cross-Sell 2`,
type: 'simple',
regular_price: secondCrossSellProductPrice,
} )
.then( ( response ) => {
product3Id = response.data.id;
} );
await api
.post( 'products', {
name: simpleProductName,
description: simpleProductDesc,
type: 'simple',
regular_price: singleProductFullPrice,
sale_price: singleProductSalePrice,
cross_sell_ids: [ product2Id, product3Id ],
manage_stock: true,
stock_quantity: 2,
} )
.then( ( response ) => {
product1Id = response.data.id;
} );
} );
test.afterAll( async ( { baseURL } ) => {
const api = new wcApi( {
url: baseURL,
consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3',
} );
await api.post( 'products/batch', {
delete: [ product1Id, product2Id, product3Id ],
} );
} );
test.beforeEach( async ( { context } ) => {
// Shopping cart is very sensitive to cookies, so be explicit
await context.clearCookies();
} );
test( 'can see empty cart block', async ( { page } ) => {
// create a new page with cart block
await page.goto( 'wp-admin/post-new.php?post_type=page' );
await page.waitForLoadState( 'networkidle' );
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();
// Close welcome popup if prompted
try {
await page
.getByLabel( 'Close', { exact: true } )
.click( { timeout: 5000 } );
} catch ( error ) {
console.log( "Welcome modal wasn't present, skipping action." );
}
await page
.getByRole( 'textbox', { name: 'Add title' } )
.fill( pageTitle );
await page.getByRole( 'button', { name: 'Add default block' } ).click();
await page
.getByRole( 'document', {
name: 'Empty block; start writing or type forward slash to choose a block',
} )
.fill( '/cart' );
await page.keyboard.press( 'Enter' );
await page
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await page
.getByRole( 'region', { name: 'Editor publish' } )
.getByRole( 'button', { name: 'Publish', exact: true } )
.click();
await expect(
page.getByText( `${ pageTitle } is now live.` )
).toBeVisible();
// go to the page to test empty cart block
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.getByText( 'Your cart is currently empty!' )
).toBeVisible();
await expect(
page.getByRole( 'link', { name: 'Browse store' } )
).toBeVisible();
await page.getByRole( 'link', { name: 'Browse store' } ).click();
await expect(
page.getByRole( 'heading', { name: 'Shop' } )
).toBeVisible();
} );
test( 'can add product to cart block, increase quantity, manage cross-sell products and proceed to checkout', async ( {
page,
} ) => {
// add product to cart block
await page.goto( `/shop/?add-to-cart=${ product1Id }` );
await page.waitForLoadState( 'networkidle' );
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await expect(
page.getByRole( 'link', { name: simpleProductName, exact: true } )
).toBeVisible();
await expect( page.getByText( simpleProductDesc ) ).toBeVisible();
await expect(
page.getByText( `Save $${ singleProductSalePrice }` )
).toBeVisible();
// increase product quantity to its maximum
await expect( page.getByText( '2 left in stock' ) ).toBeVisible();
await page
.getByRole( 'button' )
.filter( { hasText: '', exact: true } )
.click();
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText( `$${ doubleProductsPrice.toString() }` );
await expect(
page.getByRole( 'button' ).filter( { hasText: '', exact: true } )
).toBeDisabled();
// add cross-sell products to cart
await expect(
page.getByRole( 'heading', { name: 'You may be interested in…' } )
).toBeVisible();
await expect(
page.getByRole( 'link', {
name: `${ simpleProductName } Cross-Sell 1`,
exact: true,
} )
).toBeVisible();
await expect(
page.getByRole( 'link', {
name: `${ simpleProductName } Cross-Sell 2`,
exact: true,
} )
).toBeVisible();
await page
.getByRole( 'link', {
name: `${ simpleProductName } Cross-Sell 1`,
exact: true,
} )
.click();
await page.getByRole( 'button', { name: 'Add to cart' } ).click();
await page.goto( pageSlug );
await expect(
page.getByRole( 'heading', { name: pageTitle } )
).toBeVisible();
await page.locator( '.add_to_cart_button' ).click();
await expect(
page.getByRole( 'heading', { name: 'You may be interested in…' } )
).toBeHidden();
await expect(
page.locator(
'.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
)
).toContainText(
`$${ singleProductWithCrossSellProducts.toString() }`
);
// remove cross-sell products from cart
await page.locator( ':nth-match(:text("Remove item"), 3)' ).click();
await page.locator( ':nth-match(:text("Remove item"), 2)' ).click();
await expect(
page.getByRole( 'heading', { name: 'You may be interested in…' } )
).toBeVisible();
// check if the link to proceed to the checkout exists
await expect(
page.getByRole( 'link', {
name: 'Proceed to Checkout',
} )
).toBeVisible();
// remove product from cart
await page.locator( ':text("Remove item")' ).click();
await expect(
page.getByText( 'Your cart is currently empty!' )
).toBeVisible();
await expect(
page.getByRole( 'link', { name: 'Browse store' } )
).toBeVisible();
} );
} );