import { Test, TestingModule } from '@nestjs/testing' import { datatype } from 'faker' import Mockdate from 'mockdate' import { factory } from '../../../../test/factories' import { Patient, PaymentProviders, Plan, Subscription, SubscriptionSmartfit } from '../../../models' import { PatientRepository, PlanRepository, SubscriptionRepository, SubscriptionSmartfitRepository, } from '../../../repositories' import { AccountService, SmartfitApi, SubscriptionService } from '../../../services' import { LanguageCountryCode } from '../../../utils/countries' import { MockedModule } from '../../../../test/types' import { Concilliation } from './concilliation' describe('Concilliation', () => { let subject: Concilliation let patientRepository: MockedModule let planRepository: MockedModule let subscriptionRepository: MockedModule let subscriptionSmartfitRepository: MockedModule let smartfitApi: MockedModule let subscriptionService: MockedModule let accountService: MockedModule beforeAll(async () => { patientRepository = { findByDocumentNumber: jest.fn(), updateSubscription: jest.fn(), } planRepository = { get: jest.fn(), findByAddonId: jest.fn(), } subscriptionRepository = { get: jest.fn(), save: jest.fn(), cancel: jest.fn(), create: jest.fn(), } subscriptionSmartfitRepository = { getReport: jest.fn(), } smartfitApi = { getPersonByLogin: jest.fn(), } subscriptionService = { cancelSubscription: jest.fn(), addSubscription: jest.fn(), } accountService = { createPatientIfStudentOrCollaborator: jest.fn(), } const app: TestingModule = await Test.createTestingModule({ controllers: [], providers: [ { provide: PatientRepository, useValue: patientRepository, }, { provide: PlanRepository, useValue: planRepository, }, { provide: SubscriptionRepository, useValue: subscriptionRepository, }, { provide: SubscriptionSmartfitRepository, useValue: subscriptionSmartfitRepository, }, { provide: SmartfitApi, useValue: smartfitApi, }, { provide: SubscriptionService, useValue: subscriptionService, }, { provide: AccountService, useValue: accountService, }, Concilliation, ], }).compile() subject = app.get(Concilliation) }) describe('#getPlan()', () => { let plan: Plan let id: string let result: Plan beforeAll(() => { id = datatype.uuid() }) beforeEach(() => { planRepository.get = jest.fn().mockResolvedValue(plan) }) afterAll(() => { subject['plans'] = {} }) describe('when id does not found', () => { beforeAll(() => { plan = null }) it('throws error', async () => { await expect(subject['getPlan'](id)).rejects.toThrowError(`Plano ${id} não encontrado`) }) }) describe('when get a plan', () => { beforeAll(async () => { plan = await factory.build('plan:smartfit') id = plan.id }) beforeEach(async () => { result = await subject['getPlan'](id) }) describe('when called the first time', () => { it('calls get plan', () => { expect(planRepository.get).toBeCalled() }) it('returns plan', () => { expect(result).toEqual(plan) }) }) describe('when called the second time', () => { it('does not call get plan', () => { expect(planRepository.get).not.toBeCalled() }) it('returns plan', () => { expect(result).toEqual(plan) }) }) }) }) describe('#getPlanByAddonId()', () => { let plan: Plan let id: string let result: Plan beforeAll(() => { id = datatype.uuid() }) beforeEach(() => { planRepository.findByAddonId = jest.fn().mockResolvedValue(plan) }) describe('when addon id does not found', () => { beforeAll(() => { plan = null }) it('throws error', async () => { await expect(subject['getPlanByAddonId'](id)).rejects.toThrowError(`Plano com addon ${id} não encontrado`) }) }) describe('when get a plan', () => { beforeAll(async () => { plan = await factory.build('plan', { payment_providers: [await factory.build('plan_payment_provider:smartfit', { smartfit_id: id })], }) }) beforeEach(async () => { result = await subject['getPlanByAddonId'](id) }) describe('when called the first time', () => { it('calls get plan', () => { expect(planRepository.findByAddonId).toBeCalled() }) it('returns plan', () => { expect(result).toEqual(plan) }) }) describe('when called the second time', () => { it('does not call get plan', () => { expect(planRepository.findByAddonId).not.toBeCalled() }) it('returns plan', () => { expect(result).toEqual(plan) }) }) }) }) describe('#checkIfIsCancelled()', () => { let patient: Patient let addon: SubscriptionSmartfit let plan: Plan describe('when addon is active', () => { beforeAll(async () => { addon = await factory.build('subscription_smartfit:active') }) it('returns false', async () => { await expect(subject['checkIfIsCancelled'](patient, addon)).resolves.toBeFalsy() }) }) describe('when addon is in_cancellation', () => { beforeAll(async () => { addon = await factory.build('subscription_smartfit:in_cancellation') }) describe('when patient is not subscriber', () => { beforeAll(async () => { patient = await factory.build('patient') }) it('returns false', async () => { await expect(subject['checkIfIsCancelled'](patient, addon)).resolves.toBeFalsy() }) }) describe('when patient is subscriber', () => { beforeAll(async () => { patient = await factory.build('patient:subscriber') plan = await factory.build('plan:smartfit') }) beforeEach(() => { planRepository.get = jest.fn().mockResolvedValue(plan) }) describe('when plan is different addon id', () => { it('returns true', async () => { await expect(subject['checkIfIsCancelled'](patient, addon)).resolves.toBeTruthy() }) }) describe('when plan is same addon id', () => { let result: boolean let subscription: Subscription beforeAll(async () => { plan.payment_providers[0].smartfit_id = addon.addonId.toString() subscription = await factory.build('subscription') subscription.trialExpiresAt = null }) beforeEach(async () => { subscriptionRepository.get = jest.fn().mockResolvedValue(subscription) subscriptionRepository.save = jest.fn().mockResolvedValue(null) result = await subject['checkIfIsCancelled'](patient, addon) }) it('cancels subscription', () => { expect(subscriptionRepository.save).toBeCalledWith( expect.objectContaining({ cancellationRequestAt: addon.cancellationRequestedAt, cancellationAt: addon.cancelledAt, trialExpiresAt: addon.trialExpiresAt, }), expect.arrayContaining(['cancellationRequestAt', 'cancellationAt', 'trialExpiresAt']), ) }) it('returns true', () => { expect(result).toBeTruthy() }) }) }) }) }) describe('#checkIfIsActive()', () => { let patient: Patient let addon: SubscriptionSmartfit let plan: Plan beforeAll(async () => { patient = await factory.build('patient') plan = await factory.build('plan:smartfit') }) describe('when addon is in cancellation or cancelled', () => { beforeAll(async () => { addon = await factory.build('subscription_smartfit:cancelled') }) it('returns false', async () => { await expect(subject['checkIfIsActive'](patient, addon)).resolves.toBeFalsy() }) }) describe('when addon is active', () => { let result: boolean beforeAll(async () => { addon = await factory.build('subscription_smartfit:active') subject['plans'] = {} }) beforeEach(async () => { planRepository.get = jest.fn().mockResolvedValue(plan) planRepository.findByAddonId = jest.fn().mockResolvedValue(plan) subscriptionRepository.cancel = jest.fn().mockResolvedValue(null) result = await subject['checkIfIsActive'](patient, addon) }) it('create subscription', () => { expect(subscriptionService.addSubscription).toBeCalledWith({ patient, plan, paymentProvider: { provider: PaymentProviders.SMARTFIT }, data: {}, options: expect.objectContaining({ trialExpiresAt: addon.trialExpiresAt }), }) }) describe('when patient is subscriber', () => { beforeAll(async () => { patient = await factory.build('patient:subscriber') }) describe('when plan is same addon id', () => { beforeAll(() => { plan.payment_providers[0].smartfit_id = addon.addonId.toString() }) it('returns true', () => { expect(result).toBeTruthy() }) }) describe('when plan is different addon id', () => { beforeAll(() => { plan.payment_providers[0].smartfit_id = datatype.uuid() }) it('cancels subscription', () => { expect(subscriptionService.cancelSubscription).toBeCalled() }) it('returns true', () => { expect(result).toBeTruthy() }) }) }) }) }) describe('#run()', () => { const now = new Date() let patient: Patient let addons: SubscriptionSmartfit[] beforeAll(async () => { addons = [await factory.build('subscription_smartfit:active', { countryCode: LanguageCountryCode.PT_BR })] Mockdate.set(now) }) beforeEach(async () => { const plan = await factory.build('plan:smartfit') subscriptionSmartfitRepository.getReport.mockResolvedValue(addons) planRepository.get.mockResolvedValue(plan) planRepository.findByAddonId.mockResolvedValue(plan) patientRepository.findByDocumentNumber.mockResolvedValue(patient) smartfitApi.getPersonByLogin.mockResolvedValue({}) }) afterEach(() => { subscriptionSmartfitRepository.getReport.mockRestore() accountService.createPatientIfStudentOrCollaborator.mockRestore() }) it('finds patient', async () => { await subject.run() expect(patientRepository.findByDocumentNumber).toBeCalled() }) describe('when does not find patient', () => { beforeAll(() => { patient = null }) it('creates patient', async () => { await subject.run() expect(accountService.createPatientIfStudentOrCollaborator).toBeCalled() }) }) describe('when finds patient', () => { beforeAll(async () => { patient = await factory.build('patient') }) it('does not create patient', async () => { await subject.run() expect(accountService.createPatientIfStudentOrCollaborator).not.toBeCalled() }) }) describe('when addon is cancelled', () => { let checkIfIsActiveSpy: jest.SpyInstance beforeEach(() => { subject['checkIfIsCancelled'] = jest.fn().mockResolvedValue(true) checkIfIsActiveSpy = jest.spyOn(subject, 'checkIfIsActive') }) it('does not check if is active', async () => { await subject.run() expect(checkIfIsActiveSpy).not.toBeCalled() }) }) describe('when addon is not cancelled', () => { let checkIfIsActiveSpy: jest.SpyInstance beforeEach(() => { subject['checkIfIsCancelled'] = jest.fn().mockResolvedValue(false) checkIfIsActiveSpy = jest.spyOn(subject, 'checkIfIsActive') }) it('checks if is active', async () => { await subject.run() expect(checkIfIsActiveSpy).toBeCalled() }) }) }) })