Add new Puppeteer front-end e2e test: cart page
This commit is contained in:
parent
fc24adce30
commit
409775287e
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { activatePlugin } from '@wordpress/e2e-test-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createSimpleProduct } from '../../utils/components';
|
||||
import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows';
|
||||
import { uiUnblocked } from '../../utils';
|
||||
|
||||
describe( 'Cart page', () => {
|
||||
beforeAll( async () => {
|
||||
await activatePlugin( 'woocommerce' );
|
||||
await createSimpleProduct();
|
||||
await StoreOwnerFlow.logout();
|
||||
} );
|
||||
|
||||
it( 'should displays no item in the cart', async () => {
|
||||
await CustomerFlow.goToCart();
|
||||
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
|
||||
} );
|
||||
|
||||
it( 'should adds the product to the cart when "Add to cart" is clicked', async () => {
|
||||
await CustomerFlow.goToShop();
|
||||
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
|
||||
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.productIsInCart( 'Simple product' );
|
||||
} );
|
||||
|
||||
it( 'should increases item qty when "Add to cart" of the same product is clicked', async () => {
|
||||
await CustomerFlow.goToShop();
|
||||
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
|
||||
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.productIsInCart( 'Simple product', 2 );
|
||||
} );
|
||||
|
||||
it( 'should updates qty when updated via qty input', async () => {
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.setCartQuantity( 'Simple product', 4 );
|
||||
await expect( page ).toClick( 'button', { text: 'Update cart' } );
|
||||
await uiUnblocked();
|
||||
|
||||
await CustomerFlow.productIsInCart( 'Simple product', 4 );
|
||||
} );
|
||||
|
||||
it( 'should remove the item from the cart when remove is clicked', async () => {
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.removeFromCart( 'Simple product' );
|
||||
await uiUnblocked();
|
||||
|
||||
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
|
||||
} );
|
||||
|
||||
it( 'should update subtotal in cart totals when adding product to the cart', async () => {
|
||||
await CustomerFlow.goToShop();
|
||||
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
|
||||
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.productIsInCart( 'Simple product', 1 );
|
||||
await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$9.99' } );
|
||||
|
||||
await CustomerFlow.setCartQuantity( 'Simple product', 2 );
|
||||
await expect( page ).toClick( 'button', { text: 'Update cart' } );
|
||||
await uiUnblocked();
|
||||
|
||||
await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$19.98' } );
|
||||
} );
|
||||
|
||||
it( 'should go to the checkout page when "Proceed to Checkout" is clicked', async () => {
|
||||
await CustomerFlow.goToCart();
|
||||
await Promise.all( [
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
expect( page ).toClick( '.checkout-button', { text: 'Proceed to checkout' } ),
|
||||
] );
|
||||
|
||||
await expect( page ).toMatchElement( '#order_review' );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from "./flows";
|
||||
import { clickTab, uiUnblocked } from "./index";
|
||||
|
||||
const verifyAndPublish = async () => {
|
||||
// Wait for auto save
|
||||
await page.waitFor( 2000 );
|
||||
|
||||
// Publish product
|
||||
await expect( page ).toClick( '#publish' );
|
||||
await page.waitForSelector( '.updated.notice' );
|
||||
|
||||
// Verify
|
||||
await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Create simple product.
|
||||
*/
|
||||
const createSimpleProduct = async () => {
|
||||
// Go to "add product" page
|
||||
await StoreOwnerFlow.openNewProduct();
|
||||
|
||||
// Make sure we're on the add order page
|
||||
await expect(page.title()).resolves.toMatch('Add new product');
|
||||
|
||||
// Set product data
|
||||
await expect(page).toFill('#title', 'Simple product');
|
||||
await expect(page).toClick('#_virtual');
|
||||
await clickTab('General');
|
||||
await expect(page).toFill('#_regular_price', '9.99');
|
||||
|
||||
await verifyAndPublish();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create variable product.
|
||||
*/
|
||||
const createVariableProduct = async () => {
|
||||
// Go to "add product" page
|
||||
await StoreOwnerFlow.openNewProduct();
|
||||
|
||||
// Make sure we're on the add order page
|
||||
await expect( page.title() ).resolves.toMatch( 'Add new product' );
|
||||
|
||||
// Set product data
|
||||
await expect( page ).toFill( '#title', 'Variable Product with Two Variations' );
|
||||
await expect( page ).toSelect( '#product-type', 'Variable product' );
|
||||
|
||||
// Create attributes for variations
|
||||
await clickTab( 'Attributes' );
|
||||
await expect( page ).toSelect( 'select[name="attribute_taxonomy"]', 'Custom product attribute' );
|
||||
|
||||
for ( let i = 0; i < 3; i++ ) {
|
||||
await expect( page ).toClick( 'button.add_attribute', { text: 'Add' } );
|
||||
// Wait for attribute form to load
|
||||
await uiUnblocked();
|
||||
|
||||
await page.focus( `input[name="attribute_names[${ i }]"]` );
|
||||
await expect( page ).toFill( `input[name="attribute_names[${ i }]"]`, 'attr #' + ( i + 1 ) );
|
||||
await expect( page ).toFill( `textarea[name="attribute_values[${ i }]"]`, 'val1 | val2' );
|
||||
await expect( page ).toClick( `input[name="attribute_variation[${ i }]"]` );
|
||||
}
|
||||
|
||||
await expect( page ).toClick( 'button', { text: 'Save attributes' } );
|
||||
|
||||
// Wait for attribute form to save (triggers 2 UI blocks)
|
||||
await uiUnblocked();
|
||||
await uiUnblocked();
|
||||
|
||||
// Create variations from attributes
|
||||
await clickTab( 'Variations' );
|
||||
await page.waitForSelector( 'select.variation_actions:not([disabled])' );
|
||||
await page.focus( 'select.variation_actions' );
|
||||
await expect( page ).toSelect( 'select.variation_actions', 'Create variations from all attributes' );
|
||||
|
||||
const firstDialog = await expect( page ).toDisplayDialog( async () => {
|
||||
// Using this technique since toClick() isn't working.
|
||||
// See: https://github.com/GoogleChrome/puppeteer/issues/1805#issuecomment-464802876
|
||||
page.$eval( 'a.do_variation_action', elem => elem.click() );
|
||||
|
||||
} );
|
||||
|
||||
expect( firstDialog.message() ).toMatch( 'Are you sure you want to link all variations?' );
|
||||
|
||||
const secondDialog = await expect( page ).toDisplayDialog( async () => {
|
||||
await firstDialog.accept();
|
||||
} );
|
||||
|
||||
expect( secondDialog.message() ).toMatch( '8 variations added' );
|
||||
await secondDialog.dismiss();
|
||||
|
||||
// Set some variation data
|
||||
await uiUnblocked();
|
||||
await uiUnblocked();
|
||||
|
||||
await page.waitForSelector( '.woocommerce_variation .handlediv' );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(1) .handlediv' );
|
||||
await page.focus( 'input[name="variable_is_virtual[0]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_is_virtual[0]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[0]"]', '9.99' );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(2) .handlediv' );
|
||||
await page.focus( 'input[name="variable_is_virtual[1]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_is_virtual[1]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[1]"]', '11.99' );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(3) .handlediv' );
|
||||
await page.focus( 'input[name="variable_manage_stock[2]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_manage_stock[2]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[2]"]', '20' );
|
||||
await expect( page ).toFill( 'input[name="variable_weight[2]"]', '200' );
|
||||
await expect( page ).toFill( 'input[name="variable_length[2]"]', '10' );
|
||||
await expect( page ).toFill( 'input[name="variable_width[2]"]', '20' );
|
||||
await expect( page ).toFill( 'input[name="variable_height[2]"]', '15' );
|
||||
|
||||
await page.focus( 'button.save-variation-changes' );
|
||||
await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } );
|
||||
|
||||
await verifyAndPublish();
|
||||
};
|
||||
|
||||
export { createSimpleProduct };
|
|
@ -2,11 +2,116 @@
|
|||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { pressKeyWithModifier } from '@wordpress/e2e-test-utils';
|
||||
|
||||
const baseUrl = process.env.WP_BASE_URL;
|
||||
|
||||
const WP_ADMIN_NEW_PRODUCT = baseUrl + '/wp-admin/post-new.php?post_type=product';
|
||||
|
||||
const SHOP_PAGE = baseUrl + '/shop/';
|
||||
const SHOP_CART_PAGE = baseUrl + '/cart/';
|
||||
|
||||
const getProductColumnExpression = ( productTitle ) => (
|
||||
'td[@class="product-name" and ' +
|
||||
`a[contains(text(), "${ productTitle }")]` +
|
||||
']'
|
||||
);
|
||||
|
||||
const getQtyColumnExpression = ( args ) => (
|
||||
'td[@class="product-quantity" and ' +
|
||||
'.//' + getQtyInputExpression( args ) +
|
||||
']'
|
||||
);
|
||||
|
||||
const getQtyInputExpression = ( args = {} ) => {
|
||||
let qtyValue = '';
|
||||
|
||||
if ( args.checkQty ) {
|
||||
qtyValue = ` and @value="${ args.qty }"`;
|
||||
}
|
||||
|
||||
return 'input[contains(@class, "input-text")' + qtyValue + ']';
|
||||
};
|
||||
|
||||
const getCartItemExpression = ( productTitle, args ) => (
|
||||
'//tr[contains(@class, "cart_item") and ' +
|
||||
getProductColumnExpression( productTitle ) +
|
||||
' and ' +
|
||||
getQtyColumnExpression( args ) +
|
||||
']'
|
||||
);
|
||||
|
||||
const getRemoveExpression = () => (
|
||||
'td[@class="product-remove"]//a[@class="remove"]'
|
||||
);
|
||||
|
||||
|
||||
const CustomerFlow = {
|
||||
addToCartFromShopPage: async ( productTitle ) => {
|
||||
const addToCartXPath = `//li[contains(@class, "type-product") and a/h2[contains(text(), "${ productTitle }")]]` +
|
||||
'//a[contains(@class, "add_to_cart_button") and contains(@class, "ajax_add_to_cart")';
|
||||
|
||||
const [ addToCartButton ] = await page.$x( addToCartXPath + ']' );
|
||||
addToCartButton.click();
|
||||
|
||||
await page.waitFor( addToCartXPath + ' and contains(@class, "added")]' );
|
||||
},
|
||||
|
||||
removeFromCart: async ( productTitle ) => {
|
||||
const cartItemXPath = getCartItemExpression( productTitle );
|
||||
const removeItemXPath = cartItemXPath + '//' + getRemoveExpression();
|
||||
|
||||
const [ removeButton ] = await page.$x( removeItemXPath );
|
||||
await removeButton.click();
|
||||
},
|
||||
|
||||
goToCart: async () => {
|
||||
await page.goto( SHOP_CART_PAGE, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
goToShop: async () => {
|
||||
await page.goto( SHOP_PAGE, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
productIsInCart: async ( productTitle, quantity = null ) => {
|
||||
const cartItemArgs = quantity ? { qty: quantity } : {};
|
||||
const cartItemXPath = getCartItemExpression( productTitle, cartItemArgs );
|
||||
|
||||
await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 );
|
||||
},
|
||||
|
||||
setCartQuantity: async ( productTitle, quantityValue ) => {
|
||||
const cartItemXPath = getCartItemExpression( productTitle );
|
||||
const quantityInputXPath = cartItemXPath + '//' + getQtyInputExpression();
|
||||
|
||||
const [ quantityInput ] = await page.$x( quantityInputXPath );
|
||||
await quantityInput.focus();
|
||||
await pressKeyWithModifier( 'primary', 'a' );
|
||||
await quantityInput.type( quantityValue.toString() );
|
||||
},
|
||||
};
|
||||
|
||||
const StoreOwnerFlow = {
|
||||
logout: async () => {
|
||||
await page.goto( baseUrl + '/wp-login.php?action=logout', {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
|
||||
await expect( page ).toMatch( 'You are attempting to log out' );
|
||||
|
||||
await Promise.all( [
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
page.click( 'a' ),
|
||||
] );
|
||||
},
|
||||
|
||||
openNewProduct: async () => {
|
||||
await page.goto( WP_ADMIN_NEW_PRODUCT, {
|
||||
waitUntil: 'networkidle0',
|
||||
|
@ -14,4 +119,4 @@ const StoreOwnerFlow = {
|
|||
},
|
||||
};
|
||||
|
||||
export { StoreOwnerFlow };
|
||||
export { CustomerFlow, StoreOwnerFlow };
|
||||
|
|
Loading…
Reference in New Issue