Shopper → Checkout → Can apply single-use coupon once (https://github.com/woocommerce/woocommerce-blocks/pull/6174)

* Add "single-use" coupon to the fixture data

* Create a first draft of the coupon e2e test

* Create single use coupon code constant

* Create "applyCouponFromCheckout" function

* Remove the "single-use" coupon from the fixture data

* Setup coupon creation using Woo's Rest API

* Add single-use coupon E2E test

* Move discount XPath definition to the expressions file

* Clean comments

* Remove unnecessary delay function

* Refactor to a more human friendly check

* Clear the setup in the afterAll branch (delete coupon)

Co-authored-by: Saad Tarhi <saad.tarhi@automattic.com>
This commit is contained in:
Saad Tarhi 2022-04-01 23:09:54 +00:00 committed by GitHub
parent eb196226d8
commit c636cb1bbe
3 changed files with 134 additions and 0 deletions

View File

@ -0,0 +1,71 @@
/**
* External dependencies
*/
import { withRestApi } from '@woocommerce/e2e-utils';
/**
* Internal dependencies
*/
import { shopper } from '../../../utils';
import { createCoupon } from '../../utils';
import { SIMPLE_PRODUCT_NAME } from '../../../utils/constants';
if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 )
// eslint-disable-next-line jest/no-focused-tests
test.only( `Skipping checkout tests`, () => {} );
let coupon;
beforeAll( async () => {
coupon = await createCoupon( { usageLimit: 1 } );
await shopper.block.emptyCart();
} );
afterAll( async () => {
await withRestApi.deleteCoupon( coupon.id );
await shopper.block.emptyCart();
} );
describe( 'Shopper → Checkout → Can apply single-use coupon once', () => {
it( 'allows checkout to apply single-use coupon once', async () => {
await shopper.goToShop();
await shopper.addToCartFromShopPage( SIMPLE_PRODUCT_NAME );
await shopper.block.goToCheckout();
await shopper.block.applyCouponFromCheckout( coupon.code );
const discountBlockSelector = '.wc-block-components-totals-discount';
const discountAppliedCouponCodeSelector =
'.wc-block-components-totals-discount__coupon-list-item span.wc-block-components-chip__text';
const discountValueSelector =
'.wc-block-components-totals-discount .wc-block-components-totals-item__value';
// Verify that the discount had been applied correctly on the checkout page.
await page.waitForSelector( discountBlockSelector );
await expect( page ).toMatchElement( discountValueSelector, {
text: coupon.amount,
} );
await expect( page ).toMatchElement(
discountAppliedCouponCodeSelector,
{
text: coupon.code,
}
);
await shopper.block.placeOrder();
await expect( page ).toMatch( 'Your order has been received.' );
// Verify that the discount had been applied correctly on the order confirmation page.
await expect( page ).toMatchElement( `th`, { text: 'Discount' } );
await expect( page ).toMatchElement( `span.woocommerce-Price-amount`, {
text: coupon.amount,
} );
} );
it( 'Prevents checkout applying single-use coupon twice', async () => {
await shopper.goToShop();
await shopper.addToCartFromShopPage( SIMPLE_PRODUCT_NAME );
await shopper.block.goToCheckout();
await shopper.block.applyCouponFromCheckout( coupon.code );
await expect( page ).toMatch( 'Coupon usage limit has been reached.' );
} );
} );

View File

@ -1,6 +1,7 @@
/** /**
* External dependencies * External dependencies
*/ */
import { Coupon, HTTPClientFactory } from '@woocommerce/api';
import config from 'config'; import config from 'config';
import { import {
activateTheme, activateTheme,
@ -29,6 +30,11 @@ import { elementExists, getElementData, getTextContent } from './page-utils';
*/ */
export const BASE_URL = config.get( 'url' ); export const BASE_URL = config.get( 'url' );
export const adminUsername = config.get( 'users.admin.username' );
export const adminPassword = config.get( 'users.admin.password' );
export const client = HTTPClientFactory.build( BASE_URL )
.withBasicAuth( adminUsername, adminPassword )
.create();
export const GUTENBERG_EDITOR_CONTEXT = export const GUTENBERG_EDITOR_CONTEXT =
process.env.GUTENBERG_EDITOR_CONTEXT || 'core'; process.env.GUTENBERG_EDITOR_CONTEXT || 'core';
export const DEFAULT_TIMEOUT = 30000; export const DEFAULT_TIMEOUT = 30000;
@ -352,3 +358,46 @@ export const addBlockToFSEArea = async ( blockName ) => {
); );
await insertButton.click(); await insertButton.click();
}; };
/**
* Creates a basic coupon with the provided coupon amount. Returns the coupon code.
*
* @param {Object} [coupon] Coupon object. Default to fixed cart type and amount = 5.
* @param {string} [coupon.amount] Amount to be applied. Defaults to 5.
* @param {string} [coupon.discountType] Type of a coupon. Defaults to Fixed cart discount.
* @param {number} [coupon.usageLimit] How many times the coupon can be used in total. Defaults to -1.
*/
export const createCoupon = async ( coupon ) => {
const {
amount = '5',
discountType = 'Fixed cart discount',
usageLimit = -1,
} = coupon || { amount: '5', discountType: 'Fixed cart discount' };
let couponType;
switch ( discountType ) {
case 'Fixed cart discount':
couponType = 'fixed_cart';
break;
case 'Fixed product discount':
couponType = 'fixed_product';
break;
case 'Percentage discount':
couponType = 'percent';
break;
default:
couponType = discountType;
}
// Fill in coupon code
const couponCode = 'code-' + couponType + new Date().getTime().toString();
const repository = Coupon.restRepository( client );
const createdCoupon = await repository.create( {
code: couponCode,
discountType: couponType,
amount,
usageLimit,
} );
return createdCoupon;
};

View File

@ -390,6 +390,20 @@ export const shopper = {
await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 ); await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 );
}, },
applyCouponFromCheckout: async ( couponCode ) => {
const couponInputSelector =
'#wc-block-components-totals-coupon__input-0';
const couponApplyButtonSelector =
'.wc-block-components-totals-coupon__button';
const couponExpandButtonSelector =
'.wc-block-components-totals-coupon button';
await expect( page ).toClick( couponExpandButtonSelector );
await expect( page ).toFill( couponInputSelector, couponCode );
await expect( page ).toClick( couponApplyButtonSelector );
await page.waitForNetworkIdle();
},
}, },
isLoggedIn: async () => { isLoggedIn: async () => {