Merge pull request #168 from SELab-2/github-actions/coverage
github actions: Test Coverage Reports
This commit is contained in:
		
						commit
						e604aab8e6
					
				
					 17 changed files with 495 additions and 12 deletions
				
			
		
							
								
								
									
										20
									
								
								.github/workflows/backend-testing.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/backend-testing.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -29,6 +29,12 @@ jobs: | ||||||
|     if: '! github.event.pull_request.draft' |     if: '! github.event.pull_request.draft' | ||||||
|     runs-on: [self-hosted, Linux, X64] |     runs-on: [self-hosted, Linux, X64] | ||||||
| 
 | 
 | ||||||
|  |     permissions: | ||||||
|  |       # Required to checkout the code | ||||||
|  |       contents: read | ||||||
|  |       # Required to put a comment into the pull-request | ||||||
|  |       pull-requests: write | ||||||
|  | 
 | ||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         node-version: [22.x] |         node-version: [22.x] | ||||||
|  | @ -42,4 +48,16 @@ jobs: | ||||||
|         node-version: ${{ matrix.node-version }} |         node-version: ${{ matrix.node-version }} | ||||||
|         cache: 'npm' |         cache: 'npm' | ||||||
|     - run: npm ci |     - run: npm ci | ||||||
|     - run: npm run test:unit -w backend |     - run: npm run build | ||||||
|  |     - run: npm run test:coverage -w backend | ||||||
|  |     - name: 'Report Backend Coverage' | ||||||
|  |       # Set if: always() to also generate the report if tests are failing | ||||||
|  |       # Only works if you set `reportOnFailure: true` in your vite config as specified above | ||||||
|  |       if: always()  | ||||||
|  |       uses:  davelosert/vitest-coverage-report-action@v2 | ||||||
|  |       with: | ||||||
|  |         name: 'Backend' | ||||||
|  |         json-summary-path: './backend/coverage/coverage-summary.json' | ||||||
|  |         json-final-path: './backend/coverage/coverage-final.json' | ||||||
|  |         vite-config-path: './backend/vitest.config.ts' | ||||||
|  |         file-coverage-mode: all | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								.github/workflows/frontend-testing.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/frontend-testing.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -38,6 +38,12 @@ jobs: | ||||||
|     if: '! github.event.pull_request.draft' |     if: '! github.event.pull_request.draft' | ||||||
|     runs-on: [self-hosted, Linux, X64] |     runs-on: [self-hosted, Linux, X64] | ||||||
| 
 | 
 | ||||||
|  |     permissions: | ||||||
|  |       # Required to checkout the code | ||||||
|  |       contents: read | ||||||
|  |       # Required to put a comment into the pull-request | ||||||
|  |       pull-requests: write | ||||||
|  | 
 | ||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         node-version: [22.x] |         node-version: [22.x] | ||||||
|  | @ -51,4 +57,16 @@ jobs: | ||||||
|         node-version: ${{ matrix.node-version }} |         node-version: ${{ matrix.node-version }} | ||||||
|         cache: 'npm' |         cache: 'npm' | ||||||
|     - run: npm ci |     - run: npm ci | ||||||
|     - run: npm run test:unit -w frontend |     - run: npm run build | ||||||
|  |     - run: npm run test:coverage -w frontend | ||||||
|  |     - name: 'Report Frontend Coverage' | ||||||
|  |       # Set if: always() to also generate the report if tests are failing | ||||||
|  |       # Only works if you set `reportOnFailure: true` in your vite config as specified above | ||||||
|  |       if: always()  | ||||||
|  |       uses:  davelosert/vitest-coverage-report-action@v2 | ||||||
|  |       with: | ||||||
|  |         name: 'Frontend' | ||||||
|  |         json-summary-path: './frontend/coverage/coverage-summary.json' | ||||||
|  |         json-final-path: './frontend/coverage/coverage-final.json' | ||||||
|  |         vite-config-path: './frontend/vitest.config.ts' | ||||||
|  |         file-coverage-mode: all | ||||||
|  |  | ||||||
|  | @ -14,7 +14,8 @@ | ||||||
|         "format-check": "prettier --check src/", |         "format-check": "prettier --check src/", | ||||||
|         "lint": "eslint . --fix", |         "lint": "eslint . --fix", | ||||||
|         "pretest:unit": "tsx ../docs/api/generate.ts && npm run build", |         "pretest:unit": "tsx ../docs/api/generate.ts && npm run build", | ||||||
|         "test:unit": "vitest --run" |         "test:unit": "vitest --run", | ||||||
|  |         "test:coverage": "vitest --run --coverage.enabled true" | ||||||
|     }, |     }, | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|         "@mikro-orm/core": "6.4.12", |         "@mikro-orm/core": "6.4.12", | ||||||
|  |  | ||||||
|  | @ -5,5 +5,17 @@ export default defineConfig({ | ||||||
|         environment: 'node', |         environment: 'node', | ||||||
|         globals: true, |         globals: true, | ||||||
|         testTimeout: 100000, |         testTimeout: 100000, | ||||||
|  |         coverage: { | ||||||
|  |             reporter: ['text', 'json-summary', 'json'], | ||||||
|  |             // If you want a coverage reports even if your tests are failing, include the reportOnFailure option
 | ||||||
|  |             reportOnFailure: true, | ||||||
|  |             exclude: ['**/*config*', '**/tests/**', 'src/*.ts', '**/dist/**', '**/node_modules/**', 'src/logging/**', 'src/routes/**'], | ||||||
|  |             thresholds: { | ||||||
|  |                 lines: 50, | ||||||
|  |                 branches: 50, | ||||||
|  |                 functions: 50, | ||||||
|  |                 statements: 50, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|     }, |     }, | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
|         "format-check": "prettier --check src/", |         "format-check": "prettier --check src/", | ||||||
|         "lint": "eslint . --fix", |         "lint": "eslint . --fix", | ||||||
|         "test:unit": "vitest --run", |         "test:unit": "vitest --run", | ||||||
|  |         "test:coverage": "vitest --run --coverage.enabled true", | ||||||
|         "test:e2e": "playwright test" |         "test:e2e": "playwright test" | ||||||
|     }, |     }, | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|  |  | ||||||
							
								
								
									
										64
									
								
								frontend/tests/controllers/assignments-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								frontend/tests/controllers/assignments-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | ||||||
|  | import { describe, it, expect, beforeEach } from "vitest"; | ||||||
|  | import { AssignmentController } from "../../src/controllers/assignments"; | ||||||
|  | 
 | ||||||
|  | describe("AssignmentController Tests", () => { | ||||||
|  |     let controller: AssignmentController; | ||||||
|  | 
 | ||||||
|  |     beforeEach(() => { | ||||||
|  |         controller = new AssignmentController("8764b861-90a6-42e5-9732-c0d9eb2f55f9"); // Example class ID
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch all assignments", async () => { | ||||||
|  |         const result = await controller.getAll(true); | ||||||
|  |         expect(result).toHaveProperty("assignments"); | ||||||
|  |         expect(Array.isArray(result.assignments)).toBe(true); | ||||||
|  |         expect(result.assignments.length).toBeGreaterThan(0); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch an assignment by number", async () => { | ||||||
|  |         const assignmentNumber = 21000; // Example assignment ID
 | ||||||
|  |         const result = await controller.getByNumber(assignmentNumber); | ||||||
|  |         expect(result).toHaveProperty("assignment"); | ||||||
|  |         expect(result.assignment).toHaveProperty("id", assignmentNumber); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should update an existing assignment", async () => { | ||||||
|  |         const assignmentNumber = 21000; | ||||||
|  |         const updatedData = { title: "Updated Assignment Title" }; | ||||||
|  |         const result = await controller.updateAssignment(assignmentNumber, updatedData); | ||||||
|  |         expect(result).toHaveProperty("assignment"); | ||||||
|  |         expect(result.assignment).toHaveProperty("id", assignmentNumber); | ||||||
|  |         expect(result.assignment).toHaveProperty("title", updatedData.title); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch submissions for an assignment", async () => { | ||||||
|  |         const assignmentNumber = 21000; | ||||||
|  |         const result = await controller.getSubmissions(assignmentNumber, true); | ||||||
|  |         expect(result).toHaveProperty("submissions"); | ||||||
|  |         expect(Array.isArray(result.submissions)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch questions for an assignment", async () => { | ||||||
|  |         const assignmentNumber = 21000; | ||||||
|  |         const result = await controller.getQuestions(assignmentNumber, true); | ||||||
|  |         expect(result).toHaveProperty("questions"); | ||||||
|  |         expect(Array.isArray(result.questions)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch groups for an assignment", async () => { | ||||||
|  |         const assignmentNumber = 21000; | ||||||
|  |         const result = await controller.getGroups(assignmentNumber, true); | ||||||
|  |         expect(result).toHaveProperty("groups"); | ||||||
|  |         expect(Array.isArray(result.groups)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should handle fetching a non-existent assignment", async () => { | ||||||
|  |         const assignmentNumber = 99999; // Non-existent assignment ID
 | ||||||
|  |         await expect(controller.getByNumber(assignmentNumber)).rejects.toThrow(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should handle deleting a non-existent assignment", async () => { | ||||||
|  |         const assignmentNumber = 99999; // Non-existent assignment ID
 | ||||||
|  |         await expect(controller.deleteAssignment(assignmentNumber)).rejects.toThrow(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										10
									
								
								frontend/tests/controllers/classes-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								frontend/tests/controllers/classes-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | import { describe, expect, it } from "vitest"; | ||||||
|  | import { ClassController } from "../../src/controllers/classes"; | ||||||
|  | 
 | ||||||
|  | describe("Test controller classes", () => { | ||||||
|  |     it("Get classes", async () => { | ||||||
|  |         const controller = new ClassController(); | ||||||
|  |         const data = await controller.getAll(true); | ||||||
|  |         expect(data.classes).to.have.length.greaterThan(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										13
									
								
								frontend/tests/controllers/groups.controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								frontend/tests/controllers/groups.controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | import { describe, expect, it } from "vitest"; | ||||||
|  | import { GroupController } from "../../src/controllers/groups"; | ||||||
|  | 
 | ||||||
|  | describe("Test controller groups", () => { | ||||||
|  |     it("Get groups", async () => { | ||||||
|  |         const classId = "8764b861-90a6-42e5-9732-c0d9eb2f55f9"; | ||||||
|  |         const assignmentNumber = 21000; | ||||||
|  | 
 | ||||||
|  |         const controller = new GroupController(classId, assignmentNumber); | ||||||
|  |         const data = await controller.getAll(true); | ||||||
|  |         expect(data.groups).to.have.length.greaterThan(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										21
									
								
								frontend/tests/controllers/learning-paths-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								frontend/tests/controllers/learning-paths-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | import { beforeEach, describe, expect, it } from "vitest"; | ||||||
|  | import { LearningPathController } from "../../src/controllers/learning-paths"; | ||||||
|  | import { Language } from "../../src/data-objects/language"; | ||||||
|  | 
 | ||||||
|  | describe("Test controller learning paths", () => { | ||||||
|  |     let controller: LearningPathController; | ||||||
|  | 
 | ||||||
|  |     beforeEach(async () => { | ||||||
|  |         controller = new LearningPathController(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Can search for learning paths", async () => { | ||||||
|  |         const data = await controller.search("kiks", Language.Dutch); | ||||||
|  |         expect(data).to.have.length.greaterThan(0); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Can get learning path by id", async () => { | ||||||
|  |         const data = await controller.getAllByTheme("kiks"); | ||||||
|  |         expect(data).to.have.length.greaterThan(0); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | @ -1,19 +1,39 @@ | ||||||
| import { StudentController } from "../../src/controllers/students"; | import { StudentController } from "../../src/controllers/students"; | ||||||
| import { expect, it, describe, afterAll, beforeAll } from "vitest"; | import { beforeEach, describe, expect, it, test } from "vitest"; | ||||||
| import { setup, teardown } from "../setup-backend.js"; |  | ||||||
| 
 | 
 | ||||||
| describe("Test controller students", () => { | describe("Test controller students", () => { | ||||||
|     beforeAll(async () => { |     let controller: StudentController; | ||||||
|         await setup(); |  | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     afterAll(async () => { |     beforeEach(async () => { | ||||||
|         await teardown(); |         controller = new StudentController(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     it("Get students", async () => { |     it("Get students", async () => { | ||||||
|         const controller = new StudentController(); |  | ||||||
|         const data = await controller.getAll(true); |         const data = await controller.getAll(true); | ||||||
|         expect(data.students).to.have.length.greaterThan(0); |         expect(data.students).to.have.length.greaterThan(0); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get student by username", async () => { | ||||||
|  |         const username = "testleerling1"; | ||||||
|  |         const data = await controller.getByUsername(username); | ||||||
|  |         expect(data.student.username).to.equal(username); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const controller = new StudentController(); | ||||||
|  | 
 | ||||||
|  | test.each([ | ||||||
|  |     { username: "Noordkaap", firstName: "Stijn", lastName: "Meuris" }, | ||||||
|  |     { username: "DireStraits", firstName: "Mark", lastName: "Knopfler" }, | ||||||
|  |     { username: "Tool", firstName: "Maynard", lastName: "Keenan" }, | ||||||
|  |     { username: "SmashingPumpkins", firstName: "Billy", lastName: "Corgan" }, | ||||||
|  |     { username: "PinkFloyd", firstName: "David", lastName: "Gilmoure" }, | ||||||
|  |     { username: "TheDoors", firstName: "Jim", lastName: "Morisson" }, | ||||||
|  |     // ⚠️ Deze mag niet gebruikt worden in elke test!
 | ||||||
|  |     { username: "Nirvana", firstName: "Kurt", lastName: "Cobain" }, | ||||||
|  |     // Makes sure when logged in as leerling1, there exists a corresponding user
 | ||||||
|  |     { username: "testleerling1", firstName: "Gerald", lastName: "Schmittinger" }, | ||||||
|  | ])("Get classes of student", async (student) => { | ||||||
|  |     const data = await controller.getClasses(student.username, true); | ||||||
|  |     expect(data.classes).to.have.length.greaterThan(0); | ||||||
| }); | }); | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								frontend/tests/controllers/submissions-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								frontend/tests/controllers/submissions-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | import { describe, expect, it } from "vitest"; | ||||||
|  | import { SubmissionController } from "../../src/controllers/submissions"; | ||||||
|  | import { Language } from "../../src/data-objects/language"; | ||||||
|  | 
 | ||||||
|  | describe("Test controller submissions", () => { | ||||||
|  |     it("Get submission by number", async () => { | ||||||
|  |         const hruid = "id03"; | ||||||
|  |         const classId = "8764b861-90a6-42e5-9732-c0d9eb2f55f9"; | ||||||
|  |         const controller = new SubmissionController(hruid); | ||||||
|  | 
 | ||||||
|  |         const data = await controller.getByNumber(Language.English, 1, classId, 1, 1, 1); | ||||||
|  | 
 | ||||||
|  |         expect(data.submission).to.have.property("submissionNumber"); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										53
									
								
								frontend/tests/controllers/teacher-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								frontend/tests/controllers/teacher-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | ||||||
|  | import { beforeEach, describe, expect, it } from "vitest"; | ||||||
|  | import { TeacherController } from "../../src/controllers/teachers"; | ||||||
|  | 
 | ||||||
|  | describe("Test controller teachers", () => { | ||||||
|  |     let controller: TeacherController; | ||||||
|  | 
 | ||||||
|  |     beforeEach(async () => { | ||||||
|  |         controller = new TeacherController(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get all teachers", async () => { | ||||||
|  |         const data = await controller.getAll(true); | ||||||
|  |         expect(data.teachers).to.have.length.greaterThan(0); | ||||||
|  |         expect(data.teachers[0]).to.have.property("username"); | ||||||
|  |         expect(data.teachers[0]).to.have.property("firstName"); | ||||||
|  |         expect(data.teachers[0]).to.have.property("lastName"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get teacher by username", async () => { | ||||||
|  |         const username = "testleerkracht1"; | ||||||
|  |         const data = await controller.getByUsername(username); | ||||||
|  |         expect(data.teacher.username).to.equal(username); | ||||||
|  |         expect(data.teacher).to.have.property("firstName"); | ||||||
|  |         expect(data.teacher).to.have.property("lastName"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get teacher by non-existent username", async () => { | ||||||
|  |         const username = "nonexistentuser"; | ||||||
|  |         await expect(controller.getByUsername(username)).rejects.toThrow(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Handle deletion of non-existent teacher", async () => { | ||||||
|  |         const username = "nonexistentuser"; | ||||||
|  |         await expect(controller.deleteTeacher(username)).rejects.toThrow(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get classes for a teacher", async () => { | ||||||
|  |         const username = "testleerkracht1"; | ||||||
|  |         const data = await controller.getClasses(username, true); | ||||||
|  |         expect(data.classes).to.have.length.greaterThan(0); | ||||||
|  |         expect(data.classes[0]).to.have.property("id"); | ||||||
|  |         expect(data.classes[0]).to.have.property("displayName"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("Get students for a teacher", async () => { | ||||||
|  |         const username = "testleerkracht1"; | ||||||
|  |         const data = await controller.getStudents(username, true); | ||||||
|  |         expect(data.students).to.have.length.greaterThan(0); | ||||||
|  |         expect(data.students[0]).to.have.property("username"); | ||||||
|  |         expect(data.students[0]).to.have.property("firstName"); | ||||||
|  |         expect(data.students[0]).to.have.property("lastName"); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										48
									
								
								frontend/tests/controllers/theme-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								frontend/tests/controllers/theme-controller.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | import { describe, it, expect, beforeEach } from "vitest"; | ||||||
|  | import { ThemeController } from "../../src/controllers/themes"; | ||||||
|  | 
 | ||||||
|  | describe("ThemeController Tests", () => { | ||||||
|  |     let controller: ThemeController; | ||||||
|  | 
 | ||||||
|  |     beforeEach(() => { | ||||||
|  |         controller = new ThemeController(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch all themes", async () => { | ||||||
|  |         const result = await controller.getAll(); | ||||||
|  |         expect(Array.isArray(result)).toBe(true); | ||||||
|  |         expect(result.length).toBeGreaterThan(0); | ||||||
|  |         expect(result[0]).toHaveProperty("key"); | ||||||
|  |         expect(result[0]).toHaveProperty("title"); | ||||||
|  |         expect(result[0]).toHaveProperty("description"); | ||||||
|  |         expect(result[0]).toHaveProperty("image"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch all themes filtered by language", async () => { | ||||||
|  |         const language = "en"; | ||||||
|  |         const result = await controller.getAll(language); | ||||||
|  |         expect(Array.isArray(result)).toBe(true); | ||||||
|  |         expect(result.length).toBeGreaterThan(0); | ||||||
|  |         result.forEach((theme) => { | ||||||
|  |             expect(theme).toHaveProperty("key"); | ||||||
|  |             expect(theme).toHaveProperty("title"); | ||||||
|  |             expect(theme).toHaveProperty("description"); | ||||||
|  |             expect(theme).toHaveProperty("image"); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should fetch HRUIDs by theme key", async () => { | ||||||
|  |         const themeKey = "kiks"; | ||||||
|  |         const result = await controller.getHruidsByKey(themeKey); | ||||||
|  |         expect(Array.isArray(result)).toBe(true); | ||||||
|  |         expect(result.length).toBeGreaterThan(0); | ||||||
|  |         result.forEach((hruid) => { | ||||||
|  |             expect(typeof hruid).toBe("string"); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should handle fetching HRUIDs for a non-existent theme key", async () => { | ||||||
|  |         const themeKey = "nonexistent"; | ||||||
|  |         await expect(controller.getHruidsByKey(themeKey)).rejects.toThrow(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										82
									
								
								frontend/tests/utils/assingment-rules.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								frontend/tests/utils/assingment-rules.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | ||||||
|  | import { describe, expect, it } from "vitest"; | ||||||
|  | import { | ||||||
|  |     assignmentTitleRules, | ||||||
|  |     classRules, | ||||||
|  |     deadlineRules, | ||||||
|  |     descriptionRules, | ||||||
|  |     learningPathRules, | ||||||
|  | } from "../../src/utils/assignment-rules"; | ||||||
|  | 
 | ||||||
|  | describe("Validation Rules", () => { | ||||||
|  |     describe("assignmentTitleRules", () => { | ||||||
|  |         it("should return true for a valid title", () => { | ||||||
|  |             const result = assignmentTitleRules[0]("Valid Title"); | ||||||
|  |             expect(result).toBe(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an empty title", () => { | ||||||
|  |             const result = assignmentTitleRules[0](""); | ||||||
|  |             expect(result).toBe("Title cannot be empty."); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe("learningPathRules", () => { | ||||||
|  |         it("should return true for a valid learning path", () => { | ||||||
|  |             const result = learningPathRules[0]({ hruid: "123", title: "Path Title" }); | ||||||
|  |             expect(result).toBe(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an invalid learning path", () => { | ||||||
|  |             const result = learningPathRules[0]({ hruid: "", title: "" }); | ||||||
|  |             expect(result).toBe("You must select a learning path."); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe("classRules", () => { | ||||||
|  |         it("should return true for a valid class", () => { | ||||||
|  |             const result = classRules[0]("Class 1"); | ||||||
|  |             expect(result).toBe(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an empty class", () => { | ||||||
|  |             const result = classRules[0](""); | ||||||
|  |             expect(result).toBe("You must select at least one class."); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe("deadlineRules", () => { | ||||||
|  |         it("should return true for a valid future deadline", () => { | ||||||
|  |             const futureDate = new Date(Date.now() + 1000 * 60 * 60).toISOString(); | ||||||
|  |             const result = deadlineRules[0](futureDate); | ||||||
|  |             expect(result).toBe(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for a past deadline", () => { | ||||||
|  |             const pastDate = new Date(Date.now() - 1000 * 60 * 60).toISOString(); | ||||||
|  |             const result = deadlineRules[0](pastDate); | ||||||
|  |             expect(result).toBe("The deadline must be in the future."); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an invalid date", () => { | ||||||
|  |             const result = deadlineRules[0]("invalid-date"); | ||||||
|  |             expect(result).toBe("Invalid date or time."); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an empty deadline", () => { | ||||||
|  |             const result = deadlineRules[0](""); | ||||||
|  |             expect(result).toBe("You must set a deadline."); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe("descriptionRules", () => { | ||||||
|  |         it("should return true for a valid description", () => { | ||||||
|  |             const result = descriptionRules[0]("This is a valid description."); | ||||||
|  |             expect(result).toBe(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return an error message for an empty description", () => { | ||||||
|  |             const result = descriptionRules[0](""); | ||||||
|  |             expect(result).toBe("Description cannot be empty."); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
							
								
								
									
										68
									
								
								frontend/tests/utils/deep-equals.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								frontend/tests/utils/deep-equals.test.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | ||||||
|  | import { describe, it, expect } from "vitest"; | ||||||
|  | import { deepEquals } from "../../src/utils/deep-equals"; | ||||||
|  | 
 | ||||||
|  | describe("deepEquals", () => { | ||||||
|  |     it("should return true for identical primitive values", () => { | ||||||
|  |         expect(deepEquals(1, 1)).toBe(true); | ||||||
|  |         expect(deepEquals("test", "test")).toBe(true); | ||||||
|  |         expect(deepEquals(true, true)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for different primitive values", () => { | ||||||
|  |         expect(deepEquals(1, 2)).toBe(false); | ||||||
|  |         expect(deepEquals("test", "other")).toBe(false); | ||||||
|  |         expect(deepEquals(true, false)).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return true for identical objects", () => { | ||||||
|  |         const obj1 = { a: 1, b: { c: 2 } }; | ||||||
|  |         const obj2 = { a: 1, b: { c: 2 } }; | ||||||
|  |         expect(deepEquals(obj1, obj2)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for different objects", () => { | ||||||
|  |         const obj1 = { a: 1, b: { c: 2 } }; | ||||||
|  |         const obj2 = { a: 1, b: { c: 3 } }; | ||||||
|  |         expect(deepEquals(obj1, obj2)).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return true for identical arrays", () => { | ||||||
|  |         const arr1 = [1, 2, [3, 4]]; | ||||||
|  |         const arr2 = [1, 2, [3, 4]]; | ||||||
|  |         expect(deepEquals(arr1, arr2)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for different arrays", () => { | ||||||
|  |         const arr1 = [1, 2, [3, 4]]; | ||||||
|  |         const arr2 = [1, 2, [3, 5]]; | ||||||
|  |         expect(deepEquals(arr1, arr2)).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for objects and arrays compared", () => { | ||||||
|  |         expect(deepEquals({ a: 1 }, [1])).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return true for null compared to null", () => { | ||||||
|  |         expect(deepEquals(null, null)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for null compared to an object", () => { | ||||||
|  |         expect(deepEquals(null, {})).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for undefined compared to null", () => { | ||||||
|  |         expect(deepEquals(undefined, null)).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return true for deeply nested identical structures", () => { | ||||||
|  |         const obj1 = { a: [1, { b: 2, c: [3, 4] }] }; | ||||||
|  |         const obj2 = { a: [1, { b: 2, c: [3, 4] }] }; | ||||||
|  |         expect(deepEquals(obj1, obj2)).toBe(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it("should return false for deeply nested different structures", () => { | ||||||
|  |         const obj1 = { a: [1, { b: 2, c: [3, 4] }] }; | ||||||
|  |         const obj2 = { a: [1, { b: 2, c: [3, 5] }] }; | ||||||
|  |         expect(deepEquals(obj1, obj2)).toBe(false); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  | @ -9,6 +9,43 @@ export default mergeConfig( | ||||||
|             environment: "jsdom", |             environment: "jsdom", | ||||||
|             exclude: [...configDefaults.exclude, "e2e/**"], |             exclude: [...configDefaults.exclude, "e2e/**"], | ||||||
|             root: fileURLToPath(new URL("./", import.meta.url)), |             root: fileURLToPath(new URL("./", import.meta.url)), | ||||||
|  |             testTimeout: 100000, | ||||||
|  |             coverage: { | ||||||
|  |                 reporter: ["text", "json-summary", "json"], | ||||||
|  |                 // If you want a coverage reports even if your tests are failing, include the reportOnFailure option
 | ||||||
|  |                 reportOnFailure: true, | ||||||
|  |                 exclude: [ | ||||||
|  |                     "**/*config*", | ||||||
|  |                     "**/tests/**", | ||||||
|  |                     "playwright-report/**", | ||||||
|  |                     "**/dist/**", | ||||||
|  |                     "**/e2e/**", | ||||||
|  |                     "**/*config*", | ||||||
|  |                     "**/node_modules/**", | ||||||
|  | 
 | ||||||
|  |                     "src/main.ts", | ||||||
|  |                     "src/router/index.ts", | ||||||
|  |                     "src/utils/constants.ts", | ||||||
|  | 
 | ||||||
|  |                     "**/*.d.ts", | ||||||
|  | 
 | ||||||
|  |                     "src/**/*.vue", | ||||||
|  |                     "src/assets/**", | ||||||
|  |                     "src/i18n/**", | ||||||
|  | 
 | ||||||
|  |                     "src/data-objects/**", | ||||||
|  |                     "src/exception/**", // TODO Might be useful to test later
 | ||||||
|  |                     "src/queries/**", // TODO Might be useful to test later
 | ||||||
|  |                     "src/views/learning-paths/gift-adapters/**", // TODO Might be useful to test later
 | ||||||
|  |                     "src/services/auth/**", // TODO Might be useful to test later
 | ||||||
|  |                 ], | ||||||
|  |                 thresholds: { | ||||||
|  |                     lines: 50, | ||||||
|  |                     branches: 50, | ||||||
|  |                     functions: 50, | ||||||
|  |                     statements: 50, | ||||||
|  |                 }, | ||||||
|  |             }, | ||||||
| 
 | 
 | ||||||
|             /* |             /* | ||||||
|              * The test-backend server can be started for each test-file individually using `beforeAll(() => setup())`, |              * The test-backend server can be started for each test-file individually using `beforeAll(() => setup())`, | ||||||
|  | @ -16,6 +53,7 @@ export default mergeConfig( | ||||||
|              globalSetup: ["./tests/setup-backend.ts"], |              globalSetup: ["./tests/setup-backend.ts"], | ||||||
|              * In this project, the backend server is started for each test-file individually. |              * In this project, the backend server is started for each test-file individually. | ||||||
|              */ |              */ | ||||||
|  |             globalSetup: ["./tests/setup-backend.ts"], | ||||||
|         }, |         }, | ||||||
|     }), |     }), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | @ -13,7 +13,8 @@ | ||||||
|         "format-check": "npm run format-check --workspace=backend --workspace=common --workspace=frontend", |         "format-check": "npm run format-check --workspace=backend --workspace=common --workspace=frontend", | ||||||
|         "lint": "npm run lint --workspace=backend --workspace=common --workspace=frontend", |         "lint": "npm run lint --workspace=backend --workspace=common --workspace=frontend", | ||||||
|         "pretest:unit": "npm run build", |         "pretest:unit": "npm run build", | ||||||
|         "test:unit": "npm run test:unit --workspace=backend --workspace=frontend" |         "test:unit": "npm run test:unit --workspace=backend --workspace=frontend", | ||||||
|  |         "test:coverage": "npm run test:coverage --workspace=backend --workspace=frontend" | ||||||
|     }, |     }, | ||||||
|     "workspaces": [ |     "workspaces": [ | ||||||
|         "backend", |         "backend", | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Timo De Meyst
						Timo De Meyst