diff --git a/frontend/src/components/assignments/GroupSelector.vue b/frontend/src/components/assignments/GroupSelector.vue index 90b86e2a..16dc93e8 100644 --- a/frontend/src/components/assignments/GroupSelector.vue +++ b/frontend/src/components/assignments/GroupSelector.vue @@ -90,11 +90,6 @@ } function saveRandomGroups(): void { - if (randomGroupsPreview.value.length === 0) { - alert(t("please-generate-groups-first")); - return; - } - emit( "groupsUpdated", randomGroupsPreview.value.map((g) => g.map((s) => s.username)), @@ -104,11 +99,11 @@ emit("close"); } - function addNewGroup() { + function addNewGroup(): void { currentGroups.value.push([]); } - function removeGroup(index: number) { + function removeGroup(index: number): void { // Move students back to unassigned unassignedStudents.value.push(...currentGroups.value[index]); currentGroups.value.splice(index, 1); @@ -317,11 +312,6 @@ } function saveDragDrop(): void { - if (unassignedStudents.value.length > 0) { - alert(t("please-assign-all-students")); - return; - } - emit( "groupsUpdated", currentGroups.value.map((g) => g.map((s) => s.username)), @@ -331,9 +321,7 @@ emit("close"); } - const showGroupsPreview = computed(() => { - return currentGroups.value.length > 0 || unassignedStudents.value.length > 0; - }); + const showGroupsPreview = computed(() => currentGroups.value.length > 0 || unassignedStudents.value.length > 0); function removeStudent(groupIndex: number, student: StudentItem): void { const group = currentGroups.value[groupIndex]; diff --git a/frontend/src/utils/assignment-rules.ts b/frontend/src/utils/assignment-rules.ts deleted file mode 100644 index d0f96797..00000000 --- a/frontend/src/utils/assignment-rules.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Validation rule for the assignment title. - * - * Ensures that the title is not empty. - */ - -/** - * Validation rule for the classes selection. - * - * Ensures that at least one class is selected. - */ - -/** - * Validation rule for the deadline field. - * - * Ensures that a valid deadline is selected and is in the future. - */ diff --git a/frontend/tests/controllers/classes-controller.test.ts b/frontend/tests/controllers/classes-controller.test.ts index 8768aee8..927fab57 100644 --- a/frontend/tests/controllers/classes-controller.test.ts +++ b/frontend/tests/controllers/classes-controller.test.ts @@ -1,10 +1,59 @@ -import { describe, expect, it } from "vitest"; +import { describe, it, expect, beforeEach } 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); +describe("ClassController Tests", () => { + let controller: ClassController; + const testClassId = "X2J9QT"; + + beforeEach(() => { + controller = new ClassController(); + }); + + it("should fetch all classes", async () => { + const result = await controller.getAll(true); + expect(result).toHaveProperty("classes"); + expect(Array.isArray(result.classes)).toBe(true); + expect(result.classes.length).toBeGreaterThan(0); + }); + + it("should fetch a class by ID", async () => { + const result = await controller.getById(testClassId); + expect(result).toHaveProperty("class"); + expect(result.class).toHaveProperty("id", testClassId); + }); + + + it("should fetch students for a class", async () => { + const result = await controller.getStudents(testClassId, true); + expect(result).toHaveProperty("students"); + expect(Array.isArray(result.students)).toBe(true); + }); + + it("should fetch teachers for a class", async () => { + const result = await controller.getTeachers(testClassId, true); + expect(result).toHaveProperty("teachers"); + expect(Array.isArray(result.teachers)).toBe(true); + }); + + it("should fetch teacher invitations for a class", async () => { + const result = await controller.getTeacherInvitations(testClassId, true); + expect(result).toHaveProperty("invitations"); + expect(Array.isArray(result.invitations)).toBe(true); + }); + + it("should fetch assignments for a class", async () => { + const result = await controller.getAssignments(testClassId, true); + expect(result).toHaveProperty("assignments"); + expect(Array.isArray(result.assignments)).toBe(true); + }); + + it("should handle fetching a non-existent class", async () => { + const nonExistentId = "NON_EXISTENT_ID"; + await expect(controller.getById(nonExistentId)).rejects.toThrow(); + }); + + it("should handle deleting a non-existent class", async () => { + const nonExistentId = "NON_EXISTENT_ID"; + await expect(controller.deleteClass(nonExistentId)).rejects.toThrow(); }); }); diff --git a/frontend/tests/utils/array-utils.test.ts b/frontend/tests/utils/array-utils.test.ts new file mode 100644 index 00000000..1b7f54be --- /dev/null +++ b/frontend/tests/utils/array-utils.test.ts @@ -0,0 +1,50 @@ +import {copyArrayWith} from "../../src/utils/array-utils"; +import { describe, it, expect } from "vitest"; + +describe('copyArrayWith', () => { + it('should replace the element at the specified index', () => { + const original = [1, 2, 3, 4]; + const result = copyArrayWith(2, 99, original); + expect(result).toEqual([1, 2, 99, 4]); + }); + + it('should not modify the original array', () => { + const original = ['a', 'b', 'c']; + const result = copyArrayWith(1, 'x', original); + expect(original).toEqual(['a', 'b', 'c']); // Original remains unchanged + expect(result).toEqual(['a', 'x', 'c']); + }); + + it('should handle replacing the first element', () => { + const original = [true, false, true]; + const result = copyArrayWith(0, false, original); + expect(result).toEqual([false, false, true]); + }); + + it('should handle replacing the last element', () => { + const original = ['apple', 'banana', 'cherry']; + const result = copyArrayWith(2, 'date', original); + expect(result).toEqual(['apple', 'banana', 'date']); + }); + + it('should work with complex objects', () => { + const original = [{ id: 1 }, { id: 2 }, { id: 3 }]; + const newValue = { id: 99 }; + const result = copyArrayWith(1, newValue, original); + expect(result).toEqual([{ id: 1 }, { id: 99 }, { id: 3 }]); + expect(original[1].id).toBe(2); // Original remains unchanged + }); + + + it('should allow setting to undefined', () => { + const original = [1, 2, 3]; + const result = copyArrayWith(1, undefined, original); + expect(result).toEqual([1, undefined, 3]); + }); + + it('should allow setting to null', () => { + const original = [1, 2, 3]; + const result = copyArrayWith(1, null, original); + expect(result).toEqual([1, null, 3]); + }); +}); diff --git a/frontend/tests/utils/assignment-utils.test.ts b/frontend/tests/utils/assignment-utils.test.ts new file mode 100644 index 00000000..46f99af8 --- /dev/null +++ b/frontend/tests/utils/assignment-utils.test.ts @@ -0,0 +1,87 @@ +import {LearningPathNode} from "@dwengo-1/backend/dist/entities/content/learning-path-node.entity"; +import {calculateProgress} from "../../src/utils/assignment-utils"; +import {LearningPath} from "../../src/data-objects/learning-paths/learning-path"; +import { describe, it, expect } from "vitest"; + +describe("calculateProgress", () => { + it("should return 0 when no nodes are completed", () => { + const lp = new LearningPath({ + language: "en", + hruid: "test-path", + title: "Test Path", + description: "Test Description", + amountOfNodes: 10, + amountOfNodesLeft: 10, + keywords: ["test"], + targetAges: { min: 10, max: 15 }, + startNode: {} as LearningPathNode, + }); + + expect(calculateProgress(lp)).toBe(0); + }); + + it("should return 100 when all nodes are completed", () => { + const lp = new LearningPath({ + language: "en", + hruid: "test-path", + title: "Test Path", + description: "Test Description", + amountOfNodes: 10, + amountOfNodesLeft: 0, + keywords: ["test"], + targetAges: { min: 10, max: 15 }, + startNode: {} as LearningPathNode, + }); + + expect(calculateProgress(lp)).toBe(100); + }); + + it("should return 50 when half of the nodes are completed", () => { + const lp = new LearningPath({ + language: "en", + hruid: "test-path", + title: "Test Path", + description: "Test Description", + amountOfNodes: 10, + amountOfNodesLeft: 5, + keywords: ["test"], + targetAges: { min: 10, max: 15 }, + startNode: {} as LearningPathNode, + }); + + expect(calculateProgress(lp)).toBe(50); + }); + + it("should handle floating point progress correctly", () => { + const lp = new LearningPath({ + language: "en", + hruid: "test-path", + title: "Test Path", + description: "Test Description", + amountOfNodes: 3, + amountOfNodesLeft: 1, + keywords: ["test"], + targetAges: { min: 10, max: 15 }, + startNode: {} as LearningPathNode, + }); + + expect(calculateProgress(lp)).toBeCloseTo(66.666, 2); + }); + + + it("should handle edge case where amountOfNodesLeft is negative", () => { + const lp = new LearningPath({ + language: "en", + hruid: "test-path", + title: "Test Path", + description: "Test Description", + amountOfNodes: 10, + amountOfNodesLeft: -5, + keywords: ["test"], + targetAges: { min: 10, max: 15 }, + startNode: {} as LearningPathNode, + }); + + expect(calculateProgress(lp)).toBe(150); + }); +});