diff --git a/backend/src/controllers/submissions.ts b/backend/src/controllers/submissions.ts index a117d7bf..012636ea 100644 --- a/backend/src/controllers/submissions.ts +++ b/backend/src/controllers/submissions.ts @@ -62,6 +62,11 @@ export async function getAllSubmissionsHandler(req: Request, res: Response): Pro // TODO: gerald moet nog dingen toevoegen aan de databank voor dat dit gefinaliseerd kan worden export async function createSubmissionHandler(req: Request, res: Response): Promise { + const submitter = req.body.submitter; + const usernameSubmitter = req.body.submitter.username; + const group = req.body.group; + requireFields({ group, submitter, usernameSubmitter }); + const submissionDTO = req.body as SubmissionDTO; const submission = await createSubmission(submissionDTO); diff --git a/backend/src/services/students.ts b/backend/src/services/students.ts index 77ec6648..809b23e4 100644 --- a/backend/src/services/students.ts +++ b/backend/src/services/students.ts @@ -42,7 +42,7 @@ export async function fetchStudent(username: string): Promise { const user = await studentRepository.findByUsername(username); if (!user) { - throw new NotFoundException('Student with username not found'); + throw new NotFoundException(`Student with username ${username} not found`); } return user; diff --git a/backend/tests/controllers/assignments.test.ts b/backend/tests/controllers/assignments.test.ts new file mode 100644 index 00000000..88cac366 --- /dev/null +++ b/backend/tests/controllers/assignments.test.ts @@ -0,0 +1,76 @@ +import { setupTestApp } from '../setup-tests.js'; +import { describe, it, expect, beforeAll, beforeEach, vi, Mock } from 'vitest'; +import { Request, Response } from 'express'; +import { getAssignmentHandler, getAllAssignmentsHandler, getAssignmentsSubmissionsHandler } from '../../src/controllers/assignments.js'; +import { NotFoundException } from '../../src/exceptions/not-found-exception'; +import { getClass01 } from '../test_assets/classes/classes.testdata'; +import { getAssignment01 } from '../test_assets/assignments/assignments.testdata'; + +function createRequestObject( + classid: string, + assignmentid: string +): { + query: { full: string }; + params: { classid: string; id: string }; +} { + return { + params: { + classid: classid, + id: assignmentid, + }, + query: { + full: 'true', + }, + }; +} + +describe('Assignment controllers', () => { + let req: Partial; + let res: Partial; + + let jsonMock: Mock; + let statusMock: Mock; + + beforeAll(async () => { + await setupTestApp(); + }); + + beforeEach(async () => { + jsonMock = vi.fn(); + statusMock = vi.fn().mockReturnThis(); + + res = { + json: jsonMock, + status: statusMock, + }; + }); + + it('return error non-existing assignment', async () => { + req = createRequestObject('doesnotexist', '43000'); // Should not exist + + await expect(async () => getAssignmentHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return an assignment', async () => { + const assignment = getAssignment01(); + req = createRequestObject(assignment.within.classId as string, (assignment.id ?? 1).toString()); + + await getAssignmentHandler(req as Request, res as Response); + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ assignment: expect.anything() })); + }); + + it('should return a list of assignments', async () => { + req = createRequestObject(getClass01().classId as string, 'irrelevant'); + + await getAllAssignmentsHandler(req as Request, res as Response); + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ assignments: expect.anything() })); + }); + + it('should return a list of submissions for an assignment', async () => { + const assignment = getAssignment01(); + req = createRequestObject(assignment.within.classId as string, (assignment.id ?? 1).toString()); + + await getAssignmentsSubmissionsHandler(req as Request, res as Response); + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ submissions: expect.anything() })); + }); +}); diff --git a/backend/tests/controllers/classes.test.ts b/backend/tests/controllers/classes.test.ts index ab941773..d9614a3b 100644 --- a/backend/tests/controllers/classes.test.ts +++ b/backend/tests/controllers/classes.test.ts @@ -1,8 +1,17 @@ import { setupTestApp } from '../setup-tests.js'; import { describe, it, expect, beforeAll, beforeEach, vi, Mock } from 'vitest'; +import { + createClassHandler, + deleteClassHandler, + getAllClassesHandler, + getClassHandler, + getClassStudentsHandler, + getTeacherInvitationsHandler, +} from '../../src/controllers/classes.js'; import { Request, Response } from 'express'; -import { createClassHandler, deleteClassHandler } from '../../src/controllers/classes'; - +import { NotFoundException } from '../../src/exceptions/not-found-exception'; +import { BadRequestException } from '../../src/exceptions/bad-request-exception'; +import { getClass01 } from '../test_assets/classes/classes.testdata'; describe('Class controllers', () => { let req: Partial; let res: Partial; @@ -44,4 +53,71 @@ describe('Class controllers', () => { expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ class: expect.anything() })); }); + + it('Error class not found', async () => { + req = { + params: { id: 'doesnotexist' }, + }; + + await expect(async () => getClassHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('Error create a class without name', async () => { + req = { + body: {}, + }; + + await expect(async () => createClassHandler(req as Request, res as Response)).rejects.toThrow(BadRequestException); + }); + + it('return list of students', async () => { + req = { + params: { id: getClass01().classId as string }, + query: {}, + }; + + await getClassStudentsHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ students: expect.anything() })); + }); + + it('Error students on a non-existent class', async () => { + req = { + params: { id: 'doesnotexist' }, + query: {}, + }; + + await expect(async () => getClassStudentsHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return 200 and a list of teacher-invitations', async () => { + const classId = getClass01().classId as string; + req = { + params: { id: classId }, + query: {}, + }; + + await getTeacherInvitationsHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ invitations: expect.anything() })); + }); + + it('Error teacher-invitations on a non-existent class', async () => { + req = { + params: { id: 'doesnotexist' }, + query: {}, + }; + + await expect(async () => getTeacherInvitationsHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return a list of classes', async () => { + req = { + query: {}, + }; + + await getAllClassesHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ classes: expect.anything() })); + }); }); diff --git a/backend/tests/controllers/groups.test.ts b/backend/tests/controllers/groups.test.ts new file mode 100644 index 00000000..f9e35cea --- /dev/null +++ b/backend/tests/controllers/groups.test.ts @@ -0,0 +1,140 @@ +import { setupTestApp } from '../setup-tests.js'; +import { describe, it, expect, beforeAll, beforeEach, vi, Mock } from 'vitest'; +import { Request, Response } from 'express'; +import { + createGroupHandler, + deleteGroupHandler, + getAllGroupsHandler, + getGroupHandler, + getGroupSubmissionsHandler, +} from '../../src/controllers/groups.js'; +import { NotFoundException } from '../../src/exceptions/not-found-exception'; +import { getClass01 } from '../test_assets/classes/classes.testdata'; +import { getAssignment01, getAssignment02 } from '../test_assets/assignments/assignments.testdata'; +import { getTestGroup01 } from '../test_assets/assignments/groups.testdata'; + +function createRequestObject( + classid: string, + assignmentid: string, + groupNumber: string +): { + query: { full: string }; + params: { classid: string; groupid: string; assignmentid: string }; +} { + return { + params: { + classid: classid, + assignmentid: assignmentid, + groupid: groupNumber, + }, + query: { + full: 'true', + }, + }; +} + +describe('Group controllers', () => { + let req: Partial; + let res: Partial; + + let jsonMock: Mock; + let statusMock: Mock; + + beforeAll(async () => { + await setupTestApp(); + }); + + beforeEach(async () => { + jsonMock = vi.fn(); + statusMock = vi.fn().mockReturnThis(); + + res = { + json: jsonMock, + status: statusMock, + }; + }); + + it('Error not found on a non-existing group', async () => { + req = { + params: { + classid: 'id01', + assignmentid: '1', + groupid: '154981', // Should not exist + }, + query: {}, + }; + + await expect(async () => getGroupHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return 404 not found on a non-existing assignment', async () => { + req = { + params: { + classid: 'id01', + assignmentid: '1000', // Should not exist + groupid: '42000', // Should not exist + }, + query: {}, + }; + + await expect(async () => getGroupHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return 404 not found ont a non-existing class', async () => { + req = { + params: { + classid: 'doesnotexist', // Should not exist + assignmentid: '1000', // Should not exist + groupid: '42000', // Should not exist + }, + query: {}, + }; + + await expect(async () => getGroupHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return an existing group', async () => { + const group = getTestGroup01(); + const classId = getClass01().classId as string; + req = createRequestObject(classId, (group.assignment.id ?? 1).toString(), (group.groupNumber ?? 1).toString()); + + await getGroupHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ group: expect.anything() })); + }); + + it('Create and delete', async () => { + const assignment = getAssignment02(); + const classId = assignment.within.classId as string; + req = createRequestObject(classId, (assignment.id ?? 1).toString(), '1'); + req.body = { + members: ['Noordkaap', 'DireStraits'], + }; + + await createGroupHandler(req as Request, res as Response); + + await deleteGroupHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ group: expect.anything() })); + }); + + it('should return the submissions for a group', async () => { + const group = getTestGroup01(); + const classId = getClass01().classId as string; + req = createRequestObject(classId, (group.assignment.id ?? 1).toString(), (group.groupNumber ?? 1).toString()); + + await getGroupSubmissionsHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ submissions: expect.anything() })); + }); + + it('should return a list of groups for an assignment', async () => { + const assignment = getAssignment01(); + const classId = assignment.within.classId as string; + req = createRequestObject(classId, (assignment.id ?? 1).toString(), '1'); + + await getAllGroupsHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ groups: expect.anything() })); + }); +}); diff --git a/backend/tests/controllers/submissions.test.ts b/backend/tests/controllers/submissions.test.ts new file mode 100644 index 00000000..942b51f8 --- /dev/null +++ b/backend/tests/controllers/submissions.test.ts @@ -0,0 +1,61 @@ +import { setupTestApp } from '../setup-tests.js'; +import { describe, it, expect, beforeAll, beforeEach, vi, Mock } from 'vitest'; +import { getSubmissionHandler, getAllSubmissionsHandler } from '../../src/controllers/submissions.js'; +import { Request, Response } from 'express'; +import { NotFoundException } from '../../src/exceptions/not-found-exception'; +import { getClass02 } from '../test_assets/classes/classes.testdata'; + +function createRequestObject( + hruid: string, + submissionNumber: string +): { + query: { language: string; version: string }; + params: { hruid: string; id: string }; +} { + return { + params: { + hruid: hruid, + id: submissionNumber, + }, + query: { + language: 'en', + version: '1', + }, + }; +} + +describe('Submission controllers', () => { + let req: Partial; + let res: Partial; + + let jsonMock: Mock; + let statusMock: Mock; + + beforeAll(async () => { + await setupTestApp(); + }); + + beforeEach(async () => { + jsonMock = vi.fn(); + statusMock = vi.fn().mockReturnThis(); + + res = { + json: jsonMock, + status: statusMock, + }; + }); + + it('error submission is not found', async () => { + req = createRequestObject('id01', '1000000'); + + await expect(async () => getSubmissionHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException); + }); + + it('should return a list of submissions for a learning object', async () => { + req = createRequestObject(getClass02().classId as string, 'irrelevant'); + + await getAllSubmissionsHandler(req as Request, res as Response); + + expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ submissions: expect.anything() })); + }); +});