diff --git a/sources/packages/backend/apps/api/src/testHelpers/index.ts b/sources/packages/backend/apps/api/src/testHelpers/index.ts index db1e44250d..82bae832aa 100644 --- a/sources/packages/backend/apps/api/src/testHelpers/index.ts +++ b/sources/packages/backend/apps/api/src/testHelpers/index.ts @@ -3,8 +3,6 @@ export * from "./moked-http-contexts/http-context-mock"; export * from "./moked-http-contexts/reflector-mock"; export * from "./auth/token-helpers"; export * from "./mocked-providers/jwt-service-mock"; -export * from "./mocked-providers/queue-module-mock"; -export * from "./mocked-providers/zeebe-client-mock"; export * from "./testing-modules/testing-modules-helper"; export * from "./auth"; export * from "./fake-entities"; diff --git a/sources/packages/backend/apps/api/src/testHelpers/mocked-providers/queue-module-mock.ts b/sources/packages/backend/apps/api/src/testHelpers/mocked-providers/queue-module-mock.ts deleted file mode 100644 index 8a41aaa521..0000000000 --- a/sources/packages/backend/apps/api/src/testHelpers/mocked-providers/queue-module-mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Global, Module, Provider } from "@nestjs/common"; -import { QueueService } from "@sims/services/queue"; -import { QueueNames } from "@sims/utilities"; - -@Global() -@Module({ - providers: [...getMockedQueueProviders(), QueueService], - exports: [...getMockedQueueProviders(), QueueService], -}) -export class MockedQueueModule {} - -function getMockedQueueProviders(): Provider[] { - return Object.values(QueueNames).map((queue) => ({ - provide: `BullQueue_${queue}`, - useValue: {}, - })); -} diff --git a/sources/packages/backend/apps/api/src/testHelpers/testing-modules/testing-modules-helper.ts b/sources/packages/backend/apps/api/src/testHelpers/testing-modules/testing-modules-helper.ts index 1c0f239b06..9b12596dad 100644 --- a/sources/packages/backend/apps/api/src/testHelpers/testing-modules/testing-modules-helper.ts +++ b/sources/packages/backend/apps/api/src/testHelpers/testing-modules/testing-modules-helper.ts @@ -4,8 +4,13 @@ import { DataSource } from "typeorm"; import { AppModule } from "../../app.module"; import { KeycloakConfig } from "../../auth"; import { setGlobalPipes } from "../../utilities"; -import { MockedQueueModule } from "../mocked-providers/queue-module-mock"; -import { createMockedZeebeModule } from "../mocked-providers/zeebe-client-mock"; +import { + QueueModuleMock, + createZeebeModuleMock, + overrideImportsMetadata, +} from "@sims/test-utils"; +import { QueueModule } from "@sims/services/queue"; +import { ZeebeModule } from "@sims/services"; /** * Result from a createTestingModule to support E2E tests creation. @@ -21,9 +26,20 @@ export class CreateTestingModuleResult { * @returns creation results with objects to support E2E tests. */ export async function createTestingAppModule(): Promise { + overrideImportsMetadata( + AppModule, + { + replace: QueueModule, + by: QueueModuleMock, + }, + { + replace: ZeebeModule, + by: createZeebeModuleMock(), + }, + ); await KeycloakConfig.load(); const module: TestingModule = await Test.createTestingModule({ - imports: [AppModule, createMockedZeebeModule(), MockedQueueModule], + imports: [AppModule], }).compile(); const nestApplication = module.createNestApplication(); setGlobalPipes(nestApplication); diff --git a/sources/packages/backend/apps/api/test/auth.e2e-spec.ts b/sources/packages/backend/apps/api/test/auth.e2e-spec.ts index 1cb2797e7f..885fc5dfd1 100644 --- a/sources/packages/backend/apps/api/test/auth.e2e-spec.ts +++ b/sources/packages/backend/apps/api/test/auth.e2e-spec.ts @@ -9,7 +9,7 @@ import { } from "../src/utilities/certificate-utils"; import { AuthTestController } from "../src/testHelpers/controllers/auth-test/auth-test.controller"; import { KeycloakService } from "../src/services/auth/keycloak/keycloak.service"; -import { createMockedZeebeModule } from "../src/testHelpers/mocked-providers/zeebe-client-mock"; +import { createZeebeModuleMock } from "@sims/test-utils"; describe("Authentication (e2e)", () => { // Nest application to be shared for all e2e tests @@ -41,7 +41,7 @@ describe("Authentication (e2e)", () => { aestAccessToken = aestToken.access_token; const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule, createMockedZeebeModule()], + imports: [AppModule, createZeebeModuleMock()], // AuthTestController is used only for e2e tests and could be // changed as needed to implement more test scenarios. controllers: [AuthTestController], diff --git a/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/cancel-application-assessment.processor.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/cancel-application-assessment.processor.e2e-spec.ts new file mode 100644 index 0000000000..64b41c22c7 --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/cancel-application-assessment.processor.e2e-spec.ts @@ -0,0 +1,195 @@ +import { ZBClient } from "zeebe-node"; +import { Job } from "bull"; +import { createMock } from "@golevelup/ts-jest"; +import { INestApplication } from "@nestjs/common"; +import { CancelAssessmentQueueInDTO } from "@sims/services/queue"; +import { QueueNames } from "@sims/utilities"; +import { + createTestingAppModule, + describeProcessorRootTest, +} from "../../../../test/helpers"; +import { CancelApplicationAssessmentProcessor } from "../cancel-application-assessment.processor"; +import { DataSource, Repository } from "typeorm"; +import { + createFakeDisbursementOveraward, + saveFakeApplicationDisbursements, +} from "@sims/test-utils"; +import { + ApplicationStatus, + DisbursementOveraward, + DisbursementSchedule, + DisbursementScheduleStatus, + StudentAssessment, +} from "@sims/sims-db"; +import * as faker from "faker"; + +describe( + describeProcessorRootTest(QueueNames.CancelApplicationAssessment), + () => { + let app: INestApplication; + let processor: CancelApplicationAssessmentProcessor; + let zbClientMock: ZBClient; + let appDataSource: DataSource; + let studentAssessmentRepo: Repository; + let disbursementOverawardRepo: Repository; + let disbursementScheduleRepo: Repository; + + beforeAll(async () => { + const { nestApplication, dataSource, zbClient } = + await createTestingAppModule(); + app = nestApplication; + zbClientMock = zbClient; + appDataSource = dataSource; + studentAssessmentRepo = dataSource.getRepository(StudentAssessment); + disbursementOverawardRepo = dataSource.getRepository( + DisbursementOveraward, + ); + disbursementScheduleRepo = dataSource.getRepository(DisbursementSchedule); + // Processor under test. + processor = app.get(CancelApplicationAssessmentProcessor); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it("Should cancel the assessment pending disbursements and rollback overawards when the cancelled application has overawards and also one sent and one pending disbursements.", async () => { + // Arrange + const workflowInstanceId = faker.random + .number({ + min: 1000000000, + max: 9999999999, + }) + .toString(); + // Application and disbursements. + const application = await saveFakeApplicationDisbursements( + appDataSource, + null, + { + applicationStatus: ApplicationStatus.Cancelled, + createSecondDisbursement: true, + }, + ); + // Adjust assessment. + const studentAssessment = application.currentAssessment; + studentAssessment.assessmentWorkflowId = workflowInstanceId; + await studentAssessmentRepo.save(application.currentAssessment); + // Adjust disbursements. + const [firstDisbursement, secondDisbursement] = + studentAssessment.disbursementSchedules; + firstDisbursement.disbursementScheduleStatus = + DisbursementScheduleStatus.Sent; + await disbursementScheduleRepo.save(firstDisbursement); + // Add a student overaward. + const overaward = createFakeDisbursementOveraward({ + student: application.student, + studentAssessment, + }); + await disbursementOverawardRepo.save(overaward); + // Queued job. + const job = createMock>({ + data: { assessmentId: studentAssessment.id }, + }); + + // Act + const result = await processor.cancelAssessment(job); + + // Assert + expect(zbClientMock.cancelProcessInstance).toBeCalledWith( + workflowInstanceId, + ); + expect(result.summary).toStrictEqual([ + `Cancelling application assessment id ${studentAssessment.id}`, + `Found workflow id ${workflowInstanceId}.`, + "Workflow instance successfully cancelled.", + "Rolling back overawards, if any.", + "Assessment cancelled with success.", + ]); + + // Assert that overawards were soft deleted. + const updatedOveraward = await disbursementOverawardRepo.findOne({ + where: { id: overaward.id }, + withDeleted: true, + }); + expect(updatedOveraward.deletedAt).toBeDefined(); + + // Assert sent disbursement was not affected. + const firstDisbursementUpdated = await disbursementScheduleRepo.findOneBy( + { id: firstDisbursement.id }, + ); + expect(firstDisbursementUpdated.disbursementScheduleStatus).toBe( + DisbursementScheduleStatus.Sent, + ); + + // Assert pending disbursement was cancelled. + const secondDisbursementUpdated = + await disbursementScheduleRepo.findOneBy({ id: secondDisbursement.id }); + expect(secondDisbursementUpdated.disbursementScheduleStatus).toBe( + DisbursementScheduleStatus.Cancelled, + ); + }); + + it("Should cancel the assessment and log a warning when the workflowInstanceId is not present.", async () => { + // Arrange + const application = await saveFakeApplicationDisbursements( + appDataSource, + null, + { applicationStatus: ApplicationStatus.Overwritten }, + ); + const studentAssessment = application.currentAssessment; + // Queued job. + const job = createMock>({ + data: { assessmentId: studentAssessment.id }, + }); + + // Act + const result = await processor.cancelAssessment(job); + + // Assert + expect(zbClientMock.cancelProcessInstance).not.toHaveBeenCalled(); + expect(result.warnings).toContain( + "Assessment was queued to be cancelled but there is no workflow id associated with.", + ); + expect(result.summary).toContain("Assessment cancelled with success."); + }); + + it("Should throw an error and call job.discard when the application is not in the expected status.", async () => { + // Arrange + const errorMessage = `Application must be in the ${ApplicationStatus.Cancelled} or ${ApplicationStatus.Overwritten} state to have the assessment cancelled.`; + const expectedError = new Error(errorMessage); + const application = await saveFakeApplicationDisbursements( + appDataSource, + null, + { applicationStatus: ApplicationStatus.Completed }, + ); + const studentAssessment = application.currentAssessment; + // Queued job. + const job = createMock>({ + data: { assessmentId: studentAssessment.id }, + }); + + // Act and Assert + await expect(processor.cancelAssessment(job)).rejects.toStrictEqual( + expectedError, + ); + expect(job.discard).toBeCalled(); + }); + + it("Should throw an error and call job.discard when the assessment id was not found.", async () => { + // Arrange + const assessmentId = 9999; + const errorMessage = `Assessment id ${assessmentId} was not found.`; + const error = new Error(errorMessage); + // Queued job. + const job = createMock>({ + data: { assessmentId }, + }); + + // Act and Assert + await expect(processor.cancelAssessment(job)).rejects.toStrictEqual( + error, + ); + expect(job.discard).toBeCalled(); + }); + }, +); diff --git a/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/start-application-assessment.processor.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/start-application-assessment.processor.e2e-spec.ts new file mode 100644 index 0000000000..c821c80627 --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/src/processors/assessment/_tests_/start-application-assessment.processor.e2e-spec.ts @@ -0,0 +1,67 @@ +import { ZBClient } from "zeebe-node"; +import { Job } from "bull"; +import { createMock } from "@golevelup/ts-jest"; +import { INestApplication } from "@nestjs/common"; +import { StartApplicationAssessmentProcessor } from "../start-application-assessment.processor"; +import { StartAssessmentQueueInDTO } from "@sims/services/queue"; +import { QueueNames } from "@sims/utilities"; +import { + createTestingAppModule, + describeProcessorRootTest, +} from "../../../../test/helpers"; + +describe( + describeProcessorRootTest(QueueNames.StartApplicationAssessment), + () => { + let app: INestApplication; + let processor: StartApplicationAssessmentProcessor; + let zbClientMock: ZBClient; + + beforeAll(async () => { + const { nestApplication, zbClient } = await createTestingAppModule(); + app = nestApplication; + zbClientMock = zbClient; + // Processor under test. + processor = app.get(StartApplicationAssessmentProcessor); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it("Should throw an error when the workflow createProcessInstance method throws an error.", async () => { + // Arrange + const dummyException = new Error("Dummy error"); + const job = createMock>(); + zbClientMock.createProcessInstance = jest.fn().mockImplementation(() => { + throw dummyException; + }); + + // Act and Assert. + await expect(processor.startAssessment(job)).rejects.toBe(dummyException); + }); + + it("Should invoke the workflow create instance method with the received job parameters.", async () => { + // Arrange + const workflowName = "dummy workflow name"; + const assessmentId = 999; + const variables = { assessmentId }; + // Queued job. + const job = createMock>({ + data: { + workflowName, + assessmentId, + }, + }); + + // Act + await processor.startAssessment(job); + + // Assert + expect(zbClientMock.createProcessInstance).toHaveBeenCalledWith( + workflowName, + variables, + ); + }); + }, +); diff --git a/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/ecert-full-time-process-integration.scheduler.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/ecert-full-time-process-integration.scheduler.e2e-spec.ts new file mode 100644 index 0000000000..437e8c903b --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/ecert-full-time-process-integration.scheduler.e2e-spec.ts @@ -0,0 +1,266 @@ +import { + Application, + ApplicationStatus, + Assessment, + COEStatus, + DisbursementOveraward, + DisbursementOverawardOriginType, + DisbursementSchedule, + DisbursementScheduleStatus, + DisbursementValue, + DisbursementValueType, + EducationProgramOffering, + MSFAANumber, + OfferingIntensity, + Student, + StudentAssessment, + User, +} from "@sims/sims-db"; +import { + createFakeApplication, + createFakeDisbursementOveraward, + createFakeDisbursementSchedule, + createFakeDisbursementValue, + createFakeEducationProgramOffering, + createFakeMSFAANumber, + createFakeStudent, + createFakeStudentAssessment, + createFakeUser, +} from "@sims/test-utils"; +import { createFakeSINValidation } from "@sims/test-utils/factories/sin-validation"; +import { IsNull, Not, Repository } from "typeorm"; +import { + createTestingAppModule, + describeQueueProcessorRootTest, +} from "../../../../../../test/helpers"; +import { INestApplication } from "@nestjs/common"; +import { QueueNames } from "@sims/utilities"; +import { FullTimeECertProcessIntegrationScheduler } from "../ecert-full-time-process-integration.scheduler"; +import { createMock } from "@golevelup/ts-jest"; +import { Job } from "bull"; + +describe( + describeQueueProcessorRootTest(QueueNames.FullTimeECertIntegration), + () => { + let app: INestApplication; + let processor: FullTimeECertProcessIntegrationScheduler; + let userRepo: Repository; + let studentRepo: Repository; + let applicationRepo: Repository; + let studentAssessmentRepo: Repository; + let educationProgramOfferingRepo: Repository; + let msfaaNumberRepo: Repository; + let disbursementOverawardRepo: Repository; + let disbursementScheduleRepo: Repository; + let disbursementValueRepo: Repository; + + beforeAll(async () => { + const { nestApplication, dataSource } = await createTestingAppModule(); + app = nestApplication; + userRepo = dataSource.getRepository(User); + studentRepo = dataSource.getRepository(Student); + applicationRepo = dataSource.getRepository(Application); + studentAssessmentRepo = dataSource.getRepository(StudentAssessment); + educationProgramOfferingRepo = dataSource.getRepository( + EducationProgramOffering, + ); + msfaaNumberRepo = dataSource.getRepository(MSFAANumber); + disbursementOverawardRepo = dataSource.getRepository( + DisbursementOveraward, + ); + disbursementScheduleRepo = dataSource.getRepository(DisbursementSchedule); + disbursementValueRepo = dataSource.getRepository(DisbursementValue); + // Processor under test. + processor = app.get(FullTimeECertProcessIntegrationScheduler); + }); + + it("Should execute overawards deductions and calculate awards effective value", async () => { + // Arrange + + // User + const savedUser = await userRepo.save(createFakeUser()); + // Student. + const savedStudent = await studentRepo.save(createFakeStudent(savedUser)); + // Student SIN Validation + savedStudent.sinValidation = createFakeSINValidation({ + student: savedStudent, + }); + await studentRepo.save(savedStudent); + // MSFAA Number. + const savedMSFAANumber = await msfaaNumberRepo.save( + createFakeMSFAANumber({ student: savedStudent }), + ); + // Create and save application. + const fakeApplication = createFakeApplication({ student: savedStudent }); + const savedApplication = await applicationRepo.save(fakeApplication); + // Original assessment. + const fakeOriginalAssessment = createFakeStudentAssessment({ + auditUser: savedUser, + }); + // Weeks are needed for the e-Cert generation but does not matter for this test. + fakeOriginalAssessment.assessmentData = { weeks: 5 } as Assessment; + fakeOriginalAssessment.application = savedApplication; + // Original assessment - first disbursement. + const firstSchedule = createFakeDisbursementSchedule({ + auditUser: savedUser, + disbursementValues: [ + createFakeDisbursementValue( + DisbursementValueType.CanadaLoan, + "CSLF", + 5000, + { disbursedAmountSubtracted: 1000 }, + ), + createFakeDisbursementValue( + DisbursementValueType.BCLoan, + "BCSL", + 4000, + { disbursedAmountSubtracted: 500 }, + ), + createFakeDisbursementValue( + DisbursementValueType.CanadaGrant, + "CSGP", + 2000, + ), + createFakeDisbursementValue( + DisbursementValueType.BCGrant, + "BCAG", + 1500, + { disbursedAmountSubtracted: 500 }, + ), + createFakeDisbursementValue( + DisbursementValueType.BCGrant, + "BGPD", + 2500, + ), + ], + }); + firstSchedule.coeStatus = COEStatus.completed; + firstSchedule.disbursementScheduleStatus = + DisbursementScheduleStatus.Pending; + firstSchedule.msfaaNumber = savedMSFAANumber; + fakeOriginalAssessment.disbursementSchedules = [firstSchedule]; + // Offering. + const fakeOffering = createFakeEducationProgramOffering({ + auditUser: savedUser, + }); + fakeOffering.offeringIntensity = OfferingIntensity.fullTime; + const savedOffering = await educationProgramOfferingRepo.save( + fakeOffering, + ); + fakeOriginalAssessment.offering = savedOffering; + const savedOriginalAssessment = await studentAssessmentRepo.save( + fakeOriginalAssessment, + ); + savedApplication.currentAssessment = savedOriginalAssessment; + savedApplication.applicationStatus = ApplicationStatus.Completed; + await applicationRepo.save(savedApplication); + // Create fake overawards. + const fakeCanadaLoanOverawardBalance = createFakeDisbursementOveraward({ + student: savedStudent, + }); + fakeCanadaLoanOverawardBalance.disbursementValueCode = "CSLF"; + fakeCanadaLoanOverawardBalance.overawardValue = 4500; + await disbursementOverawardRepo.save(fakeCanadaLoanOverawardBalance); + // Queued job. + // id and name defined to make the console log looks better only. + const job = createMock>({ + id: "FakeJobId", + name: "FakeJobName", + }); + + // Act + const result = await processor.processFullTimeECert(job); + + // Assert + + // Assert Canada Loan overawards were deducted. + const hasCanadaLoanOverawardDeduction = + await disbursementOverawardRepo.exist({ + where: { + student: { + id: savedStudent.id, + }, + overawardValue: -4000, + disbursementValueCode: "CSLF", + originType: DisbursementOverawardOriginType.AwardDeducted, + }, + }); + expect(hasCanadaLoanOverawardDeduction).toBe(true); + + // Assert schedule is updated to 'sent' with the dateSent defined. + const scheduleIsSent = await disbursementScheduleRepo.exist({ + where: { + id: firstSchedule.id, + dateSent: Not(IsNull()), + disbursementScheduleStatus: DisbursementScheduleStatus.Sent, + }, + }); + expect(scheduleIsSent).toBe(true); + + // Assert awards + + // Select all awards generated for the schedule. + const awards = await disbursementValueRepo.find({ + where: { disbursementSchedule: { id: firstSchedule.id } }, + }); + // Assert CSLF. + const hasExpectedCSLF = awards.filter( + (award) => + award.valueCode === "CSLF" && + award.disbursedAmountSubtracted === 1000 && + award.overawardAmountSubtracted === 4000 && + award.effectiveAmount === 0, + ); + expect(hasExpectedCSLF.length).toBe(1); + // Assert BCSL. + const hasExpectedBCSL = awards.filter( + (award) => + award.valueCode === "BCSL" && + award.disbursedAmountSubtracted === 500 && + !award.overawardAmountSubtracted && + award.effectiveAmount === 3500, + ); + expect(hasExpectedBCSL.length).toBe(1); + // Assert CSGP. + const hasExpectedCSGP = awards.filter( + (award) => + award.valueCode === "CSGP" && + !award.disbursedAmountSubtracted && + !award.overawardAmountSubtracted && + award.effectiveAmount === 2000, + ); + expect(hasExpectedCSGP.length).toBe(1); + // Assert BCAG. + const hasExpectedBCAG = awards.filter( + (award) => + award.valueCode === "BCAG" && + award.disbursedAmountSubtracted === 500 && + !award.overawardAmountSubtracted && + award.effectiveAmount === 1000, + ); + expect(hasExpectedBCAG.length).toBe(1); + // Assert BGPD. + const hasExpectedBGPD = awards.filter( + (award) => + award.valueCode === "BGPD" && + !award.disbursedAmountSubtracted && + !award.overawardAmountSubtracted && + award.effectiveAmount === 2500, + ); + expect(hasExpectedBGPD.length).toBe(1); + // The BC total grant (BCSG) will be generated and + // inserted during the e-Cert process. + const hasExpectedBCSG = awards.filter( + (award) => + award.valueCode === "BCSG" && + !award.disbursedAmountSubtracted && + !award.overawardAmountSubtracted && + award.effectiveAmount === 3500, + ); + expect(hasExpectedBCSG.length).toBe(1); + // At least one file must be generated. + expect(result.generatedFile).toBeTruthy(); + expect(result.uploadedRecords).toBeGreaterThanOrEqual(1); + }); + }, +); diff --git a/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/tests/ecert-full-time-process-integration.scheduler.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/tests/ecert-full-time-process-integration.scheduler.e2e-spec.ts deleted file mode 100644 index f2dc1c9e3b..0000000000 --- a/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/tests/ecert-full-time-process-integration.scheduler.e2e-spec.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { ECertFileHandler } from "@sims/integrations/esdc-integration"; -import { SshService } from "@sims/integrations/services"; -import { - Application, - ApplicationStatus, - Assessment, - COEStatus, - DisbursementOveraward, - DisbursementOverawardOriginType, - DisbursementSchedule, - DisbursementScheduleStatus, - DisbursementValue, - DisbursementValueType, - EducationProgramOffering, - MSFAANumber, - OfferingIntensity, - Student, - StudentAssessment, - User, -} from "@sims/sims-db"; -import { - createFakeApplication, - createFakeDisbursementOveraward, - createFakeDisbursementSchedule, - createFakeDisbursementValue, - createFakeEducationProgramOffering, - createFakeMSFAANumber, - createFakeStudent, - createFakeStudentAssessment, - createFakeUser, -} from "@sims/test-utils"; -import { createFakeSINValidation } from "@sims/test-utils/factories/sin-validation"; -import sshServiceMock from "@sims/test-utils/mocks/ssh-service.mock"; -import { DataSource, IsNull, Not, Repository } from "typeorm"; -import { QueueConsumersModule } from "../../../../../queue-consumers.module"; - -describe("Schedulers - e-Cert full time integration - Create e-Cert file", () => { - let eCertFileHandler: ECertFileHandler; - let userRepo: Repository; - let studentRepo: Repository; - let applicationRepo: Repository; - let studentAssessmentRepo: Repository; - let educationProgramOfferingRepo: Repository; - let msfaaNumberRepo: Repository; - let disbursementOverawardRepo: Repository; - let disbursementScheduleRepo: Repository; - let disbursementValueRepo: Repository; - - beforeAll(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [QueueConsumersModule], - }) - .overrideProvider(SshService) - .useValue(sshServiceMock) - .compile(); - const app = moduleFixture.createNestApplication(); - await app.init(); - - const dataSource = app.get(DataSource); - eCertFileHandler = app.get(ECertFileHandler); - userRepo = dataSource.getRepository(User); - studentRepo = dataSource.getRepository(Student); - applicationRepo = dataSource.getRepository(Application); - studentAssessmentRepo = dataSource.getRepository(StudentAssessment); - educationProgramOfferingRepo = dataSource.getRepository( - EducationProgramOffering, - ); - msfaaNumberRepo = dataSource.getRepository(MSFAANumber); - disbursementOverawardRepo = dataSource.getRepository(DisbursementOveraward); - disbursementScheduleRepo = dataSource.getRepository(DisbursementSchedule); - disbursementValueRepo = dataSource.getRepository(DisbursementValue); - }); - - it("Should execute overawards deductions and calculate awards effective value", async () => { - // Arrange - - // User - const savedUser = await userRepo.save(createFakeUser()); - // Student. - const savedStudent = await studentRepo.save(createFakeStudent(savedUser)); - // Student SIN Validation - savedStudent.sinValidation = createFakeSINValidation({ - student: savedStudent, - }); - await studentRepo.save(savedStudent); - // MSFAA Number. - const savedMSFAANumber = await msfaaNumberRepo.save( - createFakeMSFAANumber({ student: savedStudent }), - ); - // Create and save application. - const fakeApplication = createFakeApplication({ student: savedStudent }); - fakeApplication.applicationNumber = "ECERT_TEST"; - const savedApplication = await applicationRepo.save(fakeApplication); - // Original assessment. - const fakeOriginalAssessment = createFakeStudentAssessment({ - auditUser: savedUser, - }); - // Weeks are needed for the e-Cert generation but does not matter for this test. - fakeOriginalAssessment.assessmentData = { weeks: 5 } as Assessment; - fakeOriginalAssessment.application = savedApplication; - // Original assessment - first disbursement. - const firstSchedule = createFakeDisbursementSchedule({ - auditUser: savedUser, - disbursementValues: [ - createFakeDisbursementValue( - DisbursementValueType.CanadaLoan, - "CSLF", - 5000, - { disbursedAmountSubtracted: 1000 }, - ), - createFakeDisbursementValue( - DisbursementValueType.BCLoan, - "BCSL", - 4000, - { disbursedAmountSubtracted: 500 }, - ), - createFakeDisbursementValue( - DisbursementValueType.CanadaGrant, - "CSGP", - 2000, - ), - createFakeDisbursementValue( - DisbursementValueType.BCGrant, - "BCAG", - 1500, - { disbursedAmountSubtracted: 500 }, - ), - createFakeDisbursementValue( - DisbursementValueType.BCGrant, - "BGPD", - 2500, - ), - ], - }); - firstSchedule.coeStatus = COEStatus.completed; - firstSchedule.disbursementScheduleStatus = - DisbursementScheduleStatus.Pending; - firstSchedule.msfaaNumber = savedMSFAANumber; - fakeOriginalAssessment.disbursementSchedules = [firstSchedule]; - // Offering. - const fakeOffering = createFakeEducationProgramOffering({ - auditUser: savedUser, - }); - fakeOffering.offeringIntensity = OfferingIntensity.fullTime; - const savedOffering = await educationProgramOfferingRepo.save(fakeOffering); - fakeOriginalAssessment.offering = savedOffering; - const savedOriginalAssessment = await studentAssessmentRepo.save( - fakeOriginalAssessment, - ); - savedApplication.currentAssessment = savedOriginalAssessment; - savedApplication.applicationStatus = ApplicationStatus.Completed; - await applicationRepo.save(savedApplication); - // Create fake overawards. - const fakeCanadaLoanOverawardBalance = createFakeDisbursementOveraward({ - student: savedStudent, - }); - fakeCanadaLoanOverawardBalance.disbursementValueCode = "CSLF"; - fakeCanadaLoanOverawardBalance.overawardValue = 4500; - await disbursementOverawardRepo.save(fakeCanadaLoanOverawardBalance); - - // Act - const eCertResult = await eCertFileHandler.generateFullTimeECert(); - - // Assert - - // Assert Canada Loan overawards were deducted. - const hasCanadaLoanOverawardDeduction = - await disbursementOverawardRepo.exist({ - where: { - student: { - id: savedStudent.id, - }, - overawardValue: -4000, - disbursementValueCode: "CSLF", - originType: DisbursementOverawardOriginType.AwardDeducted, - }, - }); - expect(hasCanadaLoanOverawardDeduction).toBe(true); - - // Assert schedule is updated to 'sent' with the dateSent defined. - const scheduleIsSent = await disbursementScheduleRepo.exist({ - where: { - id: firstSchedule.id, - dateSent: Not(IsNull()), - disbursementScheduleStatus: DisbursementScheduleStatus.Sent, - }, - }); - expect(scheduleIsSent).toBe(true); - - // Assert awards - - // Select all awards generated for the schedule. - const awards = await disbursementValueRepo.find({ - where: { disbursementSchedule: { id: firstSchedule.id } }, - }); - // Assert CSLF. - const hasExpectedCSLF = awards.filter( - (award) => - award.valueCode === "CSLF" && - award.disbursedAmountSubtracted === 1000 && - award.overawardAmountSubtracted === 4000 && - award.effectiveAmount === 0, - ); - expect(hasExpectedCSLF.length).toBe(1); - // Assert BCSL. - const hasExpectedBCSL = awards.filter( - (award) => - award.valueCode === "BCSL" && - award.disbursedAmountSubtracted === 500 && - !award.overawardAmountSubtracted && - award.effectiveAmount === 3500, - ); - expect(hasExpectedBCSL.length).toBe(1); - // Assert CSGP. - const hasExpectedCSGP = awards.filter( - (award) => - award.valueCode === "CSGP" && - !award.disbursedAmountSubtracted && - !award.overawardAmountSubtracted && - award.effectiveAmount === 2000, - ); - expect(hasExpectedCSGP.length).toBe(1); - // Assert BCAG. - const hasExpectedBCAG = awards.filter( - (award) => - award.valueCode === "BCAG" && - award.disbursedAmountSubtracted === 500 && - !award.overawardAmountSubtracted && - award.effectiveAmount === 1000, - ); - expect(hasExpectedBCAG.length).toBe(1); - // Assert BGPD. - const hasExpectedBGPD = awards.filter( - (award) => - award.valueCode === "BGPD" && - !award.disbursedAmountSubtracted && - !award.overawardAmountSubtracted && - award.effectiveAmount === 2500, - ); - expect(hasExpectedBGPD.length).toBe(1); - // The BC total grant (BCSG) will be generated and - // inserted during the e-Cert process. - const hasExpectedBCSG = awards.filter( - (award) => - award.valueCode === "BCSG" && - !award.disbursedAmountSubtracted && - !award.overawardAmountSubtracted && - award.effectiveAmount === 3500, - ); - expect(hasExpectedBCSG.length).toBe(1); - // At least one file must be generated. - expect(eCertResult.generatedFile).toBeTruthy(); - expect(eCertResult.uploadedRecords).toBeGreaterThanOrEqual(1); - }); -}); diff --git a/sources/packages/backend/apps/queue-consumers/test/app.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/test/app.e2e-spec.ts deleted file mode 100644 index d9a4b2ab19..0000000000 --- a/sources/packages/backend/apps/queue-consumers/test/app.e2e-spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication } from "@nestjs/common"; -import { QueueConsumersModule } from "../src/queue-consumers.module"; - -describe("QueueConsumersModule (e2e)", () => { - let app: INestApplication; - - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [QueueConsumersModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); - }); - - it("Should be able to initialize queue-consumers module", () => { - expect(app).toBeDefined(); - }); -}); diff --git a/sources/packages/backend/apps/queue-consumers/test/helpers/index.ts b/sources/packages/backend/apps/queue-consumers/test/helpers/index.ts new file mode 100644 index 0000000000..e7dd000f55 --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/test/helpers/index.ts @@ -0,0 +1,2 @@ +export * from "./testing-modules/testing-modules-helper"; +export * from "./test-describe-helpers"; diff --git a/sources/packages/backend/apps/queue-consumers/test/helpers/test-describe-helpers.ts b/sources/packages/backend/apps/queue-consumers/test/helpers/test-describe-helpers.ts new file mode 100644 index 0000000000..011aee2433 --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/test/helpers/test-describe-helpers.ts @@ -0,0 +1,19 @@ +import { QueueNames } from "@sims/utilities"; + +/** + * Creates a common E2E test description for queue processors. + * @param queueName queue name related to the E2E test. + * @returns E2E test description. + */ +export function describeProcessorRootTest(queueName: QueueNames) { + return `Queue processor for ${queueName},`; +} + +/** + * Creates a common E2E test description for a scheduler queue processors. + * @param queueName queue name related to the E2E test. + * @returns E2E test description. + */ +export function describeQueueProcessorRootTest(queueName: QueueNames) { + return `Scheduler queue processor for ${queueName}.`; +} diff --git a/sources/packages/backend/apps/queue-consumers/test/helpers/testing-modules/testing-modules-helper.ts b/sources/packages/backend/apps/queue-consumers/test/helpers/testing-modules/testing-modules-helper.ts new file mode 100644 index 0000000000..f373ef5b0b --- /dev/null +++ b/sources/packages/backend/apps/queue-consumers/test/helpers/testing-modules/testing-modules-helper.ts @@ -0,0 +1,64 @@ +import { INestApplication } from "@nestjs/common"; +import { Test, TestingModule } from "@nestjs/testing"; +import { DataSource } from "typeorm"; +import { QueueConsumersModule } from "../../../src/queue-consumers.module"; +import { createZeebeModuleMock } from "@sims/test-utils/mocks/zeebe-client-mock"; +import { ZBClient } from "zeebe-node"; +import { SshService } from "@sims/integrations/services"; +import { + QueueModuleMock, + createSSHServiceMock, + overrideImportsMetadata, +} from "@sims/test-utils"; +import * as Client from "ssh2-sftp-client"; +import { createMock } from "@golevelup/ts-jest"; +import { QueueModule } from "@sims/services/queue"; +import { ZeebeModule } from "@sims/services"; + +/** + * Result from a createTestingModule to support E2E tests creation. + */ +export class CreateTestingModuleResult { + nestApplication: INestApplication; + module: TestingModule; + dataSource: DataSource; + zbClient: ZBClient; + sshClientMock: Client; +} + +/** + * Created the Queue Consumers root module needed to perform the E2E tests. + * @returns creation results with objects to support E2E tests. + */ +export async function createTestingAppModule(): Promise { + overrideImportsMetadata( + QueueConsumersModule, + { + replace: QueueModule, + by: QueueModuleMock, + }, + { + replace: ZeebeModule, + by: createZeebeModuleMock(), + }, + ); + const sshClientMock = createMock(); + const module: TestingModule = await Test.createTestingModule({ + imports: [QueueConsumersModule], + }) + .overrideProvider(SshService) + .useValue(createSSHServiceMock(sshClientMock)) + .compile(); + + const nestApplication = module.createNestApplication(); + await nestApplication.init(); + const dataSource = module.get(DataSource); + const zbClient = nestApplication.get(ZBClient); + return { + nestApplication, + module, + dataSource, + zbClient, + sshClientMock, + }; +} diff --git a/sources/packages/backend/apps/workers/test/jest-e2e.json b/sources/packages/backend/apps/workers/test/jest-e2e.json index ba326fb0eb..52c41aa4c0 100644 --- a/sources/packages/backend/apps/workers/test/jest-e2e.json +++ b/sources/packages/backend/apps/workers/test/jest-e2e.json @@ -22,7 +22,9 @@ "@sims/utilities/(.*)": "/../../libs/utilities/src/$1", "@sims/utilities": "/../../libs/utilities/src", "@sims/test-utils/(.*)": "/../../libs/test-utils/src/$1", - "@sims/test-utils": "/../../libs/test-utils/src" + "@sims/test-utils": "/../../libs/test-utils/src", + "@sims/integrations/(.*)": "/../../libs/integrations/src/$1", + "@sims/integrations": "/../../libs/integrations/src" }, "coveragePathIgnorePatterns": [ "node_modules", diff --git a/sources/packages/backend/libs/test-utils/src/index.ts b/sources/packages/backend/libs/test-utils/src/index.ts index baf70d36c0..67a709f5c0 100644 --- a/sources/packages/backend/libs/test-utils/src/index.ts +++ b/sources/packages/backend/libs/test-utils/src/index.ts @@ -19,3 +19,7 @@ export * from "./factories/student-scholastic-standing"; export * from "./factories/student-appeal"; export * from "./factories/student-appeal-request"; export * from "./models/common.model"; +export * from "./mocks/zeebe-client-mock"; +export * from "./mocks/ssh-service-mock"; +export * from "./mocks/queue-module-mock"; +export * from "./modules/modules-utils"; diff --git a/sources/packages/backend/libs/test-utils/src/mocks/queue-module-mock.ts b/sources/packages/backend/libs/test-utils/src/mocks/queue-module-mock.ts new file mode 100644 index 0000000000..cfe1585fd9 --- /dev/null +++ b/sources/packages/backend/libs/test-utils/src/mocks/queue-module-mock.ts @@ -0,0 +1,31 @@ +import { Global, Module, Provider } from "@nestjs/common"; +import { QueueNames } from "@sims/utilities"; +import { Queue } from "bull"; +import { createMock } from "@golevelup/ts-jest"; +import { QueueService } from "@sims/services/queue"; + +const MOCKED_QUEUE_PROVIDERS = getMockedQueueProviders(); + +/** + * Mock to entirely replace the queue module, avoiding including + * the BullModule since it is not in the scope of the E2E tests. + */ +@Global() +@Module({ + providers: [...MOCKED_QUEUE_PROVIDERS, QueueService], + exports: [...MOCKED_QUEUE_PROVIDERS, QueueService], +}) +export class QueueModuleMock {} + +/** + * Create all expected queue providers mocks. + * @returns queue providers mocks. + */ +function getMockedQueueProviders(): Provider[] { + // The 'BullQueue_' suffix is needed to properly mock the expected + // symbol used by the @InjectQueue decorator. + return Object.values(QueueNames).map((queue) => ({ + provide: `BullQueue_${queue}`, + useValue: createMock({ name: queue }), + })); +} diff --git a/sources/packages/backend/libs/test-utils/src/mocks/ssh-service-mock.ts b/sources/packages/backend/libs/test-utils/src/mocks/ssh-service-mock.ts new file mode 100644 index 0000000000..21d593d786 --- /dev/null +++ b/sources/packages/backend/libs/test-utils/src/mocks/ssh-service-mock.ts @@ -0,0 +1,14 @@ +import * as Client from "ssh2-sftp-client"; +import { SshService } from "@sims/integrations/services"; + +/** + * Creates a mocked {@link SshService} with a mocked SSH {@link Client}. + * @param sshClientMock SSH client to be returned by the {@link SshService}. + * @returns mocked {@link SshService}. + */ +export function createSSHServiceMock(sshClientMock: Client): SshService { + const sshServiceMock = new SshService(); + sshServiceMock.createClient = jest.fn().mockResolvedValue(sshClientMock); + SshService.closeQuietly = jest.fn(); + return sshServiceMock; +} diff --git a/sources/packages/backend/libs/test-utils/src/mocks/ssh-service.mock.ts b/sources/packages/backend/libs/test-utils/src/mocks/ssh-service.mock.ts deleted file mode 100644 index e0853341a4..0000000000 --- a/sources/packages/backend/libs/test-utils/src/mocks/ssh-service.mock.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as Client from "ssh2-sftp-client"; -import { SshService } from "@sims/integrations/services"; - -const sshServiceMock = new SshService(); -const sshClientMock = new Client(); - -jest.spyOn(sshServiceMock, "createClient").mockImplementation(() => { - return Promise.resolve(sshClientMock); -}); - -jest - .spyOn(sshClientMock, "put") - .mockImplementation( - ( - _input: string | Buffer | NodeJS.ReadableStream, - remoteFilePath: string, - ) => { - return Promise.resolve( - `SSH 'put' method executed from mocked SSH service, remoteFilePath: ${remoteFilePath}`, - ); - }, - ); - -jest.spyOn(SshService, "closeQuietly").mockImplementation(() => { - return Promise.resolve(); -}); - -export default sshServiceMock; diff --git a/sources/packages/backend/apps/api/src/testHelpers/mocked-providers/zeebe-client-mock.ts b/sources/packages/backend/libs/test-utils/src/mocks/zeebe-client-mock.ts similarity index 53% rename from sources/packages/backend/apps/api/src/testHelpers/mocked-providers/zeebe-client-mock.ts rename to sources/packages/backend/libs/test-utils/src/mocks/zeebe-client-mock.ts index a0f014a628..01d364dd62 100644 --- a/sources/packages/backend/apps/api/src/testHelpers/mocked-providers/zeebe-client-mock.ts +++ b/sources/packages/backend/libs/test-utils/src/mocks/zeebe-client-mock.ts @@ -2,9 +2,17 @@ import { DynamicModule, Provider } from "@nestjs/common"; import { ZeebeModule } from "@sims/services"; import { ZBClient } from "zeebe-node"; -export function createMockedZeebeModule(): DynamicModule { +/** + * Creates a mocked {@link ZeebeModule} that uses a mocked {@link ZBClient} + * and allow the assertions on method like createProcessInstance, + * publishMessage, and cancelProcessInstance. + * @returns mocked {@link ZeebeModule}. + */ +export function createZeebeModuleMock(): DynamicModule { const mockedZBClient = {} as ZBClient; + mockedZBClient.createProcessInstance = jest.fn(); mockedZBClient.publishMessage = jest.fn(); + mockedZBClient.cancelProcessInstance = jest.fn(); const zeebeClientProvider: Provider = { provide: ZBClient, useValue: mockedZBClient, diff --git a/sources/packages/backend/libs/test-utils/src/modules/modules-utils.ts b/sources/packages/backend/libs/test-utils/src/modules/modules-utils.ts new file mode 100644 index 0000000000..8e0778aeb5 --- /dev/null +++ b/sources/packages/backend/libs/test-utils/src/modules/modules-utils.ts @@ -0,0 +1,65 @@ +import { DynamicModule, Type } from "@nestjs/common"; +import { MODULE_METADATA } from "@nestjs/common/constants"; + +/** + * Nestjs module types that can be overwritten. + */ +export type ModuleType = Type | DynamicModule; +/** + * Information needed to find and have a module overwritten. + */ +export type OverrideModuleInfo = { + /** + * Current module to be found and replaced. + */ + replace: ModuleType; + /** + * Module to replace the existing one. + */ + by: ModuleType; +}; + +/** + * Find modules and replace them with the provided ones. + * So far Nestjs does not provide an out-of-box way to override an entire + * module. This is considered a work around and should only be used under + * specific circumstances. Before using this method please ensure that + * the override provider option cannot be used instead. + * @param rootModuleType module to have the 'imports' overwritten. + * @param overrides information to find and replace modules. + */ +export function overrideImportsMetadata( + rootModuleType: Type | DynamicModule, + ...overrides: OverrideModuleInfo[] +) { + const importsMetadata = Reflect.getMetadata( + MODULE_METADATA.IMPORTS, + rootModuleType, + ) as unknown[]; + overrides.forEach((override) => overrideMetadata(importsMetadata, override)); +} + +/** + * Find a module and replace it for the provided one. + * @param importsMetadata information from all the 'imports' metadata where + * the module must be found and replaced. + * @param override information to find and replace the module. + */ +function overrideMetadata( + importsMetadata: unknown[], + override: OverrideModuleInfo, +): void { + for (let i = 0; i < importsMetadata.length; i++) { + const importMetadata = importsMetadata[i]; + if ( + importMetadata === override.replace || + (importMetadata as DynamicModule).module === override.replace + ) { + importsMetadata[i] = override.by; + return; + } + } + throw new Error( + `The '${MODULE_METADATA.IMPORTS}' metadata item was not found to be overwritten.`, + ); +} diff --git a/sources/packages/backend/package-lock.json b/sources/packages/backend/package-lock.json index e956005618..b1bcd47e1c 100644 --- a/sources/packages/backend/package-lock.json +++ b/sources/packages/backend/package-lock.json @@ -49,6 +49,7 @@ "zeebe-node": "^8.1.2" }, "devDependencies": { + "@golevelup/ts-jest": "^0.3.5", "@nestjs/cli": "^9.3.0", "@nestjs/schematics": "^9.0.3", "@nestjs/testing": "^9.1.2", @@ -1216,6 +1217,12 @@ "lodash": "^4.17.15" } }, + "node_modules/@golevelup/ts-jest": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@golevelup/ts-jest/-/ts-jest-0.3.5.tgz", + "integrity": "sha512-Ul4+JsIcKSwzqM78ZwGU9xNvisNoPnHVNEwHK+t8s/WpQVOx+f8W61SIi6OcPpnkyFqyEHGBkOmTGXj3nRQwbg==", + "dev": true + }, "node_modules/@grpc/grpc-js": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.1.tgz", @@ -12481,6 +12488,12 @@ "lodash": "^4.17.15" } }, + "@golevelup/ts-jest": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@golevelup/ts-jest/-/ts-jest-0.3.5.tgz", + "integrity": "sha512-Ul4+JsIcKSwzqM78ZwGU9xNvisNoPnHVNEwHK+t8s/WpQVOx+f8W61SIi6OcPpnkyFqyEHGBkOmTGXj3nRQwbg==", + "dev": true + }, "@grpc/grpc-js": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.1.tgz", diff --git a/sources/packages/backend/package.json b/sources/packages/backend/package.json index 5c4150427b..d83233262b 100644 --- a/sources/packages/backend/package.json +++ b/sources/packages/backend/package.json @@ -28,6 +28,7 @@ "test:e2e:workflow:local": "cross-env ENVIRONMENT=test jest --verbose --config ./workflow/test/jest-e2e.json --forceExit", "test:e2e:workflow": "npm run deploy:camunda:definitions && cross-env ENVIRONMENT=test jest --verbose --config ./workflow/test/jest-e2e.json --forceExit", "test:e2e:queue-consumers": "npm run migration:run && cross-env ENVIRONMENT=test jest --collect-coverage --verbose --config ./apps/queue-consumers/test/jest-e2e.json --forceExit", + "test:e2e:queue-consumers:local": "cross-env ENVIRONMENT=test jest --verbose --config ./apps/queue-consumers/test/jest-e2e.json --forceExit", "migration:run": "node --abort-on-uncaught-exception --require ts-node/register apps/db-migrations/src/main.ts", "migration:create": "cd apps/db-migrations/src/migrations && npx typeorm-ts-node-commonjs migration:create", "migration:revert": "npx typeorm-ts-node-commonjs migration:revert -d apps/db-migrations/src/data-source.ts", @@ -77,6 +78,7 @@ "zeebe-node": "^8.1.2" }, "devDependencies": { + "@golevelup/ts-jest": "^0.3.5", "@nestjs/cli": "^9.3.0", "@nestjs/schematics": "^9.0.3", "@nestjs/testing": "^9.1.2", diff --git a/sources/packages/backend/workflow/test/jest-e2e.json b/sources/packages/backend/workflow/test/jest-e2e.json index 4f0a222032..5af33a03d9 100644 --- a/sources/packages/backend/workflow/test/jest-e2e.json +++ b/sources/packages/backend/workflow/test/jest-e2e.json @@ -22,6 +22,8 @@ "@sims/utilities/(.*)": "/../libs/utilities/src/$1", "@sims/utilities": "/../libs/utilities/src", "@sims/test-utils/(.*)": "/../libs/test-utils/src/$1", - "@sims/test-utils": "/../libs/test-utils/src" + "@sims/test-utils": "/../libs/test-utils/src", + "@sims/integrations/(.*)": "/../libs/integrations/src/$1", + "@sims/integrations": "/../libs/integrations/src" } } \ No newline at end of file diff --git a/sources/tests/docker-compose.yml b/sources/tests/docker-compose.yml index 02a7cdf1cc..b0d1f25901 100644 --- a/sources/tests/docker-compose.yml +++ b/sources/tests/docker-compose.yml @@ -70,7 +70,6 @@ services: restart: always depends_on: - postgres - - redis # - API # Workers workers: @@ -102,7 +101,6 @@ services: restart: always depends_on: - postgres - - redis # - Workers # Queue consumers queue-consumers: @@ -160,7 +158,6 @@ services: restart: always depends_on: - postgres - - redis # - Queues # Postgres postgres: @@ -176,17 +173,7 @@ services: networks: - local-network-tests # - Postgres - # Redis - redis: - image: redis-${PROJECT_NAME}:${BUILD_REF}-${BUILD_ID} - container_name: local-redis-${PROJECT_NAME}-${BUILD_REF}-${BUILD_ID} - build: - context: ../.docker/redis - command: "--port ${REDIS_PORT} --requirepass ${REDIS_PASSWORD} --appendonly yes --appendfsync no" - networks: - - local-network-tests - # - Redis - # - services + # - services # Networks networks: local-network-tests: