diff --git a/api/src/certification/flash-certification/application/scenario-simulator-controller.js b/api/src/certification/flash-certification/application/scenario-simulator-controller.js index efd008ed8d3..48db1af75b3 100644 --- a/api/src/certification/flash-certification/application/scenario-simulator-controller.js +++ b/api/src/certification/flash-certification/application/scenario-simulator-controller.js @@ -22,16 +22,12 @@ async function simulateFlashAssessmentScenario( }, ) { const { - stopAtChallenge, initialCapacity, numberOfIterations = 1, challengePickProbability, challengesBetweenSameCompetence, - limitToOneQuestionPerTube, minimumEstimatedSuccessRateRanges: minimumEstimatedSuccessRateRangesDto, - doubleMeasuresUntil, variationPercent, - variationPercentUntil, capacity, } = request.payload; @@ -54,14 +50,10 @@ async function simulateFlashAssessmentScenario( pickAnswerStatus, pickChallenge, locale, - stopAtChallenge, initialCapacity, challengesBetweenSameCompetence, - limitToOneQuestionPerTube, minimumEstimatedSuccessRateRanges, - doubleMeasuresUntil, variationPercent, - variationPercentUntil, }, _.isUndefined, ); diff --git a/api/src/certification/flash-certification/application/scenario-simulator-route.js b/api/src/certification/flash-certification/application/scenario-simulator-route.js index 4e830212a7d..5bcb1d6674c 100644 --- a/api/src/certification/flash-certification/application/scenario-simulator-route.js +++ b/api/src/certification/flash-certification/application/scenario-simulator-route.js @@ -11,15 +11,11 @@ const _successRatesConfigurationValidator = Joi.object({ const _baseScenarioParametersValidator = Joi.object().keys({ initialCapacity: Joi.number().integer().min(-8).max(8), - stopAtChallenge: Joi.number().integer().min(0), numberOfIterations: Joi.number().integer().min(0), challengePickProbability: Joi.number().min(0).max(100), challengesBetweenSameCompetence: Joi.number().min(0), - limitToOneQuestionPerTube: Joi.boolean(), minimumEstimatedSuccessRateRanges: Joi.array().items(_successRatesConfigurationValidator), - doubleMeasuresUntil: Joi.number().min(0), variationPercent: Joi.number().min(0).max(1), - variationPercentUntil: Joi.number().min(0), }); const register = async (server) => { diff --git a/api/src/certification/flash-certification/domain/models/AssessmentSimulator.js b/api/src/certification/flash-certification/domain/models/AssessmentSimulator.js index 5a7d4cb3b50..82af75f54e6 100644 --- a/api/src/certification/flash-certification/domain/models/AssessmentSimulator.js +++ b/api/src/certification/flash-certification/domain/models/AssessmentSimulator.js @@ -1,8 +1,8 @@ import { logger } from '../../../../shared/infrastructure/utils/logger.js'; export class AssessmentSimulator { - constructor({ getStrategy }) { - this.getStrategy = getStrategy; + constructor({ strategy }) { + this.strategy = strategy; } run({ challengesAnswers } = { challengesAnswers: [] }) { @@ -14,7 +14,7 @@ export class AssessmentSimulator { do { hasNextAnswer = false; - const simulatorStepResult = this.getStrategy(stepIndex).run({ challengesAnswers, stepIndex }); + const simulatorStepResult = this.strategy.run({ challengesAnswers, stepIndex }); if (simulatorStepResult) { stepIndex = simulatorStepResult.nextStepIndex; challengesAnswers.push(...simulatorStepResult.challengeAnswers); diff --git a/api/src/certification/flash-certification/domain/models/AssessmentSimulatorDoubleMeasureStrategy.js b/api/src/certification/flash-certification/domain/models/AssessmentSimulatorDoubleMeasureStrategy.js deleted file mode 100644 index 141f73ff613..00000000000 --- a/api/src/certification/flash-certification/domain/models/AssessmentSimulatorDoubleMeasureStrategy.js +++ /dev/null @@ -1,99 +0,0 @@ -import { Answer } from '../../../../evaluation/domain/models/Answer.js'; - -const NUMBER_OF_MEASURES = 2; -export class AssessmentSimulatorDoubleMeasureStrategy { - constructor({ algorithm, challenges, pickChallenge, pickAnswerStatus, initialCapacity, doubleMeasuresUntil }) { - this.algorithm = algorithm; - this.challenges = challenges; - this.pickAnswerStatus = pickAnswerStatus; - this.pickChallenge = pickChallenge; - this.initialCapacity = initialCapacity; - this.doubleMeasuresUntil = doubleMeasuresUntil; - } - - run({ challengesAnswers, stepIndex }) { - const results = []; - const newAnswers = []; - - const { capacity: capacityBefore } = this.algorithm.getCapacityAndErrorRate({ - allAnswers: challengesAnswers, - challenges: this.challenges, - initialCapacity: this.initialCapacity, - doubleMeasuresUntil: this.doubleMeasuresUntil, - }); - - for (let index = 0; index < NUMBER_OF_MEASURES; index++) { - const possibleChallenges = this.algorithm.getPossibleNextChallenges({ - assessmentAnswers: [...challengesAnswers, ...newAnswers], - challenges: this.challenges, - initialCapacity: this.initialCapacity, - answersForComputingCapacity: challengesAnswers, - }); - - const availableChallenges = possibleChallenges.filter(({ id }) => { - return newAnswers.every(({ challengeId }) => challengeId !== id); - }); - const { hasAssessmentEnded, nextChallenge, answer } = this._getNextChallengeAndAnswer({ - possibleChallenges: availableChallenges, - stepIndex: stepIndex + index, - }); - - if (hasAssessmentEnded) { - return null; - } - - const reward = this.algorithm.getReward({ - capacity: capacityBefore, - difficulty: nextChallenge.difficulty, - discriminant: nextChallenge.discriminant, - }); - - results.push({ - challenge: nextChallenge, - answerStatus: answer.result.status, - reward, - }); - - newAnswers.push(answer); - } - - const { capacity } = this.algorithm.getCapacityAndErrorRate({ - allAnswers: [...challengesAnswers, ...newAnswers], - challenges: this.challenges, - initialCapacity: this.initialCapacity, - doubleMeasuresUntil: this.doubleMeasuresUntil, - }); - - return { - results: results.map((result) => ({ ...result, capacity })), - challengeAnswers: newAnswers, - nextStepIndex: stepIndex + NUMBER_OF_MEASURES, - }; - } - - _getNextChallengeAndAnswer({ possibleChallenges, stepIndex }) { - const nextChallenge = this.pickChallenge({ possibleChallenges }); - - const answerStatus = this.pickAnswerStatus({ - answerIndex: stepIndex, - nextChallenge, - }); - - const noMoreAnswerRemaining = !answerStatus; - - if (noMoreAnswerRemaining) { - return { - hasAssessmentEnded: true, - }; - } - - return { - nextChallenge, - answer: new Answer({ - result: answerStatus, - challengeId: nextChallenge.id, - }), - hasAssessmentEnded: false, - }; - } -} diff --git a/api/src/certification/flash-certification/domain/usecases/simulate-flash-assessment-scenario.js b/api/src/certification/flash-certification/domain/usecases/simulate-flash-assessment-scenario.js index 1b23dacd5ff..a187a8ddb4d 100644 --- a/api/src/certification/flash-certification/domain/usecases/simulate-flash-assessment-scenario.js +++ b/api/src/certification/flash-certification/domain/usecases/simulate-flash-assessment-scenario.js @@ -1,6 +1,5 @@ import { FlashAssessmentAlgorithmConfiguration } from '../../../shared/domain/models/FlashAssessmentAlgorithmConfiguration.js'; import { AssessmentSimulator } from '../models/AssessmentSimulator.js'; -import { AssessmentSimulatorDoubleMeasureStrategy } from '../models/AssessmentSimulatorDoubleMeasureStrategy.js'; import { AssessmentSimulatorSingleMeasureStrategy } from '../models/AssessmentSimulatorSingleMeasureStrategy.js'; import { FlashAssessmentAlgorithm } from '../models/FlashAssessmentAlgorithm.js'; @@ -8,32 +7,29 @@ export async function simulateFlashAssessmentScenario({ locale, pickChallenge, pickAnswerStatus, - stopAtChallenge, initialCapacity, challengesBetweenSameCompetence = 0, - limitToOneQuestionPerTube = true, minimumEstimatedSuccessRateRanges = [], - doubleMeasuresUntil = 0, variationPercent, - variationPercentUntil, challengeRepository, flashAlgorithmService, + sharedFlashAlgorithmConfigurationRepository, }) { const challenges = await challengeRepository.findActiveFlashCompatible({ locale }); - const enablePassageByAllCompetencesValueInProduction = true; + const configurationUsedInProduction = await sharedFlashAlgorithmConfigurationRepository.getMostRecent(); const flashAssessmentAlgorithm = new FlashAssessmentAlgorithm({ flashAlgorithmImplementation: flashAlgorithmService, configuration: new FlashAssessmentAlgorithmConfiguration({ - limitToOneQuestionPerTube, + limitToOneQuestionPerTube: configurationUsedInProduction.limitToOneQuestionPerTube, minimumEstimatedSuccessRateRanges, - enablePassageByAllCompetences: enablePassageByAllCompetencesValueInProduction, + enablePassageByAllCompetences: configurationUsedInProduction.enablePassageByAllCompetences, variationPercent, - variationPercentUntil, - doubleMeasuresUntil, + variationPercentUntil: undefined, + doubleMeasuresUntil: 0, challengesBetweenSameCompetence, - maximumAssessmentLength: stopAtChallenge, + maximumAssessmentLength: configurationUsedInProduction.maximumAssessmentLength, }), }); @@ -45,19 +41,8 @@ export async function simulateFlashAssessmentScenario({ initialCapacity, }); - const doubleMeasureStrategy = new AssessmentSimulatorDoubleMeasureStrategy({ - algorithm: flashAssessmentAlgorithm, - challenges, - pickChallenge, - pickAnswerStatus, - initialCapacity, - }); - - const getStrategy = (questionIndex) => - questionIndex >= doubleMeasuresUntil ? singleMeasureStrategy : doubleMeasureStrategy; - const simulator = new AssessmentSimulator({ - getStrategy, + strategy: singleMeasureStrategy, }); return simulator.run(); diff --git a/api/src/certification/scoring/domain/services/scoring-degradation-service.js b/api/src/certification/scoring/domain/services/scoring-degradation-service.js index 4625303739a..dfcca93b54b 100644 --- a/api/src/certification/scoring/domain/services/scoring-degradation-service.js +++ b/api/src/certification/scoring/domain/services/scoring-degradation-service.js @@ -30,10 +30,8 @@ export const downgradeCapacity = ({ initialCapacity: capacity, }); - const getStrategy = () => singleMeasureStrategy; - const simulator = new AssessmentSimulator({ - getStrategy, + strategy: singleMeasureStrategy, }); const result = simulator.run({ challengesAnswers: allAnswers }); diff --git a/api/tests/acceptance/application/scenario-simulator/scenario-simulator-controller_test.js b/api/tests/acceptance/application/scenario-simulator/scenario-simulator-controller_test.js index 53db3317e61..b4815805084 100644 --- a/api/tests/acceptance/application/scenario-simulator/scenario-simulator-controller_test.js +++ b/api/tests/acceptance/application/scenario-simulator/scenario-simulator-controller_test.js @@ -15,25 +15,23 @@ const { describe('Acceptance | Controller | scenario-simulator-controller', function () { let server; let adminAuthorization; - let validCapacityPayload; - let stopAtChallenge; + let validPayload; beforeEach(async function () { const { id: adminId } = databaseBuilder.factory.buildUser.withRole({ role: SUPER_ADMIN, }); - stopAtChallenge = databaseBuilder.factory.buildFlashAlgorithmConfiguration({ + databaseBuilder.factory.buildFlashAlgorithmConfiguration({ maximumAssessmentLength: 2, createdAt: new Date('2022-02-01'), - }).maximumAssessmentLength; + }); adminAuthorization = generateValidRequestAuthorizationHeader(adminId); await databaseBuilder.commit(); - validCapacityPayload = { + validPayload = { capacity: 4.5, - stopAtChallenge, }; const learningContent = { @@ -151,10 +149,6 @@ describe('Acceptance | Controller | scenario-simulator-controller', function () describe('when a number of challenges to pass is specified', function () { it('should return a payload with the same number of simulation scenario results', async function () { // given - const validPayload = { - ...validCapacityPayload, - stopAtChallenge, - }; options.headers.authorization = adminAuthorization; options.payload = validPayload; @@ -179,7 +173,7 @@ describe('Acceptance | Controller | scenario-simulator-controller', function () it('should return a payload with simulation the capacity scenario results', async function () { // given options.headers.authorization = adminAuthorization; - options.payload = validCapacityPayload; + options.payload = validPayload; // when const response = await server.inject(options); @@ -209,7 +203,7 @@ describe('Acceptance | Controller | scenario-simulator-controller', function () const { id: userId } = databaseBuilder.factory.buildUser(); options.headers.authorization = generateValidRequestAuthorizationHeader(userId); await databaseBuilder.commit(); - options.payload = validCapacityPayload; + options.payload = validPayload; // when const response = await server.inject(options); diff --git a/api/tests/certification/flash-certification/integration/application/scenario-simulator-controller_test.js b/api/tests/certification/flash-certification/integration/application/scenario-simulator-controller_test.js index 9d8c45c63dc..943550d1190 100644 --- a/api/tests/certification/flash-certification/integration/application/scenario-simulator-controller_test.js +++ b/api/tests/certification/flash-certification/integration/application/scenario-simulator-controller_test.js @@ -175,65 +175,6 @@ describe('Integration | Application | scenario-simulator-controller', function ( }); }); - context('When configuring the limit of challenges per tube', function () { - it('should call simulateFlashAssessmentScenario usecase with correct arguments', async function () { - // given - const limitToOneQuestionPerTube = true; - - const pickChallengeImplementation = sinon.stub(); - pickChallengeService.chooseNextChallenge.withArgs().returns(pickChallengeImplementation); - const pickAnswerStatusForCapacityImplementation = sinon.stub(); - pickAnswerStatusService.pickAnswerStatusForCapacity - .withArgs(6) - .returns(pickAnswerStatusForCapacityImplementation); - - usecases.simulateFlashAssessmentScenario - .withArgs({ - pickAnswerStatus: pickAnswerStatusForCapacityImplementation, - locale: 'en', - pickChallenge: pickChallengeImplementation, - initialCapacity, - limitToOneQuestionPerTube, - }) - .resolves(simulationResults); - securityPreHandlers.checkAdminMemberHasRoleSuperAdmin.returns(() => true); - - // when - const response = await httpTestServer.request( - 'POST', - '/api/scenario-simulator', - { - initialCapacity, - capacity: 6, - limitToOneQuestionPerTube, - }, - null, - { 'accept-language': 'en' }, - ); - - // then - expect(response.statusCode).to.equal(200); - const parsedResult = parseJsonStream(response); - expect(parsedResult).to.deep.equal([ - { - index: 0, - simulationReport: [ - { - challengeId: challenge1.id, - errorRate: errorRate1, - capacity: capacity1, - minimumCapability: 0.6190392084062237, - answerStatus: 'ok', - reward: reward1, - difficulty: challenge1.difficulty, - discriminant: challenge1.discriminant, - }, - ], - }, - ]); - }); - }); - context('When configuring the minimum success rates', function () { context('When providing valid parameters', function () { it('should call simulateFlashAssessmentScenario usecase with correct arguments', async function () { diff --git a/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulatorDoubleMeasureStrategy_test.js b/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulatorDoubleMeasureStrategy_test.js deleted file mode 100644 index d0ff83aacd0..00000000000 --- a/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulatorDoubleMeasureStrategy_test.js +++ /dev/null @@ -1,193 +0,0 @@ -import { AssessmentSimulatorDoubleMeasureStrategy } from '../../../../../../src/certification/flash-certification/domain/models/AssessmentSimulatorDoubleMeasureStrategy.js'; -import { Answer, AnswerStatus } from '../../../../../../src/shared/domain/models/index.js'; -import { domainBuilder, expect, sinon } from '../../../../../test-helper.js'; - -describe('Unit | Domain | Models | AssessmentSimulatorDoubleMeasureStrategy', function () { - describe('#run', function () { - context('when there is no available answer', function () { - it('should return null', function () { - // given - const challenge1 = domainBuilder.buildChallenge({ id: 'rec1' }); - const challenge2 = domainBuilder.buildChallenge({ id: 'rec2' }); - const allChallenges = [challenge1, challenge2]; - const initialCapacity = 0; - const doubleMeasuresUntil = 2; - const algorithm = { - getPossibleNextChallenges: sinon.stub(), - getCapacityAndErrorRate: sinon.stub(), - getReward: sinon.stub(), - }; - const pickChallenge = sinon.stub(); - const pickAnswerStatus = sinon.stub(); - - algorithm.getCapacityAndErrorRate - .withArgs({ - allAnswers: [], - challenges: allChallenges, - initialCapacity, - doubleMeasuresUntil, - }) - .returns({ - capacity: initialCapacity, - }); - - algorithm.getPossibleNextChallenges - .withArgs({ - assessmentAnswers: [], - challenges: allChallenges, - initialCapacity, - answersForComputingCapacity: [], - }) - .returns([challenge2, challenge1]); - - pickChallenge.withArgs({ possibleChallenges: [challenge2, challenge1] }).returns(challenge2); - pickAnswerStatus.withArgs({ nextChallenge: challenge2, answerIndex: 0 }).returns(undefined); - - // when - const strategy = new AssessmentSimulatorDoubleMeasureStrategy({ - algorithm, - challenges: allChallenges, - pickChallenge, - pickAnswerStatus, - initialCapacity, - doubleMeasuresUntil, - }); - const result = strategy.run({ challengesAnswers: [], stepIndex: 0 }); - - // then - expect(result).to.be.null; - }); - }); - - context('when there are two available answers', function () { - it('should return the result for both challenges', function () { - // given - const stepIndex = 0; - const challenge1 = domainBuilder.buildChallenge({ id: 'rec1', difficulty: 1, discriminant: 0.5 }); - const challenge2 = domainBuilder.buildChallenge({ id: 'rec2', difficulty: 2, discriminant: 1.5 }); - const challenge1Reward = 2; - const challenge2Reward = 3; - const allChallenges = [challenge1, challenge2]; - const answerStatusForSimulator1 = AnswerStatus.OK; - const answerStatusForSimulator2 = AnswerStatus.OK; - const newAnswer1 = new Answer({ challengeId: challenge1.id, result: answerStatusForSimulator1 }); - const newAnswer2 = new Answer({ challengeId: challenge2.id, result: answerStatusForSimulator2 }); - const capacityBeforeAnswering = -0.5; - const expectedCapacity = 0.4; - const initialCapacity = 0; - const algorithm = { - getPossibleNextChallenges: sinon.stub(), - getCapacityAndErrorRate: sinon.stub(), - getReward: sinon.stub(), - }; - const pickChallenge = sinon.stub(); - const pickAnswerStatus = sinon.stub(); - - algorithm.getPossibleNextChallenges - .withArgs({ - assessmentAnswers: [], - challenges: allChallenges, - initialCapacity, - answersForComputingCapacity: [], - }) - .returns([challenge2, challenge1]) - .withArgs({ - assessmentAnswers: [newAnswer2], - challenges: allChallenges, - initialCapacity, - answersForComputingCapacity: [], - }) - .returns([challenge1]); - - algorithm.getCapacityAndErrorRate - .withArgs({ - allAnswers: [], - challenges: allChallenges, - initialCapacity, - doubleMeasuresUntil: 2, - }) - .returns({ - capacity: capacityBeforeAnswering, - }) - .withArgs({ - allAnswers: [sinon.match(newAnswer2), sinon.match(newAnswer1)], - challenges: allChallenges, - initialCapacity, - doubleMeasuresUntil: 2, - }) - .returns({ - capacity: expectedCapacity, - }); - - algorithm.getReward - .withArgs({ - capacity: capacityBeforeAnswering, - difficulty: challenge1.difficulty, - discriminant: challenge1.discriminant, - }) - .returns(challenge1Reward) - .withArgs({ - capacity: capacityBeforeAnswering, - difficulty: challenge2.difficulty, - discriminant: challenge2.discriminant, - }) - .returns(challenge2Reward); - - pickChallenge - .withArgs({ possibleChallenges: [challenge2, challenge1] }) - .returns(challenge2) - .withArgs({ possibleChallenges: [challenge1] }) - .returns(challenge1); - - pickAnswerStatus - .withArgs({ nextChallenge: challenge2, answerIndex: 0 }) - .returns(answerStatusForSimulator1) - .withArgs({ nextChallenge: challenge1, answerIndex: 1 }) - .returns(answerStatusForSimulator2); - - // when - const expectedResult = { - results: [ - { - challenge: challenge2, - capacity: expectedCapacity, - answerStatus: answerStatusForSimulator2.status, - reward: challenge2Reward, - }, - { - challenge: challenge1, - capacity: expectedCapacity, - answerStatus: answerStatusForSimulator1.status, - reward: challenge1Reward, - }, - ], - challengeAnswers: [ - new Answer({ - result: answerStatusForSimulator1, - challengeId: challenge2.id, - }), - new Answer({ - result: answerStatusForSimulator2, - challengeId: challenge1.id, - }), - ], - nextStepIndex: stepIndex + 2, - }; - - const strategy = new AssessmentSimulatorDoubleMeasureStrategy({ - algorithm, - challenges: allChallenges, - pickChallenge, - pickAnswerStatus, - initialCapacity, - doubleMeasuresUntil: 2, - }); - - const result = strategy.run({ challengesAnswers: [], stepIndex }); - - // then - expect(result).to.deep.equal(expectedResult); - }); - }); - }); -}); diff --git a/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulator_test.js b/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulator_test.js index d5a3beb2277..8c143b64d5d 100644 --- a/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulator_test.js +++ b/api/tests/certification/flash-certification/unit/domain/models/AssessmentSimulator_test.js @@ -11,11 +11,7 @@ describe('Unit | Domain | Models | AssessmentSimulator', function () { const expectedEstimatedLevels = [0.4, 0.2]; const expectedErrorRates = [0.2, 0.1]; const expectedRewards = [5, 3]; - const strategy1 = { - run: sinon.stub(), - }; - - const strategy2 = { + const strategy = { run: sinon.stub(), }; @@ -28,7 +24,7 @@ describe('Unit | Domain | Models | AssessmentSimulator', function () { challengeId: secondChallenge.id, }); - strategy1.run + strategy.run .withArgs({ challengesAnswers: [], stepIndex: 0, @@ -45,8 +41,7 @@ describe('Unit | Domain | Models | AssessmentSimulator', function () { ], challengeAnswers: [firstRunAnswer], nextStepIndex: 1, - }); - strategy2.run + }) .withArgs({ challengesAnswers: [firstRunAnswer], stepIndex: 1, @@ -65,8 +60,6 @@ describe('Unit | Domain | Models | AssessmentSimulator', function () { nextStepIndex: 2, }); - const getStrategy = (stepIndex) => (stepIndex === 0 ? strategy1 : strategy2); - // when const expectedResult = [ { @@ -86,7 +79,7 @@ describe('Unit | Domain | Models | AssessmentSimulator', function () { ]; const result = new AssessmentSimulator({ - getStrategy, + strategy, }).run(); // then diff --git a/api/tests/unit/domain/usecases/simulate-flash-assessment-scenario_test.js b/api/tests/unit/domain/usecases/simulate-flash-assessment-scenario_test.js index 835a4efbd31..34572de9219 100644 --- a/api/tests/unit/domain/usecases/simulate-flash-assessment-scenario_test.js +++ b/api/tests/unit/domain/usecases/simulate-flash-assessment-scenario_test.js @@ -16,16 +16,22 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { context('when no initial capacity is provided', function () { it('should return an array of capacity, challenge, reward and error rate for each answer', async function () { // given - const { challengeRepository, pickChallenge, pickAnswerStatus, flashAlgorithmService } = prepareStubs(); + const { + challengeRepository, + sharedFlashAlgorithmConfigurationRepository, + pickChallenge, + pickAnswerStatus, + flashAlgorithmService, + } = prepareStubs(); // when const result = await simulateFlashAssessmentScenario({ - stopAtChallenge: 3, challengeRepository, locale, pickChallenge, pickAnswerStatus, flashAlgorithmService, + sharedFlashAlgorithmConfigurationRepository, }); // then @@ -45,10 +51,16 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { // given const initialCapacity = 7; - const { challengeRepository, firstChallenge, pickChallenge, pickAnswerStatus, flashAlgorithmService } = - prepareStubs({ - initialCapacity, - }); + const { + challengeRepository, + sharedFlashAlgorithmConfigurationRepository, + firstChallenge, + pickChallenge, + pickAnswerStatus, + flashAlgorithmService, + } = prepareStubs({ + initialCapacity, + }); flashAlgorithmService.getReward .withArgs({ @@ -60,14 +72,13 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { // when const result = await simulateFlashAssessmentScenario({ - stopAtChallenge: 3, challengeRepository, + sharedFlashAlgorithmConfigurationRepository, locale, pickChallenge, pickAnswerStatus, initialCapacity, flashAlgorithmService, - limitToOneQuestionPerTube: false, }); // then @@ -85,18 +96,15 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { context('when we don‘t limit the number of challenges per tube', function () { it('should return an array of estimated level, challenge, reward and error rate for each answer', async function () { // given - const limitToOneQuestionPerTube = false; - const { challengeRepository, + sharedFlashAlgorithmConfigurationRepository, pickChallenge, pickAnswerStatus, flashAlgorithmService: baseFlashAlgorithmService, getNextChallengesOptionsMatcher, allChallenges, - } = prepareStubs({ - limitToOneQuestionPerTube, - }); + } = prepareStubs(); const flashAlgorithmService = { ...baseFlashAlgorithmService, @@ -126,12 +134,11 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { // when const result = await simulateFlashAssessmentScenario({ - stopAtChallenge: 3, challengeRepository, + sharedFlashAlgorithmConfigurationRepository, locale, pickChallenge, pickAnswerStatus, - limitToOneQuestionPerTube, flashAlgorithmService, }); @@ -150,7 +157,6 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { context('when we set a minimum estimated success rate range', function () { it('should return an array of estimated level, challenge, reward and error rate for each answer', async function () { // given - const limitToOneQuestionPerTube = false; const minimumEstimatedSuccessRateRanges = [ domainBuilder.buildFlashAssessmentAlgorithmSuccessRateHandlerFixed({ startingChallengeIndex: 0, @@ -159,20 +165,25 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { }), ]; - const { challengeRepository, pickChallenge, pickAnswerStatus, flashAlgorithmService } = prepareStubs({ + const { + challengeRepository, + sharedFlashAlgorithmConfigurationRepository, + pickChallenge, + pickAnswerStatus, + flashAlgorithmService, + } = prepareStubs({ minimalSuccessRate: 0.8, }); // when const result = await simulateFlashAssessmentScenario({ - stopAtChallenge: 3, challengeRepository, + sharedFlashAlgorithmConfigurationRepository, locale, pickChallenge, pickAnswerStatus, minimumEstimatedSuccessRateRanges, flashAlgorithmService, - limitToOneQuestionPerTube, }); // then @@ -186,43 +197,19 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { }); }); }); - - context('when doing a double measure', function () { - it('should return an array of estimated level, challenge, reward and error rate for each answer', async function () { - // given - const { challengeRepository, pickChallenge, pickAnswerStatus, flashAlgorithmService } = prepareStubs({ - doubleMeasuresUntil: 2, - }); - - // when - const result = await simulateFlashAssessmentScenario({ - stopAtChallenge: 3, - challengeRepository, - locale, - pickChallenge, - pickAnswerStatus, - flashAlgorithmService, - doubleMeasuresUntil: 2, - }); - - // then - expect(result).to.have.lengthOf(3); - result.forEach((answer) => { - expect(answer.challenge).not.to.be.undefined; - expect(answer.capacity).not.to.be.undefined; - }); - }); - }); }); context('when there are not enough flash challenges left', function () { it('should stop simulating', async function () { // given - const limitToOneQuestionPerTube = false; const challenge = domainBuilder.buildChallenge({ id: 1 }); const challengeRepository = { findActiveFlashCompatible: sinon.stub(), }; + const sharedFlashAlgorithmConfigurationRepository = { + getMostRecent: sinon.stub(), + }; + sharedFlashAlgorithmConfigurationRepository.getMostRecent.resolves({ enablePassageByAllCompetences: true }); challengeRepository.findActiveFlashCompatible.resolves([challenge]); const pickChallenge = sinon.stub(); @@ -265,11 +252,11 @@ describe('Unit | UseCase | simulate-flash-assessment-scenario', function () { // when const error = await catchErr(simulateFlashAssessmentScenario)({ challengeRepository, + sharedFlashAlgorithmConfigurationRepository, locale, pickChallenge, pickAnswerStatus, flashAlgorithmService, - limitToOneQuestionPerTube, }); // then @@ -314,6 +301,11 @@ function prepareStubs({ const challengeRepository = { findActiveFlashCompatible: sinon.stub(), }; + + const sharedFlashAlgorithmConfigurationRepository = { + getMostRecent: sinon.stub(), + }; + const pickChallenge = sinon.stub(); const pickAnswerStatus = sinon.stub(); const flashAlgorithmService = { @@ -331,6 +323,12 @@ function prepareStubs({ ), ); + sharedFlashAlgorithmConfigurationRepository.getMostRecent.resolves({ + enablePassageByAllCompetences: true, + maximumAssessmentLength: 3, + limitToOneQuestionPerTube: false, + }); + flashAlgorithmService.getCapacityAndErrorRate .withArgs({ allAnswers: [], @@ -445,6 +443,7 @@ function prepareStubs({ pickChallenge, pickAnswerStatus, challengeRepository, + sharedFlashAlgorithmConfigurationRepository, flashAlgorithmService, firstChallenge, allChallenges,