Commit fda344a4c22 for woocommerce
commit fda344a4c22877c1b5f53a4a1fae21cb95d04a13
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date: Mon Jun 22 12:26:15 2026 +0300
e2e-tests: move coupon discount arithmetic from E2E to PHPUnit and downsize coupons e2e tests (#65873)
testops: move coupon discount arithmetic from E2E to PHPUnit
Coupon type (fixed_cart / percent / fixed_product), duplicate-application
rejection, and removal-restores-total are now asserted in fast PHPUnit
tests. The E2E suites are trimmed to a single wiring smoke-test each:
apply a coupon, assert the success notice and a discount line render.
diff --git a/plugins/woocommerce/changelog/testops-181-coupon-e2e-downgrade-move-discount-arithmetic-to-phpunit b/plugins/woocommerce/changelog/testops-181-coupon-e2e-downgrade-move-discount-arithmetic-to-phpunit
new file mode 100644
index 00000000000..02f60a80404
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-181-coupon-e2e-downgrade-move-discount-arithmetic-to-phpunit
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Move coupon discount-arithmetic coverage from e2e to PHPUnit; reduce coupon cart e2e to a single wiring smoke.
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-block-coupons.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-block-coupons.spec.ts
index 81893ec8295..81a1c2f7602 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-block-coupons.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-block-coupons.spec.ts
@@ -12,31 +12,20 @@ import {
import { expect, tags, test as baseTest } from '../../fixtures/fixtures';
const simpleProductName = 'Cart Coupons 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 coupon = {
+ code: '5fixedcart',
+ discount_type: 'fixed_cart',
+ amount: '5.00',
+};
const couponLimitedCode = '10fixedcartlimited';
const customerBilling = {
email: 'john.doe.merchant.test@example.com',
};
-let productId: number, orderId: number, limitedCouponId: number;
+let productId: number,
+ orderId: number,
+ couponId: number,
+ limitedCouponId: number;
const test = baseTest.extend( {
page: async ( { page }, use ) => {
@@ -50,8 +39,6 @@ test.describe(
'Cart Block Applying Coupons',
{ tag: [ tags.PAYMENTS, tags.SERVICES ] },
() => {
- const couponBatchId: number[] = [];
-
test.beforeAll( async ( { restApi } ) => {
// make sure the currency is USD
await restApi.put(
@@ -65,21 +52,16 @@ test.describe(
.post( `${ WC_API_PATH }/products`, {
name: simpleProductName,
type: 'simple',
- regular_price: singleProductFullPrice,
- sale_price: singleProductSalePrice,
+ regular_price: '110.00',
} )
.then( ( response: { data: { id: number } } ) => {
productId = response.data.id;
} );
- // add coupons
+ // add coupon
await restApi
- .post( `${ WC_API_PATH }/coupons/batch`, {
- create: coupons,
- } )
- .then( ( response: { data: { create: { id: number }[] } } ) => {
- for ( let i = 0; i < response.data.create.length; i++ ) {
- couponBatchId.push( response.data.create[ i ].id );
- }
+ .post( `${ WC_API_PATH }/coupons`, coupon )
+ .then( ( response: { data: { id: number } } ) => {
+ couponId = response.data.id;
} );
// add limited coupon
await restApi
@@ -114,157 +96,38 @@ test.describe(
delete: [ productId ],
} );
await restApi.post( `${ WC_API_PATH }/coupons/batch`, {
- delete: [ ...couponBatchId, limitedCouponId ],
+ delete: [ couponId, limitedCouponId ],
} );
await restApi.post( `${ WC_API_PATH }/orders/batch`, {
delete: [ orderId ],
} );
} );
- test(
- 'allows cart block to apply coupon of any type',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page } ) => {
- const totals = [ '$50.00', '$27.50', '$45.00' ];
-
- // apply all coupon types
- for ( let i = 0; i < coupons.length; i++ ) {
- await page
- .getByRole( 'button', { name: 'Add coupons' } )
- .click();
- await page
- .getByLabel( 'Enter code' )
- .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',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- 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 all coupons and verify prices
- for ( let i = 0; i < coupons.length; i++ ) {
- await page
- .getByRole( 'button', { name: 'Add coupons' } )
- .click();
- await page
- .getByLabel( 'Enter code' )
- .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-notice-banner__content'
- )
- .getByText(
- `Coupon code "${ coupons[ i ].code }" has been removed from your cart.`
- )
- ).toBeVisible();
- await expect(
- page.locator(
- '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value'
- )
- ).toHaveText( totalsReverse[ i ] );
- }
- }
- );
+ test( 'applies a coupon via the cart block form', async ( {
+ page,
+ } ) => {
+ await page.getByRole( 'button', { name: 'Add coupons' } ).click();
+ await page.getByLabel( 'Enter code' ).fill( coupon.code );
+ await page.getByText( 'Apply', { exact: true } ).click();
- test(
- 'prevents cart block applying same coupon twice',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page } ) => {
- // try to add two same coupons and verify the error message
- await page
- .getByRole( 'button', { name: 'Add coupons' } )
- .click();
- await page.getByLabel( 'Enter code' ).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 coupons' } )
- .click();
- await page.getByLabel( 'Enter code' ).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();
- }
- );
+ // The block form is wired end-to-end: success notice renders...
+ await expect(
+ page
+ .locator( '.wc-block-components-notice-banner__content' )
+ .getByText(
+ `Coupon code "${ coupon.code }" has been applied to your cart.`
+ )
+ ).toBeVisible();
+ // ...and a discount line appears. Value is asserted in PHPUnit, not here.
+ await expect(
+ page.locator( '.wc-block-components-totals-discount' )
+ ).toBeVisible();
+ } );
test(
'prevents cart block applying coupon with usage limit',
{ tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
async ( { page } ) => {
- // add coupon with usage limit
await page
.getByRole( 'button', { name: 'Add coupons' } )
.click();
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-checkout-coupons.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-checkout-coupons.spec.ts
index 8b52ade7b93..cf39fd6ddcb 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-checkout-coupons.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/coupons/cart-checkout-coupons.spec.ts
@@ -10,62 +10,38 @@ import {
* Internal dependencies
*/
import { tags, test, expect } from '../../fixtures/fixtures';
-import {
- createClassicCartPage,
- createClassicCheckoutPage,
- CLASSIC_CART_PAGE,
- CLASSIC_CHECKOUT_PAGE,
-} from '../../utils/pages';
+import { createClassicCartPage, CLASSIC_CART_PAGE } from '../../utils/pages';
import { updateIfNeeded } from '../../utils/settings';
const firstProductName = 'Coupon test product';
-const coupons = [
- {
- code: 'fixed-cart-off',
- discount_type: 'fixed_cart',
- amount: '5.00',
- },
- {
- code: 'percent-off',
- discount_type: 'percent',
- amount: '50',
- },
- {
- code: 'fixed-product-off',
- discount_type: 'fixed_product',
- amount: '7.00',
- },
-];
-
-const discounts = [ '$5.00', '$10.00', '$7.00' ];
-const totals = [ '$15.00', '$10.00', '$13.00' ];
+const coupon = {
+ code: 'fixed-cart-off',
+ discount_type: 'fixed_cart',
+ amount: '5.00',
+};
test.describe(
- 'Cart & Checkout applying coupons',
+ 'Cart applying coupons',
{ tag: [ tags.PAYMENTS, tags.SERVICES, tags.HPOS ] },
() => {
let firstProductId: number;
- const couponBatchId: number[] = [];
+ let couponId: number;
test.beforeAll( async ( { restApi } ) => {
- // Make sure the classic cart and checkout pages exist
+ // Make sure the classic cart page exists.
await createClassicCartPage();
- await createClassicCheckoutPage();
await updateIfNeeded( 'general/woocommerce_calc_taxes', 'no' );
- // make sure the currency is USD
+ // Make sure the currency is USD.
await restApi.put(
`${ WC_API_PATH }/settings/general/woocommerce_currency`,
{
value: 'USD',
}
);
- // enable COD
- await restApi.put( `${ WC_API_PATH }/payment_gateways/cod`, {
- enabled: true,
- } );
- // add product
+
+ // Add product.
await restApi
.post( `${ WC_API_PATH }/products`, {
name: firstProductName,
@@ -75,20 +51,17 @@ test.describe(
.then( ( response: { data: { id: number } } ) => {
firstProductId = response.data.id;
} );
- // add coupons
+
+ // Add coupon.
await restApi
- .post( `${ WC_API_PATH }/coupons/batch`, {
- create: coupons,
- } )
- .then( ( response: { data: { create: { id: number }[] } } ) => {
- for ( let i = 0; i < response.data.create.length; i++ ) {
- couponBatchId.push( response.data.create[ i ].id );
- }
+ .post( `${ WC_API_PATH }/coupons`, coupon )
+ .then( ( response: { data: { id: number } } ) => {
+ couponId = response.data.id;
} );
} );
test.beforeEach( async ( { context } ) => {
- // Shopping cart is very sensitive to cookies, so be explicit
+ // Shopping cart is very sensitive to cookies, so be explicit.
await context.clearCookies();
} );
@@ -99,360 +72,36 @@ test.describe(
force: true,
}
);
- await restApi.post( `${ WC_API_PATH }/coupons/batch`, {
- delete: [ ...couponBatchId ],
- } );
- await restApi.put( `${ WC_API_PATH }/payment_gateways/cod`, {
- enabled: false,
+ await restApi.delete( `${ WC_API_PATH }/coupons/${ couponId }`, {
+ force: true,
} );
} );
- for ( let i = 0; i < coupons.length; i++ ) {
- test(
- `allows applying coupon of type ${ coupons[ i ].discount_type }`,
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page, context } ) => {
- await test.step( 'Load cart page and apply coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CART_PAGE.slug );
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ i ].code );
- await page
- .locator( '.blockOverlay' )
- .first()
- .waitFor( { state: 'hidden' } );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
-
- await expect(
- page.getByText(
- 'Coupon code applied successfully.'
- )
- ).toBeVisible();
- // Checks the coupon amount is credited properly
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ i ] } )
- ).toBeVisible();
- // Checks that the cart total is updated
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ i ] } )
- ).toBeVisible();
- } );
-
- await context.clearCookies();
-
- await test.step( 'Load checkout page and apply coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CHECKOUT_PAGE.slug );
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ i ].code );
- await page
- .locator( '.blockOverlay' )
- .first()
- .waitFor( { state: 'hidden' } );
- await page.locator( 'text=Apply coupon' ).click();
-
- await expect(
- page.getByText(
- 'Coupon code applied successfully.'
- )
- ).toBeVisible();
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ i ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ i ] } )
- ).toBeVisible();
- } );
- }
- );
- }
-
- test(
- 'prevents applying same coupon twice',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page, context } ) => {
- await test.step( 'Load cart page and try applying same coupon twice', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CART_PAGE.slug );
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
- // successful first time
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
-
- // try to apply the same coupon
- await page.goto( CLASSIC_CART_PAGE.slug );
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
-
- // error received
- await expect(
- page.getByText(
- `Coupon code "${ coupons[ 0 ].code }" already applied!`
- )
- ).toBeVisible();
- // check cart total
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ 0 ] } )
- ).toBeVisible();
- } );
-
- await context.clearCookies();
-
- await test.step( 'Load checkout page and try applying same coupon twice', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CHECKOUT_PAGE.slug );
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page.locator( 'text=Apply coupon' ).click();
- // successful first time
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
- // try to apply the same coupon
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page.locator( 'text=Apply coupon' ).click();
- // error received
- await expect(
- page.getByText(
- `Coupon code "${ coupons[ 0 ].code }" already applied!`
- )
- ).toBeVisible();
- // check cart total
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ 0 ] } )
- ).toBeVisible();
- } );
- }
- );
-
- test(
- 'allows applying multiple coupons',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page, context } ) => {
- await test.step( 'Load cart page and try applying multiple coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CHECKOUT_PAGE.slug );
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
- // successful
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
-
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 2 ].code );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
- // successful
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
- // check cart total
- await expect(
- page
- .locator( '.cart-discount .amount >> nth=0' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.cart-discount .amount >> nth=1' )
- .filter( { hasText: discounts[ 2 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: '$8.00' } )
- ).toBeVisible();
- } );
-
- await context.clearCookies();
-
- await test.step( 'Load checkout page and try applying multiple coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CHECKOUT_PAGE.slug );
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page.locator( 'text=Apply coupon' ).click();
- // successful
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
-
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 2 ].code );
- await page.locator( 'text=Apply coupon' ).click();
- // successful
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
- // check cart total
- await expect(
- page
- .locator( '.cart-discount .amount >> nth=0' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.cart-discount .amount >> nth=1' )
- .filter( { hasText: discounts[ 2 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: '$8.00' } )
- ).toBeVisible();
- } );
- }
- );
-
- test(
- 'restores total when coupons are removed',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page, context } ) => {
- await test.step( 'Load cart page and try restoring total when removed coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CART_PAGE.slug );
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page
- .getByRole( 'button', { name: 'Apply coupon' } )
- .click();
- await expect(
- page.getByText( 'Coupon code applied successfully.' )
- ).toBeVisible();
-
- // confirm numbers
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ 0 ] } )
- ).toBeVisible();
-
- await page.locator( 'a.woocommerce-remove-coupon' ).click();
-
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: '$20.00' } )
- ).toBeVisible();
- } );
-
- await context.clearCookies();
-
- await test.step( 'Load checkout page and try restoring total when removed coupons', async () => {
- await addAProductToCart( page, firstProductId );
-
- await page.goto( CLASSIC_CHECKOUT_PAGE.slug );
- await page
- .locator( 'text=Click here to enter your code' )
- .click();
- await page
- .locator( '#coupon_code' )
- .fill( coupons[ 0 ].code );
- await page.locator( 'text=Apply coupon' ).click();
-
- // confirm numbers
- await expect(
- page
- .locator( '.cart-discount .amount' )
- .filter( { hasText: discounts[ 0 ] } )
- ).toBeVisible();
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: totals[ 0 ] } )
- ).toBeVisible();
-
- await page.locator( 'a.woocommerce-remove-coupon' ).click();
-
- await expect(
- page
- .locator( '.order-total .amount' )
- .filter( { hasText: '$20.00' } )
- ).toBeVisible();
- } );
- }
- );
+ test( 'applies a coupon via the classic cart form', async ( {
+ page,
+ } ) => {
+ await addAProductToCart( page, firstProductId );
+
+ await page.goto( CLASSIC_CART_PAGE.slug );
+ await page.locator( '#coupon_code' ).fill( coupon.code );
+ await page
+ .locator( '.blockOverlay' )
+ .first()
+ .waitFor( { state: 'hidden' } );
+ await page.getByRole( 'button', { name: 'Apply coupon' } ).click();
+ await page
+ .locator( '.blockOverlay' )
+ .first()
+ .waitFor( { state: 'hidden' } );
+
+ // The form is wired end-to-end: success notice renders...
+ await expect(
+ page.getByText( 'Coupon code applied successfully.' )
+ ).toBeVisible();
+ // ...and a discount line appears. Value is asserted in PHPUnit, not here.
+ await expect(
+ page.locator( '.cart-discount .amount' )
+ ).toBeVisible();
+ } );
}
);
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
index 8ebb39c1309..d0744ab13e6 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
@@ -1416,4 +1416,38 @@ class WC_Cart_Test extends \WC_Unit_Test_Case {
$variation->delete( true );
$product->delete( true );
}
+
+ /**
+ * Applying the same coupon a second time returns false and leaves the discount total unchanged.
+ */
+ public function test_apply_same_coupon_twice_returns_false() {
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ WC()->cart->empty_cart();
+
+ $product = WC_Helper_Product::create_simple_product( true, array( 'regular_price' => 20 ) );
+ $coupon = WC_Helper_Coupon::create_coupon(
+ 'dup-coupon',
+ array(
+ 'discount_type' => 'fixed_cart',
+ 'coupon_amount' => '5',
+ )
+ );
+
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+
+ $first = WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+ $discount_after_first = WC()->cart->get_discount_total();
+
+ $second = WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ $this->assertTrue( $first, 'first application should succeed' );
+ $this->assertFalse( $second, 'second application of same coupon should be rejected' );
+ $this->assertEqualsWithDelta( $discount_after_first, WC()->cart->get_discount_total(), 0.001, 'discount total should be unchanged after rejected re-application' );
+
+ WC()->cart->empty_cart();
+ $product->delete( true );
+ $coupon->delete( true );
+ }
}
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-cart-totals-test.php b/plugins/woocommerce/tests/php/includes/class-wc-cart-totals-test.php
index 6f95c460bdc..0347b9617a1 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-cart-totals-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-cart-totals-test.php
@@ -158,4 +158,124 @@ class WC_Cart_Totals_Tests extends WC_Unit_Test_Case {
$this->assertEquals( '36.99', WC()->cart->get_total( 'edit' ) );
$this->assertEquals( '6.17', WC()->cart->get_total_tax() );
}
+
+ /**
+ * A fixed_cart $5 coupon on a $20 product yields a $5 discount and $15 total.
+ */
+ public function test_fixed_cart_coupon_discounts_cart_total() {
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ WC()->cart->empty_cart();
+
+ $product = WC_Helper_Product::create_simple_product( true, array( 'regular_price' => 20 ) );
+ $coupon = WC_Helper_Coupon::create_coupon(
+ 'fixed-cart-off',
+ array(
+ 'discount_type' => 'fixed_cart',
+ 'coupon_amount' => '5',
+ )
+ );
+
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+ WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ $this->assertEqualsWithDelta( 5.0, WC()->cart->get_discount_total(), 0.001, 'fixed_cart $5 should discount $5' );
+ $this->assertEquals( '15.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ), 'fixed_cart $5 on $20 should total $15' );
+
+ WC()->cart->empty_cart();
+ $product->delete( true );
+ $coupon->delete( true );
+ }
+
+ /**
+ * A percent 50% coupon on a $20 product yields a $10 discount and $10 total.
+ */
+ public function test_percent_coupon_discounts_cart_total() {
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ WC()->cart->empty_cart();
+
+ $product = WC_Helper_Product::create_simple_product( true, array( 'regular_price' => 20 ) );
+ $coupon = WC_Helper_Coupon::create_coupon(
+ 'percent-off',
+ array(
+ 'discount_type' => 'percent',
+ 'coupon_amount' => '50',
+ )
+ );
+
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+ WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ $this->assertEqualsWithDelta( 10.0, WC()->cart->get_discount_total(), 0.001, 'percent 50% should discount $10' );
+ $this->assertEquals( '10.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ), 'percent 50% on $20 should total $10' );
+
+ WC()->cart->empty_cart();
+ $product->delete( true );
+ $coupon->delete( true );
+ }
+
+ /**
+ * A fixed_product $7 coupon on a $20 product yields a $7 discount and $13 total.
+ */
+ public function test_fixed_product_coupon_discounts_cart_total() {
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ WC()->cart->empty_cart();
+
+ $product = WC_Helper_Product::create_simple_product( true, array( 'regular_price' => 20 ) );
+ $coupon = WC_Helper_Coupon::create_coupon(
+ 'fixed-product-off',
+ array(
+ 'discount_type' => 'fixed_product',
+ 'coupon_amount' => '7',
+ )
+ );
+
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+ WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ $this->assertEqualsWithDelta( 7.0, WC()->cart->get_discount_total(), 0.001, 'fixed_product $7 should discount $7' );
+ $this->assertEquals( '13.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ), 'fixed_product $7 on $20 should total $13' );
+
+ WC()->cart->empty_cart();
+ $product->delete( true );
+ $coupon->delete( true );
+ }
+
+ /**
+ * Removing an applied coupon restores the cart to its undiscounted total.
+ */
+ public function test_cart_total_restored_after_coupon_removed() {
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ WC()->cart->empty_cart();
+
+ $product = WC_Helper_Product::create_simple_product( true, array( 'regular_price' => 20 ) );
+ $coupon = WC_Helper_Coupon::create_coupon(
+ 'fixed-cart-restore',
+ array(
+ 'discount_type' => 'fixed_cart',
+ 'coupon_amount' => '5',
+ )
+ );
+
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+ WC()->cart->apply_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ // Sanity: coupon is applied.
+ $this->assertEquals( '15.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ), 'coupon should reduce total to $15' );
+
+ // Act: remove the coupon.
+ WC()->cart->remove_coupon( $coupon->get_code() );
+ WC()->cart->calculate_totals();
+
+ // Assert: total restored to base, discount cleared.
+ $this->assertEqualsWithDelta( 0.0, WC()->cart->get_discount_total(), 0.001, 'discount total should be cleared after removal' );
+ $this->assertEquals( '20.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ), 'total should return to $20 after coupon removed' );
+
+ WC()->cart->empty_cart();
+ $product->delete( true );
+ $coupon->delete( true );
+ }
}