/* eslint-disable @typescript-eslint/no-var-requires */ import { Test, TestingModule } from '@nestjs/testing' import { datatype, date, internet, name, random } from 'faker' import { sample } from 'lodash' import { CardType } from '../../models' import { Secret } from '../../typings/global' import { HttpService } from '../http' import { BillingPeriod, N2BPaymentsProviders } from './enums' import { N2BPaymentsService } from './n2b-payments.service' import { GenerateSubscriptionParams } from './params' jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox()) globalThis.secret = { n2b_payments: { enable: false, endpoint: internet.url(), token: internet.password(), }, } as Secret describe('N2BPaymentsService', () => { const myFetchMock = require('node-fetch') const data = { paymentId: datatype.number({ min: 1, max: 10 }), amount: datatype.number({ min: 1, max: 10 }) } const defaultData = { paymentProvider: N2BPaymentsProviders.INGENICO, waitPaymentCharging: false } const customerData = { name: name.firstName(), country_code: random.locale(), email: internet.email(), document: random.alphaNumeric(), external_id: datatype.uuid(), } const cardData = { token: random.alphaNumeric(), kind: 'credit' as CardType, installments: 1 } let fetchResponse = {} let service: N2BPaymentsService beforeAll(async () => { const app: TestingModule = await Test.createTestingModule({ providers: [N2BPaymentsService, HttpService], }).compile() service = app.get(N2BPaymentsService) myFetchMock.config.overwriteRoutes = true }) afterEach(() => { jest.resetAllMocks() myFetchMock.mockClear() }) afterAll(() => { jest.restoreAllMocks() myFetchMock.mockRestore() }) describe('#sendData', () => { const path = random.word() beforeAll(() => { myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/${path}`, fetchResponse) }) it('fetchs using global endpoint given', async () => { await service['sendData'](data, path) expect(myFetchMock).toHaveBeenCalledWith(`${globalThis.secret.n2b_payments.endpoint}/${path}`, expect.anything()) }) it('fetchs using global token given', async () => { await service['sendData'](data, path) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/${path}`, expect.objectContaining({ headers: expect.objectContaining({ Authorization: `Bearer ${globalThis.secret.n2b_payments.token}` }), }), ) }) it('fetchs requests with POST method', async () => { await service['sendData'](data, path) expect(myFetchMock).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ method: 'POST' })) }) it('sends paymentProvider data', async () => { await service['sendData'](data, path) expect(myFetchMock).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ body: JSON.stringify({ ...data, ...defaultData }), }), ) }) describe('when fetch an status code error', () => { beforeAll(() => { myFetchMock.post({ url: `${globalThis.secret.n2b_payments.endpoint}/${path}` }, 500) }) it('throws an error', async () => { await expect(service['sendData'](data, path)).rejects.toThrowError() }) }) describe('when response body is empty', () => { describe('when status code is success', () => { beforeAll(() => { myFetchMock.post({ url: `${globalThis.secret.n2b_payments.endpoint}/${path}` }, 200) }) it('returns undefined', async () => { await expect(service['sendData'](data, path)).resolves.toBeUndefined() }) }) }) }) describe('#generateSubscription', () => { const params: GenerateSubscriptionParams = { period: sample(Object.values(BillingPeriod)), amount: datatype.number({ min: 1 }), issuedAt: date.future(), externalReferenceId: datatype.uuid(), customer: customerData, card: cardData, installmentsQuantity: 1, } beforeAll(() => { fetchResponse = { id: datatype.uuid() } myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.generateSubscription(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as false', async () => { await service.generateSubscription(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, expect.objectContaining({ body: JSON.stringify({ ...params, ...defaultData, waitPaymentCharging: false }) }), ) }) it('returns subscription data', async () => { await expect(service.generateSubscription(params)).resolves.toEqual({ subscription: fetchResponse, success: true, }) }) }) describe('#generateSubscriptionAndChargePayment', () => { const params = { period: sample(Object.values(BillingPeriod)), amount: datatype.number({ min: 1 }), issuedAt: date.future(), externalReferenceId: datatype.uuid(), customer: customerData, card: cardData, installmentsQuantity: 1, } beforeAll(() => { fetchResponse = { id: datatype.uuid(), invoice: { installments: [] } } }) beforeEach(() => { myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.generateSubscriptionAndChargePayment(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as true', async () => { await service.generateSubscriptionAndChargePayment(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/generate`, expect.objectContaining({ body: JSON.stringify({ ...params, ...defaultData, waitPaymentCharging: true }) }), ) }) it('returns subscription data', async () => { await expect(service.generateSubscriptionAndChargePayment(params)).resolves.toEqual({ subscription: fetchResponse, success: false, }) }) describe('when returns with no payments', () => { beforeAll(() => { fetchResponse = { id: datatype.uuid(), invoice: { installments: [{ payments: [{ amount: 0 }] }] } } }) it('returns success false', async () => { await expect(service.generateSubscriptionAndChargePayment(params)).resolves.toEqual( expect.objectContaining({ success: false, }), ) }) }) describe('when returns with payments', () => { beforeAll(() => { fetchResponse = { id: datatype.uuid(), invoice: { installments: [{ payments: [{ amount: datatype.number({ min: 1 }) }] }] }, } }) it('returns success true', async () => { await expect(service.generateSubscriptionAndChargePayment(params)).resolves.toEqual( expect.objectContaining({ success: true, }), ) }) }) }) describe('#askRefund', () => { const params = { paymentId: datatype.number({ min: 1, max: 10 }), amount: datatype.number({ min: 1 }), } beforeAll(() => { fetchResponse = { id: datatype.uuid() } myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.askRefund(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as false', async () => { await service.askRefund(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, expect.objectContaining({ body: JSON.stringify({ ...params, ...defaultData, waitPaymentCharging: false }) }), ) }) it('returns refund data', async () => { await expect(service.askRefund(params)).resolves.toEqual({ refund: fetchResponse, success: true, }) }) }) describe('#refund', () => { const params = { paymentId: datatype.number({ min: 1, max: 10 }), amount: datatype.number({ min: 1 }), } beforeAll(() => { fetchResponse = { id: datatype.uuid(), amount: 0 } }) beforeEach(() => { myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.refund(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as true', async () => { await service.refund(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/invoice/refund`, expect.objectContaining({ body: JSON.stringify({ ...params, ...defaultData, waitPaymentCharging: true }) }), ) }) it('returns refund data', async () => { await expect(service.refund(params)).resolves.toEqual({ refund: fetchResponse, success: false, }) }) describe('when returns with no amount', () => { beforeAll(() => { fetchResponse = { id: datatype.uuid(), amount: 0 } }) it('returns success false', async () => { await expect(service.refund(params)).resolves.toEqual( expect.objectContaining({ success: false, }), ) }) }) describe('when returns with payments', () => { beforeAll(() => { fetchResponse = { id: datatype.uuid(), amount: datatype.number({ min: 1 }) } }) it('returns success true', async () => { await expect(service.refund(params)).resolves.toEqual( expect.objectContaining({ success: true, }), ) }) }) }) describe('#askCancelSubscription', () => { const params = { subscriptionId: datatype.number({ min: 1, max: 10 }), amountToRefund: datatype.number({ min: 1 }), } beforeAll(() => { fetchResponse = { id: datatype.uuid() } myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/subscription/cancel`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.askCancelSubscription(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/cancel`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as false', async () => { await service.askCancelSubscription(params) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/cancel`, expect.objectContaining({ body: JSON.stringify({ ...params, ...defaultData, waitPaymentCharging: false }) }), ) }) it('returns subscription data', async () => { await expect(service.askCancelSubscription(params)).resolves.toEqual({ subscription: fetchResponse, success: true, }) }) }) describe('#chargeInstallment', () => { let subscriptionId: number let installmentNumber: number beforeAll(() => { subscriptionId = datatype.number() installmentNumber = datatype.number() fetchResponse = { id: datatype.uuid() } myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/subscription/charge-installment`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.chargeInstallment(subscriptionId, installmentNumber) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/charge-installment`, expect.anything(), ) }) it('fetchs with waitPaymentCharging as false', async () => { await service.chargeInstallment(subscriptionId, installmentNumber) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/subscription/charge-installment`, expect.objectContaining({ body: JSON.stringify({ ...{ subscriptionId, installmentNumber }, ...defaultData, waitPaymentCharging: false, }), }), ) }) }) describe('#generateClientSession', () => { const provider = N2BPaymentsProviders.INGENICO beforeAll(() => { fetchResponse = { clientSession: datatype.uuid() } myFetchMock.post(`${globalThis.secret.n2b_payments.endpoint}/payment-providers/${provider}/client-session`, { body: fetchResponse, status: 201, }) }) it('fetchs with correct endpoint', async () => { await service.generateClientSession(provider) expect(myFetchMock).toHaveBeenCalledWith( `${globalThis.secret.n2b_payments.endpoint}/payment-providers/${provider}/client-session`, expect.anything(), ) }) it('returns client session data', async () => { await expect(service.generateClientSession(provider)).resolves.toEqual(fetchResponse['clientSession']) }) }) })