diff --git a/e2e/src/couponsController.spec.ts b/e2e/src/couponsController.spec.ts index 43ef948f..75ab3cda 100644 --- a/e2e/src/couponsController.spec.ts +++ b/e2e/src/couponsController.spec.ts @@ -4,8 +4,12 @@ import { Environment, ProductFamiliesController, ProductFamily, + SubscriptionsController, + ProductsController, } from 'advanced-billing-sdk'; import { createClient, CONFIG } from './config'; +import { product } from './mocks/products'; +import { createMockSubscription } from './mocks/subscriptions'; const couponBody = { coupon: { @@ -35,6 +39,8 @@ describe('Coupons Controller', () => { let productFamily: ProductFamily | null; let couponsController: CouponsController; let invalidCouponsController: CouponsController; + let subscriptionsController: SubscriptionsController; + let productsController: ProductsController; beforeAll(async () => { const client = createClient(); @@ -47,6 +53,8 @@ describe('Coupons Controller', () => { basicAuthPassword: CONFIG.PASSWORD, }); couponsController = new CouponsController(client); + subscriptionsController = new SubscriptionsController(client); + productsController = new ProductsController(client); invalidCouponsController = new CouponsController(invalidClient); const productFamiliesController = new ProductFamiliesController(client); productFamily = @@ -67,6 +75,7 @@ describe('Coupons Controller', () => { { coupon: { ...couponBody.coupon, + code: 'CREATE001', productFamilyId: String(productFamily?.id), }, } @@ -161,13 +170,21 @@ describe('Coupons Controller', () => { describe('Find Coupon', () => { test('should find a coupon when the user sends coupon code', async () => { + await couponsController.createCoupon(productFamily?.id || 0, { + coupon: { + ...couponBody.coupon, + code: 'FIND01', + productFamilyId: String(productFamily?.id), + }, + }); const response = await couponsController.readCouponByCode( productFamily?.id || 0, - '15OFF' + 'FIND01' ); expect(response.statusCode).toBe(200); expect(response.result.coupon?.name).toBe('15% off'); expect(response.result.coupon?.description).toBe('15% off for life'); + expect(response.result.coupon?.code).toBe('FIND01'); }); test('should throw and 404 error when user sends incorrect product code', async () => { @@ -249,4 +266,368 @@ describe('Coupons Controller', () => { }); }); }); + + describe('Update Coupon', () => { + test('should update a coupon when user sends the correct data', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'UPDATE01', + productFamilyId: String(productFamily?.id), + }, + } + ); + const couponId = createReponse.result.coupon?.id || 0; + const payload = { + name: '15% off', + description: '15% off for life', + percentage: 15, + allowNegativeBalance: 'false', + recurring: 'false', + endDate: '2024-08-29T12:00:00-04:00', + productFamilyId: '0', + stackable: 'true', + compoundingStrategy: CompoundingStrategy.Compound, + excludeMidPeriodAllocations: true, + applyOnCancelAtEndOfPeriod: true, + }; + + const code = 'UPDATED' + Date.now(); + const updateResponse = await couponsController.updateCoupon( + productFamily?.id || 0, + couponId, + { + coupon: { + ...payload, + code, + name: 'updated name', + description: 'updated description', + }, + } + ); + + expect(updateResponse.statusCode).toBe(200); + expect(updateResponse.result.coupon?.code).toBe(code); + expect(updateResponse.result.coupon?.name).toBe('updated name'); + expect(updateResponse.result.coupon?.description).toBe( + 'updated description' + ); + }); + + test('should throw and 401 error when user sends invalid credentials', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + productFamilyId: String(productFamily?.id), + }, + } + ); + const couponId = createReponse.result.coupon?.id || 0; + + const promise = invalidCouponsController.updateCoupon( + productFamily?.id || 0, + couponId, + { + coupon: { + ...couponBody.coupon, + code: 'UPDATED' + Date.now(), + name: 'updated name', + description: 'updated description', + }, + } + ); + expect(promise).rejects.toThrow(); + await promise.catch((reason) => { + expect(reason.statusCode).toBe(401); + }); + }); + }); + + describe('Archive Coupon', () => { + test('should delete an existing coupon when user sends a valid coupon id', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'ARCHIVE01', + productFamilyId: String(productFamily?.id), + }, + } + ); + const couponId = createReponse.result.coupon?.id || 0; + const deleteResponse = await couponsController.archiveCoupon( + productFamily?.id || 0, + couponId + ); + + const readResponse = await couponsController.readCoupon( + productFamily?.id || 0, + couponId + ); + + expect(deleteResponse.statusCode).toBe(200); + expect(deleteResponse.result.coupon?.id).toBe(couponId); + expect(readResponse.result.coupon?.archivedAt).not.toBe(null); + }); + + test('should throw and 404 error when user sends incorrect coupon id', async () => { + const promise = couponsController.archiveCoupon( + productFamily?.id || 0, + 1 + ); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(404); + }); + }); + + test('should throw and 401 error when user sends invalid credentials', async () => { + const promise = invalidCouponsController.archiveCoupon( + productFamily?.id || 0, + 1 + ); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(401); + }); + }); + }); + + describe('List all Coupons', () => { + test('should list all the coupons', async () => { + await couponsController.createCoupon(productFamily?.id || 0, { + coupon: { + ...couponBody.coupon, + code: 'LIST002', + productFamilyId: String(productFamily?.id), + }, + }); + const listResponse = await couponsController.listCoupons({ + page: 1, + }); + + expect(listResponse.statusCode).toBe(200); + expect(listResponse.result.length >= 1).toBeTruthy(); + }); + + test('should throw and 401 error when user sends invalid credentials', async () => { + const promise = invalidCouponsController.listCoupons({ page: 1 }); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(401); + }); + }); + }); + + describe('List Coupon Usages', () => { + test('should list the usages coupons ', async () => { + const productResponse = await productsController.createProduct( + productFamily?.id || 0, + { + product: { ...product, handle: 'coupon-handler' }, + } + ); + + const subscriptionBody = createMockSubscription({ + productHandle: 'coupon-handler', + customerReference: 'coupon-reference', + }); + + const subscriptionResponse = ( + await subscriptionsController.createSubscription({ + subscription: subscriptionBody, + }) + ).result; + + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'TEST1', + productFamilyId: String(productFamily?.id), + }, + } + ); + await subscriptionsController.applyCouponToSubscription( + subscriptionResponse?.subscription?.id || 0, + 'TEST1' + ); + + const couponId = createReponse.result.coupon?.id || 0; + const listResponse = await couponsController.readCouponUsage( + productFamily?.id || 0, + couponId + ); + + expect(listResponse.statusCode).toBe(200); + expect(listResponse.result[0].name).toBe( + productResponse.result.product.name + ); + }); + + test('should throw and 404 error when user sends invalid code id', async () => { + const promise = couponsController.readCouponUsage( + productFamily?.id || 0, + 1 + ); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(404); + }); + }); + + test('should throw and 401 error when user sends invalid credentials', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'LIST01', + productFamilyId: String(productFamily?.id), + }, + } + ); + + const couponId = createReponse.result.coupon?.id || 0; + const promise = invalidCouponsController.readCouponUsage( + productFamily?.id || 0, + couponId + ); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(401); + }); + }); + }); + + describe('Validate Coupon', () => { + test('should validate a coupon when user sends a correct id', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'VALIDATE01', + productFamilyId: String(productFamily?.id), + }, + } + ); + const couponCode = createReponse.result.coupon?.code; + const validateResponse = await couponsController.validateCoupon( + couponCode || '' + ); + + expect(validateResponse.statusCode).toBe(200); + expect(validateResponse.result.coupon?.code).toBe(couponCode); + }); + + test('should throw and 404 error when the user sends incorrect coupon code', async () => { + const promise = couponsController.validateCoupon('FRTE21'); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(404); + }); + }); + }); + + describe('Create/Update Currency Prices', () => { + test('should create a valid currency price', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + name: 'CREATE-UPDATE', + code: 'CREATEUPDATE01', + description: '15% off for life', + allowNegativeBalance: 'false', + recurring: 'false', + endDate: '2024-08-29T12:00:00-04:00', + productFamilyId: '0', + stackable: 'true', + compoundingStrategy: CompoundingStrategy.Compound, + excludeMidPeriodAllocations: true, + applyOnCancelAtEndOfPeriod: true, + amountInCents: BigInt(1000), + }, + } + ); + const couponId = createReponse.result.coupon?.id || 0; + + const updateResponse = await couponsController.updateCouponCurrencyPrices( + couponId, + { + currencyPrices: [ + { + currency: 'EUR', + price: 10, + }, + ], + } + ); + + expect(updateResponse.statusCode).toBe(200); + }); + + test('should throw and 401 error when the user sends invalid credentials', async () => { + const promise = invalidCouponsController.updateCouponCurrencyPrices(200, { + currencyPrices: [ + { + currency: 'BS', + price: 100, + }, + ], + }); + + expect(promise).rejects.toThrow(); + await promise.catch((reason) => { + expect(reason.statusCode).toBe(401); + }); + }); + + test('should throw and 422 error when the user sends invalid or missing parameters in the PUT request', async () => { + const createReponse = await couponsController.createCoupon( + productFamily?.id || 0, + { + coupon: { + ...couponBody.coupon, + code: 'test0002', + productFamilyId: String(productFamily?.id), + }, + } + ); + const couponId = createReponse.result.coupon?.id || 0; + const promise = couponsController.updateCouponCurrencyPrices(couponId, { + currencyPrices: [ + { + currency: 'test', + price: 0, + }, + ], + }); + + expect(promise).rejects.toThrow(); + + await promise.catch((reason) => { + expect(reason.statusCode).toBe(422); + }); + }); + }); });