const { couponsApi } = require( '../../endpoints/coupons' ); const { ordersApi } = require( '../../endpoints/orders' ); const { coupon, order } = require( '../../data' ); /** * Tests for the WooCommerce Coupons API. * * @group api * @group coupons * */ describe( 'Coupons API tests', () => { let couponId; it( 'can create a coupon', async () => { const testCoupon = { ...coupon, code: `${ coupon.code }-${ Date.now() }`, }; const response = await couponsApi.create.coupon( testCoupon ); expect( response.statusCode ).toEqual( couponsApi.create.responseCode ); expect( response.body.id ).toBeDefined(); couponId = response.body.id; // Validate the created coupon object has the correct code, amount, and discount type expect( response.body ).toEqual( expect.objectContaining( { code: testCoupon.code, amount: Number( coupon.amount ).toFixed( 2 ), discount_type: coupon.discount_type, } ) ); } ); it( 'can retrieve a coupon', async () => { const response = await couponsApi.retrieve.coupon( couponId ); expect( response.statusCode ).toEqual( couponsApi.retrieve.responseCode ); expect( response.body.id ).toEqual( couponId ); } ); it( 'can update a coupon', async () => { const updatedCouponDetails = { description: '10% off storewide', maximum_amount: '500.00', usage_limit_per_user: 1, free_shipping: true, }; const response = await couponsApi.update.coupon( couponId, updatedCouponDetails ); expect( response.statusCode ).toEqual( couponsApi.update.responseCode ); expect( response.body ).toEqual( expect.objectContaining( updatedCouponDetails ) ); } ); it( 'can permanently delete a coupon', async () => { const response = await couponsApi.delete.coupon( couponId, true ); expect( response.statusCode ).toEqual( couponsApi.delete.responseCode ); const getCouponResponse = await couponsApi.retrieve.coupon( couponId ); expect( getCouponResponse.statusCode ).toEqual( 404 ); } ); describe( 'Batch update coupons', () => { /** * Coupons to be created, updated, and deleted. */ const expectedCoupons = [ { code: `batchcoupon-${ Date.now() }`, discount_type: 'percent', amount: '10', free_shipping: false, }, { code: `batchcoupon-${ Date.now() + 1 }`, discount_type: 'percent', amount: '20', }, ]; it( 'can batch create coupons', async () => { // Batch create 2 new coupons. const batchCreatePayload = { create: expectedCoupons, }; const batchCreateResponse = await couponsApi.batch.coupons( batchCreatePayload ); expect( batchCreateResponse.status ).toEqual( couponsApi.batch.responseCode ); // Verify that the 2 new coupons were created const actualCoupons = batchCreateResponse.body.create; expect( actualCoupons ).toHaveLength( expectedCoupons.length ); for ( let i = 0; i < actualCoupons.length; i++ ) { const { id, code } = actualCoupons[ i ]; const expectedCouponCode = expectedCoupons[ i ].code; expect( id ).toBeDefined(); expect( code ).toEqual( expectedCouponCode ); // Save the coupon id expectedCoupons[ i ].id = id; } } ); it( 'can batch update coupons', async () => { // Update the 1st coupon to free shipping. // Update the amount of the 2nd coupon to 25. const batchUpdatePayload = { update: [ { id: expectedCoupons[ 0 ].id, free_shipping: true, }, { id: expectedCoupons[ 1 ].id, amount: '25.00', }, ], }; const batchUpdateResponse = await couponsApi.batch.coupons( batchUpdatePayload ); // Verify the response code and the number of coupons that were updated. const updatedCoupons = batchUpdateResponse.body.update; expect( batchUpdateResponse.status ).toEqual( couponsApi.batch.responseCode ); expect( updatedCoupons ).toHaveLength( expectedCoupons.length ); // Verify that the 1st coupon was updated to free shipping. expect( updatedCoupons[ 0 ].id ).toEqual( expectedCoupons[ 0 ].id ); expect( updatedCoupons[ 0 ].free_shipping ).toEqual( true ); // Verify that the amount of the 2nd coupon was updated to 25. expect( updatedCoupons[ 1 ].id ).toEqual( expectedCoupons[ 1 ].id ); expect( updatedCoupons[ 1 ].amount ).toEqual( '25.00' ); } ); it( 'can batch delete coupons', async () => { // Batch delete the 2 coupons. const couponIdsToDelete = expectedCoupons.map( ( { id } ) => id ); const batchDeletePayload = { delete: couponIdsToDelete, }; const batchDeleteResponse = await couponsApi.batch.coupons( batchDeletePayload ); // Verify that the response shows the 2 coupons. const deletedCouponIds = batchDeleteResponse.body.delete.map( ( { id } ) => id ); expect( batchDeleteResponse.status ).toEqual( couponsApi.batch.responseCode ); expect( deletedCouponIds ).toEqual( couponIdsToDelete ); // Verify that the 2 deleted coupons cannot be retrieved. for ( const couponId of couponIdsToDelete ) { const { status } = await couponsApi.retrieve.coupon( couponId ); expect( status ).toEqual( 404 ); } } ); } ); describe( 'List coupons', () => { const allCoupons = [ { ...coupon, code: `listcoupons-01-${ Date.now() }`, description: `description-01-${ Date.now() }`, }, { ...coupon, code: `listcoupons-02-${ Date.now() }`, description: `description-02-${ Date.now() }`, }, { ...coupon, code: `listcoupons-03-${ Date.now() }`, description: `description-03-${ Date.now() }`, }, ]; beforeAll( async () => { // Create list of coupons for testing. const response = await couponsApi.batch.coupons( { create: allCoupons, } ); const actualCreatedCoupons = response.body.create; // Save their coupon ID's for ( const coupon of allCoupons ) { const { id } = actualCreatedCoupons.find( ( { code } ) => coupon.code === code ); coupon.id = id; } } ); afterAll( async () => { // Clean up created coupons const batchDeletePayload = { delete: allCoupons.map( ( { id } ) => id ), }; await couponsApi.batch.coupons( batchDeletePayload ); } ); it( 'can list all coupons by default', async () => { const response = await couponsApi.listAll.coupons(); const listedCoupons = response.body; const actualCouponIdsList = listedCoupons.map( ( { id } ) => id ); const expectedCouponIdsList = allCoupons.map( ( { id } ) => id ); expect( response.status ).toEqual( couponsApi.listAll.responseCode ); expect( actualCouponIdsList ).toEqual( expect.arrayContaining( expectedCouponIdsList ) ); } ); it( 'can limit result set to matching code', async () => { const matchingCoupon = allCoupons[ 1 ]; const payload = { code: matchingCoupon.code }; const { status, body } = await couponsApi.listAll.coupons( payload ); expect( status ).toEqual( couponsApi.listAll.responseCode ); expect( body ).toHaveLength( 1 ); expect( body[ 0 ].id ).toEqual( matchingCoupon.id ); } ); it( 'can paginate results', async () => { const pageSize = 2; const payload = { page: 1, per_page: pageSize, }; const { status, body } = await couponsApi.listAll.coupons( payload ); expect( status ).toEqual( couponsApi.listAll.responseCode ); expect( body ).toHaveLength( pageSize ); } ); it( 'can limit results to matching string', async () => { // Search by description const matchingCoupon = allCoupons[ 2 ]; const matchingString = matchingCoupon.description; const payload = { search: matchingString, }; const { status, body } = await couponsApi.listAll.coupons( payload ); expect( status ).toEqual( couponsApi.listAll.responseCode ); expect( body ).toHaveLength( 1 ); expect( body[ 0 ].id ).toEqual( matchingCoupon.id ); } ); } ); describe( 'Add coupon to order', () => { const testCoupon = { code: `coupon-${ Date.now() }`, discount_type: 'percent', amount: '10', }; let orderId; beforeAll( async () => { // Create a coupon const createCouponResponse = await couponsApi.create.coupon( testCoupon ); testCoupon.id = createCouponResponse.body.id; } ); // Clean up created coupon and order afterAll( async () => { await couponsApi.delete.coupon( testCoupon.id, true ); await ordersApi.delete.order( orderId, true ); } ); it( 'can add coupon to an order', async () => { const orderWithCoupon = { ...order, coupon_lines: [ { code: testCoupon.code } ], }; const { status, body } = await ordersApi.create.order( orderWithCoupon ); orderId = body.id; expect( status ).toEqual( ordersApi.create.responseCode ); expect( body.coupon_lines ).toHaveLength( 1 ); expect( body.coupon_lines[ 0 ].code ).toEqual( testCoupon.code ); // Test that the coupon meta data exists. // See: https://github.com/woocommerce/woocommerce/issues/28166. expect( body.coupon_lines[ 0 ].meta_data ).toEqual( expect.arrayContaining( [ expect.objectContaining( { key: 'coupon_data', value: expect.objectContaining( { code: testCoupon.code, } ), } ), ] ) ); } ); } ); } );