import { Test, TestingModule } from '@nestjs/testing' import { internet, datatype } from 'faker' import { factory } from '../../../../test/factories' import { MockedModule } from '../../../../test/types' import { BadAuthenticationError, BusinessExceptionError, NotFoundError } from '../../../errors' import { Patient, PaymentProviders, Plan } from '../../../models' import { PatientRepository, PlanRepository, SmartfitUnitRepository } from '../../../repositories' import { AccountService, SubscriptionService } from '../../../services' import { TotemPlan } from '../models' import { Plans } from './plans' describe('Plans', () => { let plans: Plans let patientRepository: MockedModule let accountService: MockedModule let subscriptionService: MockedModule let planRepository: MockedModule let smartfitUnitRepository: MockedModule beforeAll(async () => { patientRepository = { findByLogin: jest.fn(), } subscriptionService = { subscribe: jest.fn(), } planRepository = { get: jest.fn(), findAvailableWithFeatures: jest.fn(), } accountService = { createOrUpdatePatient: jest.fn(), } smartfitUnitRepository = { findByAcronym: jest.fn(), } const app: TestingModule = await Test.createTestingModule({ controllers: [], providers: [ { provide: PatientRepository, useValue: patientRepository, }, { provide: SubscriptionService, useValue: subscriptionService, }, { provide: PlanRepository, useValue: planRepository, }, { provide: AccountService, useValue: accountService, }, { provide: SmartfitUnitRepository, useValue: smartfitUnitRepository, }, Plans, ], }).compile() plans = app.get(Plans) globalThis.secret = { n2b_payments: { enable: false } } as any }) afterEach(() => { jest.resetAllMocks() }) afterAll(() => { jest.restoreAllMocks() }) describe('#getPlans', () => { const countryCode = 'pt_BR' let availablePlans: Plan[] beforeAll(async () => { availablePlans = await factory.buildMany('plan:enabled:visible', datatype.number({ min: 1, max: 10 })) }) describe('when findAvailableWithFeatures throws an error', () => { beforeEach(() => { planRepository.findAvailableWithFeatures.mockRejectedValue(new Error()) }) it('throws an error', async () => { await expect(plans.getPlans({ countryCode })).rejects.toThrowError(Error) }) }) describe('when findAvailableWithFeatures returns an array', () => { beforeEach(() => { planRepository.findAvailableWithFeatures.mockResolvedValue(availablePlans) }) it('returns array mapped to totem plan model', async () => { await expect(plans.getPlans({ countryCode })).resolves.toEqual( availablePlans.map(e => TotemPlan.fromPlan(e, { countryCode, provider: PaymentProviders.SMARTFIT })), ) }) }) }) describe('#subscribe', () => { const login = datatype.uuid() let patient: Patient beforeEach(() => { accountService.createOrUpdatePatient.mockResolvedValue(patient) }) describe('when patient does not exist', () => { beforeAll(() => { patient = null }) it('throws an error', async () => { await expect(() => plans.subscribe(login)).rejects.toThrowError(NotFoundError) }) }) describe('when patient exists', () => { describe('and already is subscribed', () => { beforeAll(() => { patient = factory.build('patient:subscriber', { document_number: login }) }) it('throws an error', async () => { await expect(() => plans.subscribe(login)).rejects.toThrowError(BusinessExceptionError) }) }) describe('and is not subscriber', () => { beforeAll(() => { patient = factory.build('patient', { document_number: login, email: 'jorge@gmail.com' }) }) it('returns masked patient email', async () => { const response = await plans.subscribe(login) expect(response).toEqual('jo***@g****.c**') }) }) }) }) describe('#confirmSubscription', () => { const login = datatype.uuid() const email = internet.email() const plan_id = datatype.uuid() let patient: Patient let plan: Plan beforeAll(async () => { patient = await factory.build('patient', { document_number: login, email }) patientRepository.findByLogin.mockResolvedValue(patient) }) describe('when email isn`t valid', () => { it('throw an error', async () => { const test_email = internet.email() await expect(() => plans.confirmAndSubscribe({ login, email: test_email, plan_id })).rejects.toThrowError( BadAuthenticationError, ) }) }) describe('when email is valid', () => { describe('and patient already is a subscriber', () => { beforeAll(async () => { patient = await factory.build('patient:subscriber', { document_number: login, email }) patientRepository.findByLogin.mockResolvedValue(patient) }) it('returns true and patient name', async () => { expect(await plans.confirmAndSubscribe({ login, email, plan_id })).toEqual( expect.objectContaining({ confirmed: true, patient_name: patient.name }), ) }) }) describe('and patient isn`t a subscriber', () => { beforeAll(async () => { patient = await factory.build('patient', { document_number: login, email }) plan = await factory.build('plan', { payment_providers: await factory.build('plan_payment_provider') }) }) beforeEach(() => { patientRepository.findByLogin.mockResolvedValue(patient) planRepository.get.mockResolvedValue(plan) subscriptionService.subscribe.mockResolvedValue(true) }) it('calls to subscribe', async () => { await plans.confirmAndSubscribe({ login, email, plan_id }) expect(subscriptionService.subscribe).toHaveBeenCalledWith( expect.objectContaining({ patient, plan, paymentProvider: { provider: PaymentProviders.SMARTFIT }, }), ) }) it('returns true', async () => { expect(await plans.confirmAndSubscribe({ login, email, plan_id })).toEqual( expect.objectContaining({ confirmed: true, patient_name: patient.name }), ) }) }) }) }) })