Skip to content

Commit

Permalink
bugfix(api): handle certification test when both answer and live aler…
Browse files Browse the repository at this point in the history
…t exists on same challenge

Co-authored-by: Yannick François <[email protected]>
Co-authored-by: Steph0 <[email protected]>
  • Loading branch information
3 people authored Dec 2, 2024
1 parent 3cb34a7 commit ade4870
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,19 @@ const getNextChallenge = async function ({
}) {
const certificationCourse = await certificationCourseRepository.get({ id: assessment.certificationCourseId });

const allAnswers = await answerRepository.findByAssessment(assessment.id);
const alreadyAnsweredChallengeIds = allAnswers.map(({ challengeId }) => challengeId);

const validatedLiveAlertChallengeIds = await _getValidatedLiveAlertChallengeIds({
assessmentId: assessment.id,
certificationChallengeLiveAlertRepository,
});

const excludedChallengeIds = [...alreadyAnsweredChallengeIds, ...validatedLiveAlertChallengeIds];
const allAnswers = await answerRepository.findByAssessmentExcludingChallengeIds({
assessmentId: assessment.id,
excludedChallengeIds: validatedLiveAlertChallengeIds,
});

const alreadyAnsweredChallengeIds = allAnswers.map(({ challengeId }) => challengeId);

const excludedChallengeIds = [...alreadyAnsweredChallengeIds, ...validatedLiveAlertChallengeIds];
const lastNonAnsweredCertificationChallenge =
await sessionManagementCertificationChallengeRepository.getNextChallengeByCourseIdForV3(
assessment.certificationCourseId,
Expand Down
11 changes: 11 additions & 0 deletions api/src/shared/infrastructure/repositories/answer-repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ const findByAssessment = async function (assessmentId) {
return _toDomainArray(answerDTOsWithoutDuplicate);
};

const findByAssessmentExcludingChallengeIds = async function ({ assessmentId, excludedChallengeIds = [] }) {
const answerDTOs = await knex
.select(COLUMNS)
.from('answers')
.where({ assessmentId })
.whereNotIn('challengeId', excludedChallengeIds);

return _toDomainArray(answerDTOs);
};

const findChallengeIdsFromAnswerIds = async function (ids) {
return knex.distinct().pluck('challengeId').from('answers').whereInArray('id', ids);
};
Expand Down Expand Up @@ -108,6 +118,7 @@ const saveWithKnowledgeElements = async function (answer, knowledgeElements) {
};
export {
findByAssessment,
findByAssessmentExcludingChallengeIds,
findByChallengeAndAssessment,
findChallengeIdsFromAnswerIds,
get,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
getMostRecentBeforeDate: sinon.stub(),
};
answerRepository = {
findByAssessment: sinon.stub(),
findByAssessmentExcludingChallengeIds: sinon.stub(),
};
challengeRepository = {
get: sinon.stub(),
Expand Down Expand Up @@ -79,7 +79,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
.withArgs(v3CertificationCourse.getStartDate())
.resolves(flashAlgorithmConfiguration);

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([]);
certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
.withArgs({ assessmentId: assessment.id })
.resolves([]);
Expand Down Expand Up @@ -170,7 +172,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
.withArgs(v3CertificationCourse.getStartDate())
.resolves(flashAlgorithmConfiguration);

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([]);
certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
.withArgs({ assessmentId: assessment.id })
.resolves([]);
Expand Down Expand Up @@ -259,7 +263,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
id: nonAnsweredCertificationChallenge.challengeId,
});

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([]);
certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
.withArgs({ assessmentId: assessment.id })
.resolves([]);
Expand Down Expand Up @@ -319,8 +325,8 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {

const answerStillValid = domainBuilder.buildAnswer({ challengeId: alreadyAnsweredChallenge.id });
const answerWithOutdatedChallenge = domainBuilder.buildAnswer({ challengeId: outdatedChallenge.id });
answerRepository.findByAssessment
.withArgs(assessment.id)
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([answerStillValid, answerWithOutdatedChallenge]);

certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
Expand Down Expand Up @@ -418,7 +424,12 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
.withArgs(v3CertificationCourse.getStartDate())
.resolves(flashAlgorithmConfiguration);

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({
assessmentId: assessment.id,
excludedChallengeIds: [nonAnsweredCertificationChallenge.challengeId],
})
.resolves([]);
challengeRepository.findActiveFlashCompatible.withArgs({ locale }).resolves([nextChallenge, lastSeenChallenge]);
challengeRepository.getMany.withArgs([]).resolves([]);

Expand Down Expand Up @@ -514,7 +525,12 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
.withArgs(v3CertificationCourse.getStartDate())
.resolves(flashAlgorithmConfiguration);

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({
assessmentId: assessment.id,
excludedChallengeIds: [nonAnsweredCertificationChallenge.challengeId],
})
.resolves([]);
challengeRepository.findActiveFlashCompatible
.withArgs()
.resolves([challengeWithLiveAlert, challengeWithOtherSkill, challengeWithLiveAlertedSkill]);
Expand Down Expand Up @@ -600,7 +616,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
.withArgs(v3CertificationCourse.getStartDate())
.resolves(flashAlgorithmConfiguration);

answerRepository.findByAssessment.withArgs(assessment.id).resolves([answer]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([answer]);
certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
.withArgs({ assessmentId: assessment.id })
.resolves([]);
Expand Down Expand Up @@ -679,7 +697,9 @@ describe('Unit | Domain | Use Cases | get-next-challenge', function () {
const assessment = domainBuilder.buildAssessment();
const locale = 'fr-FR';

answerRepository.findByAssessment.withArgs(assessment.id).resolves([]);
answerRepository.findByAssessmentExcludingChallengeIds
.withArgs({ assessmentId: assessment.id, excludedChallengeIds: [] })
.resolves([]);
certificationChallengeLiveAlertRepository.getLiveAlertValidatedChallengeIdsByAssessmentId
.withArgs({ assessmentId: assessment.id })
.resolves([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,65 @@ describe('Integration | Repository | answerRepository', function () {
});
});

describe('#findByAssessmentExcludingChallenges', function () {
context('when assessment does not exist', function () {
it('should return an empty array', async function () {
// given
databaseBuilder.factory.buildAssessment({ id: 123 });
databaseBuilder.factory.buildAnswer({ assessmentId: 123 });
await databaseBuilder.commit();

// when
const foundAnswers = await answerRepository.findByAssessmentExcludingChallengeIds({ assessmentId: 456 });

// then
expect(foundAnswers).to.be.empty;
});
});
context('when assessment exists', function () {
context('when excludingChallengeIds is not provided', function () {
it('should return all answers', async function () {
// given
databaseBuilder.factory.buildAssessment({ id: 123 });
const expectedAnswer = domainBuilder.buildAnswer({ assessmentId: 123 });
databaseBuilder.factory.buildAnswer({ ...expectedAnswer, result: expectedAnswer.result.status });
await databaseBuilder.commit();

// when
const foundAnswers = await answerRepository.findByAssessmentExcludingChallengeIds({ assessmentId: 123 });

// then
expect(foundAnswers).to.deep.equal([expectedAnswer]);
});
});

context('when excludingChallengeIds is provided', function () {
it('should return answers except the ones excluded', async function () {
// given
databaseBuilder.factory.buildAssessment({ id: 123 });
const expectedAnswer = domainBuilder.buildAnswer({ assessmentId: 123 });
const excludedAnswer = domainBuilder.buildAnswer({
id: 456,
assessmentId: 123,
challengeId: 'excludedChallengeId',
});
databaseBuilder.factory.buildAnswer({ ...expectedAnswer, result: expectedAnswer.result.status });
databaseBuilder.factory.buildAnswer({ ...excludedAnswer, result: excludedAnswer.result.status });
await databaseBuilder.commit();

// when
const foundAnswers = await answerRepository.findByAssessmentExcludingChallengeIds({
assessmentId: 123,
excludedChallengeIds: [excludedAnswer.challengeId],
});

// then
expect(foundAnswers).to.deep.equal([expectedAnswer]);
});
});
});
});

describe('#findChallengeIdsFromAnswerIds', function () {
context('when provided answerIds collection is empty', function () {
it('should return an empty array', async function () {
Expand Down

0 comments on commit ade4870

Please sign in to comment.