From b8535f35a9b8c13a5478a42885900ee2501f963d Mon Sep 17 00:00:00 2001 From: Aurelie Crouillebois Date: Fri, 31 Jan 2025 14:39:29 +0100 Subject: [PATCH 1/2] feat(api): add validation indicators on pix junior challenges --- .../infrastructure/serializers/challenge-serializer.js | 2 ++ api/src/shared/domain/models/Challenge.js | 4 ++++ .../infrastructure/repositories/challenge-repository.js | 2 ++ .../serializers/challenge-serializer_test.js | 4 ++++ .../repositories/challenge-repository_test.js | 8 ++++++++ .../tooling/domain-builder/factory/build-challenge.js | 8 ++++++++ 6 files changed, 28 insertions(+) diff --git a/api/src/school/infrastructure/serializers/challenge-serializer.js b/api/src/school/infrastructure/serializers/challenge-serializer.js index 3ed19733693..5444229571a 100644 --- a/api/src/school/infrastructure/serializers/challenge-serializer.js +++ b/api/src/school/infrastructure/serializers/challenge-serializer.js @@ -20,6 +20,8 @@ const serialize = function (challenges) { 'focused', 'timer', 'shuffled', + 'hasEmbedInternalValidation', + 'noValidationNeeded', ], transform: (challenge) => { return { diff --git a/api/src/shared/domain/models/Challenge.js b/api/src/shared/domain/models/Challenge.js index ee1d23b7420..c0f7de432ff 100644 --- a/api/src/shared/domain/models/Challenge.js +++ b/api/src/shared/domain/models/Challenge.js @@ -89,6 +89,8 @@ class Challenge { alternativeVersion, blindnessCompatibility, colorBlindnessCompatibility, + hasEmbedInternalValidation, + noValidationNeeded, } = {}) { this.id = id; this.answer = answer; @@ -121,6 +123,8 @@ class Challenge { this.alternativeVersion = alternativeVersion; this.blindnessCompatibility = blindnessCompatibility; this.colorBlindnessCompatibility = colorBlindnessCompatibility; + this.hasEmbedInternalValidation = hasEmbedInternalValidation; + this.noValidationNeeded = noValidationNeeded; } isTimed() { diff --git a/api/src/shared/infrastructure/repositories/challenge-repository.js b/api/src/shared/infrastructure/repositories/challenge-repository.js index 7d688eb1d7e..79b2a39b8c2 100644 --- a/api/src/shared/infrastructure/repositories/challenge-repository.js +++ b/api/src/shared/infrastructure/repositories/challenge-repository.js @@ -256,6 +256,8 @@ function toDomain({ challengeDto, webComponentTagName, webComponentProps, skill, blindnessCompatibility: challengeDto.accessibility1, colorBlindnessCompatibility: challengeDto.accessibility2, successProbabilityThreshold, + hasEmbedInternalValidation: challengeDto.hasEmbedInternalValidation, + noValidationNeeded: challengeDto.noValidationNeeded, }); } diff --git a/api/tests/school/unit/infrastructure/serializers/challenge-serializer_test.js b/api/tests/school/unit/infrastructure/serializers/challenge-serializer_test.js index 99a5b19f2ac..ad9b208b86c 100644 --- a/api/tests/school/unit/infrastructure/serializers/challenge-serializer_test.js +++ b/api/tests/school/unit/infrastructure/serializers/challenge-serializer_test.js @@ -29,6 +29,8 @@ describe('Unit | Serializer | challenge-serializer', function () { focused: false, illustrationAlt: 'alt', autoReply: false, + hasEmbedInternalValidation: true, + noValidationNeeded: true, }); // when @@ -58,6 +60,8 @@ describe('Unit | Serializer | challenge-serializer', function () { timer: 300, 'illustration-alt': 'alt', 'auto-reply': false, + 'has-embed-internal-validation': true, + 'no-validation-needed': true, }, }, }); 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 ca6ca54a556..ced85c9e59f 100644 --- a/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js +++ b/api/tests/shared/integration/infrastructure/repositories/challenge-repository_test.js @@ -44,6 +44,8 @@ describe('Integration | Repository | challenge-repository', function () { locales: ['fr', 'nl'], competenceId: 'competenceId00', skillId: 'skillId00', + hasEmbedInternalValidation: true, + noValidationNeeded: true, }; const challengeData01_skill00_qcu_valide_flashCompatible_fren_withEmbedJson = { id: 'challengeId01', @@ -83,6 +85,8 @@ describe('Integration | Repository | challenge-repository', function () { locales: ['fr', 'en'], competenceId: 'competenceId00', skillId: 'skillId00', + hasEmbedInternalValidation: true, + noValidationNeeded: true, }; const challengeData02_skill00_qcm_archive_flashCompatible_en_noEmbedJson = { id: 'challengeId02', @@ -531,6 +535,8 @@ describe('Integration | Repository | challenge-repository', function () { }), webComponentTagName: 'web-component', webComponentProps: { prop1: 'value1', prop2: 'value2' }, + hasEmbedInternalValidation: true, + noValidationNeeded: true, }), ); }); @@ -584,6 +590,8 @@ describe('Integration | Repository | challenge-repository', function () { difficulty: skillData00_tube00competence00_actif.level, hint: skillData00_tube00competence00_actif.hint_i18n.fr, }), + hasEmbedInternalValidation: true, + noValidationNeeded: true, }), ); }); diff --git a/api/tests/tooling/domain-builder/factory/build-challenge.js b/api/tests/tooling/domain-builder/factory/build-challenge.js index fc82a4cebf8..66f70b997d8 100644 --- a/api/tests/tooling/domain-builder/factory/build-challenge.js +++ b/api/tests/tooling/domain-builder/factory/build-challenge.js @@ -37,6 +37,8 @@ const buildChallenge = function ({ competenceId = 'recCOMP1', webComponentTagName, webComponentProps, + hasEmbedInternalValidation = false, + noValidationNeeded = false, } = {}) { return new Challenge({ id, @@ -73,6 +75,8 @@ const buildChallenge = function ({ skill, // references competenceId, + hasEmbedInternalValidation, + noValidationNeeded, }); }; @@ -109,6 +113,8 @@ const buildChallengeWithWebComponent = function ({ skill = buildSkill(), // references competenceId = 'recCOMP1', + hasEmbedInternalValidation, + noValidationNeeded, } = {}) { return new Challenge({ id, @@ -143,6 +149,8 @@ const buildChallengeWithWebComponent = function ({ skill, // references competenceId, + hasEmbedInternalValidation, + noValidationNeeded, }); }; From 27b37a33c62330e9ad5a71f3ee70d8a2feab025a Mon Sep 17 00:00:00 2001 From: Aurelie Crouillebois Date: Fri, 31 Jan 2025 14:58:41 +0100 Subject: [PATCH 2/2] feat(junior): use challenge validation indicators in challenge display --- junior/app/models/challenge.js | 6 ++- junior/tests/unit/models/challenge-test.js | 50 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/junior/app/models/challenge.js b/junior/app/models/challenge.js index 2deb7686d51..d9b23187f49 100644 --- a/junior/app/models/challenge.js +++ b/junior/app/models/challenge.js @@ -30,6 +30,8 @@ export default class Challenge extends Model { @attr('boolean') shuffled; @attr() webComponentProps; @attr('string') webComponentTagName; + @attr('boolean') hasEmbedInternalValidation; + @attr('boolean') noValidationNeeded; @hasMany('activity-answer', { async: true, inverse: 'challenge' }) activityAnswers; @@ -52,7 +54,7 @@ export default class Challenge extends Model { } get isLesson() { - return !!this.focused; + return !!this.focused || !!this.noValidationNeeded; } get isQROC() { @@ -80,7 +82,7 @@ export default class Challenge extends Model { } get isEmbedAutoValidated() { - return this.timer !== null && this.timer >= 0; + return (this.timer !== null && this.timer >= 0) || !!this.hasEmbedInternalValidation; } get hasMedia() { diff --git a/junior/tests/unit/models/challenge-test.js b/junior/tests/unit/models/challenge-test.js index 3319fdf751b..7e16b21b801 100644 --- a/junior/tests/unit/models/challenge-test.js +++ b/junior/tests/unit/models/challenge-test.js @@ -40,6 +40,56 @@ module('Unit | Model | Challenge', function (hooks) { }); }); + module('#isLesson', function () { + test('should be true if focused is true', function (assert) { + const challenge = store.createRecord('challenge', { + focused: true, + }); + assert.true(challenge.isLesson); + }); + test('should be true if noValidationNeeded is true', function (assert) { + const challenge = store.createRecord('challenge', { + noValidationNeeded: true, + }); + assert.true(challenge.isLesson); + }); + test('should be false if noValidationNeeded & focused are not set', function (assert) { + const challenge = store.createRecord('challenge'); + assert.false(challenge.isLesson); + }); + test('should be false if noValidationNeeded & focused are false', function (assert) { + const challenge = store.createRecord('challenge', { + focused: false, + noValidationNeeded: false, + }); + assert.false(challenge.isLesson); + }); + }); + module('#isEmbedAutoValidated', function () { + test('should be true if timer is set', function (assert) { + const challenge = store.createRecord('challenge', { + timer: 1, + }); + assert.true(challenge.isEmbedAutoValidated); + }); + test('should be true if hasEmbedInternalValidation is true', function (assert) { + const challenge = store.createRecord('challenge', { + hasEmbedInternalValidation: true, + }); + assert.true(challenge.isEmbedAutoValidated); + }); + test('should be false if timer & hasEmbedInternalValidation are not set', function (assert) { + const challenge = store.createRecord('challenge'); + assert.false(challenge.isEmbedAutoValidated); + }); + test('should be false hasEmbedInternalValidation is false', function (assert) { + const challenge = store.createRecord('challenge', { + hasEmbedInternalValidation: false, + }); + assert.false(challenge.isEmbedAutoValidated); + }); + }); + module('#hasWebComponent', function () { test('should be true when web component name and web component props are fields', function (assert) { const challenge = store.createRecord('challenge', {