fix(backend): Fouten in isTransitionPossible en het opzetten van de testdata verbeterd.
This commit is contained in:
		
							parent
							
								
									b539c28d8c
								
							
						
					
					
						commit
						fc46e79d05
					
				
					 10 changed files with 249 additions and 68 deletions
				
			
		|  | @ -15,8 +15,8 @@ export class Submission { | ||||||
|     }) |     }) | ||||||
|     learningObjectLanguage!: Language; |     learningObjectLanguage!: Language; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'numeric' }) | ||||||
|     learningObjectVersion: string = '1'; |     learningObjectVersion: number = 1; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|     submissionNumber!: number; |     submissionNumber!: number; | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ export class LearningObject { | ||||||
|     teacherExclusive: boolean = false; |     teacherExclusive: boolean = false; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'array' }) |     @Property({ type: 'array' }) | ||||||
|     skosConcepts!: string[]; |     skosConcepts: string[] = []; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ |     @Embedded({ | ||||||
|         entity: () => EducationalGoal, |         entity: () => EducationalGoal, | ||||||
|  | @ -64,8 +64,8 @@ export class LearningObject { | ||||||
|     @Property({ type: 'smallint', nullable: true }) |     @Property({ type: 'smallint', nullable: true }) | ||||||
|     difficulty?: number; |     difficulty?: number; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'integer' }) |     @Property({ type: 'integer', nullable: true }) | ||||||
|     estimatedTime!: number; |     estimatedTime?: number; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ |     @Embedded({ | ||||||
|         entity: () => ReturnValue, |         entity: () => ReturnValue, | ||||||
|  |  | ||||||
|  | @ -97,14 +97,26 @@ async function convertNodes( | ||||||
|                 learningobject_hruid: node.learningObjectHruid, |                 learningobject_hruid: node.learningObjectHruid, | ||||||
|                 version: learningObject.version, |                 version: learningObject.version, | ||||||
|                 transitions: node.transitions |                 transitions: node.transitions | ||||||
|                     .filter((trans) => !personalizedFor || isTransitionPossible(trans, lastSubmission)) // If we want a personalized learning path, remove all transitions that aren't possible.
 |                     .filter((trans) => | ||||||
|                     .map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition
 |                         !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(); |         .toArray(); | ||||||
|     return await Promise.all(nodesPromise); |     return await Promise.all(nodesPromise); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Helper method to convert a json string to an object, or null if it is undefined. | ||||||
|  |  */ | ||||||
|  | function optionalJsonStringToObject(jsonString?: string): object | null { | ||||||
|  |     if (!jsonString) { | ||||||
|  |         return null; | ||||||
|  |     } else { | ||||||
|  |         return JSON.parse(jsonString); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Helper function which converts a transition in the database representation to a transition in the representation |  * Helper function which converts a transition in the database representation to a transition in the representation | ||||||
|  * the Dwengo API uses. |  * the Dwengo API uses. | ||||||
|  |  | ||||||
|  | @ -36,5 +36,6 @@ export function isTransitionPossible(transition: LearningPathTransition, submitt | ||||||
|     if (submitted === null) { |     if (submitted === null) { | ||||||
|         return false; // If the transition is not unconditional and there was no submission, the transition is not possible.
 |         return false; // If the transition is not unconditional and there was no submission, the transition is not possible.
 | ||||||
|     } |     } | ||||||
|     return JSONPath({ path: transition.condition, json: submitted }).length === 0; |     const match = JSONPath({ path: transition.condition, json: {submission: submitted} }) | ||||||
|  |     return match.length === 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,7 +2,11 @@ import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
| import { LearningObject } from '../../../src/entities/content/learning-object.entity'; | import { LearningObject } from '../../../src/entities/content/learning-object.entity'; | ||||||
| import { setupTestApp } from '../../setup-tests'; | import { setupTestApp } from '../../setup-tests'; | ||||||
| import { LearningPath } from '../../../src/entities/content/learning-path.entity'; | import { LearningPath } from '../../../src/entities/content/learning-path.entity'; | ||||||
| import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; | import { | ||||||
|  |     getLearningObjectRepository, | ||||||
|  |     getLearningPathRepository, | ||||||
|  |     getStudentRepository, getSubmissionRepository | ||||||
|  | } from '../../../src/data/repositories'; | ||||||
| import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; | import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; | ||||||
| import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; | import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; | ||||||
| import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider'; | import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider'; | ||||||
|  | @ -10,6 +14,12 @@ import { expectToBeCorrectLearningPath } from '../../test-utils/expectations'; | ||||||
| import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; | import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; | ||||||
| import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; | import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; | ||||||
| import { Language } from '../../../src/entities/content/language'; | 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"; | ||||||
| 
 | 
 | ||||||
| async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { | async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { | ||||||
|     const learningObjectRepo = getLearningObjectRepository(); |     const learningObjectRepo = getLearningObjectRepository(); | ||||||
|  | @ -21,13 +31,85 @@ async function initExampleData(): Promise<{ learningObject: LearningObject; lear | ||||||
|     return { learningObject, learningPath }; |     return { learningObject, learningPath }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | async function initPersonalizationTestData(): Promise<{ | ||||||
|  |     learningContent: ConditionTestLearningPathAndLearningObjects, | ||||||
|  |     studentA: Student, | ||||||
|  |     studentB: Student | ||||||
|  | }> { | ||||||
|  |     const studentRepo = getStudentRepository(); | ||||||
|  |     const submissionRepo = getSubmissionRepository(); | ||||||
|  |     const learningPathRepo = getLearningPathRepository(); | ||||||
|  |     const learningObjectRepo = getLearningObjectRepository(); | ||||||
|  |     const learningContent = createConditionTestLearningPathAndLearningObjects(); | ||||||
|  |     await learningObjectRepo.save(learningContent.branchingObject); | ||||||
|  |     await learningObjectRepo.save(learningContent.finalObject); | ||||||
|  |     await learningObjectRepo.save(learningContent.extraExerciseObject); | ||||||
|  |     await learningPathRepo.save(learningContent.learningPath); | ||||||
|  | 
 | ||||||
|  |     console.log(await getSubmissionRepository().findAll({})); | ||||||
|  | 
 | ||||||
|  |     const studentA = studentRepo.create({ | ||||||
|  |         username: "student_a", | ||||||
|  |         firstName: "Aron", | ||||||
|  |         lastName: "Student" | ||||||
|  |     }); | ||||||
|  |     await studentRepo.save(studentA); | ||||||
|  |     const submissionA = submissionRepo.create({ | ||||||
|  |         learningObjectHruid: learningContent.branchingObject.hruid, | ||||||
|  |         learningObjectLanguage: learningContent.branchingObject.language, | ||||||
|  |         learningObjectVersion: learningContent.branchingObject.version, | ||||||
|  |         submissionNumber: 0, | ||||||
|  |         submitter: studentA, | ||||||
|  |         submissionTime: new Date(), | ||||||
|  |         content: '[0]' | ||||||
|  |     }); | ||||||
|  |     await submissionRepo.save(submissionA); | ||||||
|  | 
 | ||||||
|  |     const studentB = studentRepo.create({ | ||||||
|  |         username: "student_b", | ||||||
|  |         firstName: "Bill", | ||||||
|  |         lastName: "Student" | ||||||
|  |     }); | ||||||
|  |     await studentRepo.save(studentB); | ||||||
|  |     const submissionB = submissionRepo.create({ | ||||||
|  |         learningObjectHruid: learningContent.branchingObject.hruid, | ||||||
|  |         learningObjectLanguage: learningContent.branchingObject.language, | ||||||
|  |         learningObjectVersion: learningContent.branchingObject.version, | ||||||
|  |         submissionNumber: 1, | ||||||
|  |         submitter: studentB, | ||||||
|  |         submissionTime: new Date(), | ||||||
|  |         content: '[1]' | ||||||
|  |     }); | ||||||
|  |     await submissionRepo.save(submissionB); | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         learningContent: learningContent, | ||||||
|  |         studentA: studentA, | ||||||
|  |         studentB: studentB, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function expectBranchingObjectNode(result: LearningPathResponse, persTestData: { | ||||||
|  |     learningContent: ConditionTestLearningPathAndLearningObjects; | ||||||
|  |     studentA: Student; | ||||||
|  |     studentB: Student | ||||||
|  | }): LearningObjectNode { | ||||||
|  |     let branchingObjectMatches = result.data![0].nodes.filter( | ||||||
|  |         it => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid | ||||||
|  |     ); | ||||||
|  |     expect(branchingObjectMatches.length).toBe(1); | ||||||
|  |     return branchingObjectMatches[0]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| describe('DatabaseLearningPathProvider', () => { | describe('DatabaseLearningPathProvider', () => { | ||||||
|     let learningObjectRepo: LearningObjectRepository; |     let learningObjectRepo: LearningObjectRepository; | ||||||
|     let example: { learningObject: LearningObject; learningPath: LearningPath }; |     let example: { learningObject: LearningObject; learningPath: LearningPath }; | ||||||
|  |     let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects, studentA: Student, studentB: Student } | ||||||
| 
 | 
 | ||||||
|     beforeAll(async () => { |     beforeAll(async () => { | ||||||
|         await setupTestApp(); |         await setupTestApp(); | ||||||
|         example = await initExampleData(); |         example = await initExampleData(); | ||||||
|  |         persTestData = await initPersonalizationTestData(); | ||||||
|         learningObjectRepo = getLearningObjectRepository(); |         learningObjectRepo = getLearningObjectRepository(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | @ -55,6 +137,60 @@ describe('DatabaseLearningPathProvider', () => { | ||||||
| 
 | 
 | ||||||
|             expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); |             expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath); | ||||||
|         }); |         }); | ||||||
|  |         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} | ||||||
|  |             ); | ||||||
|  |             expect(result.success).toBeTruthy(); | ||||||
|  |             expect(result.data?.length).toBe(1); | ||||||
|  | 
 | ||||||
|  |             // 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.
 | ||||||
|  | 
 | ||||||
|  |             // For student B:
 | ||||||
|  |             result = await databaseLearningPathProvider.fetchLearningPaths( | ||||||
|  |                 [persTestData.learningContent.learningPath.hruid], | ||||||
|  |                 persTestData.learningContent.learningPath.language, | ||||||
|  |                 'the source', | ||||||
|  |                 {type: 'student', student: persTestData.studentB} | ||||||
|  |             ); | ||||||
|  |             expect(result.success).toBeTruthy(); | ||||||
|  |             expect(result.data?.length).toBe(1); | ||||||
|  | 
 | ||||||
|  |             // There should still be exactly one branching object
 | ||||||
|  |             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.
 | ||||||
|  |         }); | ||||||
|         it('returns a non-successful response if a non-existing learning path is queried', async () => { |         it('returns a non-successful response if a non-existing learning path is queried', async () => { | ||||||
|             const result = await databaseLearningPathProvider.fetchLearningPaths( |             const result = await databaseLearningPathProvider.fetchLearningPaths( | ||||||
|                 [example.learningPath.hruid], |                 [example.learningPath.hruid], | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import { LearningObject } from '../../../../src/entities/content/learning-object | ||||||
| import { Language } from '../../../../src/entities/content/language'; | import { Language } from '../../../../src/entities/content/language'; | ||||||
| import { loadTestAsset } from '../../../test-utils/load-test-asset'; | import { loadTestAsset } from '../../../test-utils/load-test-asset'; | ||||||
| import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; | import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type'; | ||||||
|  | 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 |  * Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use | ||||||
|  | @ -12,13 +13,17 @@ export function dummyLearningObject(hruid: string, language: Language, title: st | ||||||
|     return { |     return { | ||||||
|         createLearningObject: () => { |         createLearningObject: () => { | ||||||
|             const learningObject = new LearningObject(); |             const learningObject = new LearningObject(); | ||||||
|             learningObject.hruid = hruid; |             learningObject.hruid = getEnvVar(EnvVars.UserContentPrefix) + hruid; | ||||||
|             learningObject.language = language; |             learningObject.language = language; | ||||||
|             learningObject.version = 1; |             learningObject.version = 1; | ||||||
|             learningObject.title = title; |             learningObject.title = title; | ||||||
|             learningObject.description = 'Just a dummy learning object for testing purposes'; |             learningObject.description = 'Just a dummy learning object for testing purposes'; | ||||||
|             learningObject.contentType = DwengoContentType.TEXT_PLAIN; |             learningObject.contentType = DwengoContentType.TEXT_PLAIN; | ||||||
|             learningObject.content = Buffer.from('Dummy content'); |             learningObject.content = Buffer.from('Dummy content'); | ||||||
|  |             learningObject.returnValue = { | ||||||
|  |                 callbackUrl: `/learningObject/${hruid}/submissions`, | ||||||
|  |                 callbackSchema: "[]" | ||||||
|  |             } | ||||||
|             return learningObject; |             return learningObject; | ||||||
|         }, |         }, | ||||||
|         createAttachment: {}, |         createAttachment: {}, | ||||||
|  |  | ||||||
|  | @ -14,6 +14,10 @@ const example: LearningObjectExample = { | ||||||
|         learningObject.title = 'Essay question for testing'; |         learningObject.title = 'Essay question for testing'; | ||||||
|         learningObject.description = 'This essay question was only created for testing purposes.'; |         learningObject.description = 'This essay question was only created for testing purposes.'; | ||||||
|         learningObject.contentType = DwengoContentType.GIFT; |         learningObject.contentType = DwengoContentType.GIFT; | ||||||
|  |         learningObject.returnValue = { | ||||||
|  |             callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, | ||||||
|  |             callbackSchema: '["antwoord vraag 1"]' | ||||||
|  |         } | ||||||
|         learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); |         learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt'); | ||||||
|         return learningObject; |         return learningObject; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  | @ -14,6 +14,10 @@ const example: LearningObjectExample = { | ||||||
|         learningObject.title = 'Multiple choice question for testing'; |         learningObject.title = 'Multiple choice question for testing'; | ||||||
|         learningObject.description = 'This multiple choice question was only created for testing purposes.'; |         learningObject.description = 'This multiple choice question was only created for testing purposes.'; | ||||||
|         learningObject.contentType = DwengoContentType.GIFT; |         learningObject.contentType = DwengoContentType.GIFT; | ||||||
|  |         learningObject.returnValue = { | ||||||
|  |             callbackUrl: `/learningObject/${learningObject.hruid}/submissions`, | ||||||
|  |             callbackSchema: '["antwoord vraag 1"]' | ||||||
|  |         } | ||||||
|         learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); |         learningObject.content = loadTestAsset('learning-objects/test-multiple-choice/content.txt'); | ||||||
|         return learningObject; |         return learningObject; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  | @ -3,66 +3,84 @@ import { Language } from '../../../src/entities/content/language'; | ||||||
| import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; | import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example'; | ||||||
| import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; | import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example'; | ||||||
| import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; | import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils'; | ||||||
|  | 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 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export function createConditionTestLearningPathAndLearningObjects(){ | ||||||
|  |     const learningPath = new LearningPath(); | ||||||
|  |     learningPath.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}test_conditions`; | ||||||
|  |     learningPath.language = Language.English; | ||||||
|  |     learningPath.title = 'Example learning path with conditional transitions'; | ||||||
|  |     learningPath.description = 'This learning path was made for the purpose of testing conditional transitions'; | ||||||
|  | 
 | ||||||
|  |     const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); | ||||||
|  |     const extraExerciseLearningObject = dummyLearningObject( | ||||||
|  |         'test_extra_exercise', | ||||||
|  |         Language.English, | ||||||
|  |         'Extra exercise (for students with difficulties)' | ||||||
|  |     ).createLearningObject(); | ||||||
|  |     const finalLearningObject = dummyLearningObject( | ||||||
|  |         'test_final_learning_object', | ||||||
|  |         Language.English, | ||||||
|  |         'Final exercise (for everyone)' | ||||||
|  |     ).createLearningObject(); | ||||||
|  | 
 | ||||||
|  |     const branchingNode = createLearningPathNode( | ||||||
|  |         learningPath, | ||||||
|  |         0, | ||||||
|  |         branchingLearningObject.hruid, | ||||||
|  |         branchingLearningObject.version, | ||||||
|  |         branchingLearningObject.language, | ||||||
|  |         true | ||||||
|  |     ); | ||||||
|  |     const extraExerciseNode = createLearningPathNode( | ||||||
|  |         learningPath, | ||||||
|  |         1, | ||||||
|  |         extraExerciseLearningObject.hruid, | ||||||
|  |         extraExerciseLearningObject.version, | ||||||
|  |         extraExerciseLearningObject.language, | ||||||
|  |         false | ||||||
|  |     ); | ||||||
|  |     const finalNode = createLearningPathNode( | ||||||
|  |         learningPath, | ||||||
|  |         2, | ||||||
|  |         finalLearningObject.hruid, | ||||||
|  |         finalLearningObject.version, | ||||||
|  |         finalLearningObject.language, | ||||||
|  |         false | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     const transitionToExtraExercise = createLearningPathTransition( | ||||||
|  |         branchingNode, | ||||||
|  |         0, | ||||||
|  |         '$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along.
 | ||||||
|  |         extraExerciseNode | ||||||
|  |     ); | ||||||
|  |     const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode); | ||||||
|  |     const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode); | ||||||
|  | 
 | ||||||
|  |     branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; | ||||||
|  |     extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; | ||||||
|  | 
 | ||||||
|  |     learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         branchingObject: branchingLearningObject, | ||||||
|  |         finalObject: finalLearningObject, | ||||||
|  |         extraExerciseObject: extraExerciseLearningObject, | ||||||
|  |         learningPath: learningPath, | ||||||
|  |     }; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| const example: LearningPathExample = { | const example: LearningPathExample = { | ||||||
|     createLearningPath: () => { |     createLearningPath: () => { | ||||||
|         const learningPath = new LearningPath(); |         return createConditionTestLearningPathAndLearningObjects().learningPath; | ||||||
|         learningPath.hruid = 'test_conditions'; |  | ||||||
|         learningPath.language = Language.English; |  | ||||||
|         learningPath.title = 'Example learning path with conditional transitions'; |  | ||||||
|         learningPath.description = 'This learning path was made for the purpose of testing conditional transitions'; |  | ||||||
| 
 |  | ||||||
|         const branchingLearningObject = testMultipleChoiceExample.createLearningObject(); |  | ||||||
|         const extraExerciseLearningObject = dummyLearningObject( |  | ||||||
|             'test_extra_exercise', |  | ||||||
|             Language.English, |  | ||||||
|             'Extra exercise (for students with difficulties)' |  | ||||||
|         ).createLearningObject(); |  | ||||||
|         const finalLearningObject = dummyLearningObject( |  | ||||||
|             'test_final_learning_object', |  | ||||||
|             Language.English, |  | ||||||
|             'Final exercise (for everyone)' |  | ||||||
|         ).createLearningObject(); |  | ||||||
| 
 |  | ||||||
|         const branchingNode = createLearningPathNode( |  | ||||||
|             learningPath, |  | ||||||
|             0, |  | ||||||
|             branchingLearningObject.hruid, |  | ||||||
|             branchingLearningObject.version, |  | ||||||
|             branchingLearningObject.language, |  | ||||||
|             true |  | ||||||
|         ); |  | ||||||
|         const extraExerciseNode = createLearningPathNode( |  | ||||||
|             learningPath, |  | ||||||
|             1, |  | ||||||
|             extraExerciseLearningObject.hruid, |  | ||||||
|             extraExerciseLearningObject.version, |  | ||||||
|             extraExerciseLearningObject.language, |  | ||||||
|             false |  | ||||||
|         ); |  | ||||||
|         const finalNode = createLearningPathNode( |  | ||||||
|             learningPath, |  | ||||||
|             2, |  | ||||||
|             finalLearningObject.hruid, |  | ||||||
|             finalLearningObject.version, |  | ||||||
|             finalLearningObject.language, |  | ||||||
|             false |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         const transitionToExtraExercise = createLearningPathTransition( |  | ||||||
|             branchingNode, |  | ||||||
|             0, |  | ||||||
|             '$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along.
 |  | ||||||
|             extraExerciseNode |  | ||||||
|         ); |  | ||||||
|         const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode); |  | ||||||
|         const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode); |  | ||||||
| 
 |  | ||||||
|         branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal]; |  | ||||||
|         extraExerciseNode.transitions = [transitionExtraExerciseToFinal]; |  | ||||||
| 
 |  | ||||||
|         learningPath.nodes = [branchingNode, extraExerciseNode, finalNode]; |  | ||||||
| 
 |  | ||||||
|         return learningPath; |  | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -4,5 +4,6 @@ export default defineConfig({ | ||||||
|     test: { |     test: { | ||||||
|         environment: 'node', |         environment: 'node', | ||||||
|         globals: true, |         globals: true, | ||||||
|  |         testTimeout: 10000, | ||||||
|     }, |     }, | ||||||
| }); | }); | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger