/** * External dependencies */ import { setDefaultOptions, getDefaultOptions } from 'expect-puppeteer'; import { default as WooCommerceRestApi } from '@woocommerce/woocommerce-rest-api'; import { SHOP_PAGE, SHOP_CART_PAGE, SHOP_CHECKOUT_PAGE, } from '@woocommerce/e2e-utils'; /** * Internal dependencies */ import { shopper } from '../../../utils'; import { getTextContent } from '../../page-utils'; const block = { name: 'Mini Cart', }; const options = getDefaultOptions(); const clickMiniCartButton = async () => { await page.hover( '.wc-block-mini-cart__button' ); await page.waitForSelector( '.wc-block-mini-cart__drawer.is-loading', { hidden: true, } ); await page.click( '.wc-block-mini-cart__button' ); }; const closeMiniCartDrawer = async () => { await page.keyboard.press( 'Escape' ); }; /** * ConsumerKey and ConsumerSecret are not used, we use basic auth, but * not providing them will throw an error. */ const WooCommerce = new WooCommerceRestApi( { url: `${ process.env.WORDPRESS_BASE_URL }/`, consumerKey: 'consumer_key', consumerSecret: 'consumer_secret', version: 'wc/v3', axiosConfig: { auth: { username: process.env.WORDPRESS_LOGIN, password: process.env.WORDPRESS_PASSWORD, }, }, } ); if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 3 ) { // eslint-disable-next-line jest/no-focused-tests test.only( `skipping ${ block.name } tests`, () => {} ); } describe( 'Shopper → Mini Cart', () => { beforeAll( async () => { /** * Mini Cart takes time to open. Sometimes, on slow machines, 500ms * is not enough. So, we increase the default timeout to 5 seconds. */ setDefaultOptions( { ...options, timeout: 5000 } ); } ); afterAll( async () => { // Reset default options. setDefaultOptions( options ); } ); beforeEach( async () => { await shopper.block.goToBlockPage( block.name ); } ); describe( 'Icon', () => { it( 'Shopper can see the Mini Cart icon and it badge on the front end', async () => { await expect( page ).toMatchElement( '.wc-block-mini-cart' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__quantity-badge' ); // Make sure the initial quantity is 0. await expect( page ).toMatchElement( '.wc-block-mini-cart__amount', { text: '$0', } ); await expect( page ).toMatchElement( '.wc-block-mini-cart__badge', { text: '0', } ); } ); } ); describe( 'Drawer', () => { it( 'The drawer opens when shopper clicks on the mini cart icon', async () => { await clickMiniCartButton(); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); } ); it( 'The drawer closes when shopper clicks on the drawer close button', async () => { await clickMiniCartButton(); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); // Wait for the drawer to fully open. await page.waitForTimeout( 500 ); await page.click( '.wc-block-mini-cart__drawer .components-modal__header button' ); await expect( page ).not.toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); } ); it( 'The drawer closes when shopper clicks outside the drawer', async () => { await clickMiniCartButton(); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); await page.mouse.click( 50, 200 ); await expect( page ).not.toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); } ); } ); describe( 'Empty mini cart', () => { it( 'When the cart is empty, the Mini Cart Drawer show empty cart message and start shopping button', async () => { await clickMiniCartButton(); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Your cart is currently empty!', } ); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Start shopping', } ); const shopLink = await page.$eval( '.wc-block-mini-cart__shopping-button a', ( el ) => el.href ); expect( shopLink ).toMatch( SHOP_PAGE ); } ); } ); describe( 'Filled mini cart', () => { beforeAll( async () => { await shopper.block.emptyCart(); } ); afterEach( async () => { await shopper.block.emptyCart(); } ); it( 'The Mini Cart title shows correct amount', async () => { await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); await closeMiniCartDrawer(); await page.click( '.wc-block-grid__product:last-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (2 items)', } ); } ); it( 'The Mini Cart products table show added products', async () => { const products = await page.$$( '.wc-block-all-products .wc-block-grid__product' ); if ( products.length === 0 ) { throw new Error( 'No products found on the Mini Cart Block page.' ); } // Get a random product to better replicate human behavior. const product = products[ Math.floor( Math.random() * products.length ) ]; const [ productTitle ] = await getTextContent( '.wc-block-components-product-name', product ); const addToCartButton = await product.$( '.add_to_cart_button' ); await addToCartButton.click(); await expect( page ).toMatchElement( '.wc-block-mini-cart__products-table', { text: productTitle, } ); } ); it( 'Filled Mini Cart footer contains subtotal, view cart button, and go to checkout buttons', async () => { await page.click( '.add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart', } ); await expect( page ).toMatchElement( '.wc-block-mini-cart__footer', { text: 'Subtotal', } ); await expect( page ).toMatchElement( '.wc-block-mini-cart__footer-cart', { text: 'View my cart', } ); await expect( page ).toMatchElement( '.wc-block-mini-cart__footer-checkout', { text: 'Go to checkout', } ); } ); } ); describe( 'Update quantity', () => { beforeAll( async () => { await shopper.block.emptyCart(); } ); afterEach( async () => { await shopper.block.emptyCart(); } ); it( 'The quantity of a product can be updated using plus and minus button', async () => { await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); await page.waitForSelector( '.wc-block-components-quantity-selector__button--plus' ); await page.waitForTimeout( 500 ); await page.click( '.wc-block-components-quantity-selector__button--plus' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (2 items)', } ); await page.click( '.wc-block-components-quantity-selector__button--plus' ); await page.click( '.wc-block-components-quantity-selector__button--plus' ); await page.click( '.wc-block-components-quantity-selector__button--plus' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (5 items)', } ); await page.click( '.wc-block-components-quantity-selector__button--minus' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (4 items)', } ); } ); it( 'Minus button is disabled if product quantity is 1', async () => { await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); await page.waitForTimeout( 500 ); expect( await page.$( 'button.wc-block-components-quantity-selector__button--minus[disabled]' ) ).toBeTruthy(); await page.click( '.wc-block-components-quantity-selector__button--plus' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (2 items)', } ); expect( await page.$( 'button.wc-block-components-quantity-selector__button--minus[disabled]' ) ).toBeFalsy(); await page.click( '.wc-block-components-quantity-selector__button--minus' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); expect( await page.$( 'button.wc-block-components-quantity-selector__button--minus[disabled]' ) ).toBeTruthy(); } ); } ); describe( 'Tax included', () => { let taxSettings; beforeAll( async () => { taxSettings = ( await WooCommerce.get( 'settings/tax' ) ).data; /** * Set the tax display settings to show prices including tax during * cart and checkout. The price displayed in the product loop are * tax excluded. */ await WooCommerce.post( 'settings/tax/batch', { update: [ { id: 'woocommerce_tax_display_shop', value: 'excl', }, { id: 'woocommerce_tax_display_cart', value: 'incl', }, ], } ); await shopper.block.emptyCart(); } ); afterAll( async () => { const displayShop = taxSettings.find( ( setting ) => setting.id === 'woocommerce_tax_display_shop' ); const displayCart = taxSettings.find( ( setting ) => setting.id === 'woocommerce_tax_display_cart' ); await WooCommerce.post( 'settings/tax/batch', { update: [ { id: 'woocommerce_tax_display_shop', value: displayShop.value, }, { id: 'woocommerce_tax_display_cart', value: displayCart.value, }, ], } ); await shopper.block.emptyCart(); } ); it( 'Mini Cart show tax label and price including tax', async () => { const [ priceInLoop ] = await getTextContent( '.wc-block-grid__product:first-child .wc-block-grid__product-price' ); await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); await page.waitForSelector( '.wc-block-cart-item__prices' ); const [ priceInCart ] = await getTextContent( '.wc-block-cart-item__prices' ); expect( priceInLoop ).not.toMatch( priceInCart ); await closeMiniCartDrawer(); const [ priceInMiniCartButton ] = await getTextContent( '.wc-block-mini-cart__amount' ); expect( priceInLoop ).not.toMatch( priceInMiniCartButton ); expect( priceInCart ).toMatch( priceInMiniCartButton ); await expect( page ).toMatchElement( '.wc-block-mini-cart__button', { text: '(incl.', } ); } ); } ); describe( 'Remove product', () => { beforeAll( async () => { await shopper.block.emptyCart(); } ); afterAll( async () => { await shopper.block.emptyCart(); } ); it( 'Can remove product from Mini Cart', async () => { await page.click( '.add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__title', { text: 'Your cart (1 item)', } ); await page.waitForTimeout( 500 ); // Ensure the drawer is fully opened. await page.click( '.wc-block-cart-item__remove-link' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__drawer', { text: 'Your cart is currently empty!', } ); } ); } ); describe( 'Cart page', () => { beforeAll( async () => { await shopper.block.emptyCart(); } ); it( 'Can go to cart page from the Mini Cart Footer', async () => { const [ productTitle ] = await getTextContent( '.wc-block-grid__product:first-child .wc-block-components-product-name' ); await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__products-table', { text: productTitle, } ); const cartUrl = await page.$eval( '.wc-block-mini-cart__footer-cart', ( el ) => el.href ); expect( cartUrl ).toMatch( SHOP_CART_PAGE ); await page.goto( cartUrl, { waitUntil: 'networkidle0' } ); await expect( page ).toMatchElement( 'h1', { text: 'Cart' } ); await expect( page ).toMatch( productTitle ); } ); } ); describe( 'Checkout page', () => { beforeAll( async () => { await shopper.block.emptyCart(); } ); it( 'Can go to checkout page from the Mini Cart Footer', async () => { const productTitle = await page.$eval( '.wc-block-grid__product:first-child .wc-block-components-product-name', ( el ) => el.textContent ); await page.click( '.wc-block-grid__product:first-child .add_to_cart_button' ); await expect( page ).toMatchElement( '.wc-block-mini-cart__products-table', { text: productTitle, } ); const checkoutUrl = await page.$eval( '.wc-block-mini-cart__footer-checkout', ( el ) => el.href ); expect( checkoutUrl ).toMatch( SHOP_CHECKOUT_PAGE ); await page.goto( checkoutUrl, { waitUntil: 'networkidle0' } ); await expect( page ).toMatchElement( 'h1', { text: 'Checkout' } ); await expect( page ).toMatch( productTitle ); } ); } ); } );