Merge pull request #97 from SELab-2/test/testen-voor-datalaag-#87
test: Datalaag testen
This commit is contained in:
		
						commit
						17786e604f
					
				
					 43 changed files with 2456 additions and 3082 deletions
				
			
		|  | @ -60,6 +60,14 @@ De tech-stack bestaat uit: | ||||||
| Voor meer informatie over de keuze van deze tech-stack, | Voor meer informatie over de keuze van deze tech-stack, | ||||||
| zie [designkeuzes](https://github.com/SELab-2/Dwengo-1/wiki/Developer:-Design-keuzes). | zie [designkeuzes](https://github.com/SELab-2/Dwengo-1/wiki/Developer:-Design-keuzes). | ||||||
| 
 | 
 | ||||||
|  | ## Testen | ||||||
|  | 
 | ||||||
|  | Voer volgende commando's uit om de <frontend/backend> te testen: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | npm run test:unit | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Bijdragen aan Dwengo-1 | ## Bijdragen aan Dwengo-1 | ||||||
| 
 | 
 | ||||||
| Zie [CONTRIBUTING.md](./CONTRIBUTING.md) voor meer informatie over hoe je kan bijdragen aan Dwengo-1. | Zie [CONTRIBUTING.md](./CONTRIBUTING.md) voor meer informatie over hoe je kan bijdragen aan Dwengo-1. | ||||||
|  |  | ||||||
|  | @ -21,6 +21,14 @@ npm run build | ||||||
| npm run start | npm run start | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ### Tests | ||||||
|  | 
 | ||||||
|  | Voer volgend commando uit om de unit tests uit te voeren: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | npm run test:unit | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Keycloak configuratie | ## Keycloak configuratie | ||||||
| 
 | 
 | ||||||
| Tijdens development is het voldoende om gebruik te maken van de keycloak configuratie die automatisch ingeladen wordt. | Tijdens development is het voldoende om gebruik te maken van de keycloak configuratie die automatisch ingeladen wordt. | ||||||
|  |  | ||||||
|  | @ -14,12 +14,11 @@ | ||||||
|         "test:unit": "vitest" |         "test:unit": "vitest" | ||||||
|     }, |     }, | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|         "@mikro-orm/core": "6.4.6", |         "@mikro-orm/core": "6.4.9", | ||||||
|         "@mikro-orm/postgresql": "6.4.6", |         "@mikro-orm/knex": "6.4.9", | ||||||
|         "@mikro-orm/reflection": "6.4.6", |         "@mikro-orm/postgresql": "6.4.9", | ||||||
|         "@mikro-orm/sqlite": "6.4.6", |         "@mikro-orm/reflection": "6.4.9", | ||||||
|         "@types/cors": "^2.8.17", |         "@mikro-orm/sqlite": "6.4.9", | ||||||
|         "@types/js-yaml": "^4.0.9", |  | ||||||
|         "axios": "^1.8.2", |         "axios": "^1.8.2", | ||||||
|         "cors": "^2.8.5", |         "cors": "^2.8.5", | ||||||
|         "cross": "^1.0.0", |         "cross": "^1.0.0", | ||||||
|  | @ -40,8 +39,10 @@ | ||||||
|         "winston-loki": "^6.1.3" |         "winston-loki": "^6.1.3" | ||||||
|     }, |     }, | ||||||
|     "devDependencies": { |     "devDependencies": { | ||||||
|         "@mikro-orm/cli": "6.4.6", |         "@mikro-orm/cli": "6.4.9", | ||||||
|  |         "@types/cors": "^2.8.17", | ||||||
|         "@types/express": "^5.0.0", |         "@types/express": "^5.0.0", | ||||||
|  |         "@types/js-yaml": "^4.0.9", | ||||||
|         "@types/node": "^22.13.4", |         "@types/node": "^22.13.4", | ||||||
|         "@types/response-time": "^2.3.8", |         "@types/response-time": "^2.3.8", | ||||||
|         "globals": "^15.15.0", |         "globals": "^15.15.0", | ||||||
|  |  | ||||||
|  | @ -5,10 +5,12 @@ import { Teacher } from '../../entities/users/teacher.entity.js'; | ||||||
| 
 | 
 | ||||||
| export class AnswerRepository extends DwengoEntityRepository<Answer> { | export class AnswerRepository extends DwengoEntityRepository<Answer> { | ||||||
|     public createAnswer(answer: { toQuestion: Question; author: Teacher; content: string }): Promise<Answer> { |     public createAnswer(answer: { toQuestion: Question; author: Teacher; content: string }): Promise<Answer> { | ||||||
|         const answerEntity = new Answer(); |         const answerEntity = this.create({ | ||||||
|         answerEntity.toQuestion = answer.toQuestion; |             toQuestion: answer.toQuestion, | ||||||
|         answerEntity.author = answer.author; |             author: answer.author, | ||||||
|         answerEntity.content = answer.content; |             content: answer.content, | ||||||
|  |             timestamp: new Date(), | ||||||
|  |         }); | ||||||
|         return this.insert(answerEntity); |         return this.insert(answerEntity); | ||||||
|     } |     } | ||||||
|     public findAllAnswersToQuestion(question: Question): Promise<Answer[]> { |     public findAllAnswersToQuestion(question: Question): Promise<Answer[]> { | ||||||
|  |  | ||||||
|  | @ -5,7 +5,14 @@ import { Student } from '../../entities/users/student.entity.js'; | ||||||
| 
 | 
 | ||||||
| export class QuestionRepository extends DwengoEntityRepository<Question> { | export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
|     public createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> { |     public createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> { | ||||||
|         const questionEntity = new Question(); |         const questionEntity = this.create({ | ||||||
|  |             learningObjectHruid: question.loId.hruid, | ||||||
|  |             learningObjectLanguage: question.loId.language, | ||||||
|  |             learningObjectVersion: question.loId.version, | ||||||
|  |             author: question.author, | ||||||
|  |             content: question.content, | ||||||
|  |             timestamp: new Date(), | ||||||
|  |         }); | ||||||
|         questionEntity.learningObjectHruid = question.loId.hruid; |         questionEntity.learningObjectHruid = question.loId.hruid; | ||||||
|         questionEntity.learningObjectLanguage = question.loId.language; |         questionEntity.learningObjectLanguage = question.loId.language; | ||||||
|         questionEntity.learningObjectVersion = question.loId.version; |         questionEntity.learningObjectVersion = question.loId.version; | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ export const getTeacherRepository = repositoryGetter<Teacher, TeacherRepository> | ||||||
| /* Classes */ | /* Classes */ | ||||||
| export const getClassRepository = repositoryGetter<Class, ClassRepository>(Class); | export const getClassRepository = repositoryGetter<Class, ClassRepository>(Class); | ||||||
| export const getClassJoinRequestRepository = repositoryGetter<ClassJoinRequest, ClassJoinRequestRepository>(ClassJoinRequest); | export const getClassJoinRequestRepository = repositoryGetter<ClassJoinRequest, ClassJoinRequestRepository>(ClassJoinRequest); | ||||||
| export const getTeacherInvitationRepository = repositoryGetter<TeacherInvitation, TeacherInvitationRepository>(TeacherInvitationRepository); | export const getTeacherInvitationRepository = repositoryGetter<TeacherInvitation, TeacherInvitationRepository>(TeacherInvitation); | ||||||
| 
 | 
 | ||||||
| /* Assignments */ | /* Assignments */ | ||||||
| export const getAssignmentRepository = repositoryGetter<Assignment, AssignmentRepository>(Assignment); | export const getAssignmentRepository = repositoryGetter<Assignment, AssignmentRepository>(Assignment); | ||||||
|  |  | ||||||
|  | @ -7,6 +7,9 @@ import { TeacherInvitationRepository } from '../../data/classes/teacher-invitati | ||||||
|  * Invitation of a teacher into a class (in order to teach it). |  * Invitation of a teacher into a class (in order to teach it). | ||||||
|  */ |  */ | ||||||
| @Entity({ repository: () => TeacherInvitationRepository }) | @Entity({ repository: () => TeacherInvitationRepository }) | ||||||
|  | @Entity({ | ||||||
|  |     repository: () => TeacherInvitationRepository, | ||||||
|  | }) | ||||||
| export class TeacherInvitation { | export class TeacherInvitation { | ||||||
|     @ManyToOne({ |     @ManyToOne({ | ||||||
|         entity: () => Teacher, |         entity: () => Teacher, | ||||||
|  |  | ||||||
|  | @ -17,8 +17,8 @@ export class Answer { | ||||||
|     }) |     }) | ||||||
|     toQuestion!: Question; |     toQuestion!: Question; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer', autoincrement: true }) | ||||||
|     sequenceNumber!: number; |     sequenceNumber?: number; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'datetime' }) |     @Property({ type: 'datetime' }) | ||||||
|     timestamp: Date = new Date(); |     timestamp: Date = new Date(); | ||||||
|  |  | ||||||
|  | @ -17,8 +17,8 @@ export class Question { | ||||||
|     @PrimaryKey({ type: 'number' }) |     @PrimaryKey({ type: 'number' }) | ||||||
|     learningObjectVersion: number = 1; |     learningObjectVersion: number = 1; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer', autoincrement: true }) | ||||||
|     sequenceNumber!: number; |     sequenceNumber?: number; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ |     @ManyToOne({ | ||||||
|         entity: () => Student, |         entity: () => Student, | ||||||
|  |  | ||||||
|  | @ -7,4 +7,12 @@ import { TeacherRepository } from '../../data/users/teacher-repository.js'; | ||||||
| export class Teacher extends User { | export class Teacher extends User { | ||||||
|     @ManyToMany(() => Class) |     @ManyToMany(() => Class) | ||||||
|     classes!: Collection<Class>; |     classes!: Collection<Class>; | ||||||
|  | 
 | ||||||
|  |     constructor( | ||||||
|  |         public username: string, | ||||||
|  |         public firstName: string, | ||||||
|  |         public lastName: string | ||||||
|  |     ) { | ||||||
|  |         super(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ import { LearningPath } from './entities/content/learning-path.entity.js'; | ||||||
| 
 | 
 | ||||||
| import { Answer } from './entities/questions/answer.entity.js'; | import { Answer } from './entities/questions/answer.entity.js'; | ||||||
| import { Question } from './entities/questions/question.entity.js'; | import { Question } from './entities/questions/question.entity.js'; | ||||||
|  | import { SqliteAutoincrementSubscriber } from './sqlite-autoincrement-workaround.js'; | ||||||
| 
 | 
 | ||||||
| const entities = [ | const entities = [ | ||||||
|     User, |     User, | ||||||
|  | @ -47,6 +48,7 @@ function config(testingMode: boolean = false): Options { | ||||||
|         return { |         return { | ||||||
|             driver: SqliteDriver, |             driver: SqliteDriver, | ||||||
|             dbName: getEnvVar(EnvVars.DbName), |             dbName: getEnvVar(EnvVars.DbName), | ||||||
|  |             subscribers: [new SqliteAutoincrementSubscriber()], | ||||||
|             entities: entities, |             entities: entities, | ||||||
|             // EntitiesTs: entitiesTs,
 |             // EntitiesTs: entitiesTs,
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								backend/src/sqlite-autoincrement-workaround.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								backend/src/sqlite-autoincrement-workaround.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | import { EntityProperty, EventArgs, EventSubscriber } from '@mikro-orm/core'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * The tests are ran on an in-memory SQLite database. However, SQLite does not allow fields which are part of composite | ||||||
|  |  * primary keys to be autoincremented (while PostgreSQL, which we use in production, does). This Subscriber works around | ||||||
|  |  * the issue by remembering the highest values for every autoincremented part of a primary key and assigning them when | ||||||
|  |  * creating a new entity. | ||||||
|  |  * | ||||||
|  |  * However, it is important to note the following limitations: | ||||||
|  |  * - this class can only be used for in-memory SQLite databases since the information on what the highest sequence | ||||||
|  |  *   number for each of the properties is, is only saved transiently. | ||||||
|  |  * - automatically setting the generated "autoincremented" value for properties only works when the entity is created | ||||||
|  |  *   via an entityManager.create(...) or repo.create(...) method. Otherwise, onInit will not be called and therefore, | ||||||
|  |  *   the sequence number will not be filled in. | ||||||
|  |  */ | ||||||
|  | export class SqliteAutoincrementSubscriber implements EventSubscriber { | ||||||
|  |     private sequenceNumbersForEntityType: Map<string, number> = new Map(); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * When an entity with an autoincremented property which is part of the composite private key is created, | ||||||
|  |      * automatically fill this property so we won't face not-null-constraint exceptions when persisting it. | ||||||
|  |      */ | ||||||
|  |     onInit<T extends object>(args: EventArgs<T>): void { | ||||||
|  |         if (!args.meta.compositePK) { | ||||||
|  |             return; // If there is not a composite primary key, autoincrement works fine with SQLite anyway.
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (const prop of Object.values(args.meta.properties)) { | ||||||
|  |             const property = prop as EntityProperty<T>; | ||||||
|  |             if (property.primary && property.autoincrement && !(args.entity as Record<string, any>)[property.name]) { | ||||||
|  |                 // Obtain and increment sequence number of this entity.
 | ||||||
|  |                 const propertyKey = args.meta.class.name + '.' + property.name; | ||||||
|  |                 const nextSeqNumber = this.sequenceNumbersForEntityType.get(propertyKey) || 0; | ||||||
|  |                 this.sequenceNumbersForEntityType.set(propertyKey, nextSeqNumber + 1); | ||||||
|  | 
 | ||||||
|  |                 // Set the property accordingly.
 | ||||||
|  |                 (args.entity as Record<string, any>)[property.name] = nextSeqNumber + 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								backend/tests/data/assignments/assignments.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								backend/tests/data/assignments/assignments.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; | ||||||
|  | import { getAssignmentRepository, getClassRepository } from '../../../src/data/repositories'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | 
 | ||||||
|  | describe('AssignmentRepository', () => { | ||||||
|  |     let assignmentRepository: AssignmentRepository; | ||||||
|  |     let classRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         assignmentRepository = getAssignmentRepository(); | ||||||
|  |         classRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return the requested assignment', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id02'); | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 2); | ||||||
|  | 
 | ||||||
|  |         expect(assignment).toBeTruthy(); | ||||||
|  |         expect(assignment!.title).toBe('tool'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all assignments for a class', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id02'); | ||||||
|  |         const assignments = await assignmentRepository.findAllAssignmentsInClass(class_!); | ||||||
|  | 
 | ||||||
|  |         expect(assignments).toBeTruthy(); | ||||||
|  |         expect(assignments).toHaveLength(1); | ||||||
|  |         expect(assignments[0].title).toBe('tool'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find removed assignment', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id01'); | ||||||
|  |         await assignmentRepository.deleteByClassAndId(class_!, 3); | ||||||
|  | 
 | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 3); | ||||||
|  | 
 | ||||||
|  |         expect(assignment).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										49
									
								
								backend/tests/data/assignments/groups.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								backend/tests/data/assignments/groups.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { GroupRepository } from '../../../src/data/assignments/group-repository'; | ||||||
|  | import { getAssignmentRepository, getClassRepository, getGroupRepository } from '../../../src/data/repositories'; | ||||||
|  | import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | 
 | ||||||
|  | describe('GroupRepository', () => { | ||||||
|  |     let groupRepository: GroupRepository; | ||||||
|  |     let assignmentRepository: AssignmentRepository; | ||||||
|  |     let classRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         groupRepository = getGroupRepository(); | ||||||
|  |         assignmentRepository = getAssignmentRepository(); | ||||||
|  |         classRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return the requested group', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id01'); | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 1); | ||||||
|  | 
 | ||||||
|  |         const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); | ||||||
|  | 
 | ||||||
|  |         expect(group).toBeTruthy(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all groups for assignment', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id01'); | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 1); | ||||||
|  | 
 | ||||||
|  |         const groups = await groupRepository.findAllGroupsForAssignment(assignment!); | ||||||
|  | 
 | ||||||
|  |         expect(groups).toBeTruthy(); | ||||||
|  |         expect(groups).toHaveLength(3); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find removed group', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id02'); | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 2); | ||||||
|  | 
 | ||||||
|  |         await groupRepository.deleteByAssignmentAndGroupNumber(assignment!, 1); | ||||||
|  | 
 | ||||||
|  |         const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); | ||||||
|  | 
 | ||||||
|  |         expect(group).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										70
									
								
								backend/tests/data/assignments/submissions.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								backend/tests/data/assignments/submissions.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { SubmissionRepository } from '../../../src/data/assignments/submission-repository'; | ||||||
|  | import { | ||||||
|  |     getAssignmentRepository, | ||||||
|  |     getClassRepository, | ||||||
|  |     getGroupRepository, | ||||||
|  |     getStudentRepository, | ||||||
|  |     getSubmissionRepository, | ||||||
|  | } from '../../../src/data/repositories'; | ||||||
|  | import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { StudentRepository } from '../../../src/data/users/student-repository'; | ||||||
|  | import { GroupRepository } from '../../../src/data/assignments/group-repository'; | ||||||
|  | import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | 
 | ||||||
|  | describe('SubmissionRepository', () => { | ||||||
|  |     let submissionRepository: SubmissionRepository; | ||||||
|  |     let studentRepository: StudentRepository; | ||||||
|  |     let groupRepository: GroupRepository; | ||||||
|  |     let assignmentRepository: AssignmentRepository; | ||||||
|  |     let classRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         submissionRepository = getSubmissionRepository(); | ||||||
|  |         studentRepository = getStudentRepository(); | ||||||
|  |         groupRepository = getGroupRepository(); | ||||||
|  |         assignmentRepository = getAssignmentRepository(); | ||||||
|  |         classRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should find the requested submission', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id03', Language.English, '1'); | ||||||
|  |         const submission = await submissionRepository.findSubmissionByLearningObjectAndSubmissionNumber(id, 1); | ||||||
|  | 
 | ||||||
|  |         expect(submission).toBeTruthy(); | ||||||
|  |         expect(submission?.content).toBe('sub1'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should find the most recent submission for a student', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id02', Language.English, '1'); | ||||||
|  |         const student = await studentRepository.findByUsername('Noordkaap'); | ||||||
|  |         const submission = await submissionRepository.findMostRecentSubmissionForStudent(id, student!); | ||||||
|  | 
 | ||||||
|  |         expect(submission).toBeTruthy(); | ||||||
|  |         expect(submission?.submissionTime.getDate()).toBe(25); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should find the most recent submission for a group', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id03', Language.English, '1'); | ||||||
|  |         const class_ = await classRepository.findById('id01'); | ||||||
|  |         const assignment = await assignmentRepository.findByClassAndId(class_!, 1); | ||||||
|  |         const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); | ||||||
|  |         const submission = await submissionRepository.findMostRecentSubmissionForGroup(id, group!); | ||||||
|  | 
 | ||||||
|  |         expect(submission).toBeTruthy(); | ||||||
|  |         expect(submission?.submissionTime.getDate()).toBe(25); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find a deleted submission', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id01', Language.English, '1'); | ||||||
|  |         await submissionRepository.deleteSubmissionByLearningObjectAndSubmissionNumber(id, 1); | ||||||
|  | 
 | ||||||
|  |         const submission = await submissionRepository.findSubmissionByLearningObjectAndSubmissionNumber(id, 1); | ||||||
|  | 
 | ||||||
|  |         expect(submission).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										47
									
								
								backend/tests/data/classes/class-join-request.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								backend/tests/data/classes/class-join-request.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { ClassJoinRequestRepository } from '../../../src/data/classes/class-join-request-repository'; | ||||||
|  | import { getClassJoinRequestRepository, getClassRepository, getStudentRepository } from '../../../src/data/repositories'; | ||||||
|  | import { StudentRepository } from '../../../src/data/users/student-repository'; | ||||||
|  | import { Class } from '../../../src/entities/classes/class.entity'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | import { Student } from '../../../src/entities/users/student.entity'; | ||||||
|  | 
 | ||||||
|  | describe('ClassJoinRequestRepository', () => { | ||||||
|  |     let classJoinRequestRepository: ClassJoinRequestRepository; | ||||||
|  |     let studentRepository: StudentRepository; | ||||||
|  |     let cassRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         classJoinRequestRepository = getClassJoinRequestRepository(); | ||||||
|  |         studentRepository = getStudentRepository(); | ||||||
|  |         cassRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should list all requests from student to join classes', async () => { | ||||||
|  |         const student = await studentRepository.findByUsername('PinkFloyd'); | ||||||
|  |         const requests = await classJoinRequestRepository.findAllRequestsBy(student!); | ||||||
|  | 
 | ||||||
|  |         expect(requests).toBeTruthy(); | ||||||
|  |         expect(requests).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should list all requests to a single class', async () => { | ||||||
|  |         const class_ = await cassRepository.findById('id02'); | ||||||
|  |         const requests = await classJoinRequestRepository.findAllOpenRequestsTo(class_!); | ||||||
|  | 
 | ||||||
|  |         expect(requests).toBeTruthy(); | ||||||
|  |         expect(requests).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find a removed request', async () => { | ||||||
|  |         const student = await studentRepository.findByUsername('SmashingPumpkins'); | ||||||
|  |         const class_ = await cassRepository.findById('id03'); | ||||||
|  |         await classJoinRequestRepository.deleteBy(student!, class_!); | ||||||
|  | 
 | ||||||
|  |         const request = await classJoinRequestRepository.findAllRequestsBy(student!); | ||||||
|  | 
 | ||||||
|  |         expect(request).toHaveLength(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										34
									
								
								backend/tests/data/classes/classes.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								backend/tests/data/classes/classes.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { getClassRepository } from '../../../src/data/repositories'; | ||||||
|  | 
 | ||||||
|  | describe('ClassRepository', () => { | ||||||
|  |     let classRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         classRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return nothing because id does not exist', async () => { | ||||||
|  |         const classVar = await classRepository.findById('test_id'); | ||||||
|  | 
 | ||||||
|  |         expect(classVar).toBeNull(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return requested class', async () => { | ||||||
|  |         const classVar = await classRepository.findById('id01'); | ||||||
|  | 
 | ||||||
|  |         expect(classVar).toBeTruthy(); | ||||||
|  |         expect(classVar?.displayName).toBe('class01'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('class should be gone after deletion', async () => { | ||||||
|  |         await classRepository.deleteById('id04'); | ||||||
|  | 
 | ||||||
|  |         const classVar = await classRepository.findById('id04'); | ||||||
|  | 
 | ||||||
|  |         expect(classVar).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										54
									
								
								backend/tests/data/classes/teacher-invitation.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								backend/tests/data/classes/teacher-invitation.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { getClassRepository, getTeacherInvitationRepository, getTeacherRepository } from '../../../src/data/repositories'; | ||||||
|  | import { TeacherInvitationRepository } from '../../../src/data/classes/teacher-invitation-repository'; | ||||||
|  | import { TeacherRepository } from '../../../src/data/users/teacher-repository'; | ||||||
|  | import { ClassRepository } from '../../../src/data/classes/class-repository'; | ||||||
|  | 
 | ||||||
|  | describe('ClassRepository', () => { | ||||||
|  |     let teacherInvitationRepository: TeacherInvitationRepository; | ||||||
|  |     let teacherRepository: TeacherRepository; | ||||||
|  |     let classRepository: ClassRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         teacherInvitationRepository = getTeacherInvitationRepository(); | ||||||
|  |         teacherRepository = getTeacherRepository(); | ||||||
|  |         classRepository = getClassRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all invitations from a teacher', async () => { | ||||||
|  |         const teacher = await teacherRepository.findByUsername('LimpBizkit'); | ||||||
|  |         const invitations = await teacherInvitationRepository.findAllInvitationsBy(teacher!); | ||||||
|  | 
 | ||||||
|  |         expect(invitations).toBeTruthy(); | ||||||
|  |         expect(invitations).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all invitations for a teacher', async () => { | ||||||
|  |         const teacher = await teacherRepository.findByUsername('FooFighters'); | ||||||
|  |         const invitations = await teacherInvitationRepository.findAllInvitationsFor(teacher!); | ||||||
|  | 
 | ||||||
|  |         expect(invitations).toBeTruthy(); | ||||||
|  |         expect(invitations).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all invitations for a class', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id02'); | ||||||
|  |         const invitations = await teacherInvitationRepository.findAllInvitationsForClass(class_!); | ||||||
|  | 
 | ||||||
|  |         expect(invitations).toBeTruthy(); | ||||||
|  |         expect(invitations).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find a removed invitation', async () => { | ||||||
|  |         const class_ = await classRepository.findById('id01'); | ||||||
|  |         const sender = await teacherRepository.findByUsername('FooFighters'); | ||||||
|  |         const receiver = await teacherRepository.findByUsername('LimpBizkit'); | ||||||
|  |         await teacherInvitationRepository.deleteBy(class_!, sender!, receiver!); | ||||||
|  | 
 | ||||||
|  |         const invitation = await teacherInvitationRepository.findAllInvitationsBy(sender!); | ||||||
|  | 
 | ||||||
|  |         expect(invitation).toHaveLength(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										31
									
								
								backend/tests/data/content/attachments.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								backend/tests/data/content/attachments.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | 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 { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier.js'; | ||||||
|  | import { Language } from '../../../src/entities/content/language.js'; | ||||||
|  | 
 | ||||||
|  | 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!, | ||||||
|  |             Language.English, | ||||||
|  |             'attachment01' | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         expect(attachment).toBeTruthy(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										32
									
								
								backend/tests/data/content/learning-objects.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								backend/tests/data/content/learning-objects.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; | ||||||
|  | import { getLearningObjectRepository } from '../../../src/data/repositories'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | 
 | ||||||
|  | describe('LearningObjectRepository', () => { | ||||||
|  |     let learningObjectRepository: LearningObjectRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         learningObjectRepository = getLearningObjectRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const id01 = new LearningObjectIdentifier('id01', Language.English, '1'); | ||||||
|  |     const id02 = new LearningObjectIdentifier('test_id', Language.English, '1'); | ||||||
|  | 
 | ||||||
|  |     it('should return the learning object that matches identifier 1', async () => { | ||||||
|  |         const learningObject = await learningObjectRepository.findByIdentifier(id01); | ||||||
|  | 
 | ||||||
|  |         expect(learningObject).toBeTruthy(); | ||||||
|  |         expect(learningObject?.title).toBe('Undertow'); | ||||||
|  |         expect(learningObject?.description).toBe('debute'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return nothing because the identifier does not exist in the database', async () => { | ||||||
|  |         const learningObject = await learningObjectRepository.findByIdentifier(id02); | ||||||
|  | 
 | ||||||
|  |         expect(learningObject).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										28
									
								
								backend/tests/data/content/learning-paths.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								backend/tests/data/content/learning-paths.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { getLearningPathRepository } from '../../../src/data/repositories'; | ||||||
|  | import { LearningPathRepository } from '../../../src/data/content/learning-path-repository'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | 
 | ||||||
|  | describe('LearningPathRepository', () => { | ||||||
|  |     let learningPathRepository: LearningPathRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         learningPathRepository = getLearningPathRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return nothing because no match for hruid and language', async () => { | ||||||
|  |         const learningPath = await learningPathRepository.findByHruidAndLanguage('test_id', Language.Dutch); | ||||||
|  | 
 | ||||||
|  |         expect(learningPath).toBeNull(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return requested learning path', async () => { | ||||||
|  |         const learningPath = await learningPathRepository.findByHruidAndLanguage('id01', Language.English); | ||||||
|  | 
 | ||||||
|  |         expect(learningPath).toBeTruthy(); | ||||||
|  |         expect(learningPath?.title).toBe('repertoire Tool'); | ||||||
|  |         expect(learningPath?.description).toBe('all about Tool'); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										66
									
								
								backend/tests/data/questions/answers.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								backend/tests/data/questions/answers.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { AnswerRepository } from '../../../src/data/questions/answer-repository'; | ||||||
|  | import { getAnswerRepository, getQuestionRepository, getTeacherRepository } from '../../../src/data/repositories'; | ||||||
|  | import { QuestionRepository } from '../../../src/data/questions/question-repository'; | ||||||
|  | import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { TeacherRepository } from '../../../src/data/users/teacher-repository'; | ||||||
|  | 
 | ||||||
|  | describe('AnswerRepository', () => { | ||||||
|  |     let answerRepository: AnswerRepository; | ||||||
|  |     let questionRepository: QuestionRepository; | ||||||
|  |     let teacherRepository: TeacherRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         answerRepository = getAnswerRepository(); | ||||||
|  |         questionRepository = getQuestionRepository(); | ||||||
|  |         teacherRepository = getTeacherRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should find all answers to a question', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id05', Language.English, '1'); | ||||||
|  |         const questions = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         const question = questions.filter((it) => it.sequenceNumber == 2)[0]; | ||||||
|  | 
 | ||||||
|  |         const answers = await answerRepository.findAllAnswersToQuestion(question); | ||||||
|  | 
 | ||||||
|  |         expect(answers).toBeTruthy(); | ||||||
|  |         expect(answers).toHaveLength(2); | ||||||
|  |         expect(answers[0].content).toBeOneOf(['answer', 'answer2']); | ||||||
|  |         expect(answers[1].content).toBeOneOf(['answer', 'answer2']); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should create an answer to a question', async () => { | ||||||
|  |         const teacher = await teacherRepository.findByUsername('FooFighters'); | ||||||
|  |         const id = new LearningObjectIdentifier('id05', Language.English, '1'); | ||||||
|  |         const questions = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         const question = questions[0]; | ||||||
|  | 
 | ||||||
|  |         await answerRepository.createAnswer({ | ||||||
|  |             toQuestion: question, | ||||||
|  |             author: teacher!, | ||||||
|  |             content: 'created answer', | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         const answers = await answerRepository.findAllAnswersToQuestion(question); | ||||||
|  | 
 | ||||||
|  |         expect(answers).toBeTruthy(); | ||||||
|  |         expect(answers).toHaveLength(1); | ||||||
|  |         expect(answers[0].content).toBe('created answer'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find a removed answer', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id04', Language.English, '1'); | ||||||
|  |         const questions = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         await answerRepository.removeAnswerByQuestionAndSequenceNumber(questions[0], 1); | ||||||
|  | 
 | ||||||
|  |         const emptyList = await answerRepository.findAllAnswersToQuestion(questions[0]); | ||||||
|  | 
 | ||||||
|  |         expect(emptyList).toHaveLength(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										52
									
								
								backend/tests/data/questions/questions.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								backend/tests/data/questions/questions.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | import { beforeAll, describe, expect, it } from 'vitest'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { QuestionRepository } from '../../../src/data/questions/question-repository'; | ||||||
|  | import { getLearningObjectRepository, getQuestionRepository, getStudentRepository } from '../../../src/data/repositories'; | ||||||
|  | import { StudentRepository } from '../../../src/data/users/student-repository'; | ||||||
|  | import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository'; | ||||||
|  | import { LearningObjectIdentifier } from '../../../src/entities/content/learning-object-identifier'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | 
 | ||||||
|  | describe('QuestionRepository', () => { | ||||||
|  |     let questionRepository: QuestionRepository; | ||||||
|  |     let studentRepository: StudentRepository; | ||||||
|  |     let learningObjectRepository: LearningObjectRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         questionRepository = getQuestionRepository(); | ||||||
|  |         studentRepository = getStudentRepository(); | ||||||
|  |         learningObjectRepository = getLearningObjectRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return all questions part of the given learning object', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id05', Language.English, '1'); | ||||||
|  |         const questions = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         expect(questions).toBeTruthy(); | ||||||
|  |         expect(questions).toHaveLength(2); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should create new question', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id03', Language.English, '1'); | ||||||
|  |         const student = await studentRepository.findByUsername('Noordkaap'); | ||||||
|  |         await questionRepository.createQuestion({ | ||||||
|  |             loId: id, | ||||||
|  |             author: student!, | ||||||
|  |             content: 'question?', | ||||||
|  |         }); | ||||||
|  |         const question = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         expect(question).toBeTruthy(); | ||||||
|  |         expect(question).toHaveLength(1); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not find removed question', async () => { | ||||||
|  |         const id = new LearningObjectIdentifier('id04', Language.English, '1'); | ||||||
|  |         await questionRepository.removeQuestionByLearningObjectAndSequenceNumber(id, 1); | ||||||
|  | 
 | ||||||
|  |         const question = await questionRepository.findAllQuestionsAboutLearningObject(id); | ||||||
|  | 
 | ||||||
|  |         expect(question).toHaveLength(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| import { setupTestApp } from '../setup-tests.js'; | import { setupTestApp } from '../../setup-tests.js'; | ||||||
| import { Student } from '../../src/entities/users/student.entity.js'; | import { Student } from '../../../src/entities/users/student.entity.js'; | ||||||
| import { describe, it, expect, beforeAll } from 'vitest'; | import { describe, it, expect, beforeAll } from 'vitest'; | ||||||
| import { StudentRepository } from '../../src/data/users/student-repository.js'; | import { StudentRepository } from '../../../src/data/users/student-repository.js'; | ||||||
| import { getStudentRepository } from '../../src/data/repositories.js'; | import { getStudentRepository } from '../../../src/data/repositories.js'; | ||||||
| 
 | 
 | ||||||
| const username = 'teststudent'; | const username = 'teststudent'; | ||||||
| const firstName = 'John'; | const firstName = 'John'; | ||||||
|  | @ -15,6 +15,20 @@ describe('StudentRepository', () => { | ||||||
|         studentRepository = getStudentRepository(); |         studentRepository = getStudentRepository(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     it('should not return a student because username does not exist', async () => { | ||||||
|  |         const student = await studentRepository.findByUsername('test'); | ||||||
|  | 
 | ||||||
|  |         expect(student).toBeNull(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return student from the datbase', async () => { | ||||||
|  |         const student = await studentRepository.findByUsername('Noordkaap'); | ||||||
|  | 
 | ||||||
|  |         expect(student).toBeTruthy(); | ||||||
|  |         expect(student?.firstName).toBe('Stijn'); | ||||||
|  |         expect(student?.lastName).toBe('Meuris'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     it('should return the queried student after he was added', async () => { |     it('should return the queried student after he was added', async () => { | ||||||
|         await studentRepository.insert(new Student(username, firstName, lastName)); |         await studentRepository.insert(new Student(username, firstName, lastName)); | ||||||
| 
 | 
 | ||||||
							
								
								
									
										47
									
								
								backend/tests/data/users/teachers.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								backend/tests/data/users/teachers.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | import { describe, it, expect, beforeAll } from 'vitest'; | ||||||
|  | import { TeacherRepository } from '../../../src/data/users/teacher-repository'; | ||||||
|  | import { setupTestApp } from '../../setup-tests'; | ||||||
|  | import { getTeacherRepository } from '../../../src/data/repositories'; | ||||||
|  | import { Teacher } from '../../../src/entities/users/teacher.entity'; | ||||||
|  | 
 | ||||||
|  | const username = 'testteacher'; | ||||||
|  | const firstName = 'John'; | ||||||
|  | const lastName = 'Doe'; | ||||||
|  | describe('TeacherRepository', () => { | ||||||
|  |     let teacherRepository: TeacherRepository; | ||||||
|  | 
 | ||||||
|  |     beforeAll(async () => { | ||||||
|  |         await setupTestApp(); | ||||||
|  |         teacherRepository = getTeacherRepository(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should not return a teacher because username does not exist', async () => { | ||||||
|  |         const teacher = await teacherRepository.findByUsername('test'); | ||||||
|  | 
 | ||||||
|  |         expect(teacher).toBeNull(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return teacher from the datbase', async () => { | ||||||
|  |         const teacher = await teacherRepository.findByUsername('FooFighters'); | ||||||
|  | 
 | ||||||
|  |         expect(teacher).toBeTruthy(); | ||||||
|  |         expect(teacher?.firstName).toBe('Dave'); | ||||||
|  |         expect(teacher?.lastName).toBe('Grohl'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should return the queried teacher after he was added', async () => { | ||||||
|  |         await teacherRepository.insert(new Teacher(username, firstName, lastName)); | ||||||
|  | 
 | ||||||
|  |         const retrievedTeacher = await teacherRepository.findByUsername(username); | ||||||
|  |         expect(retrievedTeacher).toBeTruthy(); | ||||||
|  |         expect(retrievedTeacher?.firstName).toBe(firstName); | ||||||
|  |         expect(retrievedTeacher?.lastName).toBe(lastName); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should no longer return the queried teacher after he was removed again', async () => { | ||||||
|  |         await teacherRepository.deleteByUsername('ZesdeMetaal'); | ||||||
|  | 
 | ||||||
|  |         const retrievedTeacher = await teacherRepository.findByUsername('ZesdeMetaal'); | ||||||
|  |         expect(retrievedTeacher).toBeNull(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | @ -1,7 +1,59 @@ | ||||||
| import { initORM } from '../src/orm.js'; | import { forkEntityManager, initORM } from '../src/orm.js'; | ||||||
| import dotenv from 'dotenv'; | import dotenv from 'dotenv'; | ||||||
|  | import { makeTestStudents } from './test_assets/users/students.testdata.js'; | ||||||
|  | import { makeTestTeachers } from './test_assets/users/teachers.testdata.js'; | ||||||
|  | import { makeTestLearningObjects } from './test_assets/content/learning-objects.testdata.js'; | ||||||
|  | import { makeTestLearningPaths } from './test_assets/content/learning-paths.testdata.js'; | ||||||
|  | import { makeTestClasses } from './test_assets/classes/classes.testdata.js'; | ||||||
|  | import { makeTestAssignemnts } from './test_assets/assignments/assignments.testdata.js'; | ||||||
|  | import { makeTestGroups } from './test_assets/assignments/groups.testdata.js'; | ||||||
|  | import { makeTestTeacherInvitations } from './test_assets/classes/teacher-invitations.testdata.js'; | ||||||
|  | import { makeTestClassJoinRequests } from './test_assets/classes/class-join-requests.testdata.js'; | ||||||
|  | import { makeTestAttachments } from './test_assets/content/attachments.testdata.js'; | ||||||
|  | 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'; | ||||||
| 
 | 
 | ||||||
| export async function setupTestApp() { | export async function setupTestApp() { | ||||||
|     dotenv.config({ path: '.env.test' }); |     dotenv.config({ path: '.env.test' }); | ||||||
|     await initORM(true); |     await initORM(true); | ||||||
|  | 
 | ||||||
|  |     const em = forkEntityManager(); | ||||||
|  | 
 | ||||||
|  |     const students = makeTestStudents(em); | ||||||
|  |     const teachers = makeTestTeachers(em); | ||||||
|  |     const learningObjects = makeTestLearningObjects(em); | ||||||
|  |     const learningPaths = makeTestLearningPaths(em); | ||||||
|  |     const classes = makeTestClasses(em, students, teachers); | ||||||
|  |     const assignments = makeTestAssignemnts(em, classes); | ||||||
|  |     const groups = makeTestGroups(em, students, assignments); | ||||||
|  | 
 | ||||||
|  |     assignments[0].groups = groups.slice(0, 3); | ||||||
|  |     assignments[1].groups = groups.slice(3, 4); | ||||||
|  | 
 | ||||||
|  |     const teacherInvitations = makeTestTeacherInvitations(em, teachers, classes); | ||||||
|  |     const classJoinRequests = makeTestClassJoinRequests(em, students, classes); | ||||||
|  |     const attachments = makeTestAttachments(em, learningObjects); | ||||||
|  | 
 | ||||||
|  |     learningObjects[1].attachments = attachments; | ||||||
|  | 
 | ||||||
|  |     const questions = makeTestQuestions(em, students); | ||||||
|  |     const answers = makeTestAnswers(em, teachers, questions); | ||||||
|  |     const submissions = makeTestSubmissions(em, students, groups); | ||||||
|  | 
 | ||||||
|  |     await em.persistAndFlush([ | ||||||
|  |         ...students, | ||||||
|  |         ...teachers, | ||||||
|  |         ...learningObjects, | ||||||
|  |         ...learningPaths, | ||||||
|  |         ...classes, | ||||||
|  |         ...assignments, | ||||||
|  |         ...groups, | ||||||
|  |         ...teacherInvitations, | ||||||
|  |         ...classJoinRequests, | ||||||
|  |         ...attachments, | ||||||
|  |         ...questions, | ||||||
|  |         ...answers, | ||||||
|  |         ...submissions, | ||||||
|  |     ]); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,38 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Assignment } from '../../../src/entities/assignments/assignment.entity'; | ||||||
|  | import { Class } from '../../../src/entities/classes/class.entity'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | 
 | ||||||
|  | export function makeTestAssignemnts(em: EntityManager<IDatabaseDriver<Connection>>, classes: Array<Class>): Array<Assignment> { | ||||||
|  |     const assignment01 = em.create(Assignment, { | ||||||
|  |         within: classes[0], | ||||||
|  |         id: 1, | ||||||
|  |         title: 'dire straits', | ||||||
|  |         description: 'reading', | ||||||
|  |         learningPathHruid: 'id02', | ||||||
|  |         learningPathLanguage: Language.English, | ||||||
|  |         groups: [], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const assignment02 = em.create(Assignment, { | ||||||
|  |         within: classes[1], | ||||||
|  |         id: 2, | ||||||
|  |         title: 'tool', | ||||||
|  |         description: 'reading', | ||||||
|  |         learningPathHruid: 'id01', | ||||||
|  |         learningPathLanguage: Language.English, | ||||||
|  |         groups: [], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const assignment03 = em.create(Assignment, { | ||||||
|  |         within: classes[0], | ||||||
|  |         id: 3, | ||||||
|  |         title: 'delete', | ||||||
|  |         description: 'will be deleted', | ||||||
|  |         learningPathHruid: 'id02', | ||||||
|  |         learningPathLanguage: Language.English, | ||||||
|  |         groups: [], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [assignment01, assignment02, assignment03]; | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								backend/tests/test_assets/assignments/groups.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								backend/tests/test_assets/assignments/groups.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } 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'; | ||||||
|  | 
 | ||||||
|  | export function makeTestGroups( | ||||||
|  |     em: EntityManager<IDatabaseDriver<Connection>>, | ||||||
|  |     students: Array<Student>, | ||||||
|  |     assignments: Array<Assignment> | ||||||
|  | ): Array<Group> { | ||||||
|  |     const group01 = em.create(Group, { | ||||||
|  |         assignment: assignments[0], | ||||||
|  |         groupNumber: 1, | ||||||
|  |         members: students.slice(0, 2), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const group02 = em.create(Group, { | ||||||
|  |         assignment: assignments[0], | ||||||
|  |         groupNumber: 2, | ||||||
|  |         members: students.slice(2, 4), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const group03 = em.create(Group, { | ||||||
|  |         assignment: assignments[0], | ||||||
|  |         groupNumber: 3, | ||||||
|  |         members: students.slice(4, 6), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const group04 = em.create(Group, { | ||||||
|  |         assignment: assignments[1], | ||||||
|  |         groupNumber: 4, | ||||||
|  |         members: students.slice(3, 4), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [group01, group02, group03, group04]; | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								backend/tests/test_assets/assignments/submission.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								backend/tests/test_assets/assignments/submission.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Submission } from '../../../src/entities/assignments/submission.entity'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { Student } from '../../../src/entities/users/student.entity'; | ||||||
|  | import { Group } from '../../../src/entities/assignments/group.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestSubmissions( | ||||||
|  |     em: EntityManager<IDatabaseDriver<Connection>>, | ||||||
|  |     students: Array<Student>, | ||||||
|  |     groups: Array<Group> | ||||||
|  | ): Array<Submission> { | ||||||
|  |     const submission01 = em.create(Submission, { | ||||||
|  |         learningObjectHruid: 'id03', | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         submissionNumber: 1, | ||||||
|  |         submitter: students[0], | ||||||
|  |         submissionTime: new Date(2025, 2, 20), | ||||||
|  |         onBehalfOf: groups[0], | ||||||
|  |         content: 'sub1', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const submission02 = em.create(Submission, { | ||||||
|  |         learningObjectHruid: 'id03', | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         submissionNumber: 2, | ||||||
|  |         submitter: students[0], | ||||||
|  |         submissionTime: new Date(2025, 2, 25), | ||||||
|  |         onBehalfOf: groups[0], | ||||||
|  |         content: '', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const submission03 = em.create(Submission, { | ||||||
|  |         learningObjectHruid: 'id02', | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         submissionNumber: 1, | ||||||
|  |         submitter: students[0], | ||||||
|  |         submissionTime: new Date(2025, 2, 20), | ||||||
|  |         content: '', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const submission04 = em.create(Submission, { | ||||||
|  |         learningObjectHruid: 'id02', | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         submissionNumber: 2, | ||||||
|  |         submitter: students[0], | ||||||
|  |         submissionTime: new Date(2025, 2, 25), | ||||||
|  |         content: '', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const submission05 = em.create(Submission, { | ||||||
|  |         learningObjectHruid: 'id01', | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         submissionNumber: 1, | ||||||
|  |         submitter: students[1], | ||||||
|  |         submissionTime: new Date(2025, 2, 20), | ||||||
|  |         content: '', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [submission01, submission02, submission03, submission04, submission05]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,36 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { ClassJoinRequest, ClassJoinRequestStatus } from '../../../src/entities/classes/class-join-request.entity'; | ||||||
|  | import { Student } from '../../../src/entities/users/student.entity'; | ||||||
|  | import { Class } from '../../../src/entities/classes/class.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestClassJoinRequests( | ||||||
|  |     em: EntityManager<IDatabaseDriver<Connection>>, | ||||||
|  |     students: Array<Student>, | ||||||
|  |     classes: Array<Class> | ||||||
|  | ): Array<ClassJoinRequest> { | ||||||
|  |     const classJoinRequest01 = em.create(ClassJoinRequest, { | ||||||
|  |         requester: students[4], | ||||||
|  |         class: classes[1], | ||||||
|  |         status: ClassJoinRequestStatus.Open, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const classJoinRequest02 = em.create(ClassJoinRequest, { | ||||||
|  |         requester: students[2], | ||||||
|  |         class: classes[1], | ||||||
|  |         status: ClassJoinRequestStatus.Open, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const classJoinRequest03 = em.create(ClassJoinRequest, { | ||||||
|  |         requester: students[4], | ||||||
|  |         class: classes[2], | ||||||
|  |         status: ClassJoinRequestStatus.Open, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const classJoinRequest04 = em.create(ClassJoinRequest, { | ||||||
|  |         requester: students[3], | ||||||
|  |         class: classes[2], | ||||||
|  |         status: ClassJoinRequestStatus.Open, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [classJoinRequest01, classJoinRequest02, classJoinRequest03, classJoinRequest04]; | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								backend/tests/test_assets/classes/classes.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								backend/tests/test_assets/classes/classes.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } 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'; | ||||||
|  | 
 | ||||||
|  | export function makeTestClasses(em: EntityManager<IDatabaseDriver<Connection>>, students: Array<Student>, teachers: Array<Teacher>): Array<Class> { | ||||||
|  |     const studentsClass01 = students.slice(0, 7); | ||||||
|  |     const teacherClass01: Array<Teacher> = teachers.slice(0, 1); | ||||||
|  | 
 | ||||||
|  |     const class01 = em.create(Class, { | ||||||
|  |         classId: 'id01', | ||||||
|  |         displayName: 'class01', | ||||||
|  |         teachers: teacherClass01, | ||||||
|  |         students: studentsClass01, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const studentsClass02: Array<Student> = students.slice(0, 2).concat(students.slice(3, 4)); | ||||||
|  |     const teacherClass02: Array<Teacher> = teachers.slice(1, 2); | ||||||
|  | 
 | ||||||
|  |     const class02 = em.create(Class, { | ||||||
|  |         classId: 'id02', | ||||||
|  |         displayName: 'class02', | ||||||
|  |         teachers: teacherClass02, | ||||||
|  |         students: studentsClass02, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const studentsClass03: Array<Student> = students.slice(1, 4); | ||||||
|  |     const teacherClass03: Array<Teacher> = teachers.slice(2, 3); | ||||||
|  | 
 | ||||||
|  |     const class03 = em.create(Class, { | ||||||
|  |         classId: 'id03', | ||||||
|  |         displayName: 'class03', | ||||||
|  |         teachers: teacherClass03, | ||||||
|  |         students: studentsClass03, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const studentsClass04: Array<Student> = students.slice(0, 2); | ||||||
|  |     const teacherClass04: Array<Teacher> = teachers.slice(2, 3); | ||||||
|  | 
 | ||||||
|  |     const class04 = em.create(Class, { | ||||||
|  |         classId: 'id04', | ||||||
|  |         displayName: 'class04', | ||||||
|  |         teachers: teacherClass04, | ||||||
|  |         students: studentsClass04, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [class01, class02, class03, class04]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,36 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { TeacherInvitation } from '../../../src/entities/classes/teacher-invitation.entity'; | ||||||
|  | import { Teacher } from '../../../src/entities/users/teacher.entity'; | ||||||
|  | import { Class } from '../../../src/entities/classes/class.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestTeacherInvitations( | ||||||
|  |     em: EntityManager<IDatabaseDriver<Connection>>, | ||||||
|  |     teachers: Array<Teacher>, | ||||||
|  |     classes: Array<Class> | ||||||
|  | ): Array<TeacherInvitation> { | ||||||
|  |     const teacherInvitation01 = em.create(TeacherInvitation, { | ||||||
|  |         sender: teachers[1], | ||||||
|  |         receiver: teachers[0], | ||||||
|  |         class: classes[1], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const teacherInvitation02 = em.create(TeacherInvitation, { | ||||||
|  |         sender: teachers[1], | ||||||
|  |         receiver: teachers[2], | ||||||
|  |         class: classes[1], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const teacherInvitation03 = em.create(TeacherInvitation, { | ||||||
|  |         sender: teachers[2], | ||||||
|  |         receiver: teachers[0], | ||||||
|  |         class: classes[2], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const teacherInvitation04 = em.create(TeacherInvitation, { | ||||||
|  |         sender: teachers[0], | ||||||
|  |         receiver: teachers[1], | ||||||
|  |         class: classes[0], | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [teacherInvitation01, teacherInvitation02, teacherInvitation03, teacherInvitation04]; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								backend/tests/test_assets/content/attachments.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend/tests/test_assets/content/attachments.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Attachment } from '../../../src/entities/content/attachment.entity'; | ||||||
|  | import { LearningObject } from '../../../src/entities/content/learning-object.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestAttachments(em: EntityManager<IDatabaseDriver<Connection>>, learningObjects: Array<LearningObject>): Array<Attachment> { | ||||||
|  |     const attachment01 = em.create(Attachment, { | ||||||
|  |         learningObject: learningObjects[1], | ||||||
|  |         name: 'attachment01', | ||||||
|  |         mimeType: '', | ||||||
|  |         content: Buffer.from(''), | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [attachment01]; | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								backend/tests/test_assets/content/learning-objects.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								backend/tests/test_assets/content/learning-objects.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { LearningObject, ReturnValue } from '../../../src/entities/content/learning-object.entity'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { DwengoContentType } from '../../../src/services/learning-objects/processing/content-type'; | ||||||
|  | 
 | ||||||
|  | export function makeTestLearningObjects(em: EntityManager<IDatabaseDriver<Connection>>): Array<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 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 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 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]; | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								backend/tests/test_assets/content/learning-paths.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								backend/tests/test_assets/content/learning-paths.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { LearningPath } from '../../../src/entities/content/learning-path.entity'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity'; | ||||||
|  | import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestLearningPaths(em: EntityManager<IDatabaseDriver<Connection>>): Array<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(); | ||||||
|  | 
 | ||||||
|  |     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(); | ||||||
|  | 
 | ||||||
|  |     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: Array<LearningPathNode> = [ | ||||||
|  |         // LearningPathNode01,
 | ||||||
|  |         // LearningPathNode02,
 | ||||||
|  |     ]; | ||||||
|  |     const learningPath01 = em.create(LearningPath, { | ||||||
|  |         hruid: 'id01', | ||||||
|  |         language: Language.English, | ||||||
|  |         admins: [], | ||||||
|  |         title: 'repertoire Tool', | ||||||
|  |         description: 'all about Tool', | ||||||
|  |         image: '', | ||||||
|  |         nodes: nodes01, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const nodes02: Array<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: '', | ||||||
|  |         nodes: nodes02, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [learningPath01, learningPath02]; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								backend/tests/test_assets/questions/answers.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								backend/tests/test_assets/questions/answers.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Answer } from '../../../src/entities/questions/answer.entity'; | ||||||
|  | import { Teacher } from '../../../src/entities/users/teacher.entity'; | ||||||
|  | import { Question } from '../../../src/entities/questions/question.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestAnswers(em: EntityManager<IDatabaseDriver<Connection>>, teachers: Array<Teacher>, questions: Array<Question>): Array<Answer> { | ||||||
|  |     const answer01 = em.create(Answer, { | ||||||
|  |         author: teachers[0], | ||||||
|  |         toQuestion: questions[1], | ||||||
|  |         sequenceNumber: 1, | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'answer', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const answer02 = em.create(Answer, { | ||||||
|  |         author: teachers[0], | ||||||
|  |         toQuestion: questions[1], | ||||||
|  |         sequenceNumber: 2, | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'answer2', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const answer03 = em.create(Answer, { | ||||||
|  |         author: teachers[1], | ||||||
|  |         toQuestion: questions[3], | ||||||
|  |         sequenceNumber: 1, | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'answer3', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [answer01, answer02, answer03]; | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								backend/tests/test_assets/questions/questions.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								backend/tests/test_assets/questions/questions.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Question } from '../../../src/entities/questions/question.entity'; | ||||||
|  | import { Language } from '../../../src/entities/content/language'; | ||||||
|  | import { Student } from '../../../src/entities/users/student.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestQuestions(em: EntityManager<IDatabaseDriver<Connection>>, students: Array<Student>): Array<Question> { | ||||||
|  |     const question01 = em.create(Question, { | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         learningObjectHruid: 'id05', | ||||||
|  |         sequenceNumber: 1, | ||||||
|  |         author: students[0], | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'question', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const question02 = em.create(Question, { | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         learningObjectHruid: 'id05', | ||||||
|  |         sequenceNumber: 2, | ||||||
|  |         author: students[2], | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'question', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const question03 = em.create(Question, { | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         learningObjectHruid: 'id04', | ||||||
|  |         sequenceNumber: 1, | ||||||
|  |         author: students[0], | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'question', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const question04 = em.create(Question, { | ||||||
|  |         learningObjectLanguage: Language.English, | ||||||
|  |         learningObjectVersion: '1', | ||||||
|  |         learningObjectHruid: 'id01', | ||||||
|  |         sequenceNumber: 1, | ||||||
|  |         author: students[1], | ||||||
|  |         timestamp: new Date(), | ||||||
|  |         content: 'question', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [question01, question02, question03, question04]; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								backend/tests/test_assets/users/students.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								backend/tests/test_assets/users/students.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | import { Student } from '../../../src/entities/users/student.entity'; | ||||||
|  | 
 | ||||||
|  | export function makeTestStudents(em: EntityManager<IDatabaseDriver<Connection>>): Array<Student> { | ||||||
|  |     const student01 = em.create(Student, { | ||||||
|  |         username: 'Noordkaap', | ||||||
|  |         firstName: 'Stijn', | ||||||
|  |         lastName: 'Meuris', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const student02 = em.create(Student, { | ||||||
|  |         username: 'DireStraits', | ||||||
|  |         firstName: 'Mark', | ||||||
|  |         lastName: 'Knopfler', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const student03 = em.create(Student, { | ||||||
|  |         username: 'Tool', | ||||||
|  |         firstName: 'Maynard', | ||||||
|  |         lastName: 'Keenan', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const student04 = em.create(Student, { | ||||||
|  |         username: 'SmashingPumpkins', | ||||||
|  |         firstName: 'Billy', | ||||||
|  |         lastName: 'Corgan', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const student05 = em.create(Student, { | ||||||
|  |         username: 'PinkFloyd', | ||||||
|  |         firstName: 'David', | ||||||
|  |         lastName: 'Gilmoure', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const student06 = em.create(Student, { | ||||||
|  |         username: 'TheDoors', | ||||||
|  |         firstName: 'Jim', | ||||||
|  |         lastName: 'Morisson', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // Do not use for any tests, gets deleted in a unit test
 | ||||||
|  |     const student07 = em.create(Student, { | ||||||
|  |         username: 'Nirvana', | ||||||
|  |         firstName: 'Kurt', | ||||||
|  |         lastName: 'Cobain', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [student01, student02, student03, student04, student05, student06, student07]; | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								backend/tests/test_assets/users/teachers.testdata.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								backend/tests/test_assets/users/teachers.testdata.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | import { Teacher } from '../../../src/entities/users/teacher.entity'; | ||||||
|  | import { Connection, EntityManager, IDatabaseDriver } from '@mikro-orm/core'; | ||||||
|  | 
 | ||||||
|  | export function makeTestTeachers(em: EntityManager<IDatabaseDriver<Connection>>): Array<Teacher> { | ||||||
|  |     const teacher01 = em.create(Teacher, { | ||||||
|  |         username: 'FooFighters', | ||||||
|  |         firstName: 'Dave', | ||||||
|  |         lastName: 'Grohl', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const teacher02 = em.create(Teacher, { | ||||||
|  |         username: 'LimpBizkit', | ||||||
|  |         firstName: 'Fred', | ||||||
|  |         lastName: 'Durst', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const 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, { | ||||||
|  |         username: 'ZesdeMetaal', | ||||||
|  |         firstName: 'Wannes', | ||||||
|  |         lastName: 'Cappelle', | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return [teacher01, teacher02, teacher03, teacher04]; | ||||||
|  | } | ||||||
|  | @ -2,10 +2,10 @@ | ||||||
|     import { ref } from "vue"; |     import { ref } from "vue"; | ||||||
|     import { useRoute } from "vue-router"; |     import { useRoute } from "vue-router"; | ||||||
|     import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg"; |     import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg"; | ||||||
|     import {useI18n} from "vue-i18n"; |     import { useI18n } from "vue-i18n"; | ||||||
| 
 | 
 | ||||||
|     const route = useRoute(); |     const route = useRoute(); | ||||||
|     const { t, locale } = useI18n() |     const { t, locale } = useI18n(); | ||||||
| 
 | 
 | ||||||
|     // Instantiate variables to use in html to render right |     // Instantiate variables to use in html to render right | ||||||
|     // Links and content dependent on the role (student or teacher) |     // Links and content dependent on the role (student or teacher) | ||||||
|  | @ -30,7 +30,7 @@ | ||||||
|     // Logic to change the language of the website to the selected language |     // Logic to change the language of the website to the selected language | ||||||
|     const changeLanguage = (langCode: string) => { |     const changeLanguage = (langCode: string) => { | ||||||
|         locale.value = langCode; |         locale.value = langCode; | ||||||
|         localStorage.setItem('user-lang', langCode); |         localStorage.setItem("user-lang", langCode); | ||||||
|         console.log(langCode); |         console.log(langCode); | ||||||
|     }; |     }; | ||||||
| </script> | </script> | ||||||
|  | @ -59,22 +59,22 @@ | ||||||
|                             :to="`/${role}/${userId}/assignment`" |                             :to="`/${role}/${userId}/assignment`" | ||||||
|                             class="menu_item" |                             class="menu_item" | ||||||
|                         > |                         > | ||||||
|                             {{ t('assignments') }} |                             {{ t("assignments") }} | ||||||
|                         </router-link> |                         </router-link> | ||||||
|                     </li> |                     </li> | ||||||
|                     <li> |                     <li> | ||||||
|                         <router-link |                         <router-link | ||||||
|                             :to="`/${role}/${userId}/class`" |                             :to="`/${role}/${userId}/class`" | ||||||
|                             class="menu_item" |                             class="menu_item" | ||||||
|                             >{{ t('classes') }}</router-link |                             >{{ t("classes") }}</router-link | ||||||
|                         > |                         > | ||||||
|                     </li> |                     </li> | ||||||
|                     <li> |                     <li> | ||||||
|                         <router-link |                         <router-link | ||||||
|                             :to="`/${role}/${userId}/discussion`" |                             :to="`/${role}/${userId}/discussion`" | ||||||
|                             class="menu_item" |                             class="menu_item" | ||||||
|                             >{{ t('discussions') }} </router-link |                             >{{ t("discussions") }} | ||||||
|                         > |                         </router-link> | ||||||
|                     </li> |                     </li> | ||||||
|                     <li> |                     <li> | ||||||
|                         <v-menu open-on-hover> |                         <v-menu open-on-hover> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { createI18n } from 'vue-i18n'; | import { createI18n } from "vue-i18n"; | ||||||
| 
 | 
 | ||||||
| // Import translations
 | // Import translations
 | ||||||
| import en from "@/i18n/locale/en.json"; | import en from "@/i18n/locale/en.json"; | ||||||
|  | @ -6,11 +6,11 @@ import nl from "@/i18n/locale/nl.json"; | ||||||
| import fr from "@/i18n/locale/fr.json"; | import fr from "@/i18n/locale/fr.json"; | ||||||
| import de from "@/i18n/locale/de.json"; | import de from "@/i18n/locale/de.json"; | ||||||
| 
 | 
 | ||||||
| const savedLocale = localStorage.getItem('user-lang') || 'en'; | const savedLocale = localStorage.getItem("user-lang") || "en"; | ||||||
| 
 | 
 | ||||||
| const i18n = createI18n({ | const i18n = createI18n({ | ||||||
|     locale: savedLocale, |     locale: savedLocale, | ||||||
|     fallbackLocale: 'en', |     fallbackLocale: "en", | ||||||
|     messages: { |     messages: { | ||||||
|         en: en, |         en: en, | ||||||
|         nl: nl, |         nl: nl, | ||||||
|  |  | ||||||
|  | @ -1,8 +1,8 @@ | ||||||
| import {createApp} from "vue"; | import { createApp } from "vue"; | ||||||
| 
 | 
 | ||||||
| // Vuetify
 | // Vuetify
 | ||||||
| import "vuetify/styles"; | import "vuetify/styles"; | ||||||
| import {createVuetify} from "vuetify"; | import { createVuetify } from "vuetify"; | ||||||
| import * as components from "vuetify/components"; | import * as components from "vuetify/components"; | ||||||
| import * as directives from "vuetify/directives"; | import * as directives from "vuetify/directives"; | ||||||
| import i18n from "./i18n/i18n.ts"; | import i18n from "./i18n/i18n.ts"; | ||||||
|  | @ -11,7 +11,6 @@ import i18n from "./i18n/i18n.ts"; | ||||||
| import App from "./App.vue"; | import App from "./App.vue"; | ||||||
| import router from "./router"; | import router from "./router"; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| const app = createApp(App); | const app = createApp(App); | ||||||
| 
 | 
 | ||||||
| app.use(router); | app.use(router); | ||||||
|  |  | ||||||
							
								
								
									
										4104
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										4104
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Reference in a new issue
	
	 Laure Jablonski
						Laure Jablonski