From 52188cb4f6dfd984629e55200f0bfe5188056891 Mon Sep 17 00:00:00 2001 From: jmabramo <89821002+jmabramo@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:37:06 -0500 Subject: [PATCH] Submission score entity (#44) Add submissionScore entity to the API. This entity stores a score and feedback attached to a single submission --- ...roller.ts => codeAssignment.controller.ts} | 4 +- src/controller/submissionScore.controller.ts | 73 ++++++ ...t.ts => codeAssignment.controller.test.ts} | 8 +- .../tests/submissionScore.controller.test.ts | 208 ++++++++++++++++++ ...lidator.ts => codeAssignment.validator.ts} | 0 .../validator/submissionScore.validator.ts | 12 + ...ments.model.ts => codeAssignment.model.ts} | 2 +- src/model/index.ts | 4 +- ...nts.router.ts => codeAssignment.router.ts} | 4 +- src/router/index.ts | 4 +- src/router/submissionScore.router.ts | 53 +++++ ...s.service.ts => codeAssignment.service.ts} | 2 +- src/services/submissionScore.service.ts | 50 +++++ ...alizer.ts => codeAssignment.serializer.ts} | 2 +- .../serializer/submissionScore.serializer.ts | 15 ++ ...t.ts => codeAssignment.serializer.test.ts} | 4 +- .../tests/submissionScore.serializer.test.ts | 42 ++++ 17 files changed, 471 insertions(+), 16 deletions(-) rename src/controller/{codeAssignments.controller.ts => codeAssignment.controller.ts} (93%) create mode 100644 src/controller/submissionScore.controller.ts rename src/controller/tests/{codeAssignments.controller.test.ts => codeAssignment.controller.test.ts} (98%) create mode 100644 src/controller/tests/submissionScore.controller.test.ts rename src/middleware/validator/{codeAssignments.validator.ts => codeAssignment.validator.ts} (100%) create mode 100644 src/middleware/validator/submissionScore.validator.ts rename src/model/{codeAssignments.model.ts => codeAssignment.model.ts} (96%) rename src/router/{codeAssignments.router.ts => codeAssignment.router.ts} (92%) create mode 100644 src/router/submissionScore.router.ts rename src/services/{codeAssignments.service.ts => codeAssignment.service.ts} (97%) create mode 100644 src/services/submissionScore.service.ts rename src/utils/serializer/{codeAssignments.serializer.ts => codeAssignment.serializer.ts} (86%) create mode 100644 src/utils/serializer/submissionScore.serializer.ts rename src/utils/serializer/tests/{codeAssignments.serializer.test.ts => codeAssignment.serializer.test.ts} (91%) create mode 100644 src/utils/serializer/tests/submissionScore.serializer.test.ts diff --git a/src/controller/codeAssignments.controller.ts b/src/controller/codeAssignment.controller.ts similarity index 93% rename from src/controller/codeAssignments.controller.ts rename to src/controller/codeAssignment.controller.ts index 910d5adb..16df6f40 100644 --- a/src/controller/codeAssignments.controller.ts +++ b/src/controller/codeAssignment.controller.ts @@ -1,7 +1,7 @@ import { Request, Response, NextFunction } from 'express' -import CodeAssignmentService from '../services/codeAssignments.service' -import { serialize } from '../utils/serializer/codeAssignments.serializer' +import CodeAssignmentService from '../services/codeAssignment.service' +import { serialize } from '../utils/serializer/codeAssignment.serializer' import { GenericResponse, NotFound, Updated } from '../utils/apiResponse.utils' diff --git a/src/controller/submissionScore.controller.ts b/src/controller/submissionScore.controller.ts new file mode 100644 index 00000000..c331c3e6 --- /dev/null +++ b/src/controller/submissionScore.controller.ts @@ -0,0 +1,73 @@ +import { Request, Response, NextFunction } from 'express' +import submissionScoreService from '../services/submissionScore.service' + +import SubmissionScoreService from '../services/submissionScore.service' + +import { GenericResponse, NotFound, Updated } from '../utils/apiResponse.utils' + +import { serialize } from '../utils/serializer/submissionScore.serializer' + +export async function get(req: Request, res: Response, next: NextFunction) { + try { + const submissionScores = await SubmissionScoreService.list() + const response = submissionScores.map(serialize) + + res.status(200).json(response) + } catch (err) { + next(err) + } +} + +export async function detail(req: Request, res: Response, next: NextFunction) { + try { + const id = parseInt(req.params.id) + const submissionScore = await submissionScoreService.retrieve(id) + + if (!submissionScore) return res.status(404).json(NotFound) + + const response = serialize(submissionScore) + + res.status(200).json(response) + } catch (err) { + next(err) + } +} + +export async function post(req: Request, res: Response, next: NextFunction) { + try { + const submissionScore = await SubmissionScoreService.create(req.body) + const response = serialize(submissionScore) + + res.status(201).json(response) + } catch (err) { + res.status(400).json(new GenericResponse(err.message)) + } +} + +export async function put(req: Request, res: Response, next: NextFunction) { + try { + req.body.id = parseInt(req.params.id) + const results = await SubmissionScoreService.update(req.body) + + if (!results.affected) return res.status(404).json(NotFound) + + res.status(200).json(Updated) + } catch (err) { + next(err) + } +} + +export async function _delete(req: Request, res: Response, next: NextFunction) { + try { + const id = parseInt(req.params.id) + const results = await SubmissionScoreService._delete(id) + + if (!results.affected) return res.status(404).json(NotFound) + + res.status(204).send() + } catch (err) { + next(err) + } +} + +export default { get, detail, post, put, _delete } diff --git a/src/controller/tests/codeAssignments.controller.test.ts b/src/controller/tests/codeAssignment.controller.test.ts similarity index 98% rename from src/controller/tests/codeAssignments.controller.test.ts rename to src/controller/tests/codeAssignment.controller.test.ts index a2c5ff22..51f3f2ee 100644 --- a/src/controller/tests/codeAssignments.controller.test.ts +++ b/src/controller/tests/codeAssignment.controller.test.ts @@ -3,13 +3,13 @@ import { UpdateResult } from 'typeorm' import { CodeAssignment } from 'devu-shared-modules' -import controller from '../codeAssignments.controller' +import controller from '../codeAssignment.controller' -import CodeAssignmentModel from '../../model/codeAssignments.model' +import CodeAssignmentModel from '../../model/codeAssignment.model' -import CodeAssignmentService from '../../services/codeAssignments.service' +import CodeAssignmentService from '../../services/codeAssignment.service' -import { serialize } from '../../utils/serializer/codeAssignments.serializer' +import { serialize } from '../../utils/serializer/codeAssignment.serializer' import Testing from '../../utils/testing.utils' import { GenericResponse, NotFound, Updated } from '../../utils/apiResponse.utils' diff --git a/src/controller/tests/submissionScore.controller.test.ts b/src/controller/tests/submissionScore.controller.test.ts new file mode 100644 index 00000000..2e491777 --- /dev/null +++ b/src/controller/tests/submissionScore.controller.test.ts @@ -0,0 +1,208 @@ +import { UpdateResult } from 'typeorm' + +import { SubmissionScore } from 'devu-shared-modules' + +import controller from '../submissionScore.controller' + +import SubmissionScoreModel from '../../model/submissionScore.model' + +import SubmissionScoreService from '../../services/submissionScore.service' + +import { serialize } from '../../utils/serializer/submissionScore.serializer' + +import Testing from '../../utils/testing.utils' +import { GenericResponse, NotFound, Updated } from '../../utils/apiResponse.utils' + +// Testing Globals +let req: any +let res: any +let next: any + +let mockedSubmissionScores: SubmissionScoreModel[] +let mockedSubmissionScore: SubmissionScoreModel +let expectedResults: SubmissionScore[] +let expectedResult: SubmissionScore +let expectedError: Error + +let expectedDbResult: UpdateResult + +describe('SubmissionScoreController', () => { + beforeEach(() => { + req = Testing.fakeRequest() + res = Testing.fakeResponse() + next = Testing.fakeNext() + + mockedSubmissionScores = Testing.generateTypeOrmArray(SubmissionScoreModel, 3) + mockedSubmissionScore = Testing.generateTypeOrm(SubmissionScoreModel) + + expectedResults = mockedSubmissionScores.map(serialize) + expectedResult = serialize(mockedSubmissionScore) + expectedError = new Error('Expected Error') + + expectedDbResult = {} as UpdateResult + }) + + describe('GET - /submission-score', () => { + describe('200 - Ok', () => { + beforeEach(async () => { + SubmissionScoreService.list = jest.fn().mockImplementation(() => Promise.resolve(mockedSubmissionScores)) + await controller.get(req, res, next) // what we're testing + }) + + test('Returns list of submissionScores', () => expect(res.json).toBeCalledWith(expectedResults)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) + }) + + describe('400 - Bad request', () => { + test('Next called with expected error', async () => { + SubmissionScoreService.list = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + + try { + await controller.get(req, res, next) + + fail('Expected test to throw') + } catch { + expect(next).toBeCalledWith(expectedError) + } + }) + }) + }) + + describe('GET - /submission-score/:id', () => { + describe('200 - Ok', () => { + beforeEach(async () => { + SubmissionScoreService.retrieve = jest.fn().mockImplementation(() => Promise.resolve(mockedSubmissionScore)) + await controller.detail(req, res, next) + }) + + test('Returns expected submissionScore', () => expect(res.json).toBeCalledWith(expectedResult)) + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) + }) + + describe('404 - Not Found', () => { + beforeEach(async () => { + SubmissionScoreService.retrieve = jest.fn().mockImplementation(() => Promise.resolve()) // No results + await controller.detail(req, res, next) + }) + + test('Status code is 404 on missing submissionScore', () => expect(res.status).toBeCalledWith(404)) + test('Responds with NotFound on missing submissionScore', () => expect(res.json).toBeCalledWith(NotFound)) + test('Next not called on missing submissionScore', () => expect(next).toBeCalledTimes(0)) + }) + + describe('400 - Bad Request', () => { + test('Next called with expected error', async () => { + SubmissionScoreService.retrieve = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + + try { + await controller.detail(req, res, next) + + fail('Expected test to throw') + } catch { + expect(next).toBeCalledWith(expectedError) + } + }) + }) + }) + + describe('POST - /submission-score/', () => { + describe('201 - Created', () => { + beforeEach(async () => { + SubmissionScoreService.create = jest.fn().mockImplementation(() => Promise.resolve(mockedSubmissionScore)) + await controller.post(req, res, next) + }) + + test('Returns expected submissionScore', () => expect(res.json).toBeCalledWith(expectedResult)) + test('Status code is 201', () => expect(res.status).toBeCalledWith(201)) + }) + + describe('400 - Bad Request', () => { + beforeEach(async () => { + SubmissionScoreService.create = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + + try { + await controller.post(req, res, next) + + fail('Expected test to throw') + } catch { + // continue to tests + } + }) + + test('Status code is 400', () => expect(res.status).toBeCalledWith(400)) + test('Responds with generic error', () => + expect(res.json).toBeCalledWith(new GenericResponse(expectedError.message))) + test('Next not called', () => expect(next).toBeCalledTimes(0)) + }) + }) + + describe('PUT - /submission-score/:id', () => { + describe('200 - Ok', () => { + beforeEach(async () => { + expectedDbResult.affected = 1 // mocking service return shape + SubmissionScoreService.update = jest.fn().mockImplementation(() => Promise.resolve(expectedDbResult)) + await controller.put(req, res, next) + }) + + test('Status code is 200', () => expect(res.status).toBeCalledWith(200)) + test('Returns Updated message', () => expect(res.json).toBeCalledWith(Updated)) + test('Next is not called', () => expect(next).toHaveBeenCalledTimes(0)) + }) + + describe('404 - Not Found', () => { + beforeEach(async () => { + expectedDbResult.affected = 0 // No records affected in db + SubmissionScoreService.update = jest.fn().mockImplementation(() => Promise.resolve(expectedDbResult)) + await controller.put(req, res, next) + }) + + test('Status code is 404', () => expect(res.status).toBeCalledWith(404)) + test('Returns Not found message', () => expect(res.json).toBeCalledWith(NotFound)) + test('Next is not called', () => expect(next).toHaveBeenCalledTimes(0)) + }) + + describe('400 - Bad Request', () => { + beforeEach(async () => { + SubmissionScoreService.update = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + await controller.put(req, res, next) + }) + + test('Next is called with error', () => expect(next).toBeCalledWith(expectedError)) + }) + }) + + describe('DELETE - /submission-score/:id', () => { + describe('204 - No Content', () => { + beforeEach(async () => { + expectedDbResult.affected = 1 + SubmissionScoreService._delete = jest.fn().mockImplementation(() => Promise.resolve(expectedDbResult)) + await controller._delete(req, res, next) + }) + + test('Status code is 204', () => expect(res.status).toBeCalledWith(204)) + test('Response to have no content', () => expect(res.send).toBeCalledWith()) + test('Next not called', () => expect(next).toBeCalledTimes(0)) + }) + + describe('404 - Not Found', () => { + beforeEach(async () => { + expectedDbResult.affected = 0 + SubmissionScoreService._delete = jest.fn().mockImplementation(() => Promise.resolve(expectedDbResult)) + await controller._delete(req, res, next) + }) + + test('Status code is 404', () => expect(res.status).toBeCalledWith(404)) + test('Response to have no content', () => expect(res.json).toBeCalledWith(NotFound)) + test('Next not called', () => expect(next).toBeCalledTimes(0)) + }) + + describe('400 - Bad Request', () => { + beforeEach(async () => { + SubmissionScoreService._delete = jest.fn().mockImplementation(() => Promise.reject(expectedError)) + await controller._delete(req, res, next) + }) + + test('Next called with expected error', () => expect(next).toBeCalledWith(expectedError)) + }) + }) +}) diff --git a/src/middleware/validator/codeAssignments.validator.ts b/src/middleware/validator/codeAssignment.validator.ts similarity index 100% rename from src/middleware/validator/codeAssignments.validator.ts rename to src/middleware/validator/codeAssignment.validator.ts diff --git a/src/middleware/validator/submissionScore.validator.ts b/src/middleware/validator/submissionScore.validator.ts new file mode 100644 index 00000000..74a7f6cf --- /dev/null +++ b/src/middleware/validator/submissionScore.validator.ts @@ -0,0 +1,12 @@ +import { check } from 'express-validator' + +import validate from './generic.validator' + +const submissionId = check('submissionId').isNumeric() +const score = check('score').isNumeric().optional({ nullable: true }) +const feedback = check('feedback').isString().trim().optional({ nullable: true }) +const releasedAt = check('releasedAt').trim().isISO8601().toDate() + +const validator = [submissionId, score, feedback, releasedAt, validate] + +export default validator diff --git a/src/model/codeAssignments.model.ts b/src/model/codeAssignment.model.ts similarity index 96% rename from src/model/codeAssignments.model.ts rename to src/model/codeAssignment.model.ts index f0704d11..ad465fdc 100644 --- a/src/model/codeAssignments.model.ts +++ b/src/model/codeAssignment.model.ts @@ -20,7 +20,7 @@ import AssignmentModel from './assignment.model' * such assignments should not have and other such assignments types (eg. NonCodeAssignment, ManualAssignment). */ @Entity('code_assignments') -export default class CodeAssignmentsModel { +export default class CodeAssignmentModel { @PrimaryGeneratedColumn() id: number diff --git a/src/model/index.ts b/src/model/index.ts index 7a1d0c04..7890a9e8 100644 --- a/src/model/index.ts +++ b/src/model/index.ts @@ -5,7 +5,7 @@ import UserModel from './user.model' import UserCourseModel from './userCourse.model' import SubmissionProblemScoreModel from './submissionProblemScore.model' import SubmissionScoreModel from './submissionScore.model' -import CodeAssignmentsModel from './codeAssignments.model' +import CodeAssignmentModel from './codeAssignment.model' type Models = | AssignmentModel @@ -15,6 +15,6 @@ type Models = | UserModel | SubmissionProblemScoreModel | SubmissionScoreModel - | CodeAssignmentsModel + | CodeAssignmentModel export default Models diff --git a/src/router/codeAssignments.router.ts b/src/router/codeAssignment.router.ts similarity index 92% rename from src/router/codeAssignments.router.ts rename to src/router/codeAssignment.router.ts index 66181898..81431b50 100644 --- a/src/router/codeAssignments.router.ts +++ b/src/router/codeAssignment.router.ts @@ -1,10 +1,10 @@ import express from 'express' import multer from 'multer' -import validator from '../middleware/validator/codeAssignments.validator' +import validator from '../middleware/validator/codeAssignment.validator' import { asInt } from '../middleware/validator/generic.validator' -import CodeAssignmentController from '../controller/codeAssignments.controller' +import CodeAssignmentController from '../controller/codeAssignment.controller' const Router = express.Router() const upload = multer() diff --git a/src/router/index.ts b/src/router/index.ts index bc8c5327..cb9fd633 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -3,7 +3,7 @@ import swaggerUi from 'swagger-ui-express' import swagger from '../utils/swagger.utils' -import codeAssignment from './codeAssignments.router' +import codeAssignment from './codeAssignment.router' import userCourse from './userCourse.router' import assignments from './assignment.router' import courses from './course.router' @@ -12,6 +12,7 @@ import logout from './logout.router' import status from './status.router' import submissions from './submission.router' import users from './user.router' +import submissionScore from './submissionScore.router' import { isAuthorized } from '../middleware/auth.middleware' @@ -26,6 +27,7 @@ Router.use('/code-assignments', isAuthorized, codeAssignment) Router.use('/docs', swaggerUi.serve, swaggerUi.setup(swagger)) Router.use('/submissions', isAuthorized, submissions) Router.use('/users', isAuthorized, users) +Router.use('/submission-scores', isAuthorized, submissionScore) Router.use('/login', login) Router.use('/logout', logout) diff --git a/src/router/submissionScore.router.ts b/src/router/submissionScore.router.ts new file mode 100644 index 00000000..8f30e5de --- /dev/null +++ b/src/router/submissionScore.router.ts @@ -0,0 +1,53 @@ +// Libraries +import express from 'express' + +// Middleware +import validator from '../middleware/validator/submissionScore.validator' +import { asInt } from '../middleware/validator/generic.validator' + +// Controller +import SubmissionScoreController from '../controller/submissionScore.controller' + +const Router = express.Router() + +/** + * @swagger + * /submission-score: + * get: + * summary: Retrieve a list of submission score + */ +Router.get('/', SubmissionScoreController.get) + +/** + * @swagger + * /submission-score/{id}: + * get: + * summary: Retrieve a single submission score + */ +Router.get('/:id', asInt(), SubmissionScoreController.detail) + +/** + * @swagger + * /submission-score: + * post: + * summary: Create a submission score + */ +Router.post('/', validator, SubmissionScoreController.post) + +/** + * @swagger + * /submission-score: + * put: + * summary: Update a submission score + */ +Router.put('/:id', asInt(), validator, SubmissionScoreController.put) + +/** + * @swagger + * /submission-score/{id}: + * delete: + * summary: Delete a submission score + */ +Router.delete('/:id', asInt(), SubmissionScoreController._delete) + +export default Router diff --git a/src/services/codeAssignments.service.ts b/src/services/codeAssignment.service.ts similarity index 97% rename from src/services/codeAssignments.service.ts rename to src/services/codeAssignment.service.ts index 2f3b3890..ea427da1 100644 --- a/src/services/codeAssignments.service.ts +++ b/src/services/codeAssignment.service.ts @@ -2,7 +2,7 @@ import { getRepository, IsNull } from 'typeorm' import { CodeAssignment } from 'devu-shared-modules' -import CodeAssignmentsModel from '../model/codeAssignments.model' +import CodeAssignmentsModel from '../model/codeAssignment.model' import { minioClient, BucketNames } from '../fileStorage' const connect = () => getRepository(CodeAssignmentsModel) diff --git a/src/services/submissionScore.service.ts b/src/services/submissionScore.service.ts new file mode 100644 index 00000000..68a55df6 --- /dev/null +++ b/src/services/submissionScore.service.ts @@ -0,0 +1,50 @@ +import { getRepository, IsNull } from 'typeorm' + +import SubmissionScoreModel from '../model/submissionScore.model' + +import { SubmissionScore } from 'devu-shared-modules' + +const connect = () => getRepository(SubmissionScoreModel) + +export async function create(submissionScore: SubmissionScore) { + return await connect().save(submissionScore) +} + +export async function update(submissionScore: SubmissionScore) { + const { + id, + submissionId, + score, + feedback, + releasedAt, + } = submissionScore + + if (!id) throw new Error('Missing Id') + + return await connect().update(id, { + submissionId, + score, + feedback, + releasedAt, + }) +} + +export async function _delete(id: number) { + return await connect().softDelete({ id, deletedAt: IsNull() }) +} + +export async function retrieve(id: number) { + return await connect().findOne({ id, deletedAt: IsNull() }) +} + +export async function list() { + return await connect().find({ deletedAt: IsNull() }) +} + +export default { + create, + retrieve, + update, + _delete, + list, +} diff --git a/src/utils/serializer/codeAssignments.serializer.ts b/src/utils/serializer/codeAssignment.serializer.ts similarity index 86% rename from src/utils/serializer/codeAssignments.serializer.ts rename to src/utils/serializer/codeAssignment.serializer.ts index 63882395..d4c6ca11 100644 --- a/src/utils/serializer/codeAssignments.serializer.ts +++ b/src/utils/serializer/codeAssignment.serializer.ts @@ -1,6 +1,6 @@ import { CodeAssignment } from 'devu-shared-modules' -import CodeAssignmentModel from '../../model/codeAssignments.model' +import CodeAssignmentModel from '../../model/codeAssignment.model' export function serialize(codeAssignment: CodeAssignmentModel): CodeAssignment { return { diff --git a/src/utils/serializer/submissionScore.serializer.ts b/src/utils/serializer/submissionScore.serializer.ts new file mode 100644 index 00000000..1d05b397 --- /dev/null +++ b/src/utils/serializer/submissionScore.serializer.ts @@ -0,0 +1,15 @@ +import { SubmissionScore } from 'devu-shared-modules' + +import SubmissionScoreModel from '../../model/submissionScore.model' + +export function serialize(submissionScore: SubmissionScoreModel): SubmissionScore { + return { + id: submissionScore.id, + submissionId: submissionScore.submissionId, + score: submissionScore.score, + feedback: submissionScore.feedback, + releasedAt: submissionScore.releasedAt?.toISOString(), + createdAt: submissionScore.createdAt.toISOString(), + updatedAt: submissionScore.updatedAt.toISOString(), + } +} diff --git a/src/utils/serializer/tests/codeAssignments.serializer.test.ts b/src/utils/serializer/tests/codeAssignment.serializer.test.ts similarity index 91% rename from src/utils/serializer/tests/codeAssignments.serializer.test.ts rename to src/utils/serializer/tests/codeAssignment.serializer.test.ts index 434ec387..b5ed1baa 100644 --- a/src/utils/serializer/tests/codeAssignments.serializer.test.ts +++ b/src/utils/serializer/tests/codeAssignment.serializer.test.ts @@ -1,6 +1,6 @@ -import { serialize } from '../codeAssignments.serializer' +import { serialize } from '../codeAssignment.serializer' -import CodeAssignmentsModel from '../../../model/codeAssignments.model' +import CodeAssignmentsModel from '../../../model/codeAssignment.model' import Testing from '../../testing.utils' diff --git a/src/utils/serializer/tests/submissionScore.serializer.test.ts b/src/utils/serializer/tests/submissionScore.serializer.test.ts new file mode 100644 index 00000000..bb90b143 --- /dev/null +++ b/src/utils/serializer/tests/submissionScore.serializer.test.ts @@ -0,0 +1,42 @@ +import { serialize } from '../submissionScore.serializer' + +import SubmissionScoreModel from '../../../model/submissionScore.model' + +import Testing from '../../testing.utils' + +let mockSubmissionScore: SubmissionScoreModel + +describe('SubmissionScore Serializer', () => { + beforeEach(() => { + mockSubmissionScore = Testing.generateTypeOrm(SubmissionScoreModel) + + mockSubmissionScore.id = 10 + mockSubmissionScore.submissionId = 50 + mockSubmissionScore.score = 100 + mockSubmissionScore.feedback = 'Great Job!' + mockSubmissionScore.releasedAt = new Date() + mockSubmissionScore.createdAt = new Date() + mockSubmissionScore.updatedAt = new Date() + }) + + describe('Serializing SubmissionScore', () => { + test('SubmissionScore values exist in the response', () => { + const expectedResult = serialize(mockSubmissionScore) + + expect(expectedResult).toBeDefined() + expect(expectedResult.id).toEqual(mockSubmissionScore.id) + expect(expectedResult.submissionId).toEqual(mockSubmissionScore.submissionId) + expect(expectedResult.score).toEqual(mockSubmissionScore.score) + expect(expectedResult.feedback).toEqual(mockSubmissionScore.feedback) + }) + + test('createdAt, modifiedAt, and releasedAt are ISO strings', () => { + const expectedResult = serialize(mockSubmissionScore) + + expect(expectedResult).toBeDefined() + expect(expectedResult.updatedAt).toEqual(mockSubmissionScore.updatedAt.toISOString()) + expect(expectedResult.createdAt).toEqual(mockSubmissionScore.createdAt.toISOString()) + expect(expectedResult.releasedAt).toEqual(mockSubmissionScore.releasedAt?.toISOString()) + }) + }) +})