merge: fixed merge conflicts

This commit is contained in:
Adriaan Jacquet 2025-04-19 13:44:36 +02:00
commit 90f43e74ba
101 changed files with 2156 additions and 1470 deletions

View file

@ -91,9 +91,9 @@ describe('SubmissionRepository', () => {
expect(result[2].submissionNumber).toBe(3);
});
it("should find only the submissions for a certain learning object and assignment made for the user's group", async () => {
const result = await submissionRepository.findAllSubmissionsForLearningObjectAndAssignment(loId, assignment!, 'Tool');
// (student Tool is in group #2)
it('should find only the submissions for a certain learning object and assignment made for the given group', async () => {
const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 2);
const result = await submissionRepository.findAllSubmissionsForLearningObjectAndGroup(loId, group!);
expect(result).toHaveLength(1);

View file

@ -2,66 +2,57 @@ import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests.js';
import { getAttachmentRepository, getLearningObjectRepository } from '../../../src/data/repositories.js';
import { AttachmentRepository } from '../../../src/data/content/attachment-repository.js';
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js';
import { LearningObject } from '../../../src/entities/content/learning-object.entity.js';
import { Attachment } from '../../../src/entities/content/attachment.entity.js';
import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier.js';
const NEWER_TEST_SUFFIX = 'nEweR';
async function createTestLearningObjects(learningObjectRepo: LearningObjectRepository): Promise<{
older: LearningObject;
newer: LearningObject;
}> {
const olderExample = example.createLearningObject();
await learningObjectRepo.save(olderExample);
const newerExample = example.createLearningObject();
newerExample.title = 'Newer example';
newerExample.version = 100;
return {
older: olderExample,
newer: newerExample,
};
}
import { testLearningObjectPnNotebooks } from '../../test_assets/content/learning-objects.testdata';
import { v4 as uuidV4 } from 'uuid';
describe('AttachmentRepository', () => {
let attachmentRepo: AttachmentRepository;
let exampleLearningObjects: { older: LearningObject; newer: LearningObject };
let newLearningObject: LearningObject;
let attachmentsOlderLearningObject: Attachment[];
beforeAll(async () => {
await setupTestApp();
attachmentsOlderLearningObject = testLearningObjectPnNotebooks.attachments as Attachment[];
attachmentRepo = getAttachmentRepository();
exampleLearningObjects = await createTestLearningObjects(getLearningObjectRepository());
});
const learningObjectRepo = getLearningObjectRepository();
it('can add attachments to learning objects without throwing an error', async () => {
attachmentsOlderLearningObject = Object.values(example.createAttachment).map((fn) => fn(exampleLearningObjects.older));
const newLearningObjectData = structuredClone(testLearningObjectPnNotebooks);
newLearningObjectData.title = 'Newer example';
newLearningObjectData.version = 101;
newLearningObjectData.attachments = [];
newLearningObjectData.uuid = uuidV4();
newLearningObjectData.content = Buffer.from('Content of the newer example');
await Promise.all(attachmentsOlderLearningObject.map(async (attachment) => attachmentRepo.save(attachment)));
newLearningObject = learningObjectRepo.create(newLearningObjectData);
await learningObjectRepo.save(newLearningObject);
});
let attachmentOnlyNewer: Attachment;
it('allows us to add attachments with the same name to a different learning object without throwing an error', async () => {
attachmentOnlyNewer = Object.values(example.createAttachment)[0](exampleLearningObjects.newer);
attachmentOnlyNewer.content.write(NEWER_TEST_SUFFIX);
attachmentOnlyNewer = structuredClone(attachmentsOlderLearningObject[0]);
attachmentOnlyNewer.learningObject = newLearningObject;
attachmentOnlyNewer.content = Buffer.from('New attachment content');
await attachmentRepo.save(attachmentOnlyNewer);
await attachmentRepo.save(attachmentRepo.create(attachmentOnlyNewer));
});
let olderLearningObjectId: LearningObjectIdentifier;
it('returns the correct attachment when queried by learningObjectId and attachment name', async () => {
olderLearningObjectId = {
hruid: exampleLearningObjects.older.hruid,
language: exampleLearningObjects.older.language,
version: exampleLearningObjects.older.version,
hruid: testLearningObjectPnNotebooks.hruid,
language: testLearningObjectPnNotebooks.language,
version: testLearningObjectPnNotebooks.version,
};
const result = await attachmentRepo.findByLearningObjectIdAndName(olderLearningObjectId, attachmentsOlderLearningObject[0].name);
expect(result).toBe(attachmentsOlderLearningObject[0]);
expect(result).not.toBeNull();
expect(result!.name).toEqual(attachmentsOlderLearningObject[0].name);
expect(result!.content).toEqual(attachmentsOlderLearningObject[0].content);
});
it('returns null when queried by learningObjectId and non-existing attachment name', async () => {
@ -71,10 +62,12 @@ describe('AttachmentRepository', () => {
it('returns the newer version of the attachment when only queried by hruid, language and attachment name (but not version)', async () => {
const result = await attachmentRepo.findByMostRecentVersionOfLearningObjectAndName(
exampleLearningObjects.older.hruid,
exampleLearningObjects.older.language,
testLearningObjectPnNotebooks.hruid,
testLearningObjectPnNotebooks.language,
attachmentOnlyNewer.name
);
expect(result).toBe(attachmentOnlyNewer);
expect(result).not.toBeNull();
expect(result!.name).toEqual(attachmentOnlyNewer.name);
expect(result!.content).toEqual(attachmentOnlyNewer.content);
});
});

View file

@ -1,28 +1,21 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests.js';
import { getAttachmentRepository, getLearningObjectRepository } from '../../../src/data/repositories.js';
import { getAttachmentRepository } from '../../../src/data/repositories.js';
import { AttachmentRepository } from '../../../src/data/content/attachment-repository.js';
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier.js';
import { Language } from '@dwengo-1/common/util/language';
import { testLearningObject02 } from '../../test_assets/content/learning-objects.testdata';
describe('AttachmentRepository', () => {
let attachmentRepository: AttachmentRepository;
let learningObjectRepository: LearningObjectRepository;
beforeAll(async () => {
await setupTestApp();
attachmentRepository = getAttachmentRepository();
learningObjectRepository = getLearningObjectRepository();
});
it('should return the requested attachment', async () => {
const id = new LearningObjectIdentifier('id02', Language.English, 1);
const learningObject = await learningObjectRepository.findByIdentifier(id);
const attachment = await attachmentRepository.findByMostRecentVersionOfLearningObjectAndName(
learningObject!.hruid,
Language.English,
testLearningObject02.hruid,
testLearningObject02.language,
'attachment01'
);

View file

@ -2,48 +2,33 @@ import { beforeAll, describe, it, expect } from 'vitest';
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
import { setupTestApp } from '../../setup-tests.js';
import { getLearningObjectRepository } from '../../../src/data/repositories.js';
import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js';
import { LearningObject } from '../../../src/entities/content/learning-object.entity.js';
import { expectToBeCorrectEntity } from '../../test-utils/expectations.js';
import { testLearningObject01, testLearningObject02, testLearningObject03 } from '../../test_assets/content/learning-objects.testdata';
import { v4 } from 'uuid';
describe('LearningObjectRepository', () => {
let learningObjectRepository: LearningObjectRepository;
let exampleLearningObject: LearningObject;
beforeAll(async () => {
await setupTestApp();
learningObjectRepository = getLearningObjectRepository();
});
it('should be able to add a learning object to it without an error', async () => {
exampleLearningObject = example.createLearningObject();
await learningObjectRepository.insert(exampleLearningObject);
});
it('should return the learning object when queried by id', async () => {
it('should return a learning object when queried by id', async () => {
const result = await learningObjectRepository.findByIdentifier({
hruid: exampleLearningObject.hruid,
language: exampleLearningObject.language,
version: exampleLearningObject.version,
hruid: testLearningObject01.hruid,
language: testLearningObject02.language,
version: testLearningObject03.version,
});
expect(result).toBeInstanceOf(LearningObject);
expectToBeCorrectEntity(
{
name: 'actual',
entity: result!,
},
{
name: 'expected',
entity: exampleLearningObject,
}
);
expectToBeCorrectEntity(result!, testLearningObject01);
});
it('should return null when non-existing version is queried', async () => {
const result = await learningObjectRepository.findByIdentifier({
hruid: exampleLearningObject.hruid,
language: exampleLearningObject.language,
hruid: testLearningObject01.hruid,
language: testLearningObject01.language,
version: 100,
});
expect(result).toBe(null);
@ -52,9 +37,12 @@ describe('LearningObjectRepository', () => {
let newerExample: LearningObject;
it('should allow a learning object with the same id except a different version to be added', async () => {
newerExample = example.createLearningObject();
newerExample.version = 10;
newerExample.title += ' (nieuw)';
const testLearningObject01Newer = structuredClone(testLearningObject01);
testLearningObject01Newer.version = 10;
testLearningObject01Newer.title += ' (nieuw)';
testLearningObject01Newer.uuid = v4();
testLearningObject01Newer.content = Buffer.from('This is the new content.');
newerExample = learningObjectRepository.create(testLearningObject01Newer);
await learningObjectRepository.save(newerExample);
});
@ -66,7 +54,7 @@ describe('LearningObjectRepository', () => {
});
it('should return null when queried by non-existing hruid or language', async () => {
const result = await learningObjectRepository.findLatestByHruidAndLanguage('something_that_does_not_exist', exampleLearningObject.language);
const result = await learningObjectRepository.findLatestByHruidAndLanguage('something_that_does_not_exist', testLearningObject01.language);
expect(result).toBe(null);
});
});

View file

@ -4,6 +4,7 @@ import { getLearningObjectRepository } from '../../../src/data/repositories';
import { setupTestApp } from '../../setup-tests';
import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier';
import { Language } from '@dwengo-1/common/util/language';
import { testLearningObject01 } from '../../test_assets/content/learning-objects.testdata';
describe('LearningObjectRepository', () => {
let learningObjectRepository: LearningObjectRepository;
@ -13,8 +14,8 @@ describe('LearningObjectRepository', () => {
learningObjectRepository = getLearningObjectRepository();
});
const id01 = new LearningObjectIdentifier('id01', Language.English, 1);
const id02 = new LearningObjectIdentifier('test_id', Language.English, 1);
const id01 = new LearningObjectIdentifier(testLearningObject01.hruid, testLearningObject01.language, testLearningObject01.version);
const id02 = new LearningObjectIdentifier('non_existing_id', Language.English, 1);
it('should return the learning object that matches identifier 1', async () => {
const learningObject = await learningObjectRepository.findByIdentifier(id01);

View file

@ -2,41 +2,27 @@ import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests.js';
import { getLearningPathRepository } from '../../../src/data/repositories.js';
import { LearningPathRepository } from '../../../src/data/content/learning-path-repository.js';
import example from '../../test-assets/learning-paths/pn-werking-example.js';
import { LearningPath } from '../../../src/entities/content/learning-path.entity.js';
import { expectToBeCorrectEntity } from '../../test-utils/expectations.js';
import { expectToBeCorrectEntity, expectToHaveFoundNothing, expectToHaveFoundPrecisely } from '../../test-utils/expectations.js';
import { Language } from '@dwengo-1/common/util/language';
function expectToHaveFoundPrecisely(expected: LearningPath, result: LearningPath[]): void {
expect(result).toHaveProperty('length');
expect(result.length).toBe(1);
expectToBeCorrectEntity({ entity: result[0] }, { entity: expected });
}
function expectToHaveFoundNothing(result: LearningPath[]): void {
expect(result).toHaveProperty('length');
expect(result.length).toBe(0);
}
import { testLearningPath01 } from '../../test_assets/content/learning-paths.testdata';
import { mapToLearningPath } from '../../../src/services/learning-paths/learning-path-service';
describe('LearningPathRepository', () => {
let learningPathRepo: LearningPathRepository;
let examplePath: LearningPath;
beforeAll(async () => {
await setupTestApp();
learningPathRepo = getLearningPathRepository();
examplePath = mapToLearningPath(testLearningPath01, []);
});
let examplePath: LearningPath;
it('should be able to add a learning path without throwing an error', async () => {
examplePath = example.createLearningPath();
await learningPathRepo.insert(examplePath);
});
it('should return the added path when it is queried by hruid and language', async () => {
const result = await learningPathRepo.findByHruidAndLanguage(examplePath.hruid, examplePath.language);
it('should return a learning path when it is queried by hruid and language', async () => {
const result = await learningPathRepo.findByHruidAndLanguage(testLearningPath01.hruid, testLearningPath01.language as Language);
expect(result).toBeInstanceOf(LearningPath);
expectToBeCorrectEntity({ entity: result! }, { entity: examplePath });
expectToBeCorrectEntity(result!, examplePath);
});
it('should return null to a query on a non-existing hruid or language', async () => {
@ -45,7 +31,7 @@ describe('LearningPathRepository', () => {
});
it('should return the learning path when we search for a search term occurring in its title', async () => {
const result = await learningPathRepo.findByQueryStringAndLanguage(examplePath.title.slice(4, 9), examplePath.language);
const result = await learningPathRepo.findByQueryStringAndLanguage(examplePath.title.slice(9, 13), examplePath.language);
expectToHaveFoundPrecisely(examplePath, result);
});

View file

@ -3,6 +3,7 @@ import { getLearningPathRepository } from '../../../src/data/repositories';
import { LearningPathRepository } from '../../../src/data/content/learning-path-repository';
import { setupTestApp } from '../../setup-tests';
import { Language } from '@dwengo-1/common/util/language';
import { testLearningPath01 } from '../../test_assets/content/learning-paths.testdata';
describe('LearningPathRepository', () => {
let learningPathRepository: LearningPathRepository;
@ -19,10 +20,10 @@ describe('LearningPathRepository', () => {
});
it('should return requested learning path', async () => {
const learningPath = await learningPathRepository.findByHruidAndLanguage('id01', Language.English);
const learningPath = await learningPathRepository.findByHruidAndLanguage(testLearningPath01.hruid, testLearningPath01.language as Language);
expect(learningPath).toBeTruthy();
expect(learningPath?.title).toBe('repertoire Tool');
expect(learningPath?.description).toBe('all about Tool');
expect(learningPath?.title).toBe(testLearningPath01.title);
expect(learningPath?.description).toBe(testLearningPath01.description);
});
});

View file

@ -1,37 +1,32 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests';
import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories';
import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import databaseLearningObjectProvider from '../../../src/services/learning-objects/database-learning-object-provider';
import { expectToBeCorrectFilteredLearningObject } from '../../test-utils/expectations';
import { Language } from '@dwengo-1/common/util/language';
import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example';
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import { FilteredLearningObject } from '@dwengo-1/common/interfaces/learning-content';
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository();
const learningPathRepo = getLearningPathRepository();
const learningObject = learningObjectExample.createLearningObject();
const learningPath = learningPathExample.createLearningPath();
await learningObjectRepo.save(learningObject);
await learningPathRepo.save(learningPath);
return { learningObject, learningPath };
}
import { FilteredLearningObject, LearningObjectNode, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content';
import { testPartiallyDatabaseAndPartiallyDwengoApiLearningPath } from '../../test_assets/content/learning-paths.testdata';
import { testLearningObjectPnNotebooks } from '../../test_assets/content/learning-objects.testdata';
import { LearningPath } from '@dwengo-1/common/dist/interfaces/learning-content';
import { RequiredEntityData } from '@mikro-orm/core';
import { getHtmlRenderingForTestLearningObject } from '../../test-utils/get-html-rendering';
const EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT = 'Notebook opslaan';
describe('DatabaseLearningObjectProvider', () => {
let exampleLearningObject: LearningObject;
let exampleLearningObject: RequiredEntityData<LearningObject>;
let exampleLearningPath: LearningPath;
let exampleLearningPathId: LearningPathIdentifier;
beforeAll(async () => {
await setupTestApp();
const exampleData = await initExampleData();
exampleLearningObject = exampleData.learningObject;
exampleLearningPath = exampleData.learningPath;
exampleLearningObject = testLearningObjectPnNotebooks;
exampleLearningPath = testPartiallyDatabaseAndPartiallyDwengoApiLearningPath;
exampleLearningPathId = {
hruid: exampleLearningPath.hruid,
language: exampleLearningPath.language as Language,
};
});
describe('getLearningObjectById', () => {
it('should return the learning object when it is queried by its id', async () => {
@ -61,7 +56,7 @@ describe('DatabaseLearningObjectProvider', () => {
it('should return the correct rendering of the learning object', async () => {
const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject);
// Set newlines so your tests are platform-independent.
expect(result).toEqual(example.getHTMLRendering().replace(/\r\n/g, '\n'));
expect(result).toEqual(getHtmlRenderingForTestLearningObject(exampleLearningObject).replace(/\r\n/g, '\n'));
});
it('should return null for a non-existing learning object', async () => {
const result = await databaseLearningObjectProvider.getLearningObjectHTML({
@ -73,8 +68,8 @@ describe('DatabaseLearningObjectProvider', () => {
});
describe('getLearningObjectIdsFromPath', () => {
it('should return all learning object IDs from a path', async () => {
const result = await databaseLearningObjectProvider.getLearningObjectIdsFromPath(exampleLearningPath);
expect(new Set(result)).toEqual(new Set(exampleLearningPath.nodes.map((it) => it.learningObjectHruid)));
const result = await databaseLearningObjectProvider.getLearningObjectIdsFromPath(exampleLearningPathId);
expect(new Set(result)).toEqual(new Set(exampleLearningPath.nodes.map((it: LearningObjectNode) => it.learningobject_hruid)));
});
it('should throw an error if queried with a path identifier for which there is no learning path', async () => {
await expect(
@ -89,9 +84,11 @@ describe('DatabaseLearningObjectProvider', () => {
});
describe('getLearningObjectsFromPath', () => {
it('should correctly return all learning objects which are on the path, even those who are not in the database', async () => {
const result = await databaseLearningObjectProvider.getLearningObjectsFromPath(exampleLearningPath);
const result = await databaseLearningObjectProvider.getLearningObjectsFromPath(exampleLearningPathId);
expect(result.length).toBe(exampleLearningPath.nodes.length);
expect(new Set(result.map((it) => it.key))).toEqual(new Set(exampleLearningPath.nodes.map((it) => it.learningObjectHruid)));
expect(new Set(result.map((it) => it.key))).toEqual(
new Set(exampleLearningPath.nodes.map((it: LearningObjectNode) => it.learningobject_hruid))
);
expect(result.map((it) => it.title)).toContainEqual(EXPECTED_TITLE_FROM_DWENGO_LEARNING_OBJECT);
});

View file

@ -1,14 +1,14 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests';
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories';
import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import learningObjectService from '../../../src/services/learning-objects/learning-object-service';
import { envVars, getEnvVar } from '../../../src/util/envVars';
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example';
import { LearningObjectIdentifierDTO, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content';
import { LearningObjectIdentifierDTO, LearningPath as LearningPathDTO, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content';
import { Language } from '@dwengo-1/common/util/language';
import { testLearningObjectPnNotebooks } from '../../test_assets/content/learning-objects.testdata';
import { testPartiallyDatabaseAndPartiallyDwengoApiLearningPath } from '../../test_assets/content/learning-paths.testdata';
import { RequiredEntityData } from '@mikro-orm/core';
import { getHtmlRenderingForTestLearningObject } from '../../test-utils/get-html-rendering';
const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks';
const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifierDTO = {
@ -23,25 +23,20 @@ const DWENGO_TEST_LEARNING_PATH_ID: LearningPathIdentifier = {
};
const DWENGO_TEST_LEARNING_PATH_HRUIDS = new Set(['pn_werkingnotebooks', 'pn_werkingnotebooks2', 'pn_werkingnotebooks3']);
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository();
const learningPathRepo = getLearningPathRepository();
const learningObject = learningObjectExample.createLearningObject();
const learningPath = learningPathExample.createLearningPath();
await learningObjectRepo.save(learningObject);
await learningPathRepo.save(learningPath);
return { learningObject, learningPath };
}
describe('LearningObjectService', () => {
let exampleLearningObject: LearningObject;
let exampleLearningPath: LearningPath;
let exampleLearningObject: RequiredEntityData<LearningObject>;
let exampleLearningPath: LearningPathDTO;
let exampleLearningPathId: LearningPathIdentifier;
beforeAll(async () => {
await setupTestApp();
const exampleData = await initExampleData();
exampleLearningObject = exampleData.learningObject;
exampleLearningPath = exampleData.learningPath;
exampleLearningObject = testLearningObjectPnNotebooks;
exampleLearningPath = testPartiallyDatabaseAndPartiallyDwengoApiLearningPath;
exampleLearningPathId = {
hruid: exampleLearningPath.hruid,
language: exampleLearningPath.language as Language,
};
});
describe('getLearningObjectById', () => {
@ -69,7 +64,7 @@ describe('LearningObjectService', () => {
const result = await learningObjectService.getLearningObjectHTML(exampleLearningObject);
expect(result).not.toBeNull();
// Set newlines so your tests are platform-independent.
expect(result).toEqual(learningObjectExample.getHTMLRendering().replace(/\r\n/g, '\n'));
expect(result).toEqual(getHtmlRenderingForTestLearningObject(exampleLearningObject).replace(/\r\n/g, '\n'));
});
it(
'returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does ' +
@ -97,8 +92,8 @@ describe('LearningObjectService', () => {
describe('getLearningObjectsFromPath', () => {
it('returns all learning objects when a learning path in the database is queried', async () => {
const result = await learningObjectService.getLearningObjectsFromPath(exampleLearningPath);
expect(result.map((it) => it.key)).toEqual(exampleLearningPath.nodes.map((it) => it.learningObjectHruid));
const result = await learningObjectService.getLearningObjectsFromPath(exampleLearningPathId);
expect(result.map((it) => it.key)).toEqual(exampleLearningPath.nodes.map((it) => it.learningobject_hruid));
});
it('also returns all learning objects when a learning path from the Dwengo API is queried', async () => {
const result = await learningObjectService.getLearningObjectsFromPath(DWENGO_TEST_LEARNING_PATH_ID);
@ -115,8 +110,8 @@ describe('LearningObjectService', () => {
describe('getLearningObjectIdsFromPath', () => {
it('returns all learning objects when a learning path in the database is queried', async () => {
const result = await learningObjectService.getLearningObjectIdsFromPath(exampleLearningPath);
expect(result).toEqual(exampleLearningPath.nodes.map((it) => it.learningObjectHruid));
const result = await learningObjectService.getLearningObjectIdsFromPath(exampleLearningPathId);
expect(result).toEqual(exampleLearningPath.nodes.map((it) => it.learningobject_hruid));
});
it('also returns all learning object hruids when a learning path from the Dwengo API is queried', async () => {
const result = await learningObjectService.getLearningObjectIdsFromPath(DWENGO_TEST_LEARNING_PATH_ID);

View file

@ -1,26 +1,35 @@
import { describe, expect, it } from 'vitest';
import mdExample from '../../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import multipleChoiceExample from '../../../test-assets/learning-objects/test-multiple-choice/test-multiple-choice-example';
import essayExample from '../../../test-assets/learning-objects/test-essay/test-essay-example';
import { beforeAll, describe, expect, it } from 'vitest';
import processingService from '../../../../src/services/learning-objects/processing/processing-service';
import {
testLearningObjectEssayQuestion,
testLearningObjectMultipleChoice,
testLearningObjectPnNotebooks,
} from '../../../test_assets/content/learning-objects.testdata';
import { getHtmlRenderingForTestLearningObject } from '../../../test-utils/get-html-rendering';
import { getLearningObjectRepository } from '../../../../src/data/repositories';
import { setupTestApp } from '../../../setup-tests';
describe('ProcessingService', () => {
beforeAll(async () => {
await setupTestApp();
});
it('renders a markdown learning object correctly', async () => {
const markdownLearningObject = mdExample.createLearningObject();
const markdownLearningObject = getLearningObjectRepository().create(testLearningObjectPnNotebooks);
const result = await processingService.render(markdownLearningObject);
// Set newlines so your tests are platform-independent.
expect(result).toEqual(mdExample.getHTMLRendering().replace(/\r\n/g, '\n'));
expect(result).toEqual(getHtmlRenderingForTestLearningObject(markdownLearningObject).replace(/\r\n/g, '\n'));
});
it('renders a multiple choice question correctly', async () => {
const multipleChoiceLearningObject = multipleChoiceExample.createLearningObject();
const result = await processingService.render(multipleChoiceLearningObject);
expect(result).toEqual(multipleChoiceExample.getHTMLRendering().replace(/\r\n/g, '\n'));
const testLearningObject = getLearningObjectRepository().create(testLearningObjectMultipleChoice);
const result = await processingService.render(testLearningObject);
expect(result).toEqual(getHtmlRenderingForTestLearningObject(testLearningObjectMultipleChoice).replace(/\r\n/g, '\n'));
});
it('renders an essay question correctly', async () => {
const essayLearningObject = essayExample.createLearningObject();
const essayLearningObject = getLearningObjectRepository().create(testLearningObjectEssayQuestion);
const result = await processingService.render(essayLearningObject);
expect(result).toEqual(essayExample.getHTMLRendering().replace(/\r\n/g, '\n'));
expect(result).toEqual(getHtmlRenderingForTestLearningObject(essayLearningObject).replace(/\r\n/g, '\n'));
});
});

View file

@ -2,227 +2,112 @@ import { beforeAll, describe, expect, it } from 'vitest';
import { LearningObject } from '../../../src/entities/content/learning-object.entity.js';
import { setupTestApp } from '../../setup-tests.js';
import { LearningPath } from '../../../src/entities/content/learning-path.entity.js';
import {
getAssignmentRepository,
getClassRepository,
getGroupRepository,
getLearningObjectRepository,
getLearningPathRepository,
getStudentRepository,
getSubmissionRepository,
} from '../../../src/data/repositories.js';
import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js';
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example.js';
import { getSubmissionRepository } from '../../../src/data/repositories.js';
import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider.js';
import { expectToBeCorrectLearningPath } from '../../test-utils/expectations.js';
import learningObjectService from '../../../src/services/learning-objects/learning-object-service.js';
import { Language } from '@dwengo-1/common/util/language';
import {
ConditionTestLearningPathAndLearningObjects,
createConditionTestLearningPathAndLearningObjects,
} from '../../test-assets/learning-paths/test-conditions-example.js';
import { Student } from '../../../src/entities/users/student.entity.js';
import { LearningObjectNode, LearningPathResponse } from '@dwengo-1/common/interfaces/learning-content';
import {
testLearningObject01,
testLearningObjectEssayQuestion,
testLearningObjectMultipleChoice,
} from '../../test_assets/content/learning-objects.testdata';
import { testLearningPathWithConditions } from '../../test_assets/content/learning-paths.testdata';
import { mapToLearningPath } from '../../../src/services/learning-paths/learning-path-service';
import { getTestGroup01, getTestGroup02 } from '../../test_assets/assignments/groups.testdata';
import { Group } from '../../../src/entities/assignments/group.entity.js';
import { RequiredEntityData } from '@mikro-orm/core';
const STUDENT_A_USERNAME = 'student_a';
const STUDENT_B_USERNAME = 'student_b';
const CLASS_NAME = 'test_class';
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository();
const learningPathRepo = getLearningPathRepository();
const learningObject = learningObjectExample.createLearningObject();
const learningPath = learningPathExample.createLearningPath();
await learningObjectRepo.save(learningObject);
await learningPathRepo.save(learningPath);
return { learningObject, learningPath };
}
async function initPersonalizationTestData(): Promise<{
learningContent: ConditionTestLearningPathAndLearningObjects;
studentA: Student;
studentB: Student;
}> {
const studentRepo = getStudentRepository();
const classRepo = getClassRepository();
const assignmentRepo = getAssignmentRepository();
const groupRepo = getGroupRepository();
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);
// Create students
const studentA = studentRepo.create({
username: STUDENT_A_USERNAME,
firstName: 'Aron',
lastName: 'Student',
});
await studentRepo.save(studentA);
const studentB = studentRepo.create({
username: STUDENT_B_USERNAME,
firstName: 'Bill',
lastName: 'Student',
});
await studentRepo.save(studentB);
// Create class for students
const testClass = classRepo.create({
classId: CLASS_NAME,
displayName: 'Test class',
});
await classRepo.save(testClass);
// Create assignment for students and assign them to different groups
const assignment = assignmentRepo.create({
id: 0,
title: 'Test assignment',
description: 'Test description',
learningPathHruid: learningContent.learningPath.hruid,
learningPathLanguage: learningContent.learningPath.language,
within: testClass,
});
const groupA = groupRepo.create({
groupNumber: 0,
members: [studentA],
assignment,
});
await groupRepo.save(groupA);
const groupB = groupRepo.create({
groupNumber: 1,
members: [studentB],
assignment,
});
await groupRepo.save(groupB);
// Let each of the students make a submission in his own group.
const submissionA = submissionRepo.create({
learningObjectHruid: learningContent.branchingObject.hruid,
learningObjectLanguage: learningContent.branchingObject.language,
learningObjectVersion: learningContent.branchingObject.version,
onBehalfOf: groupA,
submitter: studentA,
submissionTime: new Date(),
content: '[0]',
});
await submissionRepo.save(submissionA);
const submissionB = submissionRepo.create({
learningObjectHruid: learningContent.branchingObject.hruid,
learningObjectLanguage: learningContent.branchingObject.language,
learningObjectVersion: learningContent.branchingObject.version,
onBehalfOf: groupA,
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 {
const branchingObjectMatches = result.data![0].nodes.filter(
(it) => it.learningobject_hruid === persTestData.learningContent.branchingObject.hruid
);
function expectBranchingObjectNode(result: LearningPathResponse): LearningObjectNode {
const branchingObjectMatches = result.data![0].nodes.filter((it) => it.learningobject_hruid === testLearningObjectMultipleChoice.hruid);
expect(branchingObjectMatches.length).toBe(1);
return branchingObjectMatches[0];
}
describe('DatabaseLearningPathProvider', () => {
let example: { learningObject: LearningObject; learningPath: LearningPath };
let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects; studentA: Student; studentB: Student };
let testLearningPath: LearningPath;
let branchingLearningObject: RequiredEntityData<LearningObject>;
let extraExerciseLearningObject: RequiredEntityData<LearningObject>;
let finalLearningObject: RequiredEntityData<LearningObject>;
let groupA: Group;
let groupB: Group;
beforeAll(async () => {
await setupTestApp();
example = await initExampleData();
persTestData = await initPersonalizationTestData();
testLearningPath = mapToLearningPath(testLearningPathWithConditions, []);
branchingLearningObject = testLearningObjectMultipleChoice;
extraExerciseLearningObject = testLearningObject01;
finalLearningObject = testLearningObjectEssayQuestion;
groupA = getTestGroup01();
groupB = getTestGroup02();
// Place different submissions for group A and B.
const submissionRepo = getSubmissionRepository();
const submissionA = submissionRepo.create({
learningObjectHruid: branchingLearningObject.hruid,
learningObjectLanguage: branchingLearningObject.language,
learningObjectVersion: branchingLearningObject.version,
content: '[0]',
onBehalfOf: groupA,
submissionTime: new Date(),
submitter: groupA.members[0],
});
await submissionRepo.save(submissionA);
const submissionB = submissionRepo.create({
learningObjectHruid: branchingLearningObject.hruid,
learningObjectLanguage: branchingLearningObject.language,
learningObjectVersion: branchingLearningObject.version,
content: '[1]',
onBehalfOf: groupB,
submissionTime: new Date(),
submitter: groupB.members[0],
});
await submissionRepo.save(submissionB);
});
describe('fetchLearningPaths', () => {
it('returns the learning path correctly', async () => {
const result = await databaseLearningPathProvider.fetchLearningPaths(
[example.learningPath.hruid],
example.learningPath.language,
'the source'
);
const result = await databaseLearningPathProvider.fetchLearningPaths([testLearningPath.hruid], testLearningPath.language, 'the source');
expect(result.success).toBe(true);
expect(result.data?.length).toBe(1);
const learningObjectsOnPath = (
await Promise.all(
example.learningPath.nodes.map(async (node) =>
learningObjectService.getLearningObjectById({
hruid: node.learningObjectHruid,
version: node.version,
language: node.language,
})
)
)
).filter((it) => it !== null);
expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath);
expectToBeCorrectLearningPath(result.data![0], testLearningPathWithConditions);
});
it('returns the correct personalized learning path', async () => {
// For student A:
let result = await databaseLearningPathProvider.fetchLearningPaths(
[persTestData.learningContent.learningPath.hruid],
persTestData.learningContent.learningPath.language,
[testLearningPath.hruid],
testLearningPath.language,
'the source',
{ type: 'student', student: persTestData.studentA }
groupA
);
expect(result.success).toBeTruthy();
expect(result.data?.length).toBe(1);
// There should be exactly one branching object
let branchingObject = expectBranchingObjectNode(result, persTestData);
let branchingObject = expectBranchingObjectNode(result);
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 === finalLearningObject.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 === extraExerciseLearningObject.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 }
);
result = await databaseLearningPathProvider.fetchLearningPaths([testLearningPath.hruid], testLearningPath.language, 'the source', groupB);
expect(result.success).toBeTruthy();
expect(result.data?.length).toBe(1);
// There should still be exactly one branching object
branchingObject = expectBranchingObjectNode(result, persTestData);
branchingObject = expectBranchingObjectNode(result);
// 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 === finalLearningObject.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 === extraExerciseLearningObject.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(
[example.learningPath.hruid],
[testLearningPath.hruid],
Language.Abkhazian, // Wrong language
'the source'
);
@ -233,27 +118,24 @@ describe('DatabaseLearningPathProvider', () => {
describe('searchLearningPaths', () => {
it('returns the correct learning path when queried with a substring of its title', async () => {
const result = await databaseLearningPathProvider.searchLearningPaths(
example.learningPath.title.substring(2, 6),
example.learningPath.language
);
const result = await databaseLearningPathProvider.searchLearningPaths(testLearningPath.title.substring(2, 6), testLearningPath.language);
expect(result.length).toBe(1);
expect(result[0].title).toBe(example.learningPath.title);
expect(result[0].description).toBe(example.learningPath.description);
expect(result[0].title).toBe(testLearningPath.title);
expect(result[0].description).toBe(testLearningPath.description);
});
it('returns the correct learning path when queried with a substring of the description', async () => {
const result = await databaseLearningPathProvider.searchLearningPaths(
example.learningPath.description.substring(5, 12),
example.learningPath.language
testLearningPath.description.substring(5, 12),
testLearningPath.language
);
expect(result.length).toBe(1);
expect(result[0].title).toBe(example.learningPath.title);
expect(result[0].description).toBe(example.learningPath.description);
expect(result[0].title).toBe(testLearningPath.title);
expect(result[0].description).toBe(testLearningPath.description);
});
it('returns an empty result when queried with a text which is not a substring of the title or the description of a learning path', async () => {
const result = await databaseLearningPathProvider.searchLearningPaths(
'substring which does not occur in the title or the description of a learning object',
example.learningPath.language
testLearningPath.language
);
expect(result.length).toBe(0);
});

View file

@ -1,22 +1,9 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { setupTestApp } from '../../setup-tests';
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import { getLearningObjectRepository, getLearningPathRepository } 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';
import learningPathService from '../../../src/services/learning-paths/learning-path-service';
import { Language } from '@dwengo-1/common/util/language';
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository();
const learningPathRepo = getLearningPathRepository();
const learningObject = learningObjectExample.createLearningObject();
const learningPath = learningPathExample.createLearningPath();
await learningObjectRepo.save(learningObject);
await learningPathRepo.save(learningPath);
return { learningObject, learningPath };
}
import { testPartiallyDatabaseAndPartiallyDwengoApiLearningPath } from '../../test_assets/content/learning-paths.testdata';
import { LearningPath as LearningPathDTO } from '@dwengo-1/common/interfaces/learning-content';
const TEST_DWENGO_LEARNING_PATH_HRUID = 'pn_werking';
const TEST_DWENGO_LEARNING_PATH_TITLE = 'Werken met notebooks';
@ -24,42 +11,49 @@ const TEST_DWENGO_EXCLUSIVE_LEARNING_PATH_SEARCH_QUERY = 'Microscopie';
const TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES = 'su$m8f9usf89ud<p9<U8SDP8UP9';
describe('LearningPathService', () => {
let example: { learningObject: LearningObject; learningPath: LearningPath };
let testLearningPath: LearningPathDTO;
beforeAll(async () => {
await setupTestApp();
example = await initExampleData();
testLearningPath = testPartiallyDatabaseAndPartiallyDwengoApiLearningPath;
});
describe('fetchLearningPaths', () => {
it('should return learning paths both from the database and from the Dwengo API', async () => {
const result = await learningPathService.fetchLearningPaths(
[example.learningPath.hruid, TEST_DWENGO_LEARNING_PATH_HRUID],
example.learningPath.language,
[testLearningPath.hruid, TEST_DWENGO_LEARNING_PATH_HRUID],
testLearningPath.language as Language,
'the source'
);
expect(result.success).toBeTruthy();
expect(result.data?.filter((it) => it.hruid === TEST_DWENGO_LEARNING_PATH_HRUID).length).not.toBe(0);
expect(result.data?.filter((it) => it.hruid === example.learningPath.hruid).length).not.toBe(0);
expect(result.data?.filter((it) => it.hruid === testLearningPath.hruid).length).not.toBe(0);
expect(result.data?.find((it) => it.hruid === TEST_DWENGO_LEARNING_PATH_HRUID)?.title).toEqual(TEST_DWENGO_LEARNING_PATH_TITLE);
expect(result.data?.find((it) => it.hruid === example.learningPath.hruid)?.title).toEqual(example.learningPath.title);
expect(result.data?.find((it) => it.hruid === testLearningPath.hruid)?.title).toEqual(testLearningPath.title);
});
it('should include both the learning objects from the Dwengo API and learning objects from the database in its response', async () => {
const result = await learningPathService.fetchLearningPaths([example.learningPath.hruid], example.learningPath.language, 'the source');
const result = await learningPathService.fetchLearningPaths(
[testLearningPath.hruid],
testLearningPath.language as Language,
'the source'
);
expect(result.success).toBeTruthy();
expect(result.data?.length).toBe(1);
// Should include all the nodes, even those pointing to foreign learning objects.
expect([...result.data![0].nodes.map((it) => it.learningobject_hruid)].sort((a, b) => a.localeCompare(b))).toEqual(
example.learningPath.nodes.map((it) => it.learningObjectHruid).sort((a, b) => a.localeCompare(b))
testLearningPath.nodes.map((it) => it.learningobject_hruid).sort((a, b) => a.localeCompare(b))
);
});
});
describe('searchLearningPath', () => {
it('should include both the learning paths from the Dwengo API and those from the database in its response', async () => {
// This matches the learning object in the database, but definitely also some learning objects in the Dwengo API.
const result = await learningPathService.searchLearningPaths(example.learningPath.title.substring(2, 3), example.learningPath.language);
const result = await learningPathService.searchLearningPaths(
testLearningPath.title.substring(2, 3),
testLearningPath.language as Language
);
// Should find the one from the database
expect(result.filter((it) => it.hruid === example.learningPath.hruid && it.title === example.learningPath.title).length).toBe(1);
expect(result.filter((it) => it.hruid === testLearningPath.hruid && it.title === testLearningPath.title).length).toBe(1);
// But should not only find that one.
expect(result.length).not.toBeLessThan(2);
@ -71,7 +65,7 @@ describe('LearningPathService', () => {
expect(result.length).not.toBe(0);
// But not the example learning path.
expect(result.filter((it) => it.hruid === example.learningPath.hruid && it.title === example.learningPath.title).length).toBe(0);
expect(result.filter((it) => it.hruid === testLearningPath.hruid && it.title === testLearningPath.title).length).toBe(0);
});
it('should return an empty list if neither the Dwengo API nor the database contains matches', async () => {
const result = await learningPathService.searchLearningPaths(TEST_SEARCH_QUERY_EXPECTING_NO_MATCHES, Language.Dutch);

View file

@ -14,6 +14,7 @@ import { makeTestQuestions } from './test_assets/questions/questions.testdata.js
import { makeTestAnswers } from './test_assets/questions/answers.testdata.js';
import { makeTestSubmissions } from './test_assets/assignments/submission.testdata.js';
import { Collection } from '@mikro-orm/core';
import { Group } from '../src/entities/assignments/group.entity';
export async function setupTestApp(): Promise<void> {
dotenv.config({ path: '.env.test' });
@ -29,8 +30,8 @@ export async function setupTestApp(): Promise<void> {
const assignments = makeTestAssignemnts(em, classes);
const groups = makeTestGroups(em, students, assignments);
assignments[0].groups = new Collection(groups.slice(0, 3));
assignments[1].groups = new Collection(groups.slice(3, 4));
assignments[0].groups = new Collection<Group>(groups.slice(0, 3));
assignments[1].groups = new Collection<Group>(groups.slice(3, 4));
const teacherInvitations = makeTestTeacherInvitations(em, teachers, classes);
const classJoinRequests = makeTestClassJoinRequests(em, students, classes);

View file

@ -1,10 +0,0 @@
import { LearningObjectExample } from './learning-object-example';
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
export function createExampleLearningObjectWithAttachments(example: LearningObjectExample): LearningObject {
const learningObject = example.createLearningObject();
for (const creationFn of Object.values(example.createAttachment)) {
learningObject.attachments.push(creationFn(learningObject));
}
return learningObject;
}

View file

@ -1,32 +0,0 @@
import { LearningObjectExample } from '../learning-object-example';
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
import { Language } from '@dwengo-1/common/util/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';
/**
* Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use
* on a path), but where the precise contents of the learning object are not important.
*/
export function dummyLearningObject(hruid: string, language: Language, title: string): LearningObjectExample {
return {
createLearningObject: (): LearningObject => {
const learningObject = new LearningObject();
learningObject.hruid = getEnvVar(envVars.UserContentPrefix) + hruid;
learningObject.language = language;
learningObject.version = 1;
learningObject.title = title;
learningObject.description = 'Just a dummy learning object for testing purposes';
learningObject.contentType = DwengoContentType.TEXT_PLAIN;
learningObject.content = Buffer.from('Dummy content');
learningObject.returnValue = {
callbackUrl: `/learningObject/${hruid}/submissions`,
callbackSchema: '[]',
};
return learningObject;
},
createAttachment: {},
getHTMLRendering: () => loadTestAsset('learning-objects/dummy/rendering.txt').toString(),
};
}

View file

@ -1,8 +0,0 @@
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import { Attachment } from '../../../src/entities/content/attachment.entity';
interface LearningObjectExample {
createLearningObject: () => LearningObject;
createAttachment: Record<string, (owner: LearningObject) => Attachment>;
getHTMLRendering: () => string;
}

View file

@ -1,74 +0,0 @@
import { LearningObjectExample } from '../learning-object-example';
import { Language } from '@dwengo-1/common/util/language';
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
import { loadTestAsset } from '../../../test-utils/load-test-asset';
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
import { Attachment } from '../../../../src/entities/content/attachment.entity';
import { envVars, getEnvVar } from '../../../../src/util/envVars';
import { EducationalGoal } from '../../../../src/entities/content/educational-goal.entity';
import { ReturnValue } from '../../../../src/entities/content/return-value.entity';
const ASSETS_PREFIX = 'learning-objects/pn-werkingnotebooks/';
const example: LearningObjectExample = {
createLearningObject: () => {
const learningObject = new LearningObject();
learningObject.hruid = `${getEnvVar(envVars.UserContentPrefix)}pn_werkingnotebooks`;
learningObject.version = 3;
learningObject.language = Language.Dutch;
learningObject.title = 'Werken met notebooks';
learningObject.description = 'Leren werken met notebooks';
learningObject.keywords = ['Python', 'KIKS', 'Wiskunde', 'STEM', 'AI'];
const educationalGoal1 = new EducationalGoal();
educationalGoal1.source = 'Source';
educationalGoal1.id = 'id';
const educationalGoal2 = new EducationalGoal();
educationalGoal2.source = 'Source2';
educationalGoal2.id = 'id2';
learningObject.educationalGoals = [educationalGoal1, educationalGoal2];
learningObject.admins = [];
learningObject.contentType = DwengoContentType.TEXT_MARKDOWN;
learningObject.teacherExclusive = false;
learningObject.skosConcepts = [
'http://ilearn.ilabt.imec.be/vocab/curr1/s-vaktaal',
'http://ilearn.ilabt.imec.be/vocab/curr1/s-digitale-media-en-toepassingen',
'http://ilearn.ilabt.imec.be/vocab/curr1/s-computers-en-systemen',
];
learningObject.copyright = 'dwengo';
learningObject.license = 'dwengo';
learningObject.estimatedTime = 10;
const returnValue = new ReturnValue();
returnValue.callbackUrl = 'callback_url_example';
returnValue.callbackSchema = '{"att": "test", "att2": "test2"}';
learningObject.returnValue = returnValue;
learningObject.available = true;
learningObject.content = loadTestAsset(`${ASSETS_PREFIX}/content.md`);
return learningObject;
},
createAttachment: {
dwengoLogo: (learningObject) => {
const att = new Attachment();
att.learningObject = learningObject;
att.name = 'dwengo.png';
att.mimeType = 'image/png';
att.content = loadTestAsset(`${ASSETS_PREFIX}/dwengo.png`);
return att;
},
knop: (learningObject) => {
const att = new Attachment();
att.learningObject = learningObject;
att.name = 'Knop.png';
att.mimeType = 'image/png';
att.content = loadTestAsset(`${ASSETS_PREFIX}/Knop.png`);
return att;
},
},
getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.txt`).toString(),
};
export default example;

View file

@ -1,2 +0,0 @@
::MC basic::
How are you? {}

View file

@ -1,7 +0,0 @@
<div class="learning-object-gift">
<div id="gift-q1" class="gift-question">
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
<p id="gift-q1-stem" class="gift-stem">How are you?</p>
<textarea id="gift-q1-answer" class="gift-essay-answer"></textarea>
</div>
</div>

View file

@ -1,28 +0,0 @@
import { LearningObjectExample } from '../learning-object-example';
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
import { loadTestAsset } from '../../../test-utils/load-test-asset';
import { envVars, getEnvVar } from '../../../../src/util/envVars';
import { Language } from '@dwengo-1/common/util/language';
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
const example: LearningObjectExample = {
createLearningObject: () => {
const learningObject = new LearningObject();
learningObject.hruid = `${getEnvVar(envVars.UserContentPrefix)}test_essay`;
learningObject.language = Language.English;
learningObject.version = 1;
learningObject.title = 'Essay question for testing';
learningObject.description = 'This essay question was only created for testing purposes.';
learningObject.contentType = DwengoContentType.GIFT;
learningObject.returnValue = {
callbackUrl: `/learningObject/${learningObject.hruid}/submissions`,
callbackSchema: '["antwoord vraag 1"]',
};
learningObject.content = loadTestAsset('learning-objects/test-essay/content.txt');
return learningObject;
},
createAttachment: {},
getHTMLRendering: () => loadTestAsset('learning-objects/test-essay/rendering.txt').toString(),
};
export default example;

View file

@ -1,28 +0,0 @@
import { LearningObjectExample } from '../learning-object-example';
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
import { loadTestAsset } from '../../../test-utils/load-test-asset';
import { envVars, getEnvVar } from '../../../../src/util/envVars';
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
import { Language } from '@dwengo-1/common/util/language';
const example: LearningObjectExample = {
createLearningObject: () => {
const learningObject = new LearningObject();
learningObject.hruid = `${getEnvVar(envVars.UserContentPrefix)}test_multiple_choice`;
learningObject.language = Language.English;
learningObject.version = 1;
learningObject.title = 'Multiple choice question for testing';
learningObject.description = 'This multiple choice question was only created for testing purposes.';
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');
return learningObject;
},
createAttachment: {},
getHTMLRendering: () => loadTestAsset('learning-objects/test-multiple-choice/rendering.txt').toString(),
};
export default example;

View file

@ -1,3 +0,0 @@
interface LearningPathExample {
createLearningPath: () => LearningPath;
}

View file

@ -1,36 +0,0 @@
import { Language } from '@dwengo-1/common/util/language';
import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity';
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
export function createLearningPathTransition(
node: LearningPathNode,
transitionNumber: number,
condition: string | null,
to: LearningPathNode
): LearningPathTransition {
const trans = new LearningPathTransition();
trans.node = node;
trans.transitionNumber = transitionNumber;
trans.condition = condition || 'true';
trans.next = to;
return trans;
}
export function createLearningPathNode(
learningPath: LearningPath,
nodeNumber: number,
learningObjectHruid: string,
version: number,
language: Language,
startNode: boolean
): LearningPathNode {
const node = new LearningPathNode();
node.learningPath = learningPath;
node.nodeNumber = nodeNumber;
node.learningObjectHruid = learningObjectHruid;
node.version = version;
node.language = language;
node.startNode = startNode;
return node;
}

View file

@ -1,30 +0,0 @@
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import { Language } from '@dwengo-1/common/util/language';
import { envVars, getEnvVar } from '../../../src/util/envVars';
import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils';
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
function createNodes(learningPath: LearningPath): LearningPathNode[] {
const nodes = [
createLearningPathNode(learningPath, 0, 'u_pn_werkingnotebooks', 3, Language.Dutch, true),
createLearningPathNode(learningPath, 1, 'pn_werkingnotebooks2', 3, Language.Dutch, false),
createLearningPathNode(learningPath, 2, 'pn_werkingnotebooks3', 3, Language.Dutch, false),
];
nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, 'true', nodes[1]));
nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, 'true', nodes[2]));
return nodes;
}
const example: LearningPathExample = {
createLearningPath: () => {
const path = new LearningPath();
path.language = Language.Dutch;
path.hruid = `${getEnvVar(envVars.UserContentPrefix)}pn_werking`;
path.title = 'Werken met notebooks';
path.description = 'Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?';
path.nodes = createNodes(path);
return path;
},
};
export default example;

View file

@ -1,80 +0,0 @@
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import { Language } from '@dwengo-1/common/util/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';
export interface ConditionTestLearningPathAndLearningObjects {
branchingObject: LearningObject;
extraExerciseObject: LearningObject;
finalObject: LearningObject;
learningPath: LearningPath;
}
export function createConditionTestLearningPathAndLearningObjects(): ConditionTestLearningPathAndLearningObjects {
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,
};
}

View file

@ -1,8 +1,8 @@
import { AssertionError } from 'node:assert';
import { LearningObject } from '../../src/entities/content/learning-object.entity';
import { LearningPath as LearningPathEntity } from '../../src/entities/content/learning-path.entity';
import { expect } from 'vitest';
import { FilteredLearningObject, LearningPath } from '@dwengo-1/common/interfaces/learning-content';
import { RequiredEntityData } from '@mikro-orm/core';
// Ignored properties because they belang for example to the class, not to the entity itself.
const IGNORE_PROPERTIES = ['parent'];
@ -11,53 +11,44 @@ const IGNORE_PROPERTIES = ['parent'];
* Checks if the actual entity from the database conforms to the entity that was added previously.
* @param actual The actual entity retrieved from the database
* @param expected The (previously added) entity we would expect to retrieve
* @param propertyPrefix Prefix to append to property in error messages.
*/
export function expectToBeCorrectEntity<T extends object>(actual: { entity: T; name?: string }, expected: { entity: T; name?: string }): void {
if (!actual.name) {
actual.name = 'actual';
}
if (!expected.name) {
expected.name = 'expected';
}
for (const property in expected.entity) {
if (
property in IGNORE_PROPERTIES &&
expected.entity[property] !== undefined && // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants.
typeof expected.entity[property] !== 'function' // Functions obviously are not persisted via the database
) {
if (!Object.prototype.hasOwnProperty.call(actual.entity, property)) {
throw new AssertionError({
message: `${expected.name} has defined property ${property}, but ${actual.name} is missing it.`,
});
}
if (typeof expected.entity[property] === 'boolean') {
// Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database.
if (Boolean(expected.entity[property]) !== Boolean(actual.entity[property])) {
export function expectToBeCorrectEntity<T extends object>(actual: T, expected: T, propertyPrefix = ''): void {
for (const property in expected) {
if (Object.prototype.hasOwnProperty.call(expected, property)) {
const prefixedProperty = propertyPrefix + property;
if (
property in IGNORE_PROPERTIES &&
expected[property] !== undefined && // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants.
typeof expected[property] !== 'function' // Functions obviously are not persisted via the database
) {
if (!Object.prototype.hasOwnProperty.call(actual, property)) {
throw new AssertionError({
message: `${property} was ${expected.entity[property]} in ${expected.name},
but ${actual.entity[property]} (${Boolean(expected.entity[property])}) in ${actual.name}`,
message: `Expected property ${prefixedProperty}, but it is missing.`,
});
}
} else if (typeof expected.entity[property] !== typeof actual.entity[property]) {
throw new AssertionError({
message: `${property} has type ${typeof expected.entity[property]} in ${expected.name}, but type ${typeof actual.entity[property]} in ${actual.name}.`,
});
} else if (typeof expected.entity[property] === 'object') {
expectToBeCorrectEntity(
{
name: actual.name + '.' + property,
entity: actual.entity[property] as object,
},
{
name: expected.name + '.' + property,
entity: expected.entity[property] as object,
if (typeof expected[property] === 'boolean') {
// Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database.
if (Boolean(expected[property]) !== Boolean(actual[property])) {
throw new AssertionError({
message: `Expected ${prefixedProperty} to be ${expected[property]},
but was ${actual[property]} (${Boolean(expected[property])}).`,
});
}
);
} else {
if (expected.entity[property] !== actual.entity[property]) {
} else if (typeof expected[property] !== typeof actual[property]) {
throw new AssertionError({
message: `${property} was ${expected.entity[property]} in ${expected.name}, but ${actual.entity[property]} in ${actual.name}`,
message:
`${prefixedProperty} was expected to have type ${typeof expected[property]},` +
`but had type ${typeof actual[property]}.`,
});
} else if (typeof expected[property] === 'object') {
expectToBeCorrectEntity(actual[property] as object, expected[property] as object, property);
} else {
if (expected[property] !== actual[property]) {
throw new AssertionError({
message: `${prefixedProperty} was expected to be ${expected[property]}, ` + `but was ${actual[property]}.`,
});
}
}
}
}
@ -67,9 +58,9 @@ export function expectToBeCorrectEntity<T extends object>(actual: { entity: T; n
/**
* Checks that filtered is the correct representation of original as FilteredLearningObject.
* @param filtered the representation as FilteredLearningObject
* @param original the original entity added to the database
* @param original the data of the entity in the database that was filtered.
*/
export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearningObject, original: LearningObject): void {
export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearningObject, original: RequiredEntityData<LearningObject>): void {
expect(filtered.uuid).toEqual(original.uuid);
expect(filtered.version).toEqual(original.version);
expect(filtered.language).toEqual(original.language);
@ -97,54 +88,55 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni
* is a correct representation of the given learning path entity.
*
* @param learningPath The learning path returned by the retriever, service or endpoint
* @param expectedEntity The expected entity
* @param learningObjectsOnPath The learning objects on LearningPath. Necessary since some information in
* the learning path returned from the API endpoint
* @param expected The learning path that should have been returned.
*/
export function expectToBeCorrectLearningPath(
learningPath: LearningPath,
expectedEntity: LearningPathEntity,
learningObjectsOnPath: FilteredLearningObject[]
): void {
expect(learningPath.hruid).toEqual(expectedEntity.hruid);
expect(learningPath.language).toEqual(expectedEntity.language);
expect(learningPath.description).toEqual(expectedEntity.description);
expect(learningPath.title).toEqual(expectedEntity.title);
export function expectToBeCorrectLearningPath(learningPath: LearningPath, expected: LearningPath): void {
expect(learningPath.hruid).toEqual(expected.hruid);
expect(learningPath.language).toEqual(expected.language);
expect(learningPath.description).toEqual(expected.description);
expect(learningPath.title).toEqual(expected.title);
const keywords = new Set(learningObjectsOnPath.flatMap((it) => it.keywords || []));
expect(new Set(learningPath.keywords.split(' '))).toEqual(keywords);
expect(new Set(learningPath.keywords.split(' '))).toEqual(new Set(learningPath.keywords.split(' ')));
const targetAges = new Set(learningObjectsOnPath.flatMap((it) => it.targetAges || []));
expect(new Set(learningPath.target_ages)).toEqual(targetAges);
expect(learningPath.min_age).toEqual(Math.min(...targetAges));
expect(learningPath.max_age).toEqual(Math.max(...targetAges));
expect(new Set(learningPath.target_ages)).toEqual(new Set(expected.target_ages));
expect(learningPath.min_age).toEqual(Math.min(...expected.target_ages));
expect(learningPath.max_age).toEqual(Math.max(...expected.target_ages));
expect(learningPath.num_nodes).toEqual(expectedEntity.nodes.length);
expect(learningPath.image || null).toEqual(expectedEntity.image);
expect(learningPath.num_nodes).toEqual(expected.nodes.length);
expect(learningPath.image ?? null).toEqual(expected.image ?? null);
const expectedLearningPathNodes = new Map(
expectedEntity.nodes.map((node) => [
{ learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version },
{ startNode: node.startNode, transitions: node.transitions },
])
);
for (const node of learningPath.nodes) {
const nodeKey = {
learningObjectHruid: node.learningobject_hruid,
language: node.language,
version: node.version,
};
expect(expectedLearningPathNodes.keys()).toContainEqual(nodeKey);
const expectedNode = [...expectedLearningPathNodes.entries()].find(
([key, _]) => key.learningObjectHruid === nodeKey.learningObjectHruid && key.language === node.language && key.version === node.version
)![1];
expect(node.start_node).toEqual(expectedNode.startNode);
expect(new Set(node.transitions.map((it) => it.next.hruid))).toEqual(
new Set(expectedNode.transitions.map((it) => it.next.learningObjectHruid))
for (const node of expected.nodes) {
const correspondingNode = learningPath.nodes.find(
(it) => node.learningobject_hruid === it.learningobject_hruid && node.language === it.language && node.version === it.version
);
expect(new Set(node.transitions.map((it) => it.next.language))).toEqual(new Set(expectedNode.transitions.map((it) => it.next.language)));
expect(new Set(node.transitions.map((it) => it.next.version))).toEqual(new Set(expectedNode.transitions.map((it) => it.next.version)));
expect(correspondingNode).toBeTruthy();
expect(Boolean(correspondingNode!.start_node)).toEqual(Boolean(node.start_node));
for (const transition of node.transitions) {
const correspondingTransition = correspondingNode!.transitions.find(
(it) =>
it.next.hruid === transition.next.hruid &&
it.next.language === transition.next.language &&
it.next.version === transition.next.version
);
expect(correspondingTransition).toBeTruthy();
}
}
}
/**
* Expect that the given result is a singleton list with exactly the given element.
*/
export function expectToHaveFoundPrecisely<T extends object>(expected: T, result: T[]): void {
expect(result).toHaveProperty('length');
expect(result.length).toBe(1);
expectToBeCorrectEntity(result[0], expected);
}
/**
* Expect that the given result is an empty list.
*/
export function expectToHaveFoundNothing<T>(result: T[]): void {
expect(result).toHaveProperty('length');
expect(result.length).toBe(0);
}

View file

@ -0,0 +1,10 @@
import { RequiredEntityData } from '@mikro-orm/core';
import { loadTestAsset } from './load-test-asset';
import { LearningObject } from '../../src/entities/content/learning-object.entity';
import { envVars, getEnvVar } from '../../src/util/envVars';
export function getHtmlRenderingForTestLearningObject(learningObject: RequiredEntityData<LearningObject>): string {
const userPrefix = getEnvVar(envVars.UserContentPrefix);
const cleanedHruid = learningObject.hruid.startsWith(userPrefix) ? learningObject.hruid.substring(userPrefix.length) : learningObject.hruid;
return loadTestAsset(`/content/learning-object-resources/${cleanedHruid}/rendering.txt`).toString();
}

View file

@ -1,10 +1,14 @@
import fs from 'fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const fileName = fileURLToPath(import.meta.url);
const dirName = path.dirname(fileName);
/**
* Load the asset at the given path.
* @param relPath Path of the asset relative to the test-assets folder.
*/
export function loadTestAsset(relPath: string): Buffer {
return fs.readFileSync(path.resolve(__dirname, `../test-assets/${relPath}`));
return fs.readFileSync(path.resolve(dirName, `../test_assets/${relPath}`));
}

View file

@ -2,9 +2,11 @@ import { EntityManager } from '@mikro-orm/core';
import { Assignment } from '../../../src/entities/assignments/assignment.entity';
import { Class } from '../../../src/entities/classes/class.entity';
import { Language } from '@dwengo-1/common/util/language';
import { testLearningPathWithConditions } from '../content/learning-paths.testdata';
import { getClassWithTestleerlingAndTestleerkracht } from '../classes/classes.testdata';
export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assignment[] {
const assignment01 = em.create(Assignment, {
assignment01 = em.create(Assignment, {
id: 21000,
within: classes[0],
title: 'dire straits',
@ -14,7 +16,7 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign
groups: [],
});
const assignment02 = em.create(Assignment, {
assignment02 = em.create(Assignment, {
id: 21001,
within: classes[1],
title: 'tool',
@ -24,7 +26,7 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign
groups: [],
});
const assignment03 = em.create(Assignment, {
assignment03 = em.create(Assignment, {
id: 21002,
within: classes[0],
title: 'delete',
@ -34,7 +36,7 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign
groups: [],
});
const assignment04 = em.create(Assignment, {
assignment04 = em.create(Assignment, {
id: 21003,
within: classes[0],
title: 'another assignment',
@ -44,5 +46,41 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign
groups: [],
});
return [assignment01, assignment02, assignment03, assignment04];
conditionalPathAssignment = em.create(Assignment, {
within: getClassWithTestleerlingAndTestleerkracht(),
id: 1,
title: 'Assignment: Conditional Learning Path',
description: 'You have to do the testing learning path with a condition.',
learningPathHruid: testLearningPathWithConditions.hruid,
learningPathLanguage: testLearningPathWithConditions.language as Language,
groups: [],
});
return [assignment01, assignment02, assignment03, assignment04, conditionalPathAssignment];
}
let assignment01: Assignment;
let assignment02: Assignment;
let assignment03: Assignment;
let assignment04: Assignment;
let conditionalPathAssignment: Assignment;
export function getAssignment01(): Assignment {
return assignment01;
}
export function getAssignment02(): Assignment {
return assignment02;
}
export function getAssignment03(): Assignment {
return assignment03;
}
export function getAssignment04(): Assignment {
return assignment04;
}
export function getConditionalPathAssignment(): Assignment {
return conditionalPathAssignment;
}

View file

@ -2,13 +2,15 @@ import { EntityManager } from '@mikro-orm/core';
import { Group } from '../../../src/entities/assignments/group.entity';
import { Assignment } from '../../../src/entities/assignments/assignment.entity';
import { Student } from '../../../src/entities/users/student.entity';
import { getConditionalPathAssignment } from './assignments.testdata';
import { getTestleerling1 } from '../users/students.testdata';
export function makeTestGroups(em: EntityManager, students: Student[], assignments: Assignment[]): Group[] {
/*
* Group #1 for Assignment #1 in class 'id01'
* => Assigned to do learning path 'id02'
*/
const group01 = em.create(Group, {
group01 = em.create(Group, {
assignment: assignments[0],
groupNumber: 21001,
members: students.slice(0, 2),
@ -18,7 +20,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen
* Group #2 for Assignment #1 in class 'id01'
* => Assigned to do learning path 'id02'
*/
const group02 = em.create(Group, {
group02 = em.create(Group, {
assignment: assignments[0],
groupNumber: 21002,
members: students.slice(2, 4),
@ -28,7 +30,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen
* Group #3 for Assignment #1 in class 'id01'
* => Assigned to do learning path 'id02'
*/
const group03 = em.create(Group, {
group03 = em.create(Group, {
assignment: assignments[0],
groupNumber: 21003,
members: students.slice(4, 6),
@ -38,7 +40,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen
* Group #4 for Assignment #2 in class 'id02'
* => Assigned to do learning path 'id01'
*/
const group04 = em.create(Group, {
group04 = em.create(Group, {
assignment: assignments[1],
groupNumber: 21004,
members: students.slice(3, 4),
@ -48,11 +50,51 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen
* Group #5 for Assignment #4 in class 'id01'
* => Assigned to do learning path 'id01'
*/
const group05 = em.create(Group, {
group05 = em.create(Group, {
assignment: assignments[3],
groupNumber: 21001,
members: students.slice(0, 2),
});
return [group01, group02, group03, group04, group05];
/**
* Group 1 for the assignment of the testing learning path with conditions.
*/
group1ConditionalLearningPath = em.create(Group, {
assignment: getConditionalPathAssignment(),
groupNumber: 1,
members: [getTestleerling1()],
});
return [group01, group02, group03, group04, group05, group1ConditionalLearningPath];
}
let group01: Group;
let group02: Group;
let group03: Group;
let group04: Group;
let group05: Group;
let group1ConditionalLearningPath: Group;
export function getTestGroup01(): Group {
return group01;
}
export function getTestGroup02(): Group {
return group02;
}
export function getTestGroup03(): Group {
return group03;
}
export function getTestGroup04(): Group {
return group04;
}
export function getTestGroup05(): Group {
return group05;
}
export function getGroup1ConditionalLearningPath(): Group {
return group1ConditionalLearningPath;
}

View file

@ -2,12 +2,14 @@ import { EntityManager } from '@mikro-orm/core';
import { Class } from '../../../src/entities/classes/class.entity';
import { Student } from '../../../src/entities/users/student.entity';
import { Teacher } from '../../../src/entities/users/teacher.entity';
import { getTestleerkracht1 } from '../users/teachers.testdata';
import { getTestleerling1 } from '../users/students.testdata';
export function makeTestClasses(em: EntityManager, students: Student[], teachers: Teacher[]): Class[] {
const studentsClass01 = students.slice(0, 8);
const teacherClass01: Teacher[] = teachers.slice(4, 5);
const class01 = em.create(Class, {
class01 = em.create(Class, {
classId: '8764b861-90a6-42e5-9732-c0d9eb2f55f9',
displayName: 'class01',
teachers: teacherClass01,
@ -17,7 +19,7 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const studentsClass02: Student[] = students.slice(0, 2).concat(students.slice(3, 4));
const teacherClass02: Teacher[] = teachers.slice(1, 2);
const class02 = em.create(Class, {
class02 = em.create(Class, {
classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
displayName: 'class02',
teachers: teacherClass02,
@ -27,7 +29,7 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const studentsClass03: Student[] = students.slice(1, 4);
const teacherClass03: Teacher[] = teachers.slice(2, 3);
const class03 = em.create(Class, {
class03 = em.create(Class, {
classId: '80dcc3e0-1811-4091-9361-42c0eee91cfa',
displayName: 'class03',
teachers: teacherClass03,
@ -37,12 +39,45 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const studentsClass04: Student[] = students.slice(0, 2);
const teacherClass04: Teacher[] = teachers.slice(2, 3);
const class04 = em.create(Class, {
class04 = em.create(Class, {
classId: '33d03536-83b8-4880-9982-9bbf2f908ddf',
displayName: 'class04',
teachers: teacherClass04,
students: studentsClass04,
});
return [class01, class02, class03, class04];
classWithTestleerlingAndTestleerkracht = em.create(Class, {
classId: 'a75298b5-18aa-471d-8eeb-5d77eb989393',
displayName: 'Testklasse',
teachers: [getTestleerkracht1()],
students: [getTestleerling1()],
});
return [class01, class02, class03, class04, classWithTestleerlingAndTestleerkracht];
}
let class01: Class;
let class02: Class;
let class03: Class;
let class04: Class;
let classWithTestleerlingAndTestleerkracht: Class;
export function getClass01(): Class {
return class01;
}
export function getClass02(): Class {
return class02;
}
export function getClass03(): Class {
return class03;
}
export function getClass04(): Class {
return class04;
}
export function getClassWithTestleerlingAndTestleerkracht(): Class {
return classWithTestleerlingAndTestleerkracht;
}

View file

@ -0,0 +1,2 @@
::Reflection::
Reflect on this learning path. What have you learned today? {}

View file

@ -0,0 +1,7 @@
<div class="learning-object-gift">
<div id="gift-q1" class="gift-question gift-question-type-Essay">
<h2 id="gift-q1-title" class="gift-title">Reflection</h2>
<p id="gift-q1-stem" class="gift-stem">Reflect on this learning path. What have you learned today?</p>
<textarea id="gift-q1-answer" class="gift-essay-answer"></textarea>
</div>
</div>

View file

@ -1,5 +1,5 @@
::MC basic::
Are you following along well with the class? {
::Self-evaluation::
Are you following along well? {
~No, it's very difficult to follow along.
=Yes, no problem!
}

View file

@ -1,14 +1,14 @@
<div class="learning-object-gift">
<div id="gift-q1" class="gift-question">
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
<p id="gift-q1-stem" class="gift-stem">Are you following along well with the class?</p>
<div id="gift-q1" class="gift-question gift-question-type-MC">
<h2 id="gift-q1-title" class="gift-title">Self-evaluation</h2>
<p id="gift-q1-stem" class="gift-stem">Are you following along well?</p>
<div class="gift-choice-div">
<input value="0" name="gift-q1-choices" id="gift-q1-choice-0" type="radio">
<label for="gift-q1-choice-0">[object Object]</label>
<label for="gift-q1-choice-0">No, it's very difficult to follow along.</label>
</div>
<div class="gift-choice-div">
<input value="1" name="gift-q1-choices" id="gift-q1-choice-1" type="radio">
<label for="gift-q1-choice-1">[object Object]</label>
<label for="gift-q1-choice-1">Yes, no problem!</label>
</div>
</div>
</div>

View file

@ -1,135 +1,261 @@
import { EntityManager } from '@mikro-orm/core';
import { EntityManager, RequiredEntityData } from '@mikro-orm/core';
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import { Language } from '@dwengo-1/common/util/language';
import { DwengoContentType } from '../../../src/services/learning-objects/processing/content-type';
import { ReturnValue } from '../../../src/entities/content/return-value.entity';
import { envVars, getEnvVar } from '../../../src/util/envVars';
import { loadTestAsset } from '../../test-utils/load-test-asset';
import { v4 } from 'uuid';
export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
const returnValue: ReturnValue = new ReturnValue();
returnValue.callbackSchema = '';
returnValue.callbackUrl = '';
const learningObject01 = em.create(LearningObject, {
hruid: 'id01',
language: Language.English,
version: 1,
admins: [],
title: 'Undertow',
description: 'debute',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 45,
returnValue: returnValue,
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from("there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me"),
});
const learningObject01 = em.create(LearningObject, testLearningObject01);
const learningObject02 = em.create(LearningObject, testLearningObject02);
const learningObject03 = em.create(LearningObject, testLearningObject03);
const learningObject04 = em.create(LearningObject, testLearningObject04);
const learningObject05 = em.create(LearningObject, testLearningObject05);
const learningObject02 = em.create(LearningObject, {
hruid: 'id02',
language: Language.English,
version: 1,
admins: [],
title: 'Aenema',
description: 'second album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 80,
returnValue: returnValue,
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
"I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions"
),
});
const learningObjectMultipleChoice = em.create(LearningObject, testLearningObjectMultipleChoice);
const learningObjectEssayQuestion = em.create(LearningObject, testLearningObjectEssayQuestion);
const learningObject03 = em.create(LearningObject, {
hruid: 'id03',
language: Language.English,
version: 1,
admins: [],
title: 'love over gold',
description: 'third album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: returnValue,
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
'he wrote me a prescription, he said you are depressed, \
but I am glad you came to see me to get this off your chest, \
come back and see me later next patient please \
send in another victim of industrial disease'
),
});
const learningObjectPnNotebooks = em.create(LearningObject, testLearningObjectPnNotebooks);
const learningObject04 = em.create(LearningObject, {
hruid: 'id04',
language: Language.English,
version: 1,
admins: [],
title: 'making movies',
description: 'fifth album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: returnValue,
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
'I put my hand upon the lever \
Said let it rock and let it roll \
I had the one-arm bandit fever \
There was an arrow through my heart and my soul'
),
});
const learningObject05 = em.create(LearningObject, {
hruid: 'id05',
language: Language.English,
version: 1,
admins: [],
title: 'on every street',
description: 'sixth album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: returnValue,
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from('calling Elvis, is anybody home, calling elvis, I am here all alone'),
});
return [learningObject01, learningObject02, learningObject03, learningObject04, learningObject05];
return [
learningObject01,
learningObject02,
learningObject03,
learningObject04,
learningObject05,
learningObjectMultipleChoice,
learningObjectEssayQuestion,
learningObjectPnNotebooks,
];
}
export function createReturnValue(): ReturnValue {
const returnValue: ReturnValue = new ReturnValue();
returnValue.callbackSchema = '[]';
returnValue.callbackUrl = '%SUBMISSION%';
return returnValue;
}
export const testLearningObject01: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}id01`,
language: Language.English,
version: 1,
admins: [],
title: 'Undertow',
description: 'debute',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
uuid: v4(),
targetAges: [16, 17, 18],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 45,
returnValue: createReturnValue(),
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from("there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me"),
};
export const testLearningObject02: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}id02`,
language: Language.English,
version: 1,
admins: [],
title: 'Aenema',
description: 'second album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 80,
returnValue: createReturnValue(),
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
"I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions"
),
};
export const testLearningObject03: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}id03`,
language: Language.English,
version: 1,
admins: [],
title: 'love over gold',
description: 'third album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: createReturnValue(),
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
'he wrote me a prescription, he said you are depressed, \
but I am glad you came to see me to get this off your chest, \
come back and see me later next patient please \
send in another victim of industrial disease'
),
};
export const testLearningObject04: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}id04`,
language: Language.English,
version: 1,
admins: [],
title: 'making movies',
description: 'fifth album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: createReturnValue(),
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from(
'I put my hand upon the lever \
Said let it rock and let it roll \
I had the one-arm bandit fever \
There was an arrow through my heart and my soul'
),
};
export const testLearningObject05: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}id05`,
language: Language.English,
version: 1,
admins: [],
title: 'on every street',
description: 'sixth album',
contentType: DwengoContentType.TEXT_MARKDOWN,
keywords: [],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: '',
license: '',
estimatedTime: 55,
returnValue: createReturnValue(),
available: true,
contentLocation: '',
attachments: [],
content: Buffer.from('calling Elvis, is anybody home, calling elvis, I am here all alone'),
};
export const testLearningObjectMultipleChoice: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_multiple_choice`,
language: Language.English,
version: 1,
title: 'Self-evaluation',
description: "Time to evaluate how well you understand what you've learned so far.",
keywords: ['test'],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: 'Groep 1 SEL-2 2025',
license: 'CC0',
difficulty: 1,
estimatedTime: 1,
attachments: [],
available: true,
targetAges: [10, 11, 12, 13, 14, 15, 16, 17, 18],
admins: [],
contentType: DwengoContentType.GIFT,
content: loadTestAsset('content/learning-object-resources/test_multiple_choice/content.txt'),
returnValue: {
callbackUrl: `%SUBMISSION%`,
callbackSchema: '["antwoord vraag 1"]',
},
};
export const testLearningObjectEssayQuestion: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_essay_question`,
language: Language.English,
version: 1,
title: 'Reflection',
description: 'Reflect on your learning progress.',
keywords: ['test'],
teacherExclusive: false,
skosConcepts: [],
educationalGoals: [],
copyright: 'Groep 1 SEL-2 2025',
license: 'CC0',
difficulty: 1,
estimatedTime: 1,
attachments: [],
available: true,
targetAges: [10, 11, 12, 13, 14, 15, 16, 17, 18],
admins: [],
contentType: DwengoContentType.GIFT,
content: loadTestAsset('content/learning-object-resources/test_essay_question/content.txt'),
returnValue: {
callbackUrl: `%SUBMISSION%`,
callbackSchema: '["antwoord vraag 1"]',
},
};
export const testLearningObjectPnNotebooks: RequiredEntityData<LearningObject> = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}pn_werkingnotebooks`,
version: 3,
language: Language.Dutch,
title: 'Werken met notebooks',
description: 'Leren werken met notebooks',
keywords: ['Python', 'KIKS', 'Wiskunde', 'STEM', 'AI'],
targetAges: [14, 15, 16, 17, 18],
admins: [],
copyright: 'dwengo',
educationalGoals: [],
license: 'dwengo',
contentType: DwengoContentType.TEXT_MARKDOWN,
difficulty: 3,
estimatedTime: 10,
uuid: '2adf9929-b424-4650-bf60-186f730d38ab',
teacherExclusive: false,
skosConcepts: [
'http://ilearn.ilabt.imec.be/vocab/curr1/s-vaktaal',
'http://ilearn.ilabt.imec.be/vocab/curr1/s-digitale-media-en-toepassingen',
'http://ilearn.ilabt.imec.be/vocab/curr1/s-computers-en-systemen',
],
attachments: [
{
name: 'dwengo.png',
mimeType: 'image/png',
content: loadTestAsset('/content/learning-object-resources/pn_werkingnotebooks/dwengo.png'),
},
{
name: 'Knop.png',
mimeType: 'image/png',
content: loadTestAsset('/content/learning-object-resources/pn_werkingnotebooks/Knop.png'),
},
],
available: false,
content: loadTestAsset('/content/learning-object-resources/pn_werkingnotebooks/content.md'),
returnValue: {
callbackUrl: '%SUBMISSION%',
callbackSchema: '[]',
},
};

View file

@ -1,100 +1,236 @@
import { EntityManager } from '@mikro-orm/core';
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import { Language } from '@dwengo-1/common/util/language';
import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity';
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
import { mapToLearningPath } from '../../../src/services/learning-paths/learning-path-service';
import { envVars, getEnvVar } from '../../../src/util/envVars';
import { LearningPath as LearningPathDTO } from '@dwengo-1/common/interfaces/learning-content';
import {
testLearningObject01,
testLearningObject02,
testLearningObject03,
testLearningObject04,
testLearningObject05,
testLearningObjectEssayQuestion,
testLearningObjectMultipleChoice,
testLearningObjectPnNotebooks,
} from './learning-objects.testdata';
export function makeTestLearningPaths(em: EntityManager): LearningPath[] {
const learningPathNode01: LearningPathNode = new LearningPathNode();
const learningPathNode02: LearningPathNode = new LearningPathNode();
const learningPathNode03: LearningPathNode = new LearningPathNode();
const learningPathNode04: LearningPathNode = new LearningPathNode();
const learningPathNode05: LearningPathNode = new LearningPathNode();
export function makeTestLearningPaths(_em: EntityManager): LearningPath[] {
const learningPath01 = mapToLearningPath(testLearningPath01, []);
const learningPath02 = mapToLearningPath(testLearningPath02, []);
const transitions01: LearningPathTransition = new LearningPathTransition();
const transitions02: LearningPathTransition = new LearningPathTransition();
const transitions03: LearningPathTransition = new LearningPathTransition();
const transitions04: LearningPathTransition = new LearningPathTransition();
const transitions05: LearningPathTransition = new LearningPathTransition();
const partiallyDatabasePartiallyDwengoApiLearningPath = mapToLearningPath(testPartiallyDatabaseAndPartiallyDwengoApiLearningPath, []);
const learningPathWithConditions = mapToLearningPath(testLearningPathWithConditions, []);
transitions01.condition = 'true';
transitions01.next = learningPathNode02;
transitions02.condition = 'true';
transitions02.next = learningPathNode02;
transitions03.condition = 'true';
transitions03.next = learningPathNode04;
transitions04.condition = 'true';
transitions04.next = learningPathNode05;
transitions05.condition = 'true';
transitions05.next = learningPathNode05;
learningPathNode01.instruction = '';
learningPathNode01.language = Language.English;
learningPathNode01.learningObjectHruid = 'id01';
learningPathNode01.startNode = true;
learningPathNode01.transitions = [transitions01];
learningPathNode01.version = 1;
learningPathNode02.instruction = '';
learningPathNode02.language = Language.English;
learningPathNode02.learningObjectHruid = 'id02';
learningPathNode02.startNode = false;
learningPathNode02.transitions = [transitions02];
learningPathNode02.version = 1;
learningPathNode03.instruction = '';
learningPathNode03.language = Language.English;
learningPathNode03.learningObjectHruid = 'id03';
learningPathNode03.startNode = true;
learningPathNode03.transitions = [transitions03];
learningPathNode03.version = 1;
learningPathNode04.instruction = '';
learningPathNode04.language = Language.English;
learningPathNode04.learningObjectHruid = 'id04';
learningPathNode04.startNode = false;
learningPathNode04.transitions = [transitions04];
learningPathNode04.version = 1;
learningPathNode05.instruction = '';
learningPathNode05.language = Language.English;
learningPathNode05.learningObjectHruid = 'id05';
learningPathNode05.startNode = false;
learningPathNode05.transitions = [transitions05];
learningPathNode05.version = 1;
const nodes01: LearningPathNode[] = [
// LearningPathNode01,
// LearningPathNode02,
];
const learningPath01 = em.create(LearningPath, {
hruid: 'id01',
language: Language.English,
admins: [],
title: 'repertoire Tool',
description: 'all about Tool',
image: null,
nodes: nodes01,
});
const nodes02: LearningPathNode[] = [
// LearningPathNode03,
// LearningPathNode04,
// LearningPathNode05,
];
const learningPath02 = em.create(LearningPath, {
hruid: 'id02',
language: Language.English,
admins: [],
title: 'repertoire Dire Straits',
description: 'all about Dire Straits',
image: null,
nodes: nodes02,
});
return [learningPath01, learningPath02];
return [learningPath01, learningPath02, partiallyDatabasePartiallyDwengoApiLearningPath, learningPathWithConditions];
}
const nowString = new Date().toString();
export const testLearningPath01: LearningPathDTO = {
keywords: 'test',
target_ages: [16, 17, 18],
hruid: `${getEnvVar(envVars.UserContentPrefix)}id01`,
language: Language.English,
title: 'repertoire Tool',
description: 'all about Tool',
nodes: [
{
learningobject_hruid: testLearningObject01.hruid,
language: testLearningObject01.language,
version: testLearningObject01.version,
start_node: true,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
next: {
hruid: testLearningObject02.hruid,
language: testLearningObject02.language,
version: testLearningObject02.version,
},
},
],
},
{
learningobject_hruid: testLearningObject02.hruid,
language: testLearningObject02.language,
version: testLearningObject02.version,
created_at: nowString,
updatedAt: nowString,
transitions: [],
},
],
};
export const testLearningPath02: LearningPathDTO = {
keywords: 'test',
target_ages: [16, 17, 18],
hruid: `${getEnvVar(envVars.UserContentPrefix)}id02`,
language: Language.English,
title: 'repertoire Dire Straits',
description: 'all about Dire Straits',
nodes: [
{
learningobject_hruid: testLearningObject03.hruid,
language: testLearningObject03.language,
version: testLearningObject03.version,
start_node: true,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
next: {
hruid: testLearningObject04.hruid,
language: testLearningObject04.language,
version: testLearningObject04.version,
},
},
],
},
{
learningobject_hruid: testLearningObject04.hruid,
language: testLearningObject04.language,
version: testLearningObject04.version,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
next: {
hruid: testLearningObject05.hruid,
language: testLearningObject05.language,
version: testLearningObject05.version,
},
},
],
},
{
learningobject_hruid: testLearningObject05.hruid,
language: testLearningObject05.language,
version: testLearningObject05.version,
created_at: nowString,
updatedAt: nowString,
transitions: [],
},
],
};
export const testPartiallyDatabaseAndPartiallyDwengoApiLearningPath: LearningPathDTO = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}pn_werking`,
title: 'Werken met notebooks',
language: Language.Dutch,
description: 'Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?',
keywords: 'Python KIKS Wiskunde STEM AI',
target_ages: [14, 15, 16, 17, 18],
nodes: [
{
learningobject_hruid: testLearningObjectPnNotebooks.hruid,
language: testLearningObjectPnNotebooks.language,
version: testLearningObjectPnNotebooks.version,
start_node: true,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
default: true,
next: {
hruid: 'pn_werkingnotebooks2',
language: Language.Dutch,
version: 3,
},
},
],
},
{
learningobject_hruid: 'pn_werkingnotebooks2',
language: Language.Dutch,
version: 3,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
default: true,
next: {
hruid: 'pn_werkingnotebooks3',
language: Language.Dutch,
version: 3,
},
},
],
},
{
learningobject_hruid: 'pn_werkingnotebooks3',
language: Language.Dutch,
version: 3,
created_at: nowString,
updatedAt: nowString,
transitions: [],
},
],
};
export const testLearningPathWithConditions: LearningPathDTO = {
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_conditions`,
language: Language.English,
title: 'Example learning path with conditional transitions',
description: 'This learning path was made for the purpose of testing conditional transitions',
keywords: 'test',
target_ages: [10, 11, 12, 13, 14, 15, 16, 17, 18],
nodes: [
{
learningobject_hruid: testLearningObjectMultipleChoice.hruid,
language: testLearningObjectMultipleChoice.language,
version: testLearningObjectMultipleChoice.version,
start_node: true,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
// If the answer to the first question was the first one (It's difficult to follow along):
condition: '$[?(@[0] == 0)]',
next: {
//... we let the student do an extra exercise.
hruid: testLearningObject01.hruid,
language: testLearningObject01.language,
version: testLearningObject01.version,
},
},
{
// If the answer to the first question was the second one (I can follow along):
condition: '$[?(@[0] == 1)]',
next: {
//... we let the student right through to the final question.
hruid: testLearningObjectEssayQuestion.hruid,
language: testLearningObjectEssayQuestion.language,
version: testLearningObjectEssayQuestion.version,
},
},
],
},
{
learningobject_hruid: testLearningObject01.hruid,
language: testLearningObject01.language,
version: testLearningObject01.version,
created_at: nowString,
updatedAt: nowString,
transitions: [
{
default: true,
next: {
hruid: testLearningObjectEssayQuestion.hruid,
language: testLearningObjectEssayQuestion.language,
version: testLearningObjectEssayQuestion.version,
},
},
],
},
{
learningobject_hruid: testLearningObjectEssayQuestion.hruid,
language: testLearningObjectEssayQuestion.language,
version: testLearningObjectEssayQuestion.version,
created_at: nowString,
updatedAt: nowString,
transitions: [],
},
],
};

View file

@ -15,7 +15,14 @@ export const TEST_STUDENTS = [
{ username: 'testleerling1', firstName: 'Gerald', lastName: 'Schmittinger' },
];
let testStudents: Student[];
// 🏗️ Functie die ORM entities maakt uit de data array
export function makeTestStudents(em: EntityManager): Student[] {
return TEST_STUDENTS.map((data) => em.create(Student, data));
testStudents = TEST_STUDENTS.map((data) => em.create(Student, data));
return testStudents;
}
export function getTestleerling1(): Student {
return testStudents.find((it) => it.username === 'testleerling1');
}

View file

@ -2,37 +2,63 @@ import { Teacher } from '../../../src/entities/users/teacher.entity';
import { EntityManager } from '@mikro-orm/core';
export function makeTestTeachers(em: EntityManager): Teacher[] {
const teacher01 = em.create(Teacher, {
teacher01 = em.create(Teacher, {
username: 'FooFighters',
firstName: 'Dave',
lastName: 'Grohl',
});
const teacher02 = em.create(Teacher, {
teacher02 = em.create(Teacher, {
username: 'LimpBizkit',
firstName: 'Fred',
lastName: 'Durst',
});
const teacher03 = em.create(Teacher, {
teacher03 = em.create(Teacher, {
username: 'Staind',
firstName: 'Aaron',
lastName: 'Lewis',
});
// Should not be used, gets deleted in a unit test
const teacher04 = em.create(Teacher, {
teacher04 = em.create(Teacher, {
username: 'ZesdeMetaal',
firstName: 'Wannes',
lastName: 'Cappelle',
});
// Makes sure when logged in as testleerkracht1, there exists a corresponding user
const teacher05 = em.create(Teacher, {
testleerkracht1 = em.create(Teacher, {
username: 'testleerkracht1',
firstName: 'Bob',
lastName: 'Dylan',
firstName: 'Kris',
lastName: 'Coolsaet',
});
return [teacher01, teacher02, teacher03, teacher04, teacher05];
return [teacher01, teacher02, teacher03, teacher04, testleerkracht1];
}
let teacher01: Teacher;
let teacher02: Teacher;
let teacher03: Teacher;
let teacher04: Teacher;
let testleerkracht1: Teacher;
export function getTeacher01(): Teacher {
return teacher01;
}
export function getTeacher02(): Teacher {
return teacher02;
}
export function getTeacher03(): Teacher {
return teacher03;
}
export function getTeacher04(): Teacher {
return teacher04;
}
export function getTestleerkracht1(): Teacher {
return testleerkracht1;
}