import { datatype } from 'faker' import { Test, TestingModule } from '@nestjs/testing' import MockDate from 'mockdate' import { plainToClass } from 'class-transformer' import { MessagingService, ComteleService, AwsService, SmartfitApi, ReporterProcessorService, PushPayload, MailService, } from '../../../services' import { BioimpedanceImportationRepository, CampaignMessageRepository } from '../../../repositories' import { MockedModule } from '../../../../test/types' import { TranslateNotificationsHelper } from '../i18n' import { BIO_FLUTTER_PAGE, FLUTTER_ACTION, Notifications, NOTIFICATION_REPORT_PROCESS_DELAY_IN_HOURS, } from './notifications' describe('Notifications', () => { let notifications: Notifications let messagingService: MockedModule let campaignMessageRepository: MockedModule let comteleService: MockedModule let awsService: MockedModule let smartfitApi: MockedModule let reporterProcessorService: MockedModule let mailService: MockedModule let bioimpedanceImportationRepository: MockedModule beforeAll(async () => { messagingService = { sendPushNotification: jest.fn(), } campaignMessageRepository = { create: jest.fn(), } comteleService = { sendSMS: jest.fn(), isEnabled: jest.fn(), } awsService = { sendSMS: jest.fn(), deleteSQSMessage: jest.fn(), } smartfitApi = { getPersonByLogin: jest.fn(), } reporterProcessorService = { processComteleReport: jest.fn(), } mailService = { send: jest.fn(), } bioimpedanceImportationRepository = { get: jest.fn(), } const translateNotificationsHelper = new TranslateNotificationsHelper() const app: TestingModule = await Test.createTestingModule({ controllers: [], providers: [ { provide: MessagingService, useValue: messagingService, }, { provide: CampaignMessageRepository, useValue: campaignMessageRepository, }, { provide: ComteleService, useValue: comteleService, }, { provide: AwsService, useValue: awsService, }, { provide: SmartfitApi, useValue: smartfitApi, }, { provide: ReporterProcessorService, useValue: reporterProcessorService, }, { provide: MailService, useValue: mailService, }, { provide: BioimpedanceImportationRepository, useValue: bioimpedanceImportationRepository, }, { provide: TranslateNotificationsHelper, useValue: translateNotificationsHelper, }, Notifications, ], }).compile() notifications = app.get(Notifications) }) afterEach(() => { jest.clearAllMocks() }) afterAll(() => { jest.restoreAllMocks() }) describe('#sendMessage', () => { const message: any = { DelaySeconds: 0, msg: 'Msg de teste', type: 'bio_importation_push', additional_data: { device_id: datatype.uuid(), cell_phone: '+5511900000000', document_number: '58002700074', patient_id: datatype.uuid(), }, } it('logs the message', async () => { await notifications.sendMessage(message) expect(campaignMessageRepository.create).toHaveBeenCalled() }) describe('when message is of type bio_importation_push', () => { beforeEach(() => { message.type = 'bio_importation_push' }) it('sends push using messagingService', async () => { await notifications.sendMessage(message) const msgPush: PushPayload = plainToClass(PushPayload, { notification: { title: message.title, body: message.msg, }, data: { click_action: FLUTTER_ACTION, page: BIO_FLUTTER_PAGE, }, }) expect(messagingService.sendPushNotification).toHaveBeenCalledWith(message.additional_data.device_id, msgPush) }) }) describe('when message is of type sms', () => { beforeEach(() => { message.type = 'sms' }) describe('with brazilian country code cell phone', () => { beforeEach(() => { message.additional_data.cell_phone = '+5511900000000' comteleService.isEnabled.mockResolvedValue(true) }) it('sends sms using comtele', async () => { await notifications.sendMessage(message) expect(comteleService.sendSMS).toHaveBeenCalled() }) }) describe('with a not brazilian cell phone', () => { beforeEach(() => { message.additional_data.cell_phone = '+5211900000000' }) it('sends sms using aws', async () => { await notifications.sendMessage(message) expect(awsService.sendSMS).toHaveBeenCalled() }) }) }) describe('when message is of type bio_importation_sms', () => { beforeEach(() => { message.type = 'bio_importation_sms' }) describe('with cell phone', () => { beforeEach(() => { message.additional_data.cell_phone = '+5511900000000' }) it('not get person from smartfit api', async () => { await notifications.sendMessage(message) expect(smartfitApi.getPersonByLogin).not.toHaveBeenCalled() }) }) describe('without cell phone', () => { beforeEach(() => { message.additional_data.cell_phone = '' smartfitApi.getPersonByLogin.mockResolvedValue({ id: datatype.uuid(), email: 'fake@mail.com', name: 'Fake name', phone: '+5511980008888', status: '', birthdate: new Date(), plan: '', photoUrl: '', gender: '', passwordRecoveryUrl: '', paymentMethod: '', mainPurchaseExpiredAt: null, canPurchaseAddon: false, locationAcronym: '', }) comteleService.isEnabled.mockResolvedValue(true) }) it('get person from smartfit api and send sms', async () => { await notifications.sendMessage(message) expect(smartfitApi.getPersonByLogin).toHaveBeenCalled() expect(comteleService.sendSMS).toHaveBeenCalled() }) }) }) }) describe('#deleteMessage', () => { const message: any = { receiptHandle: datatype.uuid(), } it('deletes the message from queue', async () => { await notifications.deleteMessage(message) expect(awsService.deleteSQSMessage).toHaveBeenCalledWith(process.env.NOTIFICATIONS_SQS_URL, message.receiptHandle) }) }) describe('#processNotificationReports', () => { let date: Date const hoursToSubtract = 12 beforeAll(() => { date = new Date() date.setHours(hoursToSubtract, 0, 0, 0) MockDate.set(date) }) afterAll(() => { MockDate.reset() }) it('process Comtele`s reports from 3 hours ago', async () => { await notifications.processNotificationReports() const hours = hoursToSubtract - NOTIFICATION_REPORT_PROCESS_DELAY_IN_HOURS const startDateTime = new Date() startDateTime.setHours(hours) const endDateTime = new Date() endDateTime.setHours(hours, 59, 59, 999) expect(reporterProcessorService.processComteleReport).toHaveBeenCalledWith(startDateTime, endDateTime) }) }) })