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' | ||||
|     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: | ||||
|       matrix: | ||||
|         node-version: [22.x] | ||||
|  | @ -42,4 +48,16 @@ jobs: | |||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'npm' | ||||
|     - 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' | ||||
|     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: | ||||
|       matrix: | ||||
|         node-version: [22.x] | ||||
|  | @ -51,4 +57,16 @@ jobs: | |||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'npm' | ||||
|     - 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/", | ||||
|         "lint": "eslint . --fix", | ||||
|         "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": { | ||||
|         "@mikro-orm/core": "6.4.12", | ||||
|  |  | |||
|  | @ -5,5 +5,17 @@ export default defineConfig({ | |||
|         environment: 'node', | ||||
|         globals: true, | ||||
|         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/", | ||||
|         "lint": "eslint . --fix", | ||||
|         "test:unit": "vitest --run", | ||||
|         "test:coverage": "vitest --run --coverage.enabled true", | ||||
|         "test:e2e": "playwright test" | ||||
|     }, | ||||
|     "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 { expect, it, describe, afterAll, beforeAll } from "vitest"; | ||||
| import { setup, teardown } from "../setup-backend.js"; | ||||
| import { beforeEach, describe, expect, it, test } from "vitest"; | ||||
| 
 | ||||
| describe("Test controller students", () => { | ||||
|     beforeAll(async () => { | ||||
|         await setup(); | ||||
|     }); | ||||
|     let controller: StudentController; | ||||
| 
 | ||||
|     afterAll(async () => { | ||||
|         await teardown(); | ||||
|     beforeEach(async () => { | ||||
|         controller = new StudentController(); | ||||
|     }); | ||||
| 
 | ||||
|     it("Get students", async () => { | ||||
|         const controller = new StudentController(); | ||||
|         const data = await controller.getAll(true); | ||||
|         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", | ||||
|             exclude: [...configDefaults.exclude, "e2e/**"], | ||||
|             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())`, | ||||
|  | @ -16,6 +53,7 @@ export default mergeConfig( | |||
|              globalSetup: ["./tests/setup-backend.ts"], | ||||
|              * 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", | ||||
|         "lint": "npm run lint --workspace=backend --workspace=common --workspace=frontend", | ||||
|         "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": [ | ||||
|         "backend", | ||||
|  |  | |||
		Reference in a new issue
	
	 Timo De Meyst
						Timo De Meyst