From bd607e2a3aeecb1ccccca10263ba2a34185f6d60 Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Thu, 19 Sep 2024 12:07:06 +0200 Subject: [PATCH 01/12] add `accessibilityAdjustmentNeeded` in `CertificationCandidateForSupervising` model --- .../domain/models/CertificationCandidateForSupervising.js | 2 ++ .../factory/build-certification-candidate-for-supervising.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/api/src/certification/session-management/domain/models/CertificationCandidateForSupervising.js b/api/src/certification/session-management/domain/models/CertificationCandidateForSupervising.js index 5915d9712dc..39aecef18d6 100644 --- a/api/src/certification/session-management/domain/models/CertificationCandidateForSupervising.js +++ b/api/src/certification/session-management/domain/models/CertificationCandidateForSupervising.js @@ -16,6 +16,7 @@ class CertificationCandidateForSupervising { enrolledComplementaryCertification, stillValidBadgeAcquisitions = [], isCompanionActive = false, + accessibilityAdjustmentNeeded, } = {}) { this.id = id; this.userId = userId; @@ -30,6 +31,7 @@ class CertificationCandidateForSupervising { this.enrolledComplementaryCertification = enrolledComplementaryCertification; this.stillValidBadgeAcquisitions = stillValidBadgeAcquisitions; this.isCompanionActive = isCompanionActive; + this.accessibilityAdjustmentNeeded = accessibilityAdjustmentNeeded; } authorizeToStart() { diff --git a/api/tests/tooling/domain-builder/factory/build-certification-candidate-for-supervising.js b/api/tests/tooling/domain-builder/factory/build-certification-candidate-for-supervising.js index 2d65df26669..67bec316969 100644 --- a/api/tests/tooling/domain-builder/factory/build-certification-candidate-for-supervising.js +++ b/api/tests/tooling/domain-builder/factory/build-certification-candidate-for-supervising.js @@ -13,6 +13,7 @@ const buildCertificationCandidateForSupervising = function ({ theoricalEndDateTime, enrolledComplementaryCertification, stillValidBadgeAcquisitions = [], + accessibilityAdjustmentNeeded = false, } = {}) { return new CertificationCandidateForSupervising({ id, @@ -27,6 +28,7 @@ const buildCertificationCandidateForSupervising = function ({ theoricalEndDateTime, enrolledComplementaryCertification, stillValidBadgeAcquisitions, + accessibilityAdjustmentNeeded, }); }; From 13730b6eb02938821ebb456014eb2dfac41783ba Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Thu, 19 Sep 2024 12:13:49 +0200 Subject: [PATCH 02/12] add accessibility properties in `Challenge` model --- api/src/shared/domain/models/Challenge.js | 6 ++++++ .../repositories/challenge-repository.js | 2 ++ .../repositories/challenge-repository_test.js | 2 ++ .../domain-builder/factory/build-challenge.js | 20 +++++++++++++------ ...allengeLearningContentDataObjectFixture.js | 4 ++++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api/src/shared/domain/models/Challenge.js b/api/src/shared/domain/models/Challenge.js index b7efca5edb7..846e52c981d 100644 --- a/api/src/shared/domain/models/Challenge.js +++ b/api/src/shared/domain/models/Challenge.js @@ -49,6 +49,8 @@ class Challenge { * @param successProbabilityThreshold * @param shuffled * @param alternativeVersion + * @param accessibility1 + * @param accessibility2 */ constructor({ id, @@ -80,6 +82,8 @@ class Challenge { responsive, shuffled, alternativeVersion, + accessibility1, + accessibility2, } = {}) { this.id = id; this.answer = answer; @@ -110,6 +114,8 @@ class Challenge { this.successProbabilityThreshold = successProbabilityThreshold; this.shuffled = shuffled; this.alternativeVersion = alternativeVersion; + this.accessibility1 = accessibility1; + this.accessibility2 = accessibility2; } isTimed() { diff --git a/api/src/shared/infrastructure/repositories/challenge-repository.js b/api/src/shared/infrastructure/repositories/challenge-repository.js index bf2cd10ae6d..b73b82e377e 100644 --- a/api/src/shared/infrastructure/repositories/challenge-repository.js +++ b/api/src/shared/infrastructure/repositories/challenge-repository.js @@ -205,5 +205,7 @@ function _toDomain({ challengeDataObject, skillDataObject, successProbabilityThr shuffled: challengeDataObject.shuffled, successProbabilityThreshold, alternativeVersion: challengeDataObject.alternativeVersion, + accessibility1: challengeDataObject.accessibility1, + accessibility2: challengeDataObject.accessibility2, }); } diff --git a/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js b/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js index b97c29bbb52..2213e18b126 100644 --- a/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js +++ b/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js @@ -908,5 +908,7 @@ function _buildChallenge({ skill, shuffled: false, alternativeVersion: alternativeVersion || 1, + accessibility1: 'OK', + accessibility2: 'RAS', }; } diff --git a/api/tests/tooling/domain-builder/factory/build-challenge.js b/api/tests/tooling/domain-builder/factory/build-challenge.js index 5fab9f38df8..029b39b5b26 100644 --- a/api/tests/tooling/domain-builder/factory/build-challenge.js +++ b/api/tests/tooling/domain-builder/factory/build-challenge.js @@ -27,6 +27,8 @@ const buildChallenge = function ({ focused = false, shuffled = false, alternativeVersion = undefined, + accessibility1 = 'OK', + accessibility2 = 'RAS', // includes answer, validator = new Validator(), @@ -56,15 +58,17 @@ const buildChallenge = function ({ alternativeInstruction, responsive, focused, + illustrationAlt, + shuffled, + alternativeVersion, + accessibility1, + accessibility2, // includes answer, validator, skill, // references competenceId, - illustrationAlt, - shuffled, - alternativeVersion, }); }; @@ -93,6 +97,8 @@ const buildChallengeWithWebComponent = function ({ focused = false, shuffled = false, alternativeVersion = undefined, + accessibility1, + accessibility2, // includes answer, validator = new Validator(), @@ -122,15 +128,17 @@ const buildChallengeWithWebComponent = function ({ alternativeInstruction, responsive, focused, + illustrationAlt, + shuffled, + alternativeVersion, + accessibility1, + accessibility2, // includes answer, validator, skill, // references competenceId, - illustrationAlt, - shuffled, - alternativeVersion, }); }; diff --git a/api/tests/tooling/fixtures/infrastructure/challengeLearningContentDataObjectFixture.js b/api/tests/tooling/fixtures/infrastructure/challengeLearningContentDataObjectFixture.js index dfe91f69c17..19a9cb27812 100644 --- a/api/tests/tooling/fixtures/infrastructure/challengeLearningContentDataObjectFixture.js +++ b/api/tests/tooling/fixtures/infrastructure/challengeLearningContentDataObjectFixture.js @@ -26,6 +26,8 @@ const ChallengeLearningContentDataObjectFixture = function ({ locales = ['fr'], autoReply = false, alternativeInstruction = '', + accessibility1 = 'OK', + accessibility2 = 'RAS', } = {}) { return { id, @@ -52,6 +54,8 @@ const ChallengeLearningContentDataObjectFixture = function ({ locales, autoReply, alternativeInstruction, + accessibility1, + accessibility2, }; }; From 8a1c42acec632ac46bb9d66bea1e96ab09c5dd74 Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Thu, 19 Sep 2024 12:19:33 +0200 Subject: [PATCH 03/12] feat(certif v3): select next challenge among accessible ones when candidate needs accessibility adjustment --- ...get-next-challenge-for-v3-certification.js | 24 +++- ...ext-challenge-for-v3-certification_test.js | 130 +++++++++++++++++- 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js index 623b139a714..84c42456715 100644 --- a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js @@ -7,6 +7,15 @@ * @typedef {import('./index.js').FlashAlgorithmConfigurationRepository} FlashAlgorithmConfigurationRepository * @typedef {import('./index.js').PickChallengeService} PickChallengeService * @typedef {import('./index.js').FlashAlgorithmService} FlashAlgorithmService + * @typedef {import('../../../session-management/domain/usecases/index.js').AnswerRepository} AnswerRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationChallengeRepository} CertificationChallengeRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationChallengeLiveAlertRepository} CertificationChallengeLiveAlertRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationCourseRepository} CertificationCourseRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').ChallengeRepository} ChallengeRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').FlashAlgorithmConfigurationRepository} FlashAlgorithmConfigurationRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').PickChallengeService} PickChallengeService + * @typedef {import('../../../session-management/domain/usecases/index.js').FlashAlgorithmService} FlashAlgorithmService + * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationCandidateRepository} CertificationCandidateRepository */ import { AssessmentEndedError } from '../../../../shared/domain/errors.js'; @@ -22,6 +31,7 @@ import { CertificationChallenge, FlashAssessmentAlgorithm } from '../../../../sh * @param {FlashAlgorithmConfigurationRepository} params.flashAlgorithmConfigurationRepository * @param {FlashAlgorithmService} params.flashAlgorithmService * @param {PickChallengeService} params.pickChallengeService + * @param {CertificationCandidateRepository} params.certificationCandidateRepository */ const getNextChallengeForV3Certification = async function ({ assessment, @@ -34,6 +44,8 @@ const getNextChallengeForV3Certification = async function ({ flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }) { const certificationCourse = await certificationCourseRepository.get({ id: assessment.certificationCourseId }); @@ -77,9 +89,19 @@ const getNextChallengeForV3Certification = async function ({ challenges, }); + const candidate = await certificationCandidateForSupervisingRepository.get({ certificationCandidateId }); + const challengesForCandidate = candidate.accessibilityAdjustmentNeeded + ? challengesWithoutSkillsWithAValidatedLiveAlert.filter((challenge) => { + return ( + (challenge.accessibility1 === 'OK' || challenge.accessibility1 === 'RAS') && + (challenge.accessibility2 === 'OK' || challenge.accessibility2 === 'RAS') + ); + }) + : challengesWithoutSkillsWithAValidatedLiveAlert; + const possibleChallenges = assessmentAlgorithm.getPossibleNextChallenges({ assessmentAnswers: allAnswers, - challenges: challengesWithoutSkillsWithAValidatedLiveAlert, + challenges: challengesForCandidate, }); if (_hasAnsweredToAllChallenges({ possibleChallenges })) { diff --git a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js b/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js index 8a507a5194f..4bddbfec35f 100644 --- a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js +++ b/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js @@ -13,9 +13,11 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', certificationChallengeRepository, pickChallengeService, flashAlgorithmService, - flashAlgorithmConfigurationRepository; + flashAlgorithmConfigurationRepository, + certificationCandidateForSupervisingRepository; let flashAlgorithmConfiguration; + let certificationCandidateId; beforeEach(function () { flashAlgorithmConfigurationRepository = { @@ -45,6 +47,15 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', getPossibleNextChallenges: sinon.stub(), getCapacityAndErrorRate: sinon.stub(), }; + certificationCandidateForSupervisingRepository = { + get: sinon.stub(), + }; + const candidate = domainBuilder.buildCertificationCandidateForSupervising({ + accessibilityAdjustmentNeeded: false, + }); + certificationCandidateId = candidate.id; + + certificationCandidateForSupervisingRepository.get.withArgs({ certificationCandidateId }).resolves(candidate); flashAlgorithmConfiguration = domainBuilder.buildFlashAlgorithmConfiguration(); }); @@ -52,7 +63,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', context('when there are challenges left to answer', function () { it('should save the returned next challenge', async function () { // given - const nextChallengeToAnswer = domainBuilder.buildChallenge(); + const nextChallengeToAnswer = domainBuilder.buildChallenge({ + accessibility1: 'KO', + }); const v3CertificationCourse = domainBuilder.buildCertificationCourse({ version: CERTIFICATION_VERSIONS.V3, }); @@ -118,12 +131,115 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then expect(challenge).to.equal(nextChallengeToAnswer); }); + context('when candidate needs accessibility adjustment', function () { + it('should only pick among challenges with no accessibilities issues', async function () { + // given + const nextChallengeToAnswer = domainBuilder.buildChallenge({ + accessibility1: 'RAS', + accessibility2: 'OK', + }); + const accessibleChallenge = domainBuilder.buildChallenge({ + accessibility1: 'OK', + accessibility2: 'RAS', + }); + const allChallenges = [ + nextChallengeToAnswer, + accessibleChallenge, + domainBuilder.buildChallenge({ + accessibility1: 'autre chose', + accessibility2: 'OK', + }), + ]; + const v3CertificationCourse = domainBuilder.buildCertificationCourse({ + version: CERTIFICATION_VERSIONS.V3, + }); + const assessment = domainBuilder.buildAssessment(); + const locale = 'fr-FR'; + + flashAlgorithmConfigurationRepository.getMostRecentBeforeDate + .withArgs(v3CertificationCourse.getStartDate()) + .resolves(flashAlgorithmConfiguration); + + answerRepository.findByAssessment.withArgs(assessment.id).resolves([]); + certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId + .withArgs({ assessmentId: assessment.id }) + .resolves([]); + + certificationCourseRepository.get + .withArgs({ id: assessment.certificationCourseId }) + .resolves(v3CertificationCourse); + certificationChallengeRepository.getNextChallengeByCourseIdForV3 + .withArgs(assessment.certificationCourseId, []) + .resolves(null); + + answerRepository.findByAssessment.withArgs(assessment.id).resolves([]); + challengeRepository.findActiveFlashCompatible.withArgs({ locale }).resolves(allChallenges); + + flashAlgorithmService.getCapacityAndErrorRate + .withArgs({ + allAnswers: [], + challenges: [nextChallengeToAnswer, accessibleChallenge], + capacity: config.v3Certification.defaultCandidateCapacity, + variationPercent: undefined, + variationPercentUntil: undefined, + doubleMeasuresUntil: undefined, + }) + .returns({ capacity: 0 }); + + flashAlgorithmService.getPossibleNextChallenges + .withArgs({ + availableChallenges: [nextChallengeToAnswer, accessibleChallenge], + capacity: 0, + options: sinon.match.any, + }) + .returns([nextChallengeToAnswer]); + + const chooseNextChallengeImpl = sinon.stub(); + chooseNextChallengeImpl + .withArgs({ + possibleChallenges: [nextChallengeToAnswer], + }) + .returns(nextChallengeToAnswer); + pickChallengeService.chooseNextChallenge.withArgs().returns(chooseNextChallengeImpl); + + const candidateNeedingAccessibilityAdjustment = domainBuilder.buildCertificationCandidateForSupervising({ + id: 'candidateNeedingAccessibilityAdjustmentId', + accessibilityAdjustmentNeeded: true, + }); + + certificationCandidateForSupervisingRepository.get + .withArgs({ certificationCandidateId: candidateNeedingAccessibilityAdjustment.id }) + .resolves(candidateNeedingAccessibilityAdjustment); + + // when + const challenge = await getNextChallengeForV3Certification({ + answerRepository, + assessment, + certificationChallengeRepository, + certificationChallengeLiveAlertRepository, + certificationCourseRepository, + challengeRepository, + flashAlgorithmConfigurationRepository, + flashAlgorithmService, + locale, + pickChallengeService, + certificationCandidateId: candidateNeedingAccessibilityAdjustment.id, + certificationCandidateForSupervisingRepository, + }); + + // then + expect(challenge).to.equal(nextChallengeToAnswer); + }); + }); + context('when resuming the session', function () { it('should return the last seen challenge', async function () { // given @@ -167,6 +283,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then @@ -258,6 +376,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then @@ -355,6 +475,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then @@ -412,6 +534,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then @@ -516,6 +640,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, + certificationCandidateForSupervisingRepository, + certificationCandidateId, }); // then From e8dd68a86bf8f5b321662e275f22becad3282acc Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Thu, 19 Sep 2024 15:51:31 +0200 Subject: [PATCH 04/12] refactor(certif): use a getter on Challenge to abstract accessibility Co-authored-by: --- ...get-next-challenge-for-v3-certification.js | 7 +--- api/src/shared/domain/models/Challenge.js | 14 +++++++- .../unit/domain/models/Challenge_test.js | 35 ++++++++++++++++++- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js index 84c42456715..d0d1e86ecd4 100644 --- a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js @@ -91,12 +91,7 @@ const getNextChallengeForV3Certification = async function ({ const candidate = await certificationCandidateForSupervisingRepository.get({ certificationCandidateId }); const challengesForCandidate = candidate.accessibilityAdjustmentNeeded - ? challengesWithoutSkillsWithAValidatedLiveAlert.filter((challenge) => { - return ( - (challenge.accessibility1 === 'OK' || challenge.accessibility1 === 'RAS') && - (challenge.accessibility2 === 'OK' || challenge.accessibility2 === 'RAS') - ); - }) + ? challengesWithoutSkillsWithAValidatedLiveAlert.filter((challenge) => challenge.isAccessible) : challengesWithoutSkillsWithAValidatedLiveAlert; const possibleChallenges = assessmentAlgorithm.getPossibleNextChallenges({ diff --git a/api/src/shared/domain/models/Challenge.js b/api/src/shared/domain/models/Challenge.js index 846e52c981d..53b2b4db47a 100644 --- a/api/src/shared/domain/models/Challenge.js +++ b/api/src/shared/domain/models/Challenge.js @@ -15,6 +15,11 @@ const ChallengeType = Object.freeze({ QROCM_DEP: 'QROCM-dep', }); +const Accessibility = Object.freeze({ + RAS: 'RAS', + OK: 'OK', +}); + /** * Traduction: Épreuve */ @@ -154,6 +159,13 @@ class Challenge { return this._isCompliant('Tablet'); } + get isAccessible() { + return ( + (this.accessibility1 === Accessibility.OK || this.accessibility1 === Accessibility.RAS) && + (this.accessibility2 === Accessibility.OK || this.accessibility2 === Accessibility.RAS) + ); + } + set successProbabilityThreshold(successProbabilityThreshold) { if (this.difficulty == null || this.discriminant == null || successProbabilityThreshold == null) return; this.minimumCapability = this.difficulty - Math.log(1 / successProbabilityThreshold - 1) / this.discriminant; @@ -192,4 +204,4 @@ class Challenge { Challenge.Type = ChallengeType; -export { Challenge, ChallengeType as Type }; +export { Accessibility, Challenge, ChallengeType as Type }; diff --git a/api/tests/unit/domain/models/Challenge_test.js b/api/tests/unit/domain/models/Challenge_test.js index 056ca4e54e9..677a45a4ae7 100644 --- a/api/tests/unit/domain/models/Challenge_test.js +++ b/api/tests/unit/domain/models/Challenge_test.js @@ -4,7 +4,7 @@ import { ValidatorQCU } from '../../../../src/evaluation/domain/models/Validator import { ValidatorQROC } from '../../../../src/evaluation/domain/models/ValidatorQROC.js'; import { ValidatorQROCMDep } from '../../../../src/evaluation/domain/models/ValidatorQROCMDep.js'; import { ValidatorQROCMInd } from '../../../../src/evaluation/domain/models/ValidatorQROCMInd.js'; -import { Challenge } from '../../../../src/shared/domain/models/Challenge.js'; +import { Accessibility, Challenge } from '../../../../src/shared/domain/models/Challenge.js'; import { Skill } from '../../../../src/shared/domain/models/Skill.js'; import { domainBuilder, expect } from '../../../test-helper.js'; @@ -44,6 +44,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, + accessibility1: 'OK', + accessibility2: 'KO', }; const expectedChallengeDataObject = { @@ -78,6 +80,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, + accessibility1: 'OK', + accessibility2: 'KO', }; // when @@ -122,6 +126,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, + accessibility1: 'OK', + accessibility2: 'KO', }; const expectedChallengeDataObject = { @@ -156,6 +162,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, + accessibility1: 'OK', + accessibility2: 'KO', }; // when @@ -330,4 +338,29 @@ describe('Unit | Domain | Models | Challenge', function () { expect(challenge.isFocused()).to.be.false; }); }); + + describe('#isAccessible', function () { + /* eslint-disable mocha/no-setup-in-describe */ + [ + { accessibility1: Accessibility.OK, accessibility2: Accessibility.OK, isAccessible: true }, + { accessibility1: Accessibility.OK, accessibility2: Accessibility.RAS, isAccessible: true }, + { accessibility1: Accessibility.RAS, accessibility2: Accessibility.OK, isAccessible: true }, + { accessibility1: Accessibility.RAS, accessibility2: Accessibility.RAS, isAccessible: true }, + { accessibility1: Accessibility.OK, accessibility2: 'KO', isAccessible: false }, + { accessibility1: Accessibility.OK, accessibility2: 'autre chose', isAccessible: false }, + { accessibility1: 'autre chose', accessibility2: Accessibility.OK, isAccessible: false }, + { accessibility1: 'KO', accessibility2: Accessibility.RAS, isAccessible: false }, + /* eslint-enable mocha/no-setup-in-describe */ + ].forEach(({ accessibility1, accessibility2, isAccessible }) => { + context(`when accessibility1 is ${accessibility1} and accessibility2 is ${accessibility2}`, function () { + it(`returns ${isAccessible}`, function () { + // given + const challenge = domainBuilder.buildChallenge({ accessibility1, accessibility2 }); + + // when then + expect(challenge.isAccessible).to.equal(isAccessible); + }); + }); + }); + }); }); From 11f34eb2079596dbe071c51a08d3334792211990 Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Thu, 19 Sep 2024 16:03:14 +0200 Subject: [PATCH 05/12] tech: add debug logs for get-next-challenge-for-v3-certification Co-authored-by: --- .../usecases/get-next-challenge-for-v3-certification.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js index d0d1e86ecd4..aa4ed17eed6 100644 --- a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js @@ -18,9 +18,13 @@ * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationCandidateRepository} CertificationCandidateRepository */ +import Debug from 'debug'; + import { AssessmentEndedError } from '../../../../shared/domain/errors.js'; import { CertificationChallenge, FlashAssessmentAlgorithm } from '../../../../shared/domain/models/index.js'; +const debugGetNextChallengeForV3Certification = Debug('pix:certif:v3:get-next-challenge'); + /** * @param {Object} params * @param {AnswerRepository} params.answerRepository @@ -93,6 +97,11 @@ const getNextChallengeForV3Certification = async function ({ const challengesForCandidate = candidate.accessibilityAdjustmentNeeded ? challengesWithoutSkillsWithAValidatedLiveAlert.filter((challenge) => challenge.isAccessible) : challengesWithoutSkillsWithAValidatedLiveAlert; + debugGetNextChallengeForV3Certification( + candidate.accessibilityAdjustmentNeeded + ? `Candidate needs accessibility adjustment, possible challenges have been filtered (${challengesForCandidate.length} out of ${challengesWithoutSkillsWithAValidatedLiveAlert.length} selected` + : `Candidate does need any adjustment, all ${challengesWithoutSkillsWithAValidatedLiveAlert.length} have been selected`, + ); const possibleChallenges = assessmentAlgorithm.getPossibleNextChallenges({ assessmentAnswers: allAnswers, From da7f2380c7a4b7a3fc4ebbc0ca2c39e04465d6fe Mon Sep 17 00:00:00 2001 From: P-Jeremy Date: Thu, 19 Sep 2024 17:23:46 +0200 Subject: [PATCH 06/12] add certificationCandidateRepository in Evaluation context Co-authored-by: Guillaume LAGORCE --- .../certification-candidate-repository.js | 20 +++++ ...certification-candidate-repository_test.js | 81 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js create mode 100644 api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js diff --git a/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js b/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js new file mode 100644 index 00000000000..080c1f6f08f --- /dev/null +++ b/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js @@ -0,0 +1,20 @@ +import { knex } from '../../../../../db/knex-database-connection.js'; +import { CertificationCandidateNotFoundError } from '../../../../shared/domain/errors.js'; +import { CertificationCandidate } from '../../../../shared/domain/models/CertificationCandidate.js'; + +const findByAssessmentId = async function ({ assessmentId }) { + const result = await knex('certification-candidates') + .select('certification-candidates.*') + .join('certification-courses', 'certification-courses.userId', 'certification-candidates.userId') + .join('assessments', 'assessments.certificationCourseId', 'certification-courses.id') + .where('assessments.id', assessmentId) + .first(); + + if (!result) { + throw new CertificationCandidateNotFoundError(); + } + + return new CertificationCandidate(result); +}; + +export { findByAssessmentId }; diff --git a/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js b/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js new file mode 100644 index 00000000000..5e29154502f --- /dev/null +++ b/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js @@ -0,0 +1,81 @@ +import * as certificationCandidateRepository from '../../../../../../src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js'; +import { CertificationCandidateNotFoundError } from '../../../../../../src/shared/domain/errors.js'; +import { Assessment } from '../../../../../../src/shared/domain/models/Assessment.js'; +import { catchErr, databaseBuilder, domainBuilder, expect } from '../../../../../test-helper.js'; + +describe('Integration | Repository | certification candidate', function () { + describe('#findByAssessmentId', function () { + describe('when certification candidate is found', function () { + it('should return the certification candidate', async function () { + // given + const session = databaseBuilder.factory.buildSession(); + const user = databaseBuilder.factory.buildUser(); + const candidate = databaseBuilder.factory.buildCertificationCandidate({ + lastName: 'Joplin', + firstName: 'Janis', + sessionId: session.id, + userId: user.id, + authorizedToStart: false, + }); + const certificationCourse = databaseBuilder.factory.buildCertificationCourse({ + userId: user.id, + sessionId: session.id, + createdAt: new Date('2022-10-01T14:00:00Z'), + }); + const assessmentId = databaseBuilder.factory.buildAssessment({ + certificationCourseId: certificationCourse.id, + state: Assessment.states.STARTED, + }).id; + + await databaseBuilder.commit(); + + // when + const result = await certificationCandidateRepository.findByAssessmentId({ + assessmentId, + }); + + // then + expect(result).to.deep.equal( + domainBuilder.buildCertificationCandidate({ + ...candidate, + subscriptions: [], + }), + ); + }); + }); + + describe('when certification candidate is not found', function () { + it('should throw a certification candidate not found error', async function () { + // given + const session = databaseBuilder.factory.buildSession(); + const user = databaseBuilder.factory.buildUser(); + databaseBuilder.factory.buildCertificationCandidate({ + lastName: 'Joplin', + firstName: 'Janis', + sessionId: session.id, + userId: user.id, + authorizedToStart: false, + }); + const certificationCourse = databaseBuilder.factory.buildCertificationCourse({ + userId: user.id, + sessionId: session.id, + createdAt: new Date('2022-10-01T14:00:00Z'), + }); + databaseBuilder.factory.buildAssessment({ + certificationCourseId: certificationCourse.id, + state: Assessment.states.STARTED, + }); + + await databaseBuilder.commit(); + + // when + const error = await catchErr(certificationCandidateRepository.findByAssessmentId)({ + assessmentId: 4659, + }); + + // then + expect(error).to.be.an.instanceOf(CertificationCandidateNotFoundError); + }); + }); + }); +}); From e49872f6c92bf3659d8840f14bb7aaf9a8f506a1 Mon Sep 17 00:00:00 2001 From: P-Jeremy Date: Fri, 20 Sep 2024 14:57:58 +0200 Subject: [PATCH 07/12] Move get-next-challenge-for-v3-certification to evaluation context --- ...get-next-challenge-for-v3-certification.js | 8 --- .../evaluation/domain/usecases/index.js | 52 +++++++++++++++++++ .../assessments/assessment-controller.js | 1 + ...ext-challenge-for-v3-certification_test.js | 2 +- ...ment-controller-get-next-challenge_test.js | 5 +- 5 files changed, 57 insertions(+), 11 deletions(-) rename api/src/certification/{session-management => evaluation}/domain/usecases/get-next-challenge-for-v3-certification.js (90%) create mode 100644 api/src/certification/evaluation/domain/usecases/index.js rename api/tests/certification/{session-management => evaluation}/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js (99%) diff --git a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js similarity index 90% rename from api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js rename to api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js index aa4ed17eed6..d5915561478 100644 --- a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js @@ -1,12 +1,4 @@ /** - * @typedef {import('./index.js').AnswerRepository} AnswerRepository - * @typedef {import('./index.js').CertificationChallengeRepository} CertificationChallengeRepository - * @typedef {import('./index.js').CertificationChallengeLiveAlertRepository} CertificationChallengeLiveAlertRepository - * @typedef {import('./index.js').CertificationCourseRepository} CertificationCourseRepository - * @typedef {import('./index.js').ChallengeRepository} ChallengeRepository - * @typedef {import('./index.js').FlashAlgorithmConfigurationRepository} FlashAlgorithmConfigurationRepository - * @typedef {import('./index.js').PickChallengeService} PickChallengeService - * @typedef {import('./index.js').FlashAlgorithmService} FlashAlgorithmService * @typedef {import('../../../session-management/domain/usecases/index.js').AnswerRepository} AnswerRepository * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationChallengeRepository} CertificationChallengeRepository * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationChallengeLiveAlertRepository} CertificationChallengeLiveAlertRepository diff --git a/api/src/certification/evaluation/domain/usecases/index.js b/api/src/certification/evaluation/domain/usecases/index.js new file mode 100644 index 00000000000..1186103a7bd --- /dev/null +++ b/api/src/certification/evaluation/domain/usecases/index.js @@ -0,0 +1,52 @@ +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { pickChallengeService } from '../../../../evaluation/domain/services/pick-challenge-service.js'; +import { injectDependencies } from '../../../../shared/infrastructure/utils/dependency-injection.js'; +import { importNamedExportsFromDirectory } from '../../../../shared/infrastructure/utils/import-named-exports-from-directory.js'; +import * as flashAlgorithmService from '../../../flash-certification/domain/services/algorithm-methods/flash.js'; +import { + answerRepository, + assessmentRepository, + assessmentResultRepository, + certificationChallengeRepository, + challengeRepository, + competenceMarkRepository, + cpfExportRepository, + flashAlgorithmConfigurationRepository, + sessionRepositories, + sharedCompetenceMarkRepository, +} from '../../../session-management/infrastructure/repositories/index.js'; + +const dependencies = { + ...sessionRepositories, + assessmentRepository, + assessmentResultRepository, + answerRepository, + sharedCompetenceMarkRepository, + challengeRepository, + competenceMarkRepository, + cpfExportRepository, + certificationChallengeRepository, + flashAlgorithmConfigurationRepository, + flashAlgorithmService, + pickChallengeService, +}; + +const path = dirname(fileURLToPath(import.meta.url)); + +/** + * Note : current ignoredFileNames are injected in * {@link file://./../../../shared/domain/usecases/index.js} + * This is in progress, because they should be injected in this file and not by shared sub-domain + * The only remaining file ignored should be index.js + */ +const usecasesWithoutInjectedDependencies = { + ...(await importNamedExportsFromDirectory({ + path: join(path, './'), + ignoredFileNames: ['index.js'], + })), +}; + +const usecases = injectDependencies(usecasesWithoutInjectedDependencies, dependencies); + +export { usecases }; diff --git a/api/src/shared/application/assessments/assessment-controller.js b/api/src/shared/application/assessments/assessment-controller.js index 4b6e1ea2e20..7f66fbf22f1 100644 --- a/api/src/shared/application/assessments/assessment-controller.js +++ b/api/src/shared/application/assessments/assessment-controller.js @@ -1,6 +1,7 @@ import { Serializer as JSONAPISerializer } from 'jsonapi-serializer'; import { usecases } from '../../../../lib/domain/usecases/index.js'; +import { usecases as certificationEvaluationUsecases } from '../../../certification/evaluation/domain/usecases/index.js'; import * as certificationVersionRepository from '../../../certification/results/infrastructure/repositories/certification-version-repository.js'; import { usecases as certificationUsecases } from '../../../certification/session-management/domain/usecases/index.js'; import { CertificationVersion } from '../../../certification/shared/domain/models/CertificationVersion.js'; diff --git a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js similarity index 99% rename from api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js rename to api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js index 4bddbfec35f..e32a4973015 100644 --- a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js +++ b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js @@ -1,4 +1,4 @@ -import { getNextChallengeForV3Certification } from '../../../../../../src/certification/session-management/domain/usecases/get-next-challenge-for-v3-certification.js'; +import { getNextChallengeForV3Certification } from '../../../../../../src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js'; import { CERTIFICATION_VERSIONS } from '../../../../../../src/certification/shared/domain/models/CertificationVersion.js'; import { config } from '../../../../../../src/shared/config.js'; import { AssessmentEndedError } from '../../../../../../src/shared/domain/errors.js'; diff --git a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js index 7862c093dc3..f43ab0cb622 100644 --- a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js +++ b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js @@ -1,3 +1,4 @@ +import { usecases as certificationEvaluationUsecases } from '../../../../../src/certification/evaluation/domain/usecases/index.js'; import { usecases as certificationUsecases } from '../../../../../src/certification/session-management/domain/usecases/index.js'; import { assessmentController } from '../../../../../src/shared/application/assessments/assessment-controller.js'; import { LOCALE } from '../../../../../src/shared/domain/constants.js'; @@ -63,7 +64,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio }; sinon.stub(certificationUsecases, 'getNextChallengeForV2Certification'); - sinon.stub(certificationUsecases, 'getNextChallengeForV3Certification'); + sinon.stub(certificationEvaluationUsecases, 'getNextChallengeForV3Certification'); }); describe('when the assessment is a preview', function () { @@ -246,7 +247,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio it('should reply null data when unable to find the next challenge', async function () { // given - certificationUsecases.getNextChallengeForV3Certification.rejects(new AssessmentEndedError()); + certificationEvaluationUsecases.getNextChallengeForV3Certification.rejects(new AssessmentEndedError()); // when const response = await assessmentController.getNextChallenge({ params: { id: 12 } }, null, dependencies); From 753a19779871b36466aa572ed8a8710a4499c8f5 Mon Sep 17 00:00:00 2001 From: P-Jeremy Date: Fri, 20 Sep 2024 15:20:10 +0200 Subject: [PATCH 08/12] Move get-next-challenge-for-v2-certification to evaluation context --- .../get-next-challenge-for-v2-certification.js | 4 ++-- .../assessments/assessment-controller.js | 2 +- ...-next-challenge-for-v2-certification_test.js | 2 +- ...ssment-controller-get-next-challenge_test.js | 17 ++++++++--------- 4 files changed, 12 insertions(+), 13 deletions(-) rename api/src/certification/{session-management => evaluation}/domain/usecases/get-next-challenge-for-v2-certification.js (71%) rename api/tests/certification/{session-management => evaluation}/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js (96%) diff --git a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v2-certification.js b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v2-certification.js similarity index 71% rename from api/src/certification/session-management/domain/usecases/get-next-challenge-for-v2-certification.js rename to api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v2-certification.js index 6715c2f16aa..046288daaab 100644 --- a/api/src/certification/session-management/domain/usecases/get-next-challenge-for-v2-certification.js +++ b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v2-certification.js @@ -1,6 +1,6 @@ /** - * @typedef {import('./index.js').CertificationChallengeRepository} CertificationChallengeRepository - * @typedef {import('./index.js').ChallengeRepository} ChallengeRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').CertificationChallengeRepository} CertificationChallengeRepository + * @typedef {import('../../../session-management/domain/usecases/index.js').ChallengeRepository} ChallengeRepository */ /** diff --git a/api/src/shared/application/assessments/assessment-controller.js b/api/src/shared/application/assessments/assessment-controller.js index 7f66fbf22f1..d06cf6fc770 100644 --- a/api/src/shared/application/assessments/assessment-controller.js +++ b/api/src/shared/application/assessments/assessment-controller.js @@ -201,7 +201,7 @@ async function _getChallengeByAssessmentType({ assessment, request, dependencies if (CertificationVersion.isV3(certificationCourseVersion)) { return certificationUsecases.getNextChallengeForV3Certification({ assessment, locale }); } else { - return certificationUsecases.getNextChallengeForV2Certification({ assessment, locale }); + return certificationEvaluationUsecases.getNextChallengeForV2Certification({ assessment, locale }); } } diff --git a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js similarity index 96% rename from api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js rename to api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js index ea6c4fd91b8..30b4ad2255e 100644 --- a/api/tests/certification/session-management/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js +++ b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v2-certification_test.js @@ -1,4 +1,4 @@ -import { getNextChallengeForV2Certification } from '../../../../../../src/certification/session-management/domain/usecases/get-next-challenge-for-v2-certification.js'; +import { getNextChallengeForV2Certification } from '../../../../../../src/certification/evaluation/domain/usecases/get-next-challenge-for-v2-certification.js'; import { Assessment } from '../../../../../../src/shared/domain/models/Assessment.js'; import { domainBuilder, expect, sinon } from '../../../../../test-helper.js'; diff --git a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js index f43ab0cb622..0ee995aca84 100644 --- a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js +++ b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js @@ -1,5 +1,4 @@ import { usecases as certificationEvaluationUsecases } from '../../../../../src/certification/evaluation/domain/usecases/index.js'; -import { usecases as certificationUsecases } from '../../../../../src/certification/session-management/domain/usecases/index.js'; import { assessmentController } from '../../../../../src/shared/application/assessments/assessment-controller.js'; import { LOCALE } from '../../../../../src/shared/domain/constants.js'; import { AssessmentEndedError } from '../../../../../src/shared/domain/errors.js'; @@ -63,7 +62,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio certificationVersionRepository, }; - sinon.stub(certificationUsecases, 'getNextChallengeForV2Certification'); + sinon.stub(certificationEvaluationUsecases, 'getNextChallengeForV2Certification'); sinon.stub(certificationEvaluationUsecases, 'getNextChallengeForV3Certification'); }); @@ -96,7 +95,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio describe('when the assessment is over', function () { beforeEach(function () { - certificationUsecases.getNextChallengeForV2Certification.rejects(new AssessmentEndedError()); + certificationEvaluationUsecases.getNextChallengeForV2Certification.rejects(new AssessmentEndedError()); usecases.getNextChallengeForDemo.rejects(new AssessmentEndedError()); assessmentRepository.get.resolves(assessmentWithoutScore); usecases.getAssessment.resolves(scoredAsssessment); @@ -179,7 +178,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio it('should call getNextChallengeForCertificationCourse in assessmentService', async function () { // given const locale = FRENCH_SPOKEN; - certificationUsecases.getNextChallengeForV2Certification.resolves(); + certificationEvaluationUsecases.getNextChallengeForV2Certification.resolves(); // when await assessmentController.getNextChallenge( @@ -194,8 +193,8 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio ); // then - expect(certificationUsecases.getNextChallengeForV2Certification).to.have.been.calledOnce; - expect(certificationUsecases.getNextChallengeForV2Certification).to.have.been.calledWithExactly({ + expect(certificationEvaluationUsecases.getNextChallengeForV2Certification).to.have.been.calledOnce; + expect(certificationEvaluationUsecases.getNextChallengeForV2Certification).to.have.been.calledWithExactly({ assessment: certificationAssessment, locale, }); @@ -203,7 +202,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio it('should reply null data when unable to find the next challenge', async function () { // given - certificationUsecases.getNextChallengeForV2Certification.rejects(new AssessmentEndedError()); + certificationEvaluationUsecases.getNextChallengeForV2Certification.rejects(new AssessmentEndedError()); // when const response = await assessmentController.getNextChallenge({ params: { id: 12 } }, null, dependencies); @@ -238,8 +237,8 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio ); // then - expect(certificationUsecases.getNextChallengeForV3Certification).to.have.been.calledOnce; - expect(certificationUsecases.getNextChallengeForV3Certification).to.have.been.calledWithExactly({ + expect(certificationEvaluationUsecases.getNextChallengeForV3Certification).to.have.been.calledOnce; + expect(certificationEvaluationUsecases.getNextChallengeForV3Certification).to.have.been.calledWithExactly({ assessment: certificationAssessment, locale, }); From c5cf9ff21fb703774d9bbf991bbc9de7a76e65b9 Mon Sep 17 00:00:00 2001 From: P-Jeremy Date: Fri, 20 Sep 2024 16:04:30 +0200 Subject: [PATCH 09/12] Use correct repo in get-next-challenge-for-v3-certification --- ...get-next-challenge-for-v3-certification.js | 5 ++- .../evaluation/domain/usecases/index.js | 2 ++ .../certification-candidate-repository.js | 4 +-- ...certification-candidate-repository_test.js | 2 +- ...ext-challenge-for-v3-certification_test.js | 35 ++++++++----------- ...t-next-challenge-for-certification_test.js | 3 +- 6 files changed, 24 insertions(+), 27 deletions(-) diff --git a/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js index d5915561478..eb7650431f6 100644 --- a/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js @@ -40,8 +40,7 @@ const getNextChallengeForV3Certification = async function ({ flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }) { const certificationCourse = await certificationCourseRepository.get({ id: assessment.certificationCourseId }); @@ -85,7 +84,7 @@ const getNextChallengeForV3Certification = async function ({ challenges, }); - const candidate = await certificationCandidateForSupervisingRepository.get({ certificationCandidateId }); + const candidate = await certificationCandidateRepository.findByAssessmentId({ assessmentId: assessment.id }); const challengesForCandidate = candidate.accessibilityAdjustmentNeeded ? challengesWithoutSkillsWithAValidatedLiveAlert.filter((challenge) => challenge.isAccessible) : challengesWithoutSkillsWithAValidatedLiveAlert; diff --git a/api/src/certification/evaluation/domain/usecases/index.js b/api/src/certification/evaluation/domain/usecases/index.js index 1186103a7bd..bbe86fd63ac 100644 --- a/api/src/certification/evaluation/domain/usecases/index.js +++ b/api/src/certification/evaluation/domain/usecases/index.js @@ -17,9 +17,11 @@ import { sessionRepositories, sharedCompetenceMarkRepository, } from '../../../session-management/infrastructure/repositories/index.js'; +import * as certificationCandidateRepository from '../../infrastructure/repositories/certification-candidate-repository.js'; const dependencies = { ...sessionRepositories, + certificationCandidateRepository, assessmentRepository, assessmentResultRepository, answerRepository, diff --git a/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js b/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js index 080c1f6f08f..6c9dff31584 100644 --- a/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js +++ b/api/src/certification/evaluation/infrastructure/repositories/certification-candidate-repository.js @@ -1,6 +1,6 @@ import { knex } from '../../../../../db/knex-database-connection.js'; import { CertificationCandidateNotFoundError } from '../../../../shared/domain/errors.js'; -import { CertificationCandidate } from '../../../../shared/domain/models/CertificationCandidate.js'; +import { Candidate } from '../../../enrolment/domain/models/Candidate.js'; const findByAssessmentId = async function ({ assessmentId }) { const result = await knex('certification-candidates') @@ -14,7 +14,7 @@ const findByAssessmentId = async function ({ assessmentId }) { throw new CertificationCandidateNotFoundError(); } - return new CertificationCandidate(result); + return new Candidate(result); }; export { findByAssessmentId }; diff --git a/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js b/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js index 5e29154502f..50c8a5ac3a6 100644 --- a/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js +++ b/api/tests/certification/evaluation/integration/infrastructure/repositories/certification-candidate-repository_test.js @@ -36,7 +36,7 @@ describe('Integration | Repository | certification candidate', function () { // then expect(result).to.deep.equal( - domainBuilder.buildCertificationCandidate({ + domainBuilder.certification.enrolment.buildCandidate({ ...candidate, subscriptions: [], }), diff --git a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js index e32a4973015..9ff9c406112 100644 --- a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js +++ b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js @@ -14,10 +14,11 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', pickChallengeService, flashAlgorithmService, flashAlgorithmConfigurationRepository, - certificationCandidateForSupervisingRepository; + certificationCandidateRepository; let flashAlgorithmConfiguration; let certificationCandidateId; + let assessment; beforeEach(function () { flashAlgorithmConfigurationRepository = { @@ -47,15 +48,16 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', getPossibleNextChallenges: sinon.stub(), getCapacityAndErrorRate: sinon.stub(), }; - certificationCandidateForSupervisingRepository = { - get: sinon.stub(), + certificationCandidateRepository = { + findByAssessmentId: sinon.stub(), }; + assessment = domainBuilder.buildAssessment(); const candidate = domainBuilder.buildCertificationCandidateForSupervising({ accessibilityAdjustmentNeeded: false, }); certificationCandidateId = candidate.id; - certificationCandidateForSupervisingRepository.get.withArgs({ certificationCandidateId }).resolves(candidate); + certificationCandidateRepository.findByAssessmentId.withArgs({ assessmentId: assessment.id }).resolves(candidate); flashAlgorithmConfiguration = domainBuilder.buildFlashAlgorithmConfiguration(); }); @@ -69,7 +71,6 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', const v3CertificationCourse = domainBuilder.buildCertificationCourse({ version: CERTIFICATION_VERSIONS.V3, }); - const assessment = domainBuilder.buildAssessment(); const locale = 'fr-FR'; flashAlgorithmConfigurationRepository.getMostRecentBeforeDate @@ -131,8 +132,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }); // then @@ -215,8 +215,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', accessibilityAdjustmentNeeded: true, }); - certificationCandidateForSupervisingRepository.get - .withArgs({ certificationCandidateId: candidateNeedingAccessibilityAdjustment.id }) + certificationCandidateRepository.findByAssessmentId + .withArgs({ assessmentId: assessment.id }) .resolves(candidateNeedingAccessibilityAdjustment); // when @@ -231,8 +231,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateId: candidateNeedingAccessibilityAdjustment.id, - certificationCandidateForSupervisingRepository, + certificationCandidateRepository, }); // then @@ -283,8 +282,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }); // then @@ -376,8 +374,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }); // then @@ -475,8 +472,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }); // then @@ -534,7 +530,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, + certificationCandidateRepository, certificationCandidateId, }); @@ -640,8 +636,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', flashAlgorithmService, locale, pickChallengeService, - certificationCandidateForSupervisingRepository, - certificationCandidateId, + certificationCandidateRepository, }); // then diff --git a/api/tests/shared/acceptance/application/assessments/assessment-controller-get-next-challenge-for-certification_test.js b/api/tests/shared/acceptance/application/assessments/assessment-controller-get-next-challenge-for-certification_test.js index 78ed4e3958a..d5e7889b3dd 100644 --- a/api/tests/shared/acceptance/application/assessments/assessment-controller-get-next-challenge-for-certification_test.js +++ b/api/tests/shared/acceptance/application/assessments/assessment-controller-get-next-challenge-for-certification_test.js @@ -83,7 +83,7 @@ describe('Acceptance | API | assessment-controller-get-next-challenge-for-certif let clock; beforeEach(async function () { - databaseBuilder.factory.buildUser({ id: userId }); + const user = databaseBuilder.factory.buildUser({ id: userId }); const certificationCenterId = databaseBuilder.factory.buildCertificationCenter({ isV3Pilot: true }).id; const sessionId = databaseBuilder.factory.buildSession({ certificationCenterId, @@ -96,6 +96,7 @@ describe('Acceptance | API | assessment-controller-get-next-challenge-for-certif userId, sessionId, }).id; + databaseBuilder.factory.buildCertificationCandidate({ ...user, userId: user.id, sessionId }); databaseBuilder.factory.buildAssessment({ id: assessmentId, type: Assessment.types.CERTIFICATION, From 6ce5faf48b3e6c20b30488c58b65bbde153eb9bf Mon Sep 17 00:00:00 2001 From: P-Jeremy Date: Fri, 20 Sep 2024 16:11:23 +0200 Subject: [PATCH 10/12] Fix flacky test on super fast machine --- .../repositories/center-pilot-features-repository_test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/tests/certification/configuration/integration/infrastructure/repositories/center-pilot-features-repository_test.js b/api/tests/certification/configuration/integration/infrastructure/repositories/center-pilot-features-repository_test.js index 7584c9b300d..ede7e12362e 100644 --- a/api/tests/certification/configuration/integration/infrastructure/repositories/center-pilot-features-repository_test.js +++ b/api/tests/certification/configuration/integration/infrastructure/repositories/center-pilot-features-repository_test.js @@ -41,7 +41,10 @@ describe('Certification | Configuration | Integration | Repository | center-pilo describe('update', function () { it('should update the center pilot features', async function () { // given - const centerData = databaseBuilder.factory.buildCertificationCenter({ isV3Pilot: false, updatedAt: new Date() }); + const centerData = databaseBuilder.factory.buildCertificationCenter({ + isV3Pilot: false, + updatedAt: new Date('2020-01-01'), + }); await databaseBuilder.commit(); // when From a95d6b59a217f8759637fc3255198a7f893d22b3 Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Mon, 23 Sep 2024 10:50:40 +0200 Subject: [PATCH 11/12] refactor(certif): rename `get-next-challenge-for-v3-certification` as v3 is the standard now --- ...certification.js => get-next-challenge.js} | 4 ++-- .../assessments/assessment-controller.js | 2 +- ...ion_test.js => get-next-challenge_test.js} | 20 +++++++++---------- ...ment-controller-get-next-challenge_test.js | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) rename api/src/certification/evaluation/domain/usecases/{get-next-challenge-for-v3-certification.js => get-next-challenge.js} (98%) rename api/tests/certification/evaluation/unit/domain/usecases/{get-next-challenge-for-v3-certification_test.js => get-next-challenge_test.js} (96%) diff --git a/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js b/api/src/certification/evaluation/domain/usecases/get-next-challenge.js similarity index 98% rename from api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js rename to api/src/certification/evaluation/domain/usecases/get-next-challenge.js index eb7650431f6..d8ad3223207 100644 --- a/api/src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js +++ b/api/src/certification/evaluation/domain/usecases/get-next-challenge.js @@ -29,7 +29,7 @@ const debugGetNextChallengeForV3Certification = Debug('pix:certif:v3:get-next-ch * @param {PickChallengeService} params.pickChallengeService * @param {CertificationCandidateRepository} params.certificationCandidateRepository */ -const getNextChallengeForV3Certification = async function ({ +const getNextChallenge = async function ({ assessment, answerRepository, certificationChallengeRepository, @@ -151,4 +151,4 @@ const _getValidatedLiveAlertChallengeIds = async ({ assessmentId, certificationC return certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId({ assessmentId }); }; -export { getNextChallengeForV3Certification }; +export { getNextChallenge }; diff --git a/api/src/shared/application/assessments/assessment-controller.js b/api/src/shared/application/assessments/assessment-controller.js index d06cf6fc770..398a727f68e 100644 --- a/api/src/shared/application/assessments/assessment-controller.js +++ b/api/src/shared/application/assessments/assessment-controller.js @@ -199,7 +199,7 @@ async function _getChallengeByAssessmentType({ assessment, request, dependencies }); if (CertificationVersion.isV3(certificationCourseVersion)) { - return certificationUsecases.getNextChallengeForV3Certification({ assessment, locale }); + return certificationEvaluationUsecases.getNextChallenge({ assessment, locale }); } else { return certificationEvaluationUsecases.getNextChallengeForV2Certification({ assessment, locale }); } diff --git a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js similarity index 96% rename from api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js rename to api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js index 9ff9c406112..2f8b5aede1b 100644 --- a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge-for-v3-certification_test.js +++ b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js @@ -1,11 +1,11 @@ -import { getNextChallengeForV3Certification } from '../../../../../../src/certification/evaluation/domain/usecases/get-next-challenge-for-v3-certification.js'; +import { getNextChallenge } from '../../../../../../src/certification/evaluation/domain/usecases/get-next-challenge.js'; import { CERTIFICATION_VERSIONS } from '../../../../../../src/certification/shared/domain/models/CertificationVersion.js'; import { config } from '../../../../../../src/shared/config.js'; import { AssessmentEndedError } from '../../../../../../src/shared/domain/errors.js'; import { catchErr, domainBuilder, expect, sinon } from '../../../../../test-helper.js'; -describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', function () { - describe('#getNextChallengeForV3Certification', function () { +describe('Unit | Domain | Use Cases | get-next-challenge', function () { + describe('#getNextChallenge', function () { let answerRepository, challengeRepository, certificationCourseRepository, @@ -121,7 +121,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', pickChallengeService.chooseNextChallenge.withArgs().returns(chooseNextChallengeImpl); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, @@ -220,7 +220,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', .resolves(candidateNeedingAccessibilityAdjustment); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, @@ -271,7 +271,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', challengeRepository.get.withArgs(nonAnsweredCertificationChallenge.challengeId).resolves(lastSeenChallenge); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, @@ -363,7 +363,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', pickChallengeService.chooseNextChallenge.withArgs().returns(chooseNextChallengeImpl); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, @@ -461,7 +461,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', pickChallengeService.chooseNextChallenge.withArgs().returns(chooseNextChallengeImpl); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, @@ -519,7 +519,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', challengeRepository.findActiveFlashCompatible.withArgs({ locale }).resolves([answeredChallenge]); // when - const error = await catchErr(getNextChallengeForV3Certification)({ + const error = await catchErr(getNextChallenge)({ answerRepository, assessment, certificationChallengeRepository, @@ -625,7 +625,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge-for-v3-certification', pickChallengeService.chooseNextChallenge.withArgs().returns(chooseNextChallengeImpl); // when - const challenge = await getNextChallengeForV3Certification({ + const challenge = await getNextChallenge({ answerRepository, assessment, certificationChallengeRepository, diff --git a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js index 0ee995aca84..7f968a435e9 100644 --- a/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js +++ b/api/tests/shared/unit/application/assessments/assessment-controller-get-next-challenge_test.js @@ -63,7 +63,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio }; sinon.stub(certificationEvaluationUsecases, 'getNextChallengeForV2Certification'); - sinon.stub(certificationEvaluationUsecases, 'getNextChallengeForV3Certification'); + sinon.stub(certificationEvaluationUsecases, 'getNextChallenge'); }); describe('when the assessment is a preview', function () { @@ -222,7 +222,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio it('should call getNextChallengeForCertificationCourse in assessmentService', async function () { // given const locale = FRENCH_SPOKEN; - certificationUsecases.getNextChallengeForV3Certification.resolves(); + certificationEvaluationUsecases.getNextChallenge.resolves(); // when await assessmentController.getNextChallenge( @@ -237,8 +237,8 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio ); // then - expect(certificationEvaluationUsecases.getNextChallengeForV3Certification).to.have.been.calledOnce; - expect(certificationEvaluationUsecases.getNextChallengeForV3Certification).to.have.been.calledWithExactly({ + expect(certificationEvaluationUsecases.getNextChallenge).to.have.been.calledOnce; + expect(certificationEvaluationUsecases.getNextChallenge).to.have.been.calledWithExactly({ assessment: certificationAssessment, locale, }); @@ -246,7 +246,7 @@ describe('Unit | Controller | assessment-controller-get-next-challenge', functio it('should reply null data when unable to find the next challenge', async function () { // given - certificationEvaluationUsecases.getNextChallengeForV3Certification.rejects(new AssessmentEndedError()); + certificationEvaluationUsecases.getNextChallenge.rejects(new AssessmentEndedError()); // when const response = await assessmentController.getNextChallenge({ params: { id: 12 } }, null, dependencies); From e84feeeba875b4955dc3fcc409e344d1b30e93c9 Mon Sep 17 00:00:00 2001 From: Guillaume Lagorce Date: Mon, 23 Sep 2024 14:49:53 +0200 Subject: [PATCH 12/12] refactor(api): rename accessibility1 and 2 for better clarity --- api/src/shared/domain/models/Challenge.js | 16 +++--- .../repositories/challenge-repository.js | 4 +- .../usecases/get-next-challenge_test.js | 14 ++--- .../repositories/challenge-repository_test.js | 15 ++++- .../domain-builder/factory/build-challenge.js | 16 +++--- .../unit/domain/models/Challenge_test.js | 55 ++++++++++--------- 6 files changed, 68 insertions(+), 52 deletions(-) diff --git a/api/src/shared/domain/models/Challenge.js b/api/src/shared/domain/models/Challenge.js index 53b2b4db47a..ee1d23b7420 100644 --- a/api/src/shared/domain/models/Challenge.js +++ b/api/src/shared/domain/models/Challenge.js @@ -54,8 +54,8 @@ class Challenge { * @param successProbabilityThreshold * @param shuffled * @param alternativeVersion - * @param accessibility1 - * @param accessibility2 + * @param blindnessCompatibility + * @param colorBlindnessCompatibility */ constructor({ id, @@ -87,8 +87,8 @@ class Challenge { responsive, shuffled, alternativeVersion, - accessibility1, - accessibility2, + blindnessCompatibility, + colorBlindnessCompatibility, } = {}) { this.id = id; this.answer = answer; @@ -119,8 +119,8 @@ class Challenge { this.successProbabilityThreshold = successProbabilityThreshold; this.shuffled = shuffled; this.alternativeVersion = alternativeVersion; - this.accessibility1 = accessibility1; - this.accessibility2 = accessibility2; + this.blindnessCompatibility = blindnessCompatibility; + this.colorBlindnessCompatibility = colorBlindnessCompatibility; } isTimed() { @@ -161,8 +161,8 @@ class Challenge { get isAccessible() { return ( - (this.accessibility1 === Accessibility.OK || this.accessibility1 === Accessibility.RAS) && - (this.accessibility2 === Accessibility.OK || this.accessibility2 === Accessibility.RAS) + (this.blindnessCompatibility === Accessibility.OK || this.blindnessCompatibility === Accessibility.RAS) && + (this.colorBlindnessCompatibility === Accessibility.OK || this.colorBlindnessCompatibility === Accessibility.RAS) ); } diff --git a/api/src/shared/infrastructure/repositories/challenge-repository.js b/api/src/shared/infrastructure/repositories/challenge-repository.js index b73b82e377e..ae52fd96473 100644 --- a/api/src/shared/infrastructure/repositories/challenge-repository.js +++ b/api/src/shared/infrastructure/repositories/challenge-repository.js @@ -205,7 +205,7 @@ function _toDomain({ challengeDataObject, skillDataObject, successProbabilityThr shuffled: challengeDataObject.shuffled, successProbabilityThreshold, alternativeVersion: challengeDataObject.alternativeVersion, - accessibility1: challengeDataObject.accessibility1, - accessibility2: challengeDataObject.accessibility2, + blindnessCompatibility: challengeDataObject.accessibility1, + colorBlindnessCompatibility: challengeDataObject.accessibility2, }); } diff --git a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js index 2f8b5aede1b..7f16fba12ac 100644 --- a/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js +++ b/api/tests/certification/evaluation/unit/domain/usecases/get-next-challenge_test.js @@ -66,7 +66,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () { it('should save the returned next challenge', async function () { // given const nextChallengeToAnswer = domainBuilder.buildChallenge({ - accessibility1: 'KO', + blindnessCompatibility: 'KO', }); const v3CertificationCourse = domainBuilder.buildCertificationCourse({ version: CERTIFICATION_VERSIONS.V3, @@ -143,19 +143,19 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () { it('should only pick among challenges with no accessibilities issues', async function () { // given const nextChallengeToAnswer = domainBuilder.buildChallenge({ - accessibility1: 'RAS', - accessibility2: 'OK', + blindnessCompatibility: 'RAS', + colorBlindnessCompatibility: 'OK', }); const accessibleChallenge = domainBuilder.buildChallenge({ - accessibility1: 'OK', - accessibility2: 'RAS', + blindnessCompatibility: 'OK', + colorBlindnessCompatibility: 'RAS', }); const allChallenges = [ nextChallengeToAnswer, accessibleChallenge, domainBuilder.buildChallenge({ - accessibility1: 'autre chose', - accessibility2: 'OK', + blindnessCompatibility: 'autre chose', + colorBlindnessCompatibility: 'OK', }), ]; const v3CertificationCourse = domainBuilder.buildCertificationCourse({ diff --git a/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js b/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js index 2213e18b126..4c6ea744ea7 100644 --- a/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js +++ b/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js @@ -27,6 +27,8 @@ describe('Integration | Repository | challenge-repository', function () { ...challenge, focused: challenge.focusable, skill: domainBuilder.buildSkill({ ...skill, difficulty: skill.level }), + blindnessCompatibility: challenge.accessibility1, + colorBlindnessCompatibility: challenge.accessibility2, }); // when @@ -89,6 +91,8 @@ describe('Integration | Repository | challenge-repository', function () { webComponentProps: { prop1: 'value1', prop2: 'value2' }, focused: challenge.focusable, skill: domainBuilder.buildSkill({ ...skill, difficulty: skill.level }), + blindnessCompatibility: challenge.accessibility1, + colorBlindnessCompatibility: challenge.accessibility2, }); // when @@ -113,7 +117,16 @@ describe('Integration | Repository | challenge-repository', function () { const learningContent = { skills: [{ ...skill, status: 'actif' }], - challenges: [{ ...challenge, skillId: 'recSkill1', alpha: 1, delta: 0 }], + challenges: [ + { + ...challenge, + skillId: 'recSkill1', + alpha: 1, + delta: 0, + blindnessCompatibility: challenge.accessibility1, + colorBlindnessCompatibility: challenge.accessibility2, + }, + ], }; mockLearningContent(learningContent); diff --git a/api/tests/tooling/domain-builder/factory/build-challenge.js b/api/tests/tooling/domain-builder/factory/build-challenge.js index 029b39b5b26..1b8428655fc 100644 --- a/api/tests/tooling/domain-builder/factory/build-challenge.js +++ b/api/tests/tooling/domain-builder/factory/build-challenge.js @@ -27,8 +27,8 @@ const buildChallenge = function ({ focused = false, shuffled = false, alternativeVersion = undefined, - accessibility1 = 'OK', - accessibility2 = 'RAS', + blindnessCompatibility = 'OK', + colorBlindnessCompatibility = 'RAS', // includes answer, validator = new Validator(), @@ -61,8 +61,8 @@ const buildChallenge = function ({ illustrationAlt, shuffled, alternativeVersion, - accessibility1, - accessibility2, + blindnessCompatibility, + colorBlindnessCompatibility, // includes answer, validator, @@ -97,8 +97,8 @@ const buildChallengeWithWebComponent = function ({ focused = false, shuffled = false, alternativeVersion = undefined, - accessibility1, - accessibility2, + blindnessCompatibility, + colorBlindnessCompatibility, // includes answer, validator = new Validator(), @@ -131,8 +131,8 @@ const buildChallengeWithWebComponent = function ({ illustrationAlt, shuffled, alternativeVersion, - accessibility1, - accessibility2, + blindnessCompatibility, + colorBlindnessCompatibility, // includes answer, validator, diff --git a/api/tests/unit/domain/models/Challenge_test.js b/api/tests/unit/domain/models/Challenge_test.js index 677a45a4ae7..62cc49fb4de 100644 --- a/api/tests/unit/domain/models/Challenge_test.js +++ b/api/tests/unit/domain/models/Challenge_test.js @@ -44,8 +44,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, - accessibility1: 'OK', - accessibility2: 'KO', + blindnessCompatibility: 'OK', + colorBlindnessCompatibility: 'KO', }; const expectedChallengeDataObject = { @@ -80,8 +80,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, - accessibility1: 'OK', - accessibility2: 'KO', + blindnessCompatibility: 'OK', + colorBlindnessCompatibility: 'KO', }; // when @@ -126,8 +126,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, - accessibility1: 'OK', - accessibility2: 'KO', + blindnessCompatibility: 'OK', + colorBlindnessCompatibility: 'KO', }; const expectedChallengeDataObject = { @@ -162,8 +162,8 @@ describe('Unit | Domain | Models | Challenge', function () { responsive: 'Smartphone', shuffled: false, alternativeVersion: 1, - accessibility1: 'OK', - accessibility2: 'KO', + blindnessCompatibility: 'OK', + colorBlindnessCompatibility: 'KO', }; // when @@ -342,25 +342,28 @@ describe('Unit | Domain | Models | Challenge', function () { describe('#isAccessible', function () { /* eslint-disable mocha/no-setup-in-describe */ [ - { accessibility1: Accessibility.OK, accessibility2: Accessibility.OK, isAccessible: true }, - { accessibility1: Accessibility.OK, accessibility2: Accessibility.RAS, isAccessible: true }, - { accessibility1: Accessibility.RAS, accessibility2: Accessibility.OK, isAccessible: true }, - { accessibility1: Accessibility.RAS, accessibility2: Accessibility.RAS, isAccessible: true }, - { accessibility1: Accessibility.OK, accessibility2: 'KO', isAccessible: false }, - { accessibility1: Accessibility.OK, accessibility2: 'autre chose', isAccessible: false }, - { accessibility1: 'autre chose', accessibility2: Accessibility.OK, isAccessible: false }, - { accessibility1: 'KO', accessibility2: Accessibility.RAS, isAccessible: false }, + { blindnessCompatibility: Accessibility.OK, colorBlindnessCompatibility: Accessibility.OK, isAccessible: true }, + { blindnessCompatibility: Accessibility.OK, colorBlindnessCompatibility: Accessibility.RAS, isAccessible: true }, + { blindnessCompatibility: Accessibility.RAS, colorBlindnessCompatibility: Accessibility.OK, isAccessible: true }, + { blindnessCompatibility: Accessibility.RAS, colorBlindnessCompatibility: Accessibility.RAS, isAccessible: true }, + { blindnessCompatibility: Accessibility.OK, colorBlindnessCompatibility: 'KO', isAccessible: false }, + { blindnessCompatibility: Accessibility.OK, colorBlindnessCompatibility: 'autre chose', isAccessible: false }, + { blindnessCompatibility: 'autre chose', colorBlindnessCompatibility: Accessibility.OK, isAccessible: false }, + { blindnessCompatibility: 'KO', colorBlindnessCompatibility: Accessibility.RAS, isAccessible: false }, /* eslint-enable mocha/no-setup-in-describe */ - ].forEach(({ accessibility1, accessibility2, isAccessible }) => { - context(`when accessibility1 is ${accessibility1} and accessibility2 is ${accessibility2}`, function () { - it(`returns ${isAccessible}`, function () { - // given - const challenge = domainBuilder.buildChallenge({ accessibility1, accessibility2 }); - - // when then - expect(challenge.isAccessible).to.equal(isAccessible); - }); - }); + ].forEach(({ blindnessCompatibility, colorBlindnessCompatibility, isAccessible }) => { + context( + `when blindnessCompatibility is ${blindnessCompatibility} and colorBlindnessCompatibility is ${colorBlindnessCompatibility}`, + function () { + it(`returns ${isAccessible}`, function () { + // given + const challenge = domainBuilder.buildChallenge({ blindnessCompatibility, colorBlindnessCompatibility }); + + // when then + expect(challenge.isAccessible).to.equal(isAccessible); + }); + }, + ); }); }); });