express-generator-typescript
Version:
Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead
132 lines (116 loc) • 5.17 kB
text/typescript
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
import { JetPaths as Paths } from '@src/common/constants/Paths';
import { ValidationError } from '@src/common/utils/route-errors';
import User, { IUser } from '@src/models/User.model';
import UserRepo from '@src/repos/UserRepo';
import { agent } from './support/agent';
import { TestRes } from './common/supertest-types';
import { parseValidationError } from './common/error-utils';
import UserService from '@src/services/UserService';
import { compareUserArrays } from './common/comparators';
/******************************************************************************
Constants
******************************************************************************/
const DUMMY_USERS = [
User.new({ name: 'Sean Maxwell', email: 'sean.maxwell@gmail.com' }),
User.new({ name: 'John Smith', email: 'john.smith@gmail.com' }),
User.new({ name: 'Gordan Freeman', email: 'gordan.freeman@gmail.com' }),
] as const;
const { BAD_REQUEST, CREATED, OK, NOT_FOUND } = HttpStatusCodes;
/******************************************************************************
Tests
IMPORTANT: Following TypeScript best practices, we test all scenarios that
can be triggered by a user under normal circumstances. Not all theoretically
scenarios (i.e. a failed database connection).
******************************************************************************/
describe('UserRouter', () => {
let dbUsers: IUser[] = [];
beforeEach(async () => {
await UserRepo.deleteAllUsers();
dbUsers = await UserRepo.insertMultiple(DUMMY_USERS);
});
describe(`"GET:${Paths.Users.Get()}"`, () => {
it(
'should return a JSON object with all the users and a status code of ' +
`"${OK}" if the request was successful.`,
async () => {
const res: TestRes<{ users: IUser[] }> = await agent.get(Paths.Users.Get());
expect(res.status).toBe(OK);
expect(compareUserArrays(res.body.users, DUMMY_USERS)).toBeTruthy();
},
);
});
describe(`"POST:${Paths.Users.Add()}"`, () => {
it(
`should return a status code of "${CREATED}" if the request was ` +
'successful.',
async () => {
const user = User.new({ name: 'a', email: 'a@a.com' }),
res = await agent.post(Paths.Users.Add()).send({ user });
expect(res.status).toBe(CREATED);
},
);
it(
'should return a JSON object with an error message of and a status ' +
`code of "${BAD_REQUEST}" if the user param was missing.`,
async () => {
const res: TestRes = await agent
.post(Paths.Users.Add())
.send({ user: null });
expect(res.status).toBe(BAD_REQUEST);
const errorObject = parseValidationError(res.body.error);
expect(errorObject.message).toBe(ValidationError.MESSAGE);
expect(errorObject.errors[0].key).toStrictEqual('user');
},
);
});
describe(`"PUT:${Paths.Users.Update()}"`, () => {
it(`should return a status code of "${OK}" if the request was successfull`, async () => {
const user = DUMMY_USERS[0];
user.name = 'Bill';
const res = await agent.put(Paths.Users.Update()).send({ user });
expect(res.status).toBe(OK);
});
it(
'should return a JSON object with an error message and a status code ' +
`of "${BAD_REQUEST}" if id is the wrong data type`,
async () => {
const user = User.new();
user.id = '5' as unknown as number;
const res: TestRes = await agent.put(Paths.Users.Update()).send({ user });
expect(res.status).toBe(BAD_REQUEST);
const errorObj = parseValidationError(res.body.error);
expect(errorObj.message).toBe(ValidationError.MESSAGE);
expect(errorObj.errors[0].keyPath).toStrictEqual(['user', 'id']);
},
);
it(
'should return a JSON object with the error message of ' +
`"${UserService.Errors.USER_NOT_FOUND}" and a status code of ` +
`"${NOT_FOUND}" if the id was not found.`,
async () => {
const user = User.new({ id: 4, name: 'a', email: 'a@a.com' }),
res: TestRes = await agent.put(Paths.Users.Update()).send({ user });
expect(res.status).toBe(NOT_FOUND);
expect(res.body.error).toBe(UserService.Errors.USER_NOT_FOUND);
},
);
});
describe(`"DELETE:${Paths.Users.Delete()}"`, () => {
it(`should return a status code of "${OK}" if the request was successful.`, async () => {
const id = dbUsers[0].id,
res = await agent.delete(Paths.Users.Delete({ id }));
expect(res.status).toBe(OK);
});
it(
'should return a JSON object with the error message of ' +
`"${UserService.Errors.USER_NOT_FOUND}" and a status code of ` +
`"${NOT_FOUND}" if the id was not found.`,
async () => {
const res: TestRes = await agent.delete(Paths.Users.Delete({ id: -1 }));
expect(res.status).toBe(NOT_FOUND);
expect(res.body.error).toBe(UserService.Errors.USER_NOT_FOUND);
},
);
});
});