diff --git a/backend/src/services/learning-paths/database-learning-path-provider.ts b/backend/src/services/learning-paths/database-learning-path-provider.ts index e99048f7..a0bd6a47 100644 --- a/backend/src/services/learning-paths/database-learning-path-provider.ts +++ b/backend/src/services/learning-paths/database-learning-path-provider.ts @@ -97,9 +97,10 @@ async function convertNodes( learningobject_hruid: node.learningObjectHruid, version: learningObject.version, transitions: node.transitions - .filter((trans) => - !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible. - ).map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition + .filter( + (trans) => !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible. + ) + .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition }; }) .toArray(); @@ -112,9 +113,8 @@ async function convertNodes( function optionalJsonStringToObject(jsonString?: string): object | null { if (!jsonString) { return null; - } - return JSON.parse(jsonString); - + } + return JSON.parse(jsonString); } /** diff --git a/backend/src/services/learning-paths/learning-path-personalization-util.ts b/backend/src/services/learning-paths/learning-path-personalization-util.ts index 648b7abc..29b8c5ec 100644 --- a/backend/src/services/learning-paths/learning-path-personalization-util.ts +++ b/backend/src/services/learning-paths/learning-path-personalization-util.ts @@ -36,6 +36,6 @@ export function isTransitionPossible(transition: LearningPathTransition, submitt if (submitted === null) { return false; // If the transition is not unconditional and there was no submission, the transition is not possible. } - const match = JSONPath({ path: transition.condition, json: {submission: submitted} }) + const match = JSONPath({ path: transition.condition, json: { submission: submitted } }); return match.length === 1; } diff --git a/backend/tests/services/learning-path/database-learning-path-provider.test.ts b/backend/tests/services/learning-path/database-learning-path-provider.test.ts index 1088cb2e..7e6124a3 100644 --- a/backend/tests/services/learning-path/database-learning-path-provider.test.ts +++ b/backend/tests/services/learning-path/database-learning-path-provider.test.ts @@ -5,7 +5,8 @@ import { LearningPath } from '../../../src/entities/content/learning-path.entity import { getLearningObjectRepository, getLearningPathRepository, - getStudentRepository, getSubmissionRepository + getStudentRepository, + getSubmissionRepository, } from '../../../src/data/repositories'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; @@ -16,10 +17,10 @@ import learningObjectService from '../../../src/services/learning-objects/learni import { Language } from '../../../src/entities/content/language'; import { ConditionTestLearningPathAndLearningObjects, - createConditionTestLearningPathAndLearningObjects -} from "../../test-assets/learning-paths/test-conditions-example"; -import {Student} from "../../../src/entities/users/student.entity"; -import {LearningObjectNode, LearningPathResponse} from "../../../src/interfaces/learning-content"; + createConditionTestLearningPathAndLearningObjects, +} from '../../test-assets/learning-paths/test-conditions-example'; +import { Student } from '../../../src/entities/users/student.entity'; +import { LearningObjectNode, LearningPathResponse } from '../../../src/interfaces/learning-content'; async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { const learningObjectRepo = getLearningObjectRepository(); @@ -32,9 +33,9 @@ async function initExampleData(): Promise<{ learningObject: LearningObject; lear } async function initPersonalizationTestData(): Promise<{ - learningContent: ConditionTestLearningPathAndLearningObjects, - studentA: Student, - studentB: Student + learningContent: ConditionTestLearningPathAndLearningObjects; + studentA: Student; + studentB: Student; }> { const studentRepo = getStudentRepository(); const submissionRepo = getSubmissionRepository(); @@ -49,9 +50,9 @@ async function initPersonalizationTestData(): Promise<{ console.log(await getSubmissionRepository().findAll({})); const studentA = studentRepo.create({ - username: "student_a", - firstName: "Aron", - lastName: "Student" + username: 'student_a', + firstName: 'Aron', + lastName: 'Student', }); await studentRepo.save(studentA); const submissionA = submissionRepo.create({ @@ -61,14 +62,14 @@ async function initPersonalizationTestData(): Promise<{ submissionNumber: 0, submitter: studentA, submissionTime: new Date(), - content: '[0]' + content: '[0]', }); await submissionRepo.save(submissionA); const studentB = studentRepo.create({ - username: "student_b", - firstName: "Bill", - lastName: "Student" + username: 'student_b', + firstName: 'Bill', + lastName: 'Student', }); await studentRepo.save(studentB); const submissionB = submissionRepo.create({ @@ -78,7 +79,7 @@ async function initPersonalizationTestData(): Promise<{ submissionNumber: 1, submitter: studentB, submissionTime: new Date(), - content: '[1]' + content: '[1]', }); await submissionRepo.save(submissionB); @@ -86,16 +87,19 @@ async function initPersonalizationTestData(): Promise<{ learningContent: learningContent, studentA: studentA, studentB: studentB, - } + }; } -function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { - learningContent: ConditionTestLearningPathAndLearningObjects; - studentA: Student; - studentB: Student -}): LearningObjectNode { +function expectBranchingObjectNode( + result: LearningPathResponse, + persTestData: { + learningContent: ConditionTestLearningPathAndLearningObjects; + studentA: Student; + studentB: Student; + } +): LearningObjectNode { const branchingObjectMatches = result.data![0].nodes.filter( - it => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid + (it) => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid ); expect(branchingObjectMatches.length).toBe(1); return branchingObjectMatches[0]; @@ -104,7 +108,7 @@ function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { describe('DatabaseLearningPathProvider', () => { let learningObjectRepo: LearningObjectRepository; let example: { learningObject: LearningObject; learningPath: LearningPath }; - let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects, studentA: Student, studentB: Student } + let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects; studentA: Student; studentB: Student }; beforeAll(async () => { await setupTestApp(); @@ -137,13 +141,13 @@ describe('DatabaseLearningPathProvider', () => { expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); }); - it("returns the correct personalized learning path", async () => { + it('returns the correct personalized learning path', async () => { // For student A: let result = await databaseLearningPathProvider.fetchLearningPaths( [persTestData.learningContent.learningPath.hruid], persTestData.learningContent.learningPath.language, 'the source', - {type: 'student', student: persTestData.studentA} + { type: 'student', student: persTestData.studentA } ); expect(result.success).toBeTruthy(); expect(result.data?.length).toBe(1); @@ -151,25 +155,17 @@ describe('DatabaseLearningPathProvider', () => { // There should be exactly one branching object let branchingObject = expectBranchingObjectNode(result, persTestData); - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) - .length - ).toBe(0); // StudentA picked the first option, therefore, there should be no direct path to the final object. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) - .length - ).toBe(1); // There should however be a path to the extra exercise object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.finalObject.hruid).length).toBe(0); // StudentA picked the first option, therefore, there should be no direct path to the final object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid).length).toBe( + 1 + ); // There should however be a path to the extra exercise object. // For student B: result = await databaseLearningPathProvider.fetchLearningPaths( [persTestData.learningContent.learningPath.hruid], persTestData.learningContent.learningPath.language, 'the source', - {type: 'student', student: persTestData.studentB} + { type: 'student', student: persTestData.studentB } ); expect(result.success).toBeTruthy(); expect(result.data?.length).toBe(1); @@ -178,18 +174,10 @@ describe('DatabaseLearningPathProvider', () => { branchingObject = expectBranchingObjectNode(result, persTestData); // However, now the student picks the other option. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.finalObject.hruid) - .length - ).toBe(1); // StudentB picked the second option, therefore, there should be a direct path to the final object. - expect( - branchingObject - .transitions - .filter(it => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid) - .length - ).toBe(0); // There should not be a path anymore to the extra exercise object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.finalObject.hruid).length).toBe(1); // StudentB picked the second option, therefore, there should be a direct path to the final object. + expect(branchingObject.transitions.filter((it) => it.next.hruid === persTestData.learningContent.extraExerciseObject.hruid).length).toBe( + 0 + ); // There should not be a path anymore to the extra exercise object. }); it('returns a non-successful response if a non-existing learning path is queried', async () => { const result = await databaseLearningPathProvider.fetchLearningPaths( diff --git a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts index 14f62828..2f2e78ad 100644 --- a/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts +++ b/backend/tests/test-assets/learning-objects/dummy/dummy-learning-object-example.ts @@ -3,7 +3,7 @@ import { LearningObject } from '../../../../src/entities/content/learning-object import { Language } from '../../../../src/entities/content/language'; import { loadTestAsset } from '../../../test-utils/load-test-asset'; import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; -import {EnvVars, getEnvVar} from "../../../../src/util/envvars"; +import { EnvVars, getEnvVar } from '../../../../src/util/envvars'; /** * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use @@ -22,8 +22,8 @@ export function dummyLearningObject(hruid: string, language: Language, title: st learningObject.content = Buffer.from('Dummy content'); learningObject.returnValue = { callbackUrl: `/learningObject/${hruid}/submissions`, - callbackSchema: "[]" - } + callbackSchema: '[]', + }; return learningObject; }, createAttachment: {}, diff --git a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts index c0c18c6a..d57c7a33 100644 --- a/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts +++ b/backend/tests/test-assets/learning-objects/test-essay/test-essay-example.ts @@ -16,8 +16,8 @@ const example: LearningObjectExample = { learningObject.contentType = DwengoContentType.GIFT; learningObject.returnValue = { callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, - callbackSchema: '["antwoord vraag 1"]' - } + callbackSchema: '["antwoord vraag 1"]', + }; learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts index c5dcdc94..a634878a 100644 --- a/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts +++ b/backend/tests/test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example.ts @@ -16,8 +16,8 @@ const example: LearningObjectExample = { learningObject.contentType = DwengoContentType.GIFT; learningObject.returnValue = { callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, - callbackSchema: '["antwoord vraag 1"]' - } + callbackSchema: '["antwoord vraag 1"]', + }; learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); return learningObject; }, diff --git a/backend/tests/test-assets/learning-paths/test-conditions-example.ts b/backend/tests/test-assets/learning-paths/test-conditions-example.ts index 9ac8c4d6..07857235 100644 --- a/backend/tests/test-assets/learning-paths/test-conditions-example.ts +++ b/backend/tests/test-assets/learning-paths/test-conditions-example.ts @@ -3,17 +3,17 @@ import { Language } from '../../../src/entities/content/language'; import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; -import {LearningObject} from "../../../src/entities/content/learning-object.entity"; -import {EnvVars, getEnvVar} from "../../../src/util/envvars"; +import { LearningObject } from '../../../src/entities/content/learning-object.entity'; +import { EnvVars, getEnvVar } from '../../../src/util/envvars'; export type ConditionTestLearningPathAndLearningObjects = { - branchingObject: LearningObject, - extraExerciseObject: LearningObject, - finalObject: LearningObject, - learningPath: LearningPath + branchingObject: LearningObject; + extraExerciseObject: LearningObject; + finalObject: LearningObject; + learningPath: LearningPath; }; -export function createConditionTestLearningPathAndLearningObjects(){ +export function createConditionTestLearningPathAndLearningObjects() { const learningPath = new LearningPath(); learningPath.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_conditions`; learningPath.language = Language.English;