express-generator-typescript 1.10.3 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -27
- package/bin/cli.js +2 -15
- package/lib/cli.js +1 -15
- package/lib/express-generator-typescript.js +11 -21
- package/lib/project-files/.eslintrc.json +16 -2
- package/lib/project-files/build.ts +2 -2
- package/lib/project-files/package.json +15 -5
- package/lib/project-files/spec/nodemon.json +1 -1
- package/lib/{auth-proj → project-files}/spec/support/login-agent.ts +6 -8
- package/lib/{auth-proj → project-files}/spec/tests/auth.spec.ts +18 -32
- package/lib/project-files/spec/tests/users.spec.ts +31 -22
- package/lib/project-files/spec/types/supertest/index.d.ts +14 -0
- package/lib/project-files/src/models/user-model.ts +18 -3
- package/lib/project-files/src/pre-start/env/development.env +9 -0
- package/lib/project-files/src/pre-start/env/production.env +10 -0
- package/lib/project-files/src/pre-start/env/test.env +9 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/http.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/login.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/scripts/users.js +0 -0
- package/lib/{auth-proj → project-files}/src/public/stylesheets/login.css +0 -0
- package/lib/{auth-proj → project-files}/src/public/stylesheets/users.css +0 -0
- package/lib/project-files/src/repos/mock-orm.ts +2 -2
- package/lib/project-files/src/repos/user-repo.ts +1 -1
- package/lib/project-files/src/routes/api.ts +9 -6
- package/lib/{socket-io → project-files}/src/routes/auth-router.ts +14 -15
- package/lib/{auth-proj → project-files}/src/routes/middleware.ts +10 -8
- package/lib/project-files/src/routes/user-router.ts +9 -15
- package/lib/project-files/src/server.ts +82 -73
- package/lib/{auth-proj → project-files}/src/services/auth-service.ts +1 -1
- package/lib/project-files/src/services/user-service.ts +9 -9
- package/lib/project-files/src/shared/env-vars.ts +18 -0
- package/lib/project-files/src/shared/errors.ts +11 -0
- package/lib/project-files/src/shared/types.ts +14 -0
- package/lib/project-files/src/types/express/index.d.ts +16 -8
- package/lib/{socket-io → project-files}/src/util/jwt-util.ts +10 -9
- package/lib/{auth-proj → project-files}/src/views/login.html +0 -0
- package/lib/{auth-proj → project-files}/src/views/users.html +0 -0
- package/lib/project-files/tsconfig.json +3 -0
- package/package.json +1 -1
- package/chat-screenshot.png +0 -0
- package/lib/auth-proj/.eslintignore +0 -1
- package/lib/auth-proj/.eslintrc.json +0 -27
- package/lib/auth-proj/build.ts +0 -64
- package/lib/auth-proj/gitignore +0 -3
- package/lib/auth-proj/package.json +0 -73
- package/lib/auth-proj/spec/index.ts +0 -57
- package/lib/auth-proj/spec/loadEnv.ts +0 -10
- package/lib/auth-proj/spec/nodemon.json +0 -6
- package/lib/auth-proj/spec/support/jasmine.json +0 -11
- package/lib/auth-proj/spec/tests/users.spec.ts +0 -283
- package/lib/auth-proj/src/index.ts +0 -14
- package/lib/auth-proj/src/models/user-model.ts +0 -56
- package/lib/auth-proj/src/pre-start/env/development.env +0 -23
- package/lib/auth-proj/src/pre-start/env/production.env +0 -24
- package/lib/auth-proj/src/pre-start/env/test.env +0 -23
- package/lib/auth-proj/src/pre-start/index.ts +0 -28
- package/lib/auth-proj/src/repos/database.json +0 -1
- package/lib/auth-proj/src/repos/mock-orm.ts +0 -41
- package/lib/auth-proj/src/repos/user-repo.ts +0 -88
- package/lib/auth-proj/src/routes/api.ts +0 -17
- package/lib/auth-proj/src/routes/auth-router.ts +0 -63
- package/lib/auth-proj/src/routes/user-router.ts +0 -80
- package/lib/auth-proj/src/server.ts +0 -82
- package/lib/auth-proj/src/services/user-service.ts +0 -52
- package/lib/auth-proj/src/shared/env-vars.ts +0 -20
- package/lib/auth-proj/src/shared/errors.ts +0 -45
- package/lib/auth-proj/src/shared/functions.ts +0 -18
- package/lib/auth-proj/src/types/express/index.d.ts +0 -32
- package/lib/auth-proj/src/util/jwt-util.ts +0 -47
- package/lib/auth-proj/tsconfig.json +0 -100
- package/lib/auth-proj/tsconfig.prod.json +0 -11
- package/lib/project-files/src/public/scripts/index.js +0 -183
- package/lib/project-files/src/public/stylesheets/style.css +0 -33
- package/lib/project-files/src/views/index.html +0 -31
- package/lib/socket-io/.eslintignore +0 -1
- package/lib/socket-io/.eslintrc.json +0 -27
- package/lib/socket-io/build.ts +0 -64
- package/lib/socket-io/gitignore +0 -3
- package/lib/socket-io/package.json +0 -75
- package/lib/socket-io/spec/index.ts +0 -57
- package/lib/socket-io/spec/loadEnv.ts +0 -10
- package/lib/socket-io/spec/nodemon.json +0 -6
- package/lib/socket-io/spec/support/jasmine.json +0 -11
- package/lib/socket-io/spec/support/login-agent.ts +0 -49
- package/lib/socket-io/spec/tests/auth.spec.ts +0 -159
- package/lib/socket-io/spec/tests/chat.spec.ts +0 -150
- package/lib/socket-io/spec/tests/users.spec.ts +0 -283
- package/lib/socket-io/src/index.ts +0 -14
- package/lib/socket-io/src/models/user-model.ts +0 -56
- package/lib/socket-io/src/pre-start/env/development.env +0 -23
- package/lib/socket-io/src/pre-start/env/production.env +0 -24
- package/lib/socket-io/src/pre-start/env/test.env +0 -23
- package/lib/socket-io/src/pre-start/index.ts +0 -28
- package/lib/socket-io/src/public/scripts/chat.js +0 -87
- package/lib/socket-io/src/public/scripts/http.js +0 -24
- package/lib/socket-io/src/public/scripts/index.js +0 -16
- package/lib/socket-io/src/public/scripts/login.js +0 -17
- package/lib/socket-io/src/public/scripts/users.js +0 -148
- package/lib/socket-io/src/public/stylesheets/chat.css +0 -43
- package/lib/socket-io/src/public/stylesheets/index.css +0 -13
- package/lib/socket-io/src/public/stylesheets/login.css +0 -20
- package/lib/socket-io/src/public/stylesheets/users.css +0 -40
- package/lib/socket-io/src/repos/database.json +0 -38
- package/lib/socket-io/src/repos/mock-orm.ts +0 -41
- package/lib/socket-io/src/repos/user-repo.ts +0 -88
- package/lib/socket-io/src/routes/api.ts +0 -19
- package/lib/socket-io/src/routes/chat-router.ts +0 -97
- package/lib/socket-io/src/routes/middleware.ts +0 -55
- package/lib/socket-io/src/routes/user-router.ts +0 -77
- package/lib/socket-io/src/server.ts +0 -100
- package/lib/socket-io/src/services/auth-service.ts +0 -38
- package/lib/socket-io/src/services/user-service.ts +0 -52
- package/lib/socket-io/src/shared/env-vars.ts +0 -20
- package/lib/socket-io/src/shared/errors.ts +0 -56
- package/lib/socket-io/src/shared/functions.ts +0 -18
- package/lib/socket-io/src/types/express/index.d.ts +0 -34
- package/lib/socket-io/src/views/chat.html +0 -51
- package/lib/socket-io/src/views/login.html +0 -35
- package/lib/socket-io/src/views/users.html +0 -47
- package/lib/socket-io/tsconfig.json +0 -100
- package/lib/socket-io/tsconfig.prod.json +0 -11
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import bcrypt from 'bcrypt';
|
|
2
|
-
import StatusCodes from 'http-status-codes';
|
|
3
|
-
import supertest, { SuperTest, Test, Response } from 'supertest';
|
|
4
|
-
|
|
5
|
-
import app from '@server';
|
|
6
|
-
import userRepo from '@repos/user-repo';
|
|
7
|
-
import envVars from '@shared/env-vars';
|
|
8
|
-
import User, { UserRoles } from '@models/user-model';
|
|
9
|
-
import { p as paths } from '@routes/auth-router';
|
|
10
|
-
import { pErr } from '@shared/functions';
|
|
11
|
-
import { pwdSaltRounds } from 'spec/support/login-agent';
|
|
12
|
-
import { UnauthorizedError } from '@shared/errors';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// **** Variables **** //
|
|
16
|
-
|
|
17
|
-
// Misc
|
|
18
|
-
const authPath = '/api/auth',
|
|
19
|
-
loginPath = `${authPath}${paths.login}`,
|
|
20
|
-
logoutPath = `${authPath}${paths.logout}`,
|
|
21
|
-
{ BAD_REQUEST, OK, UNAUTHORIZED } = StatusCodes;
|
|
22
|
-
|
|
23
|
-
// Test message
|
|
24
|
-
const msgs = {
|
|
25
|
-
goodLogin: `should return a response with a status of ${OK} and a cookie with a jwt if the login
|
|
26
|
-
was successful.`,
|
|
27
|
-
emailNotFound: `should return a response with a status of ${UNAUTHORIZED} and a json with the
|
|
28
|
-
"error ${UnauthorizedError.Msg}" if the email was not found.`,
|
|
29
|
-
pwdFailed: `should return a response with a status of ${UNAUTHORIZED} and a json with the error
|
|
30
|
-
"${UnauthorizedError.Msg}" if the password failed.`,
|
|
31
|
-
fallbackErr: `should return a response with a status of ${BAD_REQUEST} and a json with an error
|
|
32
|
-
for all other bad responses.`,
|
|
33
|
-
goodLogout: `should return a response with a status of ${OK}.`,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// **** Types **** //
|
|
38
|
-
|
|
39
|
-
type TReqBody = string | object | undefined;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// **** Tests **** //
|
|
43
|
-
|
|
44
|
-
describe('auth-router', () => {
|
|
45
|
-
|
|
46
|
-
let agent: SuperTest<Test>;
|
|
47
|
-
|
|
48
|
-
// Run before all tests
|
|
49
|
-
beforeAll((done) => {
|
|
50
|
-
agent = supertest.agent(app);
|
|
51
|
-
done();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Test login
|
|
55
|
-
describe(`"POST:${loginPath}"`, () => {
|
|
56
|
-
|
|
57
|
-
const callApi = (reqBody: TReqBody) => {
|
|
58
|
-
return agent.post(loginPath).type('form').send(reqBody);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Good login
|
|
62
|
-
it(msgs.goodLogin, (done) => {
|
|
63
|
-
// Setup Dummy Data
|
|
64
|
-
const creds = {
|
|
65
|
-
email: 'jsmith@gmail.com',
|
|
66
|
-
password: 'Password@1',
|
|
67
|
-
};
|
|
68
|
-
const role = UserRoles.Standard;
|
|
69
|
-
const pwdHash = hashPwd(creds.password);
|
|
70
|
-
const loginUser = User.new('john smith', creds.email, role, pwdHash);
|
|
71
|
-
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
|
|
72
|
-
// Call API
|
|
73
|
-
callApi(creds)
|
|
74
|
-
.end((err: Error, res: Response) => {
|
|
75
|
-
pErr(err);
|
|
76
|
-
expect(res.status).toBe(OK);
|
|
77
|
-
expect(res.headers['set-cookie'][0]).toContain(envVars.cookieProps.key);
|
|
78
|
-
done();
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Email not found error
|
|
83
|
-
it(msgs.emailNotFound, (done) => {
|
|
84
|
-
// Setup Dummy Data
|
|
85
|
-
const creds = {
|
|
86
|
-
email: 'jsmith@gmail.com',
|
|
87
|
-
password: 'Password@1',
|
|
88
|
-
};
|
|
89
|
-
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(null));
|
|
90
|
-
// Call API
|
|
91
|
-
callApi(creds)
|
|
92
|
-
.end((err: Error, res: Response) => {
|
|
93
|
-
pErr(err);
|
|
94
|
-
expect(res.status).toBe(UNAUTHORIZED);
|
|
95
|
-
expect(res.body.error).toBe(UnauthorizedError.Msg);
|
|
96
|
-
done();
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Password failed
|
|
101
|
-
it(msgs.pwdFailed, (done) => {
|
|
102
|
-
// Setup Dummy Data
|
|
103
|
-
const creds = {
|
|
104
|
-
email: 'jsmith@gmail.com',
|
|
105
|
-
password: 'someBadPassword',
|
|
106
|
-
};
|
|
107
|
-
const role = UserRoles.Standard;
|
|
108
|
-
const pwdHash = hashPwd('Password@1');
|
|
109
|
-
const loginUser = User.new('john smith', creds.email, role, pwdHash);
|
|
110
|
-
spyOn(userRepo, 'getOne').and.returnValue(Promise.resolve(loginUser));
|
|
111
|
-
// Call API
|
|
112
|
-
callApi(creds)
|
|
113
|
-
.end((err: Error, res: Response) => {
|
|
114
|
-
pErr(err);
|
|
115
|
-
expect(res.status).toBe(UNAUTHORIZED);
|
|
116
|
-
expect(res.body.error).toBe(UnauthorizedError.Msg);
|
|
117
|
-
done();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Fallback error
|
|
122
|
-
it(msgs.fallbackErr, (done) => {
|
|
123
|
-
// Setup Dummy Data
|
|
124
|
-
const creds = {
|
|
125
|
-
email: 'jsmith@gmail.com',
|
|
126
|
-
password: 'someBadPassword',
|
|
127
|
-
};
|
|
128
|
-
spyOn(userRepo, 'getOne').and.throwError('Database query failed.');
|
|
129
|
-
// Call API
|
|
130
|
-
callApi(creds)
|
|
131
|
-
.end((err: Error, res: Response) => {
|
|
132
|
-
pErr(err);
|
|
133
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
134
|
-
expect(res.body.error).toBeTruthy();
|
|
135
|
-
done();
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Test logout
|
|
141
|
-
describe(`"GET:${logoutPath}"`, () => {
|
|
142
|
-
|
|
143
|
-
it(msgs.goodLogout, (done) => {
|
|
144
|
-
agent.get(logoutPath)
|
|
145
|
-
.end((err: Error, res: Response) => {
|
|
146
|
-
pErr(err);
|
|
147
|
-
expect(res.status).toBe(OK);
|
|
148
|
-
done();
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// **** Helper functions **** //
|
|
156
|
-
|
|
157
|
-
function hashPwd(pwd: string) {
|
|
158
|
-
return bcrypt.hashSync(pwd, pwdSaltRounds);
|
|
159
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import supertest from 'supertest';
|
|
2
|
-
import StatusCodes from 'http-status-codes';
|
|
3
|
-
import SocketIoClient, { Socket as ClientSocket } from 'socket.io-client';
|
|
4
|
-
import { SuperTest, Test, Response } from 'supertest';
|
|
5
|
-
|
|
6
|
-
import app from '@server';
|
|
7
|
-
import { pErr } from '@shared/functions';
|
|
8
|
-
import { p as chatPaths } from '@routes/chat-router';
|
|
9
|
-
import loginAgent from '../support/login-agent';
|
|
10
|
-
import { RoomNotFoundError } from '@shared/errors';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// **** Variables **** //
|
|
14
|
-
|
|
15
|
-
// Paths
|
|
16
|
-
const chatPath = '/api/chat',
|
|
17
|
-
connectSocketRmPath = `${chatPath}${chatPaths.connect}`,
|
|
18
|
-
emitMessagePath = `${chatPath}${chatPaths.emit}`;
|
|
19
|
-
|
|
20
|
-
// Http codes
|
|
21
|
-
const { BAD_REQUEST, OK } = StatusCodes;
|
|
22
|
-
|
|
23
|
-
// Messages
|
|
24
|
-
const msgs = {
|
|
25
|
-
connectSuccess: `should return a response with a status of "${OK}" if the user successfully
|
|
26
|
-
connected to the socket room`,
|
|
27
|
-
connectionFailed: `should return a response with a status of "${RoomNotFoundError.HttpStatus}"
|
|
28
|
-
if the user did not connect to the socket room`,
|
|
29
|
-
sendMsgSuccess: `should return a response with a status of "${OK}" and the logged-in user's
|
|
30
|
-
name`,
|
|
31
|
-
sendMsgFailed: `should return a response with a status of "${BAD_REQUEST}" and if the
|
|
32
|
-
send-message request failed.`,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// **** Types **** //
|
|
37
|
-
|
|
38
|
-
type TReqBody = string | object | undefined;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// **** Tests **** //
|
|
42
|
-
|
|
43
|
-
describe('chat-router', () => {
|
|
44
|
-
|
|
45
|
-
let agent: SuperTest<Test>;
|
|
46
|
-
let socket: ClientSocket;
|
|
47
|
-
let jwtCookie = '';
|
|
48
|
-
|
|
49
|
-
// Run before all tests
|
|
50
|
-
beforeAll((done) => {
|
|
51
|
-
agent = supertest.agent(app);
|
|
52
|
-
loginAgent.login(agent, (cookie: string) => {
|
|
53
|
-
const url = agent.get('/').url;
|
|
54
|
-
jwtCookie = cookie;
|
|
55
|
-
socket = SocketIoClient(url, {
|
|
56
|
-
reconnectionDelay: 0,
|
|
57
|
-
forceNew: true,
|
|
58
|
-
});
|
|
59
|
-
socket.on('connect', async () => {
|
|
60
|
-
console.log('socket connected');
|
|
61
|
-
done();
|
|
62
|
-
});
|
|
63
|
-
socket.on('disconnect', () => {
|
|
64
|
-
console.log('socket disconnected');
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Test connect to the socket room
|
|
70
|
-
describe(`"GET - ${connectSocketRmPath}"`, () => {
|
|
71
|
-
|
|
72
|
-
const callApi = (socketId: string) => {
|
|
73
|
-
const path = connectSocketRmPath.replace(':socketId', socketId);
|
|
74
|
-
return agent.get(path).set('Cookie', jwtCookie);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Connection to the room successful
|
|
78
|
-
it(msgs.connectSuccess, (done) => {
|
|
79
|
-
callApi(socket.id)
|
|
80
|
-
.end((err: Error, res: Response) => {
|
|
81
|
-
pErr(err);
|
|
82
|
-
expect(res.status).toBe(OK);
|
|
83
|
-
done();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Connection to the room failed
|
|
88
|
-
it(msgs.connectionFailed, (done) => {
|
|
89
|
-
callApi('some-bad-socket-id')
|
|
90
|
-
.end((err: Error, res: Response) => {
|
|
91
|
-
pErr(err);
|
|
92
|
-
expect(res.status).toBe(RoomNotFoundError.HttpStatus);
|
|
93
|
-
expect(res.body.error).toBe(RoomNotFoundError.Msg);
|
|
94
|
-
done();
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Test sending a message
|
|
100
|
-
describe(`"POST - ${emitMessagePath}"`, () => {
|
|
101
|
-
|
|
102
|
-
const callApi = (reqBody: TReqBody) => {
|
|
103
|
-
return agent.post(emitMessagePath)
|
|
104
|
-
.set('Cookie', jwtCookie)
|
|
105
|
-
.type('form').send(reqBody);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// Send message successfull
|
|
109
|
-
it(msgs.sendMsgSuccess, (done) => {
|
|
110
|
-
callApi({
|
|
111
|
-
socketId: socket.id,
|
|
112
|
-
message: 'How are you today?',
|
|
113
|
-
})
|
|
114
|
-
.end((err: Error, res: Response) => {
|
|
115
|
-
pErr(err);
|
|
116
|
-
expect(res.status).toBe(OK);
|
|
117
|
-
expect(res.body.senderName).toBe(loginAgent.creds.name);
|
|
118
|
-
done();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Send message failed
|
|
123
|
-
it(msgs.sendMsgFailed, (done) => {
|
|
124
|
-
callApi({
|
|
125
|
-
socketId: 'Some bad socket id',
|
|
126
|
-
message: 'How are you today?',
|
|
127
|
-
})
|
|
128
|
-
.end((err: Error, res: Response) => {
|
|
129
|
-
pErr(err);
|
|
130
|
-
expect(res.status).toBe(RoomNotFoundError.HttpStatus);
|
|
131
|
-
expect(res.body.error).toBe(RoomNotFoundError.Msg);
|
|
132
|
-
done();
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Run after all tests
|
|
138
|
-
afterAll((done) => {
|
|
139
|
-
// Cleanup
|
|
140
|
-
if (socket.connected) {
|
|
141
|
-
console.log('socket disconnecting...');
|
|
142
|
-
socket.disconnect();
|
|
143
|
-
} else {
|
|
144
|
-
// There will not be a connection unless you have done() in beforeAll,
|
|
145
|
-
// socket.on('connect'...)
|
|
146
|
-
console.log('no connection to break...');
|
|
147
|
-
}
|
|
148
|
-
done();
|
|
149
|
-
});
|
|
150
|
-
});
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import supertest from 'supertest';
|
|
2
|
-
import StatusCodes from 'http-status-codes';
|
|
3
|
-
import { SuperTest, Test, Response } from 'supertest';
|
|
4
|
-
|
|
5
|
-
import app from '@server';
|
|
6
|
-
import userRepo from '@repos/user-repo';
|
|
7
|
-
import User, { IUser } from '@models/user-model';
|
|
8
|
-
import { pErr } from '@shared/functions';
|
|
9
|
-
import { p as userPaths } from '@routes/user-router';
|
|
10
|
-
import loginAgent from '../support/login-agent';
|
|
11
|
-
import { ParamMissingError, UserNotFoundError } from '@shared/errors';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// **** Variables **** //
|
|
15
|
-
|
|
16
|
-
// Misc
|
|
17
|
-
const usersPath = '/api/users',
|
|
18
|
-
getUsersPath = `${usersPath}${userPaths.get}`,
|
|
19
|
-
addUsersPath = `${usersPath}${userPaths.add}`,
|
|
20
|
-
updateUserPath = `${usersPath}${userPaths.update}`,
|
|
21
|
-
deleteUserPath = `${usersPath}${userPaths.delete}`,
|
|
22
|
-
{ BAD_REQUEST, CREATED, OK } = StatusCodes;
|
|
23
|
-
|
|
24
|
-
// Dummy users for GET req
|
|
25
|
-
const dummyGetAllUsers = [
|
|
26
|
-
User.new('Sean Maxwell', 'sean.maxwell@gmail.com'),
|
|
27
|
-
User.new('John Smith', 'john.smith@gmail.com'),
|
|
28
|
-
User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
|
29
|
-
] as const;
|
|
30
|
-
|
|
31
|
-
// Dummy update user
|
|
32
|
-
const dummyUserData = {
|
|
33
|
-
user: User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
|
34
|
-
} as const;
|
|
35
|
-
|
|
36
|
-
// Test messages
|
|
37
|
-
const msgs = {
|
|
38
|
-
getUsersSuccess: `should return a JSON object with all the users and a status code of
|
|
39
|
-
"${OK}" if the request was successful.`,
|
|
40
|
-
getUsersBad: `should return a JSON object containing an error message and a status code of
|
|
41
|
-
"${BAD_REQUEST}" if the request was unsuccessful.`,
|
|
42
|
-
addUserSuccess: `should return a status code of "${CREATED}" if the request was successful.`,
|
|
43
|
-
addUserFailedMissingParam: `should return a JSON object with an error message of
|
|
44
|
-
"${ParamMissingError.Msg}" and a status code of "${BAD_REQUEST}" if the user param was
|
|
45
|
-
missing.`,
|
|
46
|
-
addUserFallbackErr: `should return a JSON object with an error message and a status code
|
|
47
|
-
of "${BAD_REQUEST}" if the request was unsuccessful.`,
|
|
48
|
-
updateSuccess: `should return a status code of "${OK}" if the request was successful.`,
|
|
49
|
-
updateParamMissing: `should return a JSON object with an error message of
|
|
50
|
-
"${ParamMissingError.Msg}" and a status code of "${BAD_REQUEST}" if the user param was
|
|
51
|
-
missing.`,
|
|
52
|
-
updateUserNotFound: `should return a JSON object with the error message of
|
|
53
|
-
${UserNotFoundError.Msg} and a status code of "${UserNotFoundError.HttpStatus}" if the id
|
|
54
|
-
was not found.`,
|
|
55
|
-
updateFallbackErr: `should return a JSON object with an error message and a status code of
|
|
56
|
-
"${BAD_REQUEST}" if the request was unsuccessful.`,
|
|
57
|
-
deleteSuccessful: `should return a status code of "${OK}" if the request was successful.`,
|
|
58
|
-
deleteUserNotFound: `should return a JSON object with the error message of
|
|
59
|
-
${UserNotFoundError.Msg} and a status code of "${UserNotFoundError.HttpStatus}" if the id was
|
|
60
|
-
not found.`,
|
|
61
|
-
deleteFallbackErr: `should return a JSON object with an error message and a status code of
|
|
62
|
-
"${BAD_REQUEST}" if the request was unsuccessful.`,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// **** Types **** //
|
|
67
|
-
|
|
68
|
-
type TReqBody = string | object | undefined;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// **** Tests **** //
|
|
72
|
-
|
|
73
|
-
describe('user-router', () => {
|
|
74
|
-
|
|
75
|
-
let agent: SuperTest<Test>;
|
|
76
|
-
let jwtCookie: string;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Run before all tests
|
|
80
|
-
beforeAll((done) => {
|
|
81
|
-
agent = supertest.agent(app);
|
|
82
|
-
loginAgent.login(agent, (cookie: string) => {
|
|
83
|
-
jwtCookie = cookie;
|
|
84
|
-
done();
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Test get users
|
|
89
|
-
describe(`"GET:${getUsersPath}"`, () => {
|
|
90
|
-
|
|
91
|
-
const callApi = () =>
|
|
92
|
-
agent.get(getUsersPath)
|
|
93
|
-
.set('Cookie', jwtCookie);
|
|
94
|
-
|
|
95
|
-
// Get all users
|
|
96
|
-
it(msgs.getUsersSuccess, (done) => {
|
|
97
|
-
const ret = Promise.resolve([...dummyGetAllUsers]);
|
|
98
|
-
spyOn(userRepo, 'getAll').and.returnValue(ret);
|
|
99
|
-
// Call API
|
|
100
|
-
callApi().end((err: Error, res: Response) => {
|
|
101
|
-
pErr(err);
|
|
102
|
-
expect(res.status).toBe(OK);
|
|
103
|
-
// Caste instance-objects to 'User' objects
|
|
104
|
-
const respUsers = res.body.users;
|
|
105
|
-
const retUsers: IUser[] = respUsers.map((user: IUser) => User.copy(user));
|
|
106
|
-
expect(retUsers).toEqual(dummyGetAllUsers);
|
|
107
|
-
expect(res.body.error).toBeUndefined();
|
|
108
|
-
done();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Get all users bad
|
|
113
|
-
it(msgs.getUsersBad, (done) => {
|
|
114
|
-
const errMsg = 'Could not fetch users.';
|
|
115
|
-
spyOn(userRepo, 'getAll').and.throwError(errMsg);
|
|
116
|
-
// Call API
|
|
117
|
-
callApi()
|
|
118
|
-
.end((err: Error, res: Response) => {
|
|
119
|
-
pErr(err);
|
|
120
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
121
|
-
expect(res.body.error).toBe(errMsg);
|
|
122
|
-
done();
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Test add user
|
|
128
|
-
describe(`"POST:${addUsersPath}"`, () => {
|
|
129
|
-
|
|
130
|
-
// Consts
|
|
131
|
-
const callApi = (reqBody: TReqBody) => {
|
|
132
|
-
return agent.post(addUsersPath)
|
|
133
|
-
.set('Cookie', jwtCookie)
|
|
134
|
-
.type('form').send(reqBody);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// Test add user success
|
|
138
|
-
it(msgs.addUserSuccess, (done) => {
|
|
139
|
-
spyOn(userRepo, 'add').and.returnValue(Promise.resolve());
|
|
140
|
-
callApi(dummyUserData)
|
|
141
|
-
.end((err: Error, res: Response) => {
|
|
142
|
-
pErr(err);
|
|
143
|
-
expect(res.status).toBe(CREATED);
|
|
144
|
-
expect(res.body.error).toBeUndefined();
|
|
145
|
-
done();
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Test add user failed due to missing param
|
|
150
|
-
it(msgs.addUserFailedMissingParam, (done) => {
|
|
151
|
-
callApi({})
|
|
152
|
-
.end((err: Error, res: Response) => {
|
|
153
|
-
pErr(err);
|
|
154
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
155
|
-
expect(res.body.error).toBe(ParamMissingError.Msg);
|
|
156
|
-
done();
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Default error
|
|
161
|
-
it(msgs.addUserFallbackErr, (done) => {
|
|
162
|
-
const errMsg = 'Could not add user.';
|
|
163
|
-
spyOn(userRepo, 'add').and.throwError(errMsg);
|
|
164
|
-
// Call API
|
|
165
|
-
callApi(dummyUserData)
|
|
166
|
-
.end((err: Error, res: Response) => {
|
|
167
|
-
pErr(err);
|
|
168
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
169
|
-
expect(res.body.error).toBe(errMsg);
|
|
170
|
-
done();
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// Test update users
|
|
176
|
-
describe(`"PUT:${updateUserPath}"`, () => {
|
|
177
|
-
|
|
178
|
-
const callApi = (reqBody: TReqBody) =>
|
|
179
|
-
agent.put(updateUserPath)
|
|
180
|
-
.set('Cookie', jwtCookie)
|
|
181
|
-
.type('form').send(reqBody);
|
|
182
|
-
|
|
183
|
-
// Test updating a user success
|
|
184
|
-
it(msgs.updateSuccess, (done) => {
|
|
185
|
-
spyOn(userRepo, 'update').and.returnValue(Promise.resolve());
|
|
186
|
-
spyOn(userRepo, 'persists').and.returnValue(Promise.resolve(true));
|
|
187
|
-
// Call api
|
|
188
|
-
callApi(dummyUserData)
|
|
189
|
-
.end((err: Error, res: Response) => {
|
|
190
|
-
pErr(err);
|
|
191
|
-
expect(res.status).toBe(OK);
|
|
192
|
-
expect(res.body.error).toBeUndefined();
|
|
193
|
-
done();
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// Test updating a user failed because a param was missing
|
|
198
|
-
it(msgs.updateParamMissing, (done) => {
|
|
199
|
-
callApi({})
|
|
200
|
-
.end((err: Error, res: Response) => {
|
|
201
|
-
pErr(err);
|
|
202
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
203
|
-
expect(res.body.error).toBe(ParamMissingError.Msg);
|
|
204
|
-
done();
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Update user not found
|
|
209
|
-
it(msgs.updateUserNotFound, (done) => {
|
|
210
|
-
callApi(dummyUserData)
|
|
211
|
-
.end((err: Error, res: Response) => {
|
|
212
|
-
pErr(err);
|
|
213
|
-
expect(res.status).toBe(UserNotFoundError.HttpStatus);
|
|
214
|
-
expect(res.body.error).toBe(UserNotFoundError.Msg);
|
|
215
|
-
done();
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Update fallback error
|
|
220
|
-
it(msgs.updateFallbackErr, (done) => {
|
|
221
|
-
const updateErrMsg = 'Could not update user.';
|
|
222
|
-
spyOn(userRepo, 'persists').and.returnValue(Promise.resolve(true));
|
|
223
|
-
spyOn(userRepo, 'update').and.throwError(updateErrMsg);
|
|
224
|
-
// Call API
|
|
225
|
-
callApi(dummyUserData)
|
|
226
|
-
.end((err: Error, res: Response) => {
|
|
227
|
-
pErr(err);
|
|
228
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
229
|
-
expect(res.body.error).toBe(updateErrMsg);
|
|
230
|
-
done();
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// Test delete user
|
|
236
|
-
describe(`"DELETE:${deleteUserPath}"`, () => {
|
|
237
|
-
|
|
238
|
-
const callApi = (id: number) => {
|
|
239
|
-
const path = deleteUserPath.replace(':id', id.toString());
|
|
240
|
-
return agent.delete(path).set('Cookie', jwtCookie);
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Delete user successful
|
|
244
|
-
it(msgs.deleteSuccessful, (done) => {
|
|
245
|
-
spyOn(userRepo, 'delete').and.returnValue(Promise.resolve());
|
|
246
|
-
spyOn(userRepo, 'persists').and.returnValue(Promise.resolve(true));
|
|
247
|
-
// Call api
|
|
248
|
-
callApi(5)
|
|
249
|
-
.end((err: Error, res: Response) => {
|
|
250
|
-
pErr(err);
|
|
251
|
-
expect(res.status).toBe(OK);
|
|
252
|
-
expect(res.body.error).toBeUndefined();
|
|
253
|
-
done();
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
// Delete, user not found error
|
|
258
|
-
it(msgs.deleteUserNotFound, (done) => {
|
|
259
|
-
callApi(-1)
|
|
260
|
-
.end((err: Error, res: Response) => {
|
|
261
|
-
pErr(err);
|
|
262
|
-
expect(res.status).toBe(UserNotFoundError.HttpStatus);
|
|
263
|
-
expect(res.body.error).toBe(UserNotFoundError.Msg);
|
|
264
|
-
done();
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Delete user fallback error
|
|
269
|
-
it(msgs.deleteFallbackErr, (done) => {
|
|
270
|
-
spyOn(userRepo, 'persists').and.returnValue(Promise.resolve(true));
|
|
271
|
-
const deleteErrMsg = 'Could not delete user.';
|
|
272
|
-
spyOn(userRepo, 'delete').and.throwError(deleteErrMsg);
|
|
273
|
-
// Call API
|
|
274
|
-
callApi(1)
|
|
275
|
-
.end((err: Error, res: Response) => {
|
|
276
|
-
pErr(err);
|
|
277
|
-
expect(res.status).toBe(BAD_REQUEST);
|
|
278
|
-
expect(res.body.error).toBe(deleteErrMsg);
|
|
279
|
-
done();
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import './pre-start'; // Must be the first import
|
|
2
|
-
import logger from 'jet-logger';
|
|
3
|
-
|
|
4
|
-
import server from './server';
|
|
5
|
-
import envVars from '@shared/env-vars';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// Constants
|
|
9
|
-
const serverStartMsg = 'Express server started on port: ';
|
|
10
|
-
|
|
11
|
-
// Start server
|
|
12
|
-
server.listen(envVars.port, () => {
|
|
13
|
-
logger.info(serverStartMsg + envVars.port.toString());
|
|
14
|
-
});
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// **** Types **** //
|
|
2
|
-
|
|
3
|
-
export enum UserRoles {
|
|
4
|
-
Standard,
|
|
5
|
-
Admin,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface IUser {
|
|
9
|
-
id: number;
|
|
10
|
-
name: string;
|
|
11
|
-
email: string;
|
|
12
|
-
pwdHash: string;
|
|
13
|
-
role: UserRoles;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// **** Functions **** //
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get a new User object.
|
|
21
|
-
*/
|
|
22
|
-
function _new(
|
|
23
|
-
name: string,
|
|
24
|
-
email: string,
|
|
25
|
-
role?: UserRoles,
|
|
26
|
-
pwdHash?: string,
|
|
27
|
-
): IUser {
|
|
28
|
-
return {
|
|
29
|
-
id: -1,
|
|
30
|
-
email,
|
|
31
|
-
name,
|
|
32
|
-
role: (role ?? UserRoles.Standard),
|
|
33
|
-
pwdHash: (pwdHash ?? ''),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Copy a user object.
|
|
39
|
-
*/
|
|
40
|
-
function copy(user: IUser): IUser {
|
|
41
|
-
return {
|
|
42
|
-
id: user.id,
|
|
43
|
-
email: user.email,
|
|
44
|
-
name: user.name,
|
|
45
|
-
role: user.role,
|
|
46
|
-
pwdHash: user.pwdHash,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// **** Export default **** //
|
|
52
|
-
|
|
53
|
-
export default {
|
|
54
|
-
new: _new,
|
|
55
|
-
copy,
|
|
56
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
## Environment ##
|
|
2
|
-
NODE_ENV=development
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Server ##
|
|
6
|
-
PORT=3000
|
|
7
|
-
HOST=localhost
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## Setup jet-logger ##
|
|
11
|
-
JET_LOGGER_MODE=CONSOLE
|
|
12
|
-
JET_LOGGER_FILEPATH=jet-logger.log
|
|
13
|
-
JET_LOGGER_TIMESTAMP=TRUE
|
|
14
|
-
JET_LOGGER_FORMAT=LINE
|
|
15
|
-
|
|
16
|
-
## Authentication ##
|
|
17
|
-
COOKIE_DOMAIN=localhost
|
|
18
|
-
COOKIE_PATH=/
|
|
19
|
-
SECURE_COOKIE=false
|
|
20
|
-
JWT_SECRET=xxxxxxxxxxxxxx
|
|
21
|
-
COOKIE_SECRET=xxxxxxxxxxxxxx
|
|
22
|
-
# expires in 3 days
|
|
23
|
-
COOKIE_EXP=259200000
|