Initial commit
This commit is contained in:
77
spec/index.ts
Normal file
77
spec/index.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import dotenv from 'dotenv';
|
||||
import find from 'find';
|
||||
import Jasmine from 'jasmine';
|
||||
import { parse } from 'ts-command-line-args';
|
||||
import logger from 'jet-logger';
|
||||
|
||||
|
||||
// **** Types **** //
|
||||
|
||||
interface IArgs {
|
||||
testFile: string;
|
||||
}
|
||||
|
||||
|
||||
// **** Setup **** //
|
||||
|
||||
// ** Init ** //
|
||||
|
||||
// NOTE: MUST BE FIRST!! Load env vars
|
||||
const result2 = dotenv.config({
|
||||
path: './env/test.env',
|
||||
});
|
||||
if (result2.error) {
|
||||
throw result2.error;
|
||||
}
|
||||
|
||||
// Setup command line options.
|
||||
const args = parse<IArgs>({
|
||||
testFile: {
|
||||
type: String,
|
||||
defaultValue: '',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// ** Start Jasmine ** //
|
||||
|
||||
// Init Jasmine
|
||||
const jasmine = new Jasmine();
|
||||
jasmine.exitOnCompletion = false;
|
||||
|
||||
// Set location of test files
|
||||
jasmine.loadConfig({
|
||||
random: true,
|
||||
spec_dir: 'spec',
|
||||
spec_files: [
|
||||
'./tests/**/*.spec.ts',
|
||||
],
|
||||
stopSpecOnExpectationFailure: false,
|
||||
});
|
||||
|
||||
// Run all or a single unit-test
|
||||
let execResp: Promise<jasmine.JasmineDoneInfo> | undefined;
|
||||
if (args.testFile) {
|
||||
const testFile = args.testFile;
|
||||
find.file(testFile + '.spec.ts', './spec', (files: string[]) => {
|
||||
if (files.length === 1) {
|
||||
jasmine.execute([files[0]]);
|
||||
} else {
|
||||
logger.err('Test file not found!');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
execResp = jasmine.execute();
|
||||
}
|
||||
|
||||
// Wait for tests to finish
|
||||
(async () => {
|
||||
if (!!execResp) {
|
||||
const info = await execResp;
|
||||
if (info.overallStatus === 'passed') {
|
||||
logger.info('All tests have passed :)');
|
||||
} else {
|
||||
logger.err('At least one test has failed :(');
|
||||
}
|
||||
}
|
||||
})();
|
||||
6
spec/nodemon.json
Normal file
6
spec/nodemon.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"watch": ["spec"],
|
||||
"ext": "spec.ts",
|
||||
"ignore": ["spec/support"],
|
||||
"exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./spec"
|
||||
}
|
||||
11
spec/support/jasmine.json
Normal file
11
spec/support/jasmine.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.ts"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.js"
|
||||
],
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
1
spec/support/types.ts
Normal file
1
spec/support/types.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type TReqBody = string | object | undefined;
|
||||
213
spec/tests/users.spec.ts
Normal file
213
spec/tests/users.spec.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import supertest, { SuperTest, Test, Response } from 'supertest';
|
||||
import { defaultErrMsg as ValidatorErr } from 'jet-validator';
|
||||
import insertUrlParams from 'inserturlparams';
|
||||
|
||||
import app from '@src/server';
|
||||
|
||||
import UserRepo from '@src/repos/UserRepo';
|
||||
import User from '@src/models/User';
|
||||
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
||||
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
||||
import FullPaths from '@src/routes/constants/FullPaths';
|
||||
|
||||
import { TReqBody } from 'spec/support/types';
|
||||
|
||||
|
||||
// **** Variables **** //
|
||||
|
||||
// Paths
|
||||
const {
|
||||
Get,
|
||||
Add,
|
||||
Update,
|
||||
Delete,
|
||||
} = FullPaths.Users;
|
||||
|
||||
// StatusCodes
|
||||
const {
|
||||
OK,
|
||||
CREATED,
|
||||
NOT_FOUND,
|
||||
BAD_REQUEST,
|
||||
} = HttpStatusCodes;
|
||||
|
||||
// Dummy users for GET req
|
||||
const DummyGetAllUsers = [
|
||||
User.new('Sean Maxwell', 'sean.maxwell@gmail.com'),
|
||||
User.new('John Smith', 'john.smith@gmail.com'),
|
||||
User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
||||
] as const;
|
||||
|
||||
// Dummy update user
|
||||
const DummyUserData = {
|
||||
user: User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
||||
} as const;
|
||||
|
||||
|
||||
// **** Tests **** //
|
||||
|
||||
describe('UserRouter', () => {
|
||||
|
||||
let agent: SuperTest<Test>;
|
||||
|
||||
// Run before all tests
|
||||
beforeAll((done) => {
|
||||
agent = supertest.agent(app);
|
||||
done();
|
||||
});
|
||||
|
||||
// ** Get all users ** //
|
||||
describe(`"GET:${Get}"`, () => {
|
||||
|
||||
const callApi = () => agent.get(Get);
|
||||
|
||||
// Success
|
||||
it('should return a JSON object with all the users and a status code ' +
|
||||
`of "${OK}" if the request was successful.`, (done) => {
|
||||
// Add spy
|
||||
spyOn(UserRepo, 'getAll').and.resolveTo([...DummyGetAllUsers]);
|
||||
// Call API
|
||||
callApi()
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(OK);
|
||||
for (let i = 0; i < res.body.users.length; i++) {
|
||||
const user = res.body.users[i];
|
||||
expect(user).toEqual(DummyGetAllUsers[i]);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Test add user
|
||||
describe(`"POST:${Add}"`, () => {
|
||||
|
||||
const callApi = (reqBody: TReqBody) =>
|
||||
agent
|
||||
.post(Add)
|
||||
.type('form').send(reqBody);
|
||||
|
||||
// Test add user success
|
||||
it(`should return a status code of "${CREATED}" if the request was ` +
|
||||
'successful.', (done) => {
|
||||
// Spy
|
||||
spyOn(UserRepo, 'add').and.resolveTo();
|
||||
// Call api
|
||||
callApi(DummyUserData)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(CREATED);
|
||||
expect(res.body.error).toBeUndefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Missing param
|
||||
it('should return a JSON object with an error message of ' +
|
||||
`"${ValidatorErr}" and a status code of "${BAD_REQUEST}" if the user ` +
|
||||
'param was missing.', (done) => {
|
||||
// Call api
|
||||
callApi({})
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(BAD_REQUEST);
|
||||
expect(res.body.error).toBe(ValidatorErr);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ** Update users ** //
|
||||
describe(`"PUT:${Update}"`, () => {
|
||||
|
||||
const callApi = (reqBody: TReqBody) =>
|
||||
agent
|
||||
.put(Update)
|
||||
.type('form').send(reqBody);
|
||||
|
||||
// Success
|
||||
it(`should return a status code of "${OK}" if the request was successful.`,
|
||||
(done) => {
|
||||
// Setup spies
|
||||
spyOn(UserRepo, 'update').and.resolveTo();
|
||||
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
||||
// Call api
|
||||
callApi(DummyUserData)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(OK);
|
||||
expect(res.body.error).toBeUndefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Param missing
|
||||
it('should return a JSON object with an error message of ' +
|
||||
`"${ValidatorErr}" and a status code of "${BAD_REQUEST}" if the user ` +
|
||||
'param was missing.', (done) => {
|
||||
// Call api
|
||||
callApi({})
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(BAD_REQUEST);
|
||||
expect(res.body.error).toBe(ValidatorErr);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// User not found
|
||||
it('should return a JSON object with the error message of ' +
|
||||
`"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
|
||||
'was not found.', (done) => {
|
||||
// Call api
|
||||
callApi(DummyUserData)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(NOT_FOUND);
|
||||
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ** Delete user ** //
|
||||
describe(`"DELETE:${Delete}"`, () => {
|
||||
|
||||
const callApi = (id: number) =>
|
||||
agent
|
||||
.delete(insertUrlParams(Delete, { id }));
|
||||
|
||||
// Success
|
||||
it(`should return a status code of "${OK}" if the request was successful.`,
|
||||
(done) => {
|
||||
// Setup spies
|
||||
spyOn(UserRepo, 'delete').and.resolveTo();
|
||||
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
||||
// Call api
|
||||
callApi(5)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(OK);
|
||||
expect(res.body.error).toBeUndefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// User not found
|
||||
it('should return a JSON object with the error message of ' +
|
||||
`"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
|
||||
'was not found.', (done) => {
|
||||
callApi(-1)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(NOT_FOUND);
|
||||
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Invalid param
|
||||
it(`should return a status code of "${BAD_REQUEST}" and return an error ` +
|
||||
`message of "${ValidatorErr}" if the id was not a valid number`, (done) => {
|
||||
callApi('horse' as unknown as number)
|
||||
.end((_: Error, res: Response) => {
|
||||
expect(res.status).toBe(BAD_REQUEST);
|
||||
expect(res.body.error).toBe(ValidatorErr);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
14
spec/types/supertest/index.d.ts
vendored
Normal file
14
spec/types/supertest/index.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { IUser } from '@src/models/User';
|
||||
import 'supertest';
|
||||
|
||||
|
||||
declare module 'supertest' {
|
||||
|
||||
export interface Response {
|
||||
headers: Record<string, string[]>;
|
||||
body: {
|
||||
error: string;
|
||||
users: IUser[];
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user