test(backend): Testen voor DatabaseLearningPathProvider.fetchLearningPaths afgewerkt
Hierbij optredende problemen opgelost.
This commit is contained in:
parent
1f9e9ed70a
commit
7018a8822d
10 changed files with 139 additions and 32 deletions
|
@ -7,21 +7,30 @@ export class LearningObjectRepository extends DwengoEntityRepository<LearningObj
|
||||||
public findByIdentifier(
|
public findByIdentifier(
|
||||||
identifier: LearningObjectIdentifier
|
identifier: LearningObjectIdentifier
|
||||||
): Promise<LearningObject | null> {
|
): Promise<LearningObject | null> {
|
||||||
return this.findOne({
|
return this.findOne(
|
||||||
hruid: identifier.hruid,
|
{
|
||||||
language: identifier.language,
|
hruid: identifier.hruid,
|
||||||
version: identifier.version,
|
language: identifier.language,
|
||||||
});
|
version: identifier.version,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
populate: ["keywords"]
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public findLatestByHruidAndLanguage(hruid: string, language: Language) {
|
public findLatestByHruidAndLanguage(hruid: string, language: Language) {
|
||||||
return this.findOne({
|
return this.findOne(
|
||||||
hruid: hruid,
|
{
|
||||||
language: language
|
hruid: hruid,
|
||||||
}, {
|
language: language
|
||||||
orderBy: {
|
},
|
||||||
version: "DESC"
|
{
|
||||||
|
populate: ["keywords"],
|
||||||
|
orderBy: {
|
||||||
|
version: "DESC"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,10 @@ export class LearningPathRepository extends DwengoEntityRepository<LearningPath>
|
||||||
hruid: string,
|
hruid: string,
|
||||||
language: Language
|
language: Language
|
||||||
): Promise<LearningPath | null> {
|
): Promise<LearningPath | null> {
|
||||||
return this.findOne({ hruid: hruid, language: language });
|
return this.findOne(
|
||||||
|
{ hruid: hruid, language: language },
|
||||||
|
{ populate: ["nodes", "nodes.transitions"] }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,8 +28,8 @@ export class LearningPathRepository extends DwengoEntityRepository<LearningPath>
|
||||||
{ title: { $like: `%${query}%`} },
|
{ title: { $like: `%${query}%`} },
|
||||||
{ description: { $like: `%${query}%`} }
|
{ description: { $like: `%${query}%`} }
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
populate: ["nodes", "nodes.transitions"]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// This repository is read-only for now since creating own learning object is an extension feature.
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ import { LearningPath } from '../entities/content/learning-path.entity.js';
|
||||||
import { LearningPathRepository } from './content/learning-path-repository.js';
|
import { LearningPathRepository } from './content/learning-path-repository.js';
|
||||||
import { AttachmentRepository } from './content/attachment-repository.js';
|
import { AttachmentRepository } from './content/attachment-repository.js';
|
||||||
import { Attachment } from '../entities/content/attachment.entity.js';
|
import { Attachment } from '../entities/content/attachment.entity.js';
|
||||||
|
import {LearningPathNode} from "../entities/content/learning-path-node.entity";
|
||||||
|
import {LearningPathTransition} from "../entities/content/learning-path-transition.entity";
|
||||||
|
|
||||||
let entityManager: EntityManager | undefined;
|
let entityManager: EntityManager | undefined;
|
||||||
|
|
||||||
|
@ -113,6 +115,8 @@ export const getLearningPathRepository = repositoryGetter<
|
||||||
LearningPath,
|
LearningPath,
|
||||||
LearningPathRepository
|
LearningPathRepository
|
||||||
>(LearningPath);
|
>(LearningPath);
|
||||||
|
export const getLearningPathNodeRepository = repositoryGetter(LearningPathNode);
|
||||||
|
export const getLearningPathTransitionRepository = repositoryGetter(LearningPathTransition);
|
||||||
export const getAttachmentRepository = repositoryGetter<
|
export const getAttachmentRepository = repositoryGetter<
|
||||||
Attachment,
|
Attachment,
|
||||||
AttachmentRepository
|
AttachmentRepository
|
||||||
|
|
|
@ -5,10 +5,11 @@ import {LearningPathTransition} from "./learning-path-transition.entity";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class LearningPathNode {
|
export class LearningPathNode {
|
||||||
|
|
||||||
@ManyToOne({ entity: () => LearningPath, primary: true })
|
@ManyToOne({ entity: () => LearningPath, primary: true })
|
||||||
learningPath!: LearningPath;
|
learningPath!: LearningPath;
|
||||||
|
|
||||||
@PrimaryKey({ type: "numeric", autoincrement: true })
|
@PrimaryKey({ type: "integer", autoincrement: true })
|
||||||
nodeNumber!: number;
|
nodeNumber!: number;
|
||||||
|
|
||||||
@Property({ type: 'string' })
|
@Property({ type: 'string' })
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {LearningPathNode} from "./learning-path-node.entity";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class LearningPathTransition {
|
export class LearningPathTransition {
|
||||||
@ManyToOne({entity: () => LearningPathNode })
|
@ManyToOne({entity: () => LearningPathNode, primary: true })
|
||||||
node!: LearningPathNode;
|
node!: LearningPathNode;
|
||||||
|
|
||||||
@PrimaryKey({ type: 'numeric' })
|
@PrimaryKey({ type: 'numeric' })
|
||||||
|
|
|
@ -21,7 +21,7 @@ export interface LearningObjectNode {
|
||||||
_id: string;
|
_id: string;
|
||||||
learningobject_hruid: string;
|
learningobject_hruid: string;
|
||||||
version: number;
|
version: number;
|
||||||
language: string;
|
language: Language;
|
||||||
start_node?: boolean;
|
start_node?: boolean;
|
||||||
transitions: Transition[];
|
transitions: Transition[];
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
@ -88,7 +88,7 @@ export interface FilteredLearningObject {
|
||||||
version: number;
|
version: number;
|
||||||
title: string;
|
title: string;
|
||||||
htmlUrl: string;
|
htmlUrl: string;
|
||||||
language: string;
|
language: Language;
|
||||||
difficulty: number;
|
difficulty: number;
|
||||||
estimatedTime: number;
|
estimatedTime: number;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
|
|
|
@ -6,6 +6,10 @@ import {getLearningObjectRepository, getLearningPathRepository} from "../../../s
|
||||||
import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example";
|
import learningObjectExample from "../../test-assets/learning-objects/pn_werkingnotebooks/pn-werkingnotebooks-example";
|
||||||
import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"
|
import learningPathExample from "../../test-assets/learning-paths/pn-werking-example"
|
||||||
import databaseLearningPathProvider from "../../../src/services/learning-paths/database-learning-path-provider";
|
import databaseLearningPathProvider from "../../../src/services/learning-paths/database-learning-path-provider";
|
||||||
|
import {expectToBeCorrectLearningPath} from "../../test-utils/expectations";
|
||||||
|
import {LearningObjectRepository} from "../../../src/data/content/learning-object-repository";
|
||||||
|
import learningObjectService from "../../../src/services/learning-objects/learning-object-service";
|
||||||
|
import {Language} from "../../../src/entities/content/language";
|
||||||
|
|
||||||
async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> {
|
async function initExampleData(): Promise<{ learningObject: LearningObject, learningPath: LearningPath }> {
|
||||||
const learningObjectRepo = getLearningObjectRepository();
|
const learningObjectRepo = getLearningObjectRepository();
|
||||||
|
@ -18,15 +22,17 @@ async function initExampleData(): Promise<{ learningObject: LearningObject, lear
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("DatabaseLearningPathProvider", () => {
|
describe("DatabaseLearningPathProvider", () => {
|
||||||
|
let learningObjectRepo: LearningObjectRepository;
|
||||||
let example: {learningObject: LearningObject, learningPath: LearningPath};
|
let example: {learningObject: LearningObject, learningPath: LearningPath};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await setupTestApp();
|
await setupTestApp();
|
||||||
example = await initExampleData();
|
example = await initExampleData();
|
||||||
|
learningObjectRepo = getLearningObjectRepository();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("fetchLearningPaths", () => {
|
describe("fetchLearningPaths", () => {
|
||||||
it("returns the learning path correctly", () => {
|
it("returns the learning path correctly", async () => {
|
||||||
const result = await databaseLearningPathProvider.fetchLearningPaths(
|
const result = await databaseLearningPathProvider.fetchLearningPaths(
|
||||||
[example.learningPath.hruid],
|
[example.learningPath.hruid],
|
||||||
example.learningPath.language,
|
example.learningPath.language,
|
||||||
|
@ -34,7 +40,26 @@ describe("DatabaseLearningPathProvider", () => {
|
||||||
);
|
);
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
expect(result.data?.length).toBe(1);
|
expect(result.data?.length).toBe(1);
|
||||||
expect(result.data)
|
|
||||||
})
|
const learningObjectsOnPath = (await Promise.all(
|
||||||
|
example.learningPath.nodes.map(node =>
|
||||||
|
learningObjectService.getLearningObjectById({
|
||||||
|
hruid: node.learningObjectHruid,
|
||||||
|
version: node.version,
|
||||||
|
language: node.language
|
||||||
|
}))
|
||||||
|
)).filter(it => it !== null);
|
||||||
|
|
||||||
|
expectToBeCorrectLearningPath(result.data![0], example.learningPath, learningObjectsOnPath)
|
||||||
|
});
|
||||||
|
it("returns a non-successful response if a non-existing learning path is queried", async () => {
|
||||||
|
const result = await databaseLearningPathProvider.fetchLearningPaths(
|
||||||
|
[example.learningPath.hruid],
|
||||||
|
Language.Abkhazian, // wrong language
|
||||||
|
"the source"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
import {Language} from "../../../src/entities/content/language";
|
import {Language} from "../../../src/entities/content/language";
|
||||||
import {LearningPathTransition} from "../../../src/entities/content/learning-path-transition.entity";
|
import {LearningPathTransition} from "../../../src/entities/content/learning-path-transition.entity";
|
||||||
import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity";
|
import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity";
|
||||||
|
import {LearningPath} from "../../../src/entities/content/learning-path.entity";
|
||||||
|
|
||||||
export function createLearningPathTransition(condition: string | null, to: LearningPathNode) {
|
export function createLearningPathTransition(node: LearningPathNode, transitionNumber: number, condition: string | null, to: LearningPathNode) {
|
||||||
let trans = new LearningPathTransition();
|
let trans = new LearningPathTransition();
|
||||||
|
trans.node = node;
|
||||||
|
trans.transitionNumber = transitionNumber;
|
||||||
trans.condition = condition || "true";
|
trans.condition = condition || "true";
|
||||||
trans.next = to;
|
trans.next = to;
|
||||||
return trans;
|
return trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createLearningPathNode(
|
export function createLearningPathNode(
|
||||||
|
learningPath: LearningPath,
|
||||||
|
nodeNumber: number,
|
||||||
learningObjectHruid: string,
|
learningObjectHruid: string,
|
||||||
version: number,
|
version: number,
|
||||||
language: Language,
|
language: Language,
|
||||||
startNode: boolean
|
startNode: boolean
|
||||||
) {
|
) {
|
||||||
let node = new LearningPathNode();
|
let node = new LearningPathNode();
|
||||||
|
node.learningPath = learningPath;
|
||||||
|
node.nodeNumber = nodeNumber;
|
||||||
node.learningObjectHruid = learningObjectHruid;
|
node.learningObjectHruid = learningObjectHruid;
|
||||||
node.version = version;
|
node.version = version;
|
||||||
node.language = language;
|
node.language = language;
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import {LearningPath, LearningPathNode} from "../../../src/entities/content/learning-path.entity";
|
import {LearningPath} from "../../../src/entities/content/learning-path.entity";
|
||||||
import {Language} from "../../../src/entities/content/language";
|
import {Language} from "../../../src/entities/content/language";
|
||||||
import {EnvVars, getEnvVar} from "../../../src/util/envvars";
|
import {EnvVars, getEnvVar} from "../../../src/util/envvars";
|
||||||
import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils";
|
import {createLearningPathNode, createLearningPathTransition} from "./learning-path-utils";
|
||||||
|
import {LearningPathNode} from "../../../src/entities/content/learning-path-node.entity";
|
||||||
|
|
||||||
function createNodes(): LearningPathNode[] {
|
function createNodes(learningPath: LearningPath): LearningPathNode[] {
|
||||||
let nodes = [
|
let nodes = [
|
||||||
createLearningPathNode("u_pn_werkingnotebooks", 3, Language.Dutch, true),
|
createLearningPathNode(learningPath, 0, "u_pn_werkingnotebooks", 3, Language.Dutch, true),
|
||||||
createLearningPathNode("pn_werkingnotebooks2", 3, Language.Dutch, false),
|
createLearningPathNode(learningPath, 1, "pn_werkingnotebooks2", 3, Language.Dutch, false),
|
||||||
createLearningPathNode("pn_werkingnotebooks3", 3, Language.Dutch, false),
|
createLearningPathNode(learningPath, 2, "pn_werkingnotebooks3", 3, Language.Dutch, false),
|
||||||
];
|
];
|
||||||
nodes[0].transitions.push(createLearningPathTransition("true", nodes[1]));
|
nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, "true", nodes[1]));
|
||||||
nodes[1].transitions.push(createLearningPathTransition("true", nodes[2]));
|
nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, "true", nodes[2]));
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ const example: LearningPathExample = {
|
||||||
path.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werking`;
|
path.hruid = `${getEnvVar(EnvVars.UserContentPrefix)}pn_werking`;
|
||||||
path.title = "Werken met notebooks";
|
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.description = "Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?";
|
||||||
path.nodes = createNodes();
|
path.nodes = createNodes(path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,9 +99,66 @@ export function expectToBeCorrectFilteredLearningObject(filtered: FilteredLearni
|
||||||
*
|
*
|
||||||
* @param learningPath The learning path returned by the retriever, service or endpoint
|
* @param learningPath The learning path returned by the retriever, service or endpoint
|
||||||
* @param expectedEntity The expected entity
|
* @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
|
||||||
*/
|
*/
|
||||||
export function expectToBeCorrectLearningPath(learningPath: LearningPath, expectedEntity: LearningPathEntity) {
|
export function expectToBeCorrectLearningPath(
|
||||||
|
learningPath: LearningPath,
|
||||||
|
expectedEntity: LearningPathEntity,
|
||||||
|
learningObjectsOnPath: FilteredLearningObject[]
|
||||||
|
) {
|
||||||
expect(learningPath.hruid).toEqual(expectedEntity.hruid);
|
expect(learningPath.hruid).toEqual(expectedEntity.hruid);
|
||||||
expect(learningPath.language).toEqual(expectedEntity.language);
|
expect(learningPath.language).toEqual(expectedEntity.language);
|
||||||
expect(learningPath.description).toEqual(expectedEntity.description);
|
expect(learningPath.description).toEqual(expectedEntity.description);
|
||||||
|
expect(learningPath.title).toEqual(expectedEntity.title);
|
||||||
|
|
||||||
|
const keywords = new Set(learningObjectsOnPath.flatMap(it => it.keywords || []));
|
||||||
|
expect(new Set(learningPath.keywords.split(' '))).toEqual(keywords)
|
||||||
|
|
||||||
|
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(learningPath.num_nodes).toEqual(expectedEntity.nodes.length);
|
||||||
|
expect(learningPath.image || null).toEqual(expectedEntity.image);
|
||||||
|
|
||||||
|
let expectedLearningPathNodes = new Map(
|
||||||
|
expectedEntity.nodes.map(node => [
|
||||||
|
{learningObjectHruid: node.learningObjectHruid, language: node.language, version: node.version},
|
||||||
|
{startNode: node.startNode, transitions: node.transitions}
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let node of learningPath.nodes) {
|
||||||
|
const nodeKey = {
|
||||||
|
learningObjectHruid: node.learningobject_hruid,
|
||||||
|
language: node.language,
|
||||||
|
version: node.version
|
||||||
|
};
|
||||||
|
expect(expectedLearningPathNodes.keys()).toContainEqual(nodeKey);
|
||||||
|
let expectedNode = [...expectedLearningPathNodes.entries()]
|
||||||
|
.filter(([key, _]) =>
|
||||||
|
key.learningObjectHruid === nodeKey.learningObjectHruid
|
||||||
|
&& key.language === node.language
|
||||||
|
&& key.version === node.version
|
||||||
|
)[0][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))
|
||||||
|
);
|
||||||
|
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))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue