Add new Puppeteer front-end e2e test: cart page

This commit is contained in:
Julia Amosova 2019-09-24 12:56:02 +01:00
parent fc24adce30
commit 409775287e
3 changed files with 322 additions and 1 deletions

View File

@ -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' );
} );
} );

View File

@ -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 };

View File

@ -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 };