From 13486fdcc0ef0e7b6490bcd9f01930d2ee547739 Mon Sep 17 00:00:00 2001 From: ThomasBazin Date: Tue, 1 Oct 2024 11:26:14 +0200 Subject: [PATCH 1/4] fix(api): change ownerId field to be mandatory in csv file --- .../serializers/csv/csv-serializer.js | 5 ++- .../campaign-administration-route_test.js | 6 +-- .../serializers/csv/csv-serializer_test.js | 37 +++++++++++++++++-- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/api/src/shared/infrastructure/serializers/csv/csv-serializer.js b/api/src/shared/infrastructure/serializers/csv/csv-serializer.js index 55cbde3f289..6288df25d9d 100644 --- a/api/src/shared/infrastructure/serializers/csv/csv-serializer.js +++ b/api/src/shared/infrastructure/serializers/csv/csv-serializer.js @@ -181,6 +181,7 @@ const requiredFieldNamesForCampaignsImport = [ "Identifiant de l'organisation*", 'Nom de la campagne*', 'Identifiant du profil cible*', + 'Identifiant du propriétaire*', 'Identifiant du créateur*', ]; @@ -206,7 +207,7 @@ async function parseForCampaignsImport(cleanedData, { parseCsvData } = csvHelper "Identifiant de l'organisation*", 'Identifiant du profil cible*', 'Identifiant du créateur*', - 'Identifiant du propriétaire', + 'Identifiant du propriétaire*', ].includes(columnName) ) { value = parseInt(value, 10); @@ -231,7 +232,7 @@ async function parseForCampaignsImport(cleanedData, { parseCsvData } = csvHelper title: data['Titre du parcours'], customLandingPageText: data['Descriptif du parcours'], multipleSendings: data['Envoi multiple'].toLowerCase() === 'oui' ? true : false, - ownerId: data['Identifiant du propriétaire'] || null, + ownerId: data['Identifiant du propriétaire*'], customResultPageText: data['Texte de la page de fin de parcours'] || null, customResultPageButtonText: data['Texte du bouton de la page de fin de parcours'] || null, customResultPageButtonUrl: data['URL du bouton de la page de fin de parcours'] || null, diff --git a/api/tests/prescription/campaign/acceptance/application/campaign-administration-route_test.js b/api/tests/prescription/campaign/acceptance/application/campaign-administration-route_test.js index 5ac41c86625..1b6196378ed 100644 --- a/api/tests/prescription/campaign/acceptance/application/campaign-administration-route_test.js +++ b/api/tests/prescription/campaign/acceptance/application/campaign-administration-route_test.js @@ -236,9 +236,9 @@ describe('Acceptance | API | campaign-administration-route', function () { const targetProfileId = databaseBuilder.factory.buildTargetProfile({ ownerOrganizationId: organizationId }).id; await databaseBuilder.commit(); - const buffer = `Identifiant de l'organisation*;Nom de la campagne*;Identifiant du profil cible*;Libellé de l'identifiant externe;Identifiant du créateur*;Titre du parcours;Descriptif du parcours;Envoi multiple - ${organizationId};Parcours importé par CSV;${targetProfileId};numéro d'étudiant;${userId};;;non - ${organizationId};Autre parcours importé par CSV;${targetProfileId};numéro d'étudiant;${userId};Titre;Superbe descriptif de parcours;oui`; + const buffer = `Identifiant de l'organisation*;Nom de la campagne*;Identifiant du profil cible*;Libellé de l'identifiant externe;Identifiant du créateur*;Titre du parcours;Descriptif du parcours;Envoi multiple;Identifiant du propriétaire* + ${organizationId};Parcours importé par CSV;${targetProfileId};numéro d'étudiant;${userId};;;non;${userId}; + ${organizationId};Autre parcours importé par CSV;${targetProfileId};numéro d'étudiant;${userId};Titre;Superbe descriptif de parcours;oui;${userId};`; const options = { method: 'POST', url: '/api/admin/campaigns', diff --git a/api/tests/shared/unit/infrastructure/serializers/csv/csv-serializer_test.js b/api/tests/shared/unit/infrastructure/serializers/csv/csv-serializer_test.js index 411c7861bda..7ecd9334f43 100644 --- a/api/tests/shared/unit/infrastructure/serializers/csv/csv-serializer_test.js +++ b/api/tests/shared/unit/infrastructure/serializers/csv/csv-serializer_test.js @@ -1408,6 +1408,7 @@ describe('Unit | Serializer | CSV | csv-serializer', function () { "Identifiant de l'organisation*", 'Nom de la campagne*', 'Identifiant du profil cible*', + 'Identifiant du propriétaire*', 'Identifiant du créateur*', ]; @@ -1425,11 +1426,11 @@ describe('Unit | Serializer | CSV | csv-serializer', function () { describe('#parseForCampaignsImport', function () { const headerCsv = - "Identifiant de l'organisation*;Nom de la campagne*;Identifiant du profil cible*;Libellé de l'identifiant externe;Identifiant du créateur*;Titre du parcours;Descriptif du parcours;Envoi multiple;Identifiant du propriétaire;Texte de la page de fin de parcours;Texte du bouton de la page de fin de parcours;URL du bouton de la page de fin de parcours\n"; + "Identifiant de l'organisation*;Nom de la campagne*;Identifiant du profil cible*;Libellé de l'identifiant externe;Identifiant du créateur*;Titre du parcours;Descriptif du parcours;Envoi multiple;Identifiant du propriétaire*;Texte de la page de fin de parcours;Texte du bouton de la page de fin de parcours;URL du bouton de la page de fin de parcours\n"; it('should return parsed campaign data', async function () { // given - const csv = `${headerCsv}1;chaussette;1234;numéro étudiant;789;titre 1;descriptif 1;Oui;45\n2;chapeau;1234;identifiant;666;titre 2;descriptif 2;Non\n3;chausson;1234;identifiant;123;titre 3;descriptif 3;Non;;Bravo !;Cliquez ici;https://hmpg.net/`; + const csv = `${headerCsv}1;chaussette;1234;numéro étudiant;789;titre 1;descriptif 1;Oui;45\n2;chapeau;1234;identifiant;666;titre 2;descriptif 2;Non;77\n3;chausson;1234;identifiant;123;titre 3;descriptif 3;Non;88;Bravo !;Cliquez ici;https://hmpg.net/`; // when const parsedData = await csvSerializer.parseForCampaignsImport(csv); @@ -1459,7 +1460,7 @@ describe('Unit | Serializer | CSV | csv-serializer', function () { customLandingPageText: 'descriptif 2', creatorId: 666, multipleSendings: false, - ownerId: null, + ownerId: 77, customResultPageText: null, customResultPageButtonText: null, customResultPageButtonUrl: null, @@ -1473,7 +1474,7 @@ describe('Unit | Serializer | CSV | csv-serializer', function () { customLandingPageText: 'descriptif 3', creatorId: 123, multipleSendings: false, - ownerId: null, + ownerId: 88, customResultPageText: 'Bravo !', customResultPageButtonText: 'Cliquez ici', customResultPageButtonUrl: 'https://hmpg.net/', @@ -1566,6 +1567,34 @@ describe('Unit | Serializer | CSV | csv-serializer', function () { }); }); + describe('when ownerId field is not valid', function () { + it('should throw an error when empty', async function () { + // given + const campaignWithoutOwnerIdCsv = `${headerCsv}1;chaussette;1234;numéro étudiant;12;titre;descriptif;false;;`; + + // when + const error = await catchErr(csvSerializer.parseForCampaignsImport)(campaignWithoutOwnerIdCsv); + + // then + expect(error).to.be.instanceOf(FileValidationError); + expect(error.code).to.equal('CSV_CONTENT_NOT_VALID'); + expect(error.meta).to.equal('NaN is not a valid value for "Identifiant du propriétaire*"'); + }); + + it('should throw an error when not a number', async function () { + // given + const campaignWithBadNumberForOwnerIdCsv = `${headerCsv}1;chaussette;1234;idpixlabel;1234;titre;descriptif;false;not a number`; + + // when + const error = await catchErr(csvSerializer.parseForCampaignsImport)(campaignWithBadNumberForOwnerIdCsv); + + // then + expect(error).to.be.instanceOf(FileValidationError); + expect(error.code).to.equal('CSV_CONTENT_NOT_VALID'); + expect(error.meta).to.equal('NaN is not a valid value for "Identifiant du propriétaire*"'); + }); + }); + describe('when name field is not valid', function () { it('should throw an error', async function () { // given From 9cfc9dc358680bb8ddb3ce68acda1b60ce4c8b74 Mon Sep 17 00:00:00 2001 From: ThomasBazin Date: Tue, 1 Oct 2024 15:31:27 +0200 Subject: [PATCH 2/4] fix(api): remove admin get if owner is empty --- .../domain/usecases/create-campaigns.js | 12 ------------ .../domain/usecases/create-campaigns_test.js | 19 +++---------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/api/src/prescription/campaign/domain/usecases/create-campaigns.js b/api/src/prescription/campaign/domain/usecases/create-campaigns.js index c02bef675bc..1f4d79d79d3 100644 --- a/api/src/prescription/campaign/domain/usecases/create-campaigns.js +++ b/api/src/prescription/campaign/domain/usecases/create-campaigns.js @@ -2,23 +2,12 @@ import { CampaignTypes } from '../../../shared/domain/constants.js'; const createCampaigns = async function ({ campaignsToCreate, - membershipRepository, campaignAdministrationRepository, campaignCreatorRepository, codeGenerator, }) { const enrichedCampaignsData = await Promise.all( campaignsToCreate.map(async (campaign) => { - let ownerId; - if (campaign.ownerId) { - ownerId = campaign.ownerId; - } else { - const [administrator] = await membershipRepository.findAdminsByOrganizationId({ - organizationId: campaign.organizationId, - }); - ownerId = administrator.user.id; - } - const generatedCampaignCode = await codeGenerator.generate(campaignAdministrationRepository); const campaignCreator = await campaignCreatorRepository.get(campaign.organizationId); @@ -26,7 +15,6 @@ const createCampaigns = async function ({ ...campaign, type: CampaignTypes.ASSESSMENT, code: generatedCampaignCode, - ownerId, }); }), ); diff --git a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js index 325432773b1..c14c1db5956 100644 --- a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js +++ b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js @@ -9,15 +9,9 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function }; const code1 = Symbol('code1'); const code2 = Symbol('code2'); - const administrator = domainBuilder.buildUser(); const someoneId = 454756; const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); const organization = domainBuilder.buildOrganization({ id: 4 }); - const administratorMembership = domainBuilder.buildMembership({ - user: administrator, - organization: otherOrganization, - organizationRole: 'ADMIN', - }); const codeGeneratorStub = { generate: sinon @@ -42,6 +36,7 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function name: 'My other Campaign', targetProfileId: 3, creatorId: 1, + ownerId: someoneId, }, ]; @@ -54,7 +49,7 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function { ...campaignsToCreate[1], type: 'ASSESSMENT', - ownerId: administrator.id, + ownerId: someoneId, code: code2, }, ]; @@ -67,7 +62,7 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) .resolves(campaignsWithAllData[0]); campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: administrator.id }) + .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) .resolves(campaignsWithAllData[1]); const campaignCreatorRepositoryStub = { @@ -80,16 +75,8 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function const createdCampaignsSymbol = Symbol(''); campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); - const membershipRepository = { - findAdminsByOrganizationId: sinon.stub(), - }; - membershipRepository.findAdminsByOrganizationId - .withArgs({ organizationId: otherOrganization.id }) - .resolves([administratorMembership]); - const result = await createCampaigns({ campaignsToCreate, - membershipRepository, campaignAdministrationRepository, codeGenerator: codeGeneratorStub, campaignCreatorRepository: campaignCreatorRepositoryStub, From e4d83cabcdca3536a3e8db42ae59bbe953879d14 Mon Sep 17 00:00:00 2001 From: ThomasBazin Date: Tue, 1 Oct 2024 18:19:12 +0200 Subject: [PATCH 3/4] feat(api): check if owner and organization exist --- .../domain/usecases/create-campaigns.js | 13 + .../domain/usecases/create-campaigns_test.js | 361 ++++++++++++++---- 2 files changed, 295 insertions(+), 79 deletions(-) diff --git a/api/src/prescription/campaign/domain/usecases/create-campaigns.js b/api/src/prescription/campaign/domain/usecases/create-campaigns.js index 1f4d79d79d3..e1ce8d1ae3b 100644 --- a/api/src/prescription/campaign/domain/usecases/create-campaigns.js +++ b/api/src/prescription/campaign/domain/usecases/create-campaigns.js @@ -5,9 +5,14 @@ const createCampaigns = async function ({ campaignAdministrationRepository, campaignCreatorRepository, codeGenerator, + userRepository, + organizationRepository, }) { const enrichedCampaignsData = await Promise.all( campaignsToCreate.map(async (campaign) => { + await _checkIfOwnerIsExistingUser(userRepository, campaign.ownerId); + await _checkIfOrganizationExists(organizationRepository, campaign.organizationId); + const generatedCampaignCode = await codeGenerator.generate(campaignAdministrationRepository); const campaignCreator = await campaignCreatorRepository.get(campaign.organizationId); @@ -22,4 +27,12 @@ const createCampaigns = async function ({ return campaignAdministrationRepository.save(enrichedCampaignsData); }; +const _checkIfOwnerIsExistingUser = async function (userRepository, userId) { + await userRepository.get(userId); +}; + +const _checkIfOrganizationExists = async function (organizationRepository, organizationId) { + await organizationRepository.get(organizationId); +}; + export { createCampaigns }; diff --git a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js index c14c1db5956..7f6dfa9fc8b 100644 --- a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js +++ b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js @@ -1,87 +1,290 @@ import { createCampaigns } from '../../../../../../src/prescription/campaign/domain/usecases/create-campaigns.js'; import { CampaignTypes } from '../../../../../../src/prescription/shared/domain/constants.js'; -import { domainBuilder, expect, sinon } from '../../../../../test-helper.js'; +import { NotFoundError, UserNotFoundError } from '../../../../../../src/shared/domain/errors.js'; +import { catchErr, domainBuilder, expect, sinon } from '../../../../../test-helper.js'; describe('Unit | UseCase | campaign-administration | create-campaigns', function () { - it('should create campaigns', async function () { - const campaignAdministrationRepository = { - save: sinon.stub(), - }; - const code1 = Symbol('code1'); - const code2 = Symbol('code2'); - const someoneId = 454756; - const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); - const organization = domainBuilder.buildOrganization({ id: 4 }); - - const codeGeneratorStub = { - generate: sinon - .stub() - .withArgs(campaignAdministrationRepository) - .onFirstCall() - .resolves(code1) - .onSecondCall() - .resolves(code2), - }; - - const campaignsToCreate = [ - { - organizationId: organization.id, - name: 'My Campaign', - targetProfileId: 3, - creatorId: 2, - ownerId: someoneId, - }, - { - organizationId: otherOrganization.id, - name: 'My other Campaign', - targetProfileId: 3, - creatorId: 1, - ownerId: someoneId, - }, - ]; - - const campaignsWithAllData = [ - { - ...campaignsToCreate[0], - type: 'ASSESSMENT', - code: code1, - }, - { - ...campaignsToCreate[1], - type: 'ASSESSMENT', - ownerId: someoneId, - code: code2, - }, - ]; - - const campaignCreatorPOJO = { - createCampaign: sinon.stub(), - }; - - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) - .resolves(campaignsWithAllData[0]); - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) - .resolves(campaignsWithAllData[1]); - - const campaignCreatorRepositoryStub = { - get: sinon.stub(), - }; - - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); - - const createdCampaignsSymbol = Symbol(''); - campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); - - const result = await createCampaigns({ - campaignsToCreate, - campaignAdministrationRepository, - codeGenerator: codeGeneratorStub, - campaignCreatorRepository: campaignCreatorRepositoryStub, + describe('success case', function () { + it('should create campaigns', async function () { + const campaignAdministrationRepository = { + save: sinon.stub(), + }; + const userRepositoryStub = { + get: sinon.stub(), + }; + const organizationRepositoryStub = { + get: sinon.stub(), + }; + const code1 = Symbol('code1'); + const code2 = Symbol('code2'); + const someoneId = 454756; + const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); + const organization = domainBuilder.buildOrganization({ id: 4 }); + + const codeGeneratorStub = { + generate: sinon + .stub() + .withArgs(campaignAdministrationRepository) + .onFirstCall() + .resolves(code1) + .onSecondCall() + .resolves(code2), + }; + + const campaignsToCreate = [ + { + organizationId: organization.id, + name: 'My Campaign', + targetProfileId: 3, + creatorId: 2, + ownerId: someoneId, + }, + { + organizationId: otherOrganization.id, + name: 'My other Campaign', + targetProfileId: 3, + creatorId: 1, + ownerId: someoneId, + }, + ]; + + const campaignsWithAllData = [ + { + ...campaignsToCreate[0], + type: 'ASSESSMENT', + code: code1, + }, + { + ...campaignsToCreate[1], + type: 'ASSESSMENT', + code: code2, + }, + ]; + + const campaignCreatorPOJO = { + createCampaign: sinon.stub(), + }; + + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) + .resolves(campaignsWithAllData[0]); + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) + .resolves(campaignsWithAllData[1]); + + const campaignCreatorRepositoryStub = { + get: sinon.stub(), + }; + + organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(); + userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).resolves(); + organizationRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(); + userRepositoryStub.get.withArgs(campaignsToCreate[1].ownerId).resolves(); + + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); + + const createdCampaignsSymbol = Symbol(''); + campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); + + const result = await createCampaigns({ + campaignsToCreate, + campaignAdministrationRepository, + codeGenerator: codeGeneratorStub, + campaignCreatorRepository: campaignCreatorRepositoryStub, + userRepository: userRepositoryStub, + organizationRepository: organizationRepositoryStub, + }); + + expect(result).to.equal(createdCampaignsSymbol); }); + }); + + describe('errors case', function () { + it('should throw error if ownerId does not exist', async function () { + const campaignAdministrationRepository = { + save: sinon.stub(), + }; + const userRepositoryStub = { + get: sinon.stub(), + }; + const organizationRepositoryStub = { + get: sinon.stub(), + }; + const code1 = Symbol('code1'); + const code2 = Symbol('code2'); + const someoneId = 454756; + const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); + const organization = domainBuilder.buildOrganization({ id: 4 }); + + const codeGeneratorStub = { + generate: sinon + .stub() + .withArgs(campaignAdministrationRepository) + .onFirstCall() + .resolves(code1) + .onSecondCall() + .resolves(code2), + }; + + const campaignsToCreate = [ + { + organizationId: organization.id, + name: 'My Campaign', + targetProfileId: 3, + creatorId: 2, + ownerId: someoneId, + }, + { + organizationId: otherOrganization.id, + name: 'My other Campaign', + targetProfileId: 3, + creatorId: 1, + ownerId: someoneId, + }, + ]; + + const campaignsWithAllData = [ + { + ...campaignsToCreate[0], + type: 'ASSESSMENT', + code: code1, + }, + { + ...campaignsToCreate[1], + type: 'ASSESSMENT', + code: code2, + }, + ]; + + const campaignCreatorPOJO = { + createCampaign: sinon.stub(), + }; + + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) + .resolves(campaignsWithAllData[0]); + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) + .resolves(campaignsWithAllData[1]); + + const campaignCreatorRepositoryStub = { + get: sinon.stub(), + }; - expect(result).to.equal(createdCampaignsSymbol); + organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(); + userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).rejects(new UserNotFoundError()); + + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); + + const createdCampaignsSymbol = Symbol(''); + campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); + + const error = await catchErr(createCampaigns)({ + campaignsToCreate, + campaignAdministrationRepository, + codeGenerator: codeGeneratorStub, + campaignCreatorRepository: campaignCreatorRepositoryStub, + userRepository: userRepositoryStub, + organizationRepository: organizationRepositoryStub, + }); + + expect(error).to.throw; + expect(error).to.be.an.instanceof(UserNotFoundError); + }); + + it('should throw error if organization does not exist', async function () { + const campaignAdministrationRepository = { + save: sinon.stub(), + }; + const userRepositoryStub = { + get: sinon.stub(), + }; + const organizationRepositoryStub = { + get: sinon.stub(), + }; + const code1 = Symbol('code1'); + const code2 = Symbol('code2'); + const someoneId = 454756; + const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); + const organization = domainBuilder.buildOrganization({ id: 4 }); + + const codeGeneratorStub = { + generate: sinon + .stub() + .withArgs(campaignAdministrationRepository) + .onFirstCall() + .resolves(code1) + .onSecondCall() + .resolves(code2), + }; + + const campaignsToCreate = [ + { + organizationId: organization.id, + name: 'My Campaign', + targetProfileId: 3, + creatorId: 2, + ownerId: someoneId, + }, + { + organizationId: otherOrganization.id, + name: 'My other Campaign', + targetProfileId: 3, + creatorId: 1, + ownerId: someoneId, + }, + ]; + + const campaignsWithAllData = [ + { + ...campaignsToCreate[0], + type: 'ASSESSMENT', + code: code1, + }, + { + ...campaignsToCreate[1], + type: 'ASSESSMENT', + code: code2, + }, + ]; + + const campaignCreatorPOJO = { + createCampaign: sinon.stub(), + }; + + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) + .resolves(campaignsWithAllData[0]); + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) + .resolves(campaignsWithAllData[1]); + + const campaignCreatorRepositoryStub = { + get: sinon.stub(), + }; + + organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).rejects(new NotFoundError()); + userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).resolves(); + + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); + + const createdCampaignsSymbol = Symbol(''); + campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); + + const error = await catchErr(createCampaigns)({ + campaignsToCreate, + campaignAdministrationRepository, + codeGenerator: codeGeneratorStub, + campaignCreatorRepository: campaignCreatorRepositoryStub, + userRepository: userRepositoryStub, + organizationRepository: organizationRepositoryStub, + }); + + expect(error).to.throw; + expect(error).to.be.an.instanceof(NotFoundError); + }); }); }); From bca28a66cb93621c41985fd17844a9f30b927e95 Mon Sep 17 00:00:00 2001 From: Alexandre Monney Date: Wed, 2 Oct 2024 16:57:29 +0200 Subject: [PATCH 4/4] tests?(api): refacto usecase tests --- .../domain/usecases/create-campaigns_test.js | 320 +++++------------- 1 file changed, 89 insertions(+), 231 deletions(-) diff --git a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js index 7f6dfa9fc8b..a504d044ea1 100644 --- a/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js +++ b/api/tests/prescription/campaign/unit/domain/usecases/create-campaigns_test.js @@ -4,92 +4,102 @@ import { NotFoundError, UserNotFoundError } from '../../../../../../src/shared/d import { catchErr, domainBuilder, expect, sinon } from '../../../../../test-helper.js'; describe('Unit | UseCase | campaign-administration | create-campaigns', function () { + let codeGeneratorStub; + let campaignsToCreate; + let campaignAdministrationRepositoryStub; + let campaignCreatorRepositoryStub; + let userRepositoryStub; + let organizationRepositoryStub; + let createdCampaignsSymbol; + + beforeEach(function () { + campaignAdministrationRepositoryStub = { + save: sinon.stub(), + }; + userRepositoryStub = { + get: sinon.stub(), + }; + organizationRepositoryStub = { + get: sinon.stub(), + }; + const code1 = Symbol('code1'); + const code2 = Symbol('code2'); + const someoneId = 454756; + const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); + const organization = domainBuilder.buildOrganization({ id: 4 }); + + codeGeneratorStub = { + generate: sinon + .stub() + .withArgs(campaignAdministrationRepositoryStub) + .onFirstCall() + .resolves(code1) + .onSecondCall() + .resolves(code2), + }; + + campaignsToCreate = [ + { + organizationId: organization.id, + name: 'My Campaign', + targetProfileId: 3, + creatorId: 2, + ownerId: someoneId, + }, + { + organizationId: otherOrganization.id, + name: 'My other Campaign', + targetProfileId: 3, + creatorId: 1, + ownerId: someoneId, + }, + ]; + + const campaignsWithAllData = [ + { + ...campaignsToCreate[0], + type: 'ASSESSMENT', + code: code1, + }, + { + ...campaignsToCreate[1], + type: 'ASSESSMENT', + code: code2, + }, + ]; + + const campaignCreatorPOJO = { + createCampaign: sinon.stub(), + }; + + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) + .resolves(campaignsWithAllData[0]); + campaignCreatorPOJO.createCampaign + .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) + .resolves(campaignsWithAllData[1]); + + campaignCreatorRepositoryStub = { + get: sinon.stub(), + }; + + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); + campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); + + createdCampaignsSymbol = Symbol(''); + campaignAdministrationRepositoryStub.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); + }); + describe('success case', function () { it('should create campaigns', async function () { - const campaignAdministrationRepository = { - save: sinon.stub(), - }; - const userRepositoryStub = { - get: sinon.stub(), - }; - const organizationRepositoryStub = { - get: sinon.stub(), - }; - const code1 = Symbol('code1'); - const code2 = Symbol('code2'); - const someoneId = 454756; - const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); - const organization = domainBuilder.buildOrganization({ id: 4 }); - - const codeGeneratorStub = { - generate: sinon - .stub() - .withArgs(campaignAdministrationRepository) - .onFirstCall() - .resolves(code1) - .onSecondCall() - .resolves(code2), - }; - - const campaignsToCreate = [ - { - organizationId: organization.id, - name: 'My Campaign', - targetProfileId: 3, - creatorId: 2, - ownerId: someoneId, - }, - { - organizationId: otherOrganization.id, - name: 'My other Campaign', - targetProfileId: 3, - creatorId: 1, - ownerId: someoneId, - }, - ]; - - const campaignsWithAllData = [ - { - ...campaignsToCreate[0], - type: 'ASSESSMENT', - code: code1, - }, - { - ...campaignsToCreate[1], - type: 'ASSESSMENT', - code: code2, - }, - ]; - - const campaignCreatorPOJO = { - createCampaign: sinon.stub(), - }; - - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) - .resolves(campaignsWithAllData[0]); - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) - .resolves(campaignsWithAllData[1]); - - const campaignCreatorRepositoryStub = { - get: sinon.stub(), - }; - organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(); userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).resolves(); organizationRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(); userRepositoryStub.get.withArgs(campaignsToCreate[1].ownerId).resolves(); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); - - const createdCampaignsSymbol = Symbol(''); - campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); - const result = await createCampaigns({ campaignsToCreate, - campaignAdministrationRepository, + campaignAdministrationRepository: campaignAdministrationRepositoryStub, codeGenerator: codeGeneratorStub, campaignCreatorRepository: campaignCreatorRepositoryStub, userRepository: userRepositoryStub, @@ -102,88 +112,12 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function describe('errors case', function () { it('should throw error if ownerId does not exist', async function () { - const campaignAdministrationRepository = { - save: sinon.stub(), - }; - const userRepositoryStub = { - get: sinon.stub(), - }; - const organizationRepositoryStub = { - get: sinon.stub(), - }; - const code1 = Symbol('code1'); - const code2 = Symbol('code2'); - const someoneId = 454756; - const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); - const organization = domainBuilder.buildOrganization({ id: 4 }); - - const codeGeneratorStub = { - generate: sinon - .stub() - .withArgs(campaignAdministrationRepository) - .onFirstCall() - .resolves(code1) - .onSecondCall() - .resolves(code2), - }; - - const campaignsToCreate = [ - { - organizationId: organization.id, - name: 'My Campaign', - targetProfileId: 3, - creatorId: 2, - ownerId: someoneId, - }, - { - organizationId: otherOrganization.id, - name: 'My other Campaign', - targetProfileId: 3, - creatorId: 1, - ownerId: someoneId, - }, - ]; - - const campaignsWithAllData = [ - { - ...campaignsToCreate[0], - type: 'ASSESSMENT', - code: code1, - }, - { - ...campaignsToCreate[1], - type: 'ASSESSMENT', - code: code2, - }, - ]; - - const campaignCreatorPOJO = { - createCampaign: sinon.stub(), - }; - - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) - .resolves(campaignsWithAllData[0]); - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) - .resolves(campaignsWithAllData[1]); - - const campaignCreatorRepositoryStub = { - get: sinon.stub(), - }; - organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(); userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).rejects(new UserNotFoundError()); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); - - const createdCampaignsSymbol = Symbol(''); - campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); - const error = await catchErr(createCampaigns)({ campaignsToCreate, - campaignAdministrationRepository, + campaignAdministrationRepository: campaignAdministrationRepositoryStub, codeGenerator: codeGeneratorStub, campaignCreatorRepository: campaignCreatorRepositoryStub, userRepository: userRepositoryStub, @@ -195,88 +129,12 @@ describe('Unit | UseCase | campaign-administration | create-campaigns', function }); it('should throw error if organization does not exist', async function () { - const campaignAdministrationRepository = { - save: sinon.stub(), - }; - const userRepositoryStub = { - get: sinon.stub(), - }; - const organizationRepositoryStub = { - get: sinon.stub(), - }; - const code1 = Symbol('code1'); - const code2 = Symbol('code2'); - const someoneId = 454756; - const otherOrganization = domainBuilder.buildOrganization({ id: 3 }); - const organization = domainBuilder.buildOrganization({ id: 4 }); - - const codeGeneratorStub = { - generate: sinon - .stub() - .withArgs(campaignAdministrationRepository) - .onFirstCall() - .resolves(code1) - .onSecondCall() - .resolves(code2), - }; - - const campaignsToCreate = [ - { - organizationId: organization.id, - name: 'My Campaign', - targetProfileId: 3, - creatorId: 2, - ownerId: someoneId, - }, - { - organizationId: otherOrganization.id, - name: 'My other Campaign', - targetProfileId: 3, - creatorId: 1, - ownerId: someoneId, - }, - ]; - - const campaignsWithAllData = [ - { - ...campaignsToCreate[0], - type: 'ASSESSMENT', - code: code1, - }, - { - ...campaignsToCreate[1], - type: 'ASSESSMENT', - code: code2, - }, - ]; - - const campaignCreatorPOJO = { - createCampaign: sinon.stub(), - }; - - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[0], type: CampaignTypes.ASSESSMENT, code: code1, ownerId: someoneId }) - .resolves(campaignsWithAllData[0]); - campaignCreatorPOJO.createCampaign - .withArgs({ ...campaignsToCreate[1], type: CampaignTypes.ASSESSMENT, code: code2, ownerId: someoneId }) - .resolves(campaignsWithAllData[1]); - - const campaignCreatorRepositoryStub = { - get: sinon.stub(), - }; - organizationRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).rejects(new NotFoundError()); userRepositoryStub.get.withArgs(campaignsToCreate[0].ownerId).resolves(); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[0].organizationId).resolves(campaignCreatorPOJO); - campaignCreatorRepositoryStub.get.withArgs(campaignsToCreate[1].organizationId).resolves(campaignCreatorPOJO); - - const createdCampaignsSymbol = Symbol(''); - campaignAdministrationRepository.save.withArgs(campaignsWithAllData).resolves(createdCampaignsSymbol); - const error = await catchErr(createCampaigns)({ campaignsToCreate, - campaignAdministrationRepository, + campaignAdministrationRepository: campaignAdministrationRepositoryStub, codeGenerator: codeGeneratorStub, campaignCreatorRepository: campaignCreatorRepositoryStub, userRepository: userRepositoryStub,