express-generator-typescript 2.4.4 → 2.4.7
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/lib/express-generator-typescript.js +1 -1
- package/lib/project-files/package.json +3 -2
- package/lib/project-files/spec/support/Paths.ts +10 -0
- package/lib/project-files/spec/tests/users.spec.ts +34 -30
- package/lib/project-files/src/{routes/constants → constants}/Paths.ts +2 -10
- package/lib/project-files/src/routes/api.ts +1 -1
- package/lib/project-files/src/server.ts +1 -1
- package/lib/project-files-auth/package.json +3 -2
- package/lib/project-files-auth/spec/support/Paths.ts +10 -0
- package/lib/project-files-auth/spec/support/login.ts +6 -4
- package/lib/project-files-auth/spec/tests/auth.spec.ts +19 -15
- package/lib/project-files-auth/spec/tests/users.spec.ts +34 -30
- package/lib/project-files-auth/src/{routes/constants → constants}/Paths.ts +2 -10
- package/lib/project-files-auth/src/routes/api.ts +1 -1
- package/lib/project-files-auth/src/server.ts +1 -1
- package/package.json +1 -1
- package/lib/project-files/src/other/types.ts +0 -4
- package/lib/project-files/src/routes/constants/FullPaths.ts +0 -40
- package/lib/project-files-auth/src/other/types.ts +0 -4
- package/lib/project-files-auth/src/routes/constants/FullPaths.ts +0 -40
|
@@ -20,7 +20,7 @@ const PROJECT_FOLDER_PATH = './project-files';
|
|
|
20
20
|
// Project-folder dependencies
|
|
21
21
|
const DEPENDENCIES = 'express dotenv morgan cookie-parser jet-logger ' +
|
|
22
22
|
'module-alias express-async-errors helmet jsonfile inserturlparams ' +
|
|
23
|
-
'jet-validator ts-command-line-args',
|
|
23
|
+
'jet-validator ts-command-line-args jet-paths',
|
|
24
24
|
DEPENDENCIES_AUTH = ' bcrypt jsonwebtoken',
|
|
25
25
|
DEV_DEPENDENCIES = 'ts-node typescript nodemon find jasmine supertest ' +
|
|
26
26
|
'@types/node @types/express @types/jasmine @types/find @types/morgan ' +
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"inserturlparams": "^1.0.1",
|
|
37
37
|
"jet-logger": "^1.3.1",
|
|
38
38
|
"jet-validator": "^1.0.3",
|
|
39
|
+
"jet-paths": "^1.0.5",
|
|
39
40
|
"jsonfile": "^6.1.0",
|
|
40
41
|
"jsonwebtoken": "^8.5.1",
|
|
41
42
|
"module-alias": "^2.2.2",
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
"@types/jsonwebtoken": "^8.5.9",
|
|
54
55
|
"@types/morgan": "^1.9.3",
|
|
55
56
|
"@types/node": "^18.7.14",
|
|
56
|
-
"@types/supertest": "^
|
|
57
|
+
"@types/supertest": "^6.0.2",
|
|
57
58
|
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
|
58
59
|
"@typescript-eslint/parser": "^5.36.1",
|
|
59
60
|
"eslint": "^8.23.0",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"fs-extra": "^10.1.0",
|
|
63
64
|
"jasmine": "^4.3.0",
|
|
64
65
|
"nodemon": "^2.0.19",
|
|
65
|
-
"supertest": "^6.
|
|
66
|
+
"supertest": "^6.3.4",
|
|
66
67
|
"ts-node": "^10.9.1",
|
|
67
68
|
"tsconfig-paths": "^4.1.0",
|
|
68
69
|
"typescript": "^4.8.2"
|
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
import supertest, {
|
|
1
|
+
import supertest, { Test, Response } from 'supertest';
|
|
2
|
+
import TestAgent from 'supertest/lib/agent';
|
|
2
3
|
import { defaultErrMsg as ValidatorErr } from 'jet-validator';
|
|
3
4
|
import insertUrlParams from 'inserturlparams';
|
|
4
5
|
|
|
5
6
|
import app from '@src/server';
|
|
6
7
|
|
|
7
8
|
import UserRepo from '@src/repos/UserRepo';
|
|
8
|
-
import User from '@src/models/User';
|
|
9
|
+
import User, { IUser } from '@src/models/User';
|
|
9
10
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
10
11
|
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
|
11
|
-
import FullPaths from '@src/routes/constants/FullPaths';
|
|
12
12
|
|
|
13
|
+
import Paths from 'spec/support/Paths';
|
|
13
14
|
import { TReqBody } from 'spec/support/types';
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
// **** Variables **** //
|
|
17
18
|
|
|
18
|
-
// Paths
|
|
19
|
-
const {
|
|
20
|
-
Get,
|
|
21
|
-
Add,
|
|
22
|
-
Update,
|
|
23
|
-
Delete,
|
|
24
|
-
} = FullPaths.Users;
|
|
25
|
-
|
|
26
19
|
// StatusCodes
|
|
27
20
|
const {
|
|
28
21
|
OK,
|
|
@@ -44,11 +37,21 @@ const DummyUserData = {
|
|
|
44
37
|
} as const;
|
|
45
38
|
|
|
46
39
|
|
|
40
|
+
// **** Types **** //
|
|
41
|
+
|
|
42
|
+
type TRes = Omit<Response, 'body'> & {
|
|
43
|
+
body: {
|
|
44
|
+
users: IUser[];
|
|
45
|
+
error: string;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
|
|
47
50
|
// **** Tests **** //
|
|
48
51
|
|
|
49
52
|
describe('UserRouter', () => {
|
|
50
53
|
|
|
51
|
-
let agent:
|
|
54
|
+
let agent: TestAgent<Test>;
|
|
52
55
|
|
|
53
56
|
// Run before all tests
|
|
54
57
|
beforeAll((done) => {
|
|
@@ -57,9 +60,9 @@ describe('UserRouter', () => {
|
|
|
57
60
|
});
|
|
58
61
|
|
|
59
62
|
// ** Get all users ** //
|
|
60
|
-
describe(`"GET:${Get}"`, () => {
|
|
63
|
+
describe(`"GET:${Paths.Users.Get}"`, () => {
|
|
61
64
|
|
|
62
|
-
const callApi = () => agent.get(Get);
|
|
65
|
+
const callApi = () => agent.get(Paths.Users.Get);
|
|
63
66
|
|
|
64
67
|
// Success
|
|
65
68
|
it('should return a JSON object with all the users and a status code ' +
|
|
@@ -68,7 +71,7 @@ describe('UserRouter', () => {
|
|
|
68
71
|
spyOn(UserRepo, 'getAll').and.resolveTo([...DummyGetAllUsers]);
|
|
69
72
|
// Call API
|
|
70
73
|
callApi()
|
|
71
|
-
.end((_: Error, res:
|
|
74
|
+
.end((_: Error, res: TRes) => {
|
|
72
75
|
expect(res.status).toBe(OK);
|
|
73
76
|
for (let i = 0; i < res.body.users.length; i++) {
|
|
74
77
|
const user = res.body.users[i];
|
|
@@ -80,13 +83,13 @@ describe('UserRouter', () => {
|
|
|
80
83
|
});
|
|
81
84
|
|
|
82
85
|
// Test add user
|
|
83
|
-
describe(`"POST:${Add}"`, () => {
|
|
86
|
+
describe(`"POST:${Paths.Users.Add}"`, () => {
|
|
84
87
|
|
|
85
88
|
const ERROR_MSG = `${ValidatorErr}"user".`;
|
|
86
89
|
|
|
87
90
|
const callApi = (reqBody: TReqBody) =>
|
|
88
91
|
agent
|
|
89
|
-
.post(Add)
|
|
92
|
+
.post(Paths.Users.Add)
|
|
90
93
|
.type('form').send(reqBody);
|
|
91
94
|
|
|
92
95
|
// Test add user success
|
|
@@ -96,7 +99,7 @@ describe('UserRouter', () => {
|
|
|
96
99
|
spyOn(UserRepo, 'add').and.resolveTo();
|
|
97
100
|
// Call api
|
|
98
101
|
callApi(DummyUserData)
|
|
99
|
-
.end((_: Error, res:
|
|
102
|
+
.end((_: Error, res: TRes) => {
|
|
100
103
|
expect(res.status).toBe(CREATED);
|
|
101
104
|
expect(res.body.error).toBeUndefined();
|
|
102
105
|
done();
|
|
@@ -109,7 +112,7 @@ describe('UserRouter', () => {
|
|
|
109
112
|
'param was missing.', (done) => {
|
|
110
113
|
// Call api
|
|
111
114
|
callApi({})
|
|
112
|
-
.end((_: Error, res:
|
|
115
|
+
.end((_: Error, res: TRes) => {
|
|
113
116
|
expect(res.status).toBe(BAD_REQUEST);
|
|
114
117
|
expect(res.body.error).toBe(ERROR_MSG);
|
|
115
118
|
done();
|
|
@@ -118,13 +121,13 @@ describe('UserRouter', () => {
|
|
|
118
121
|
});
|
|
119
122
|
|
|
120
123
|
// ** Update users ** //
|
|
121
|
-
describe(`"PUT:${Update}"`, () => {
|
|
124
|
+
describe(`"PUT:${Paths.Users.Update}"`, () => {
|
|
122
125
|
|
|
123
126
|
const ERROR_MSG = `${ValidatorErr}"user".`;
|
|
124
127
|
|
|
125
128
|
const callApi = (reqBody: TReqBody) =>
|
|
126
129
|
agent
|
|
127
|
-
.put(Update)
|
|
130
|
+
.put(Paths.Users.Update)
|
|
128
131
|
.type('form').send(reqBody);
|
|
129
132
|
|
|
130
133
|
// Success
|
|
@@ -135,7 +138,7 @@ describe('UserRouter', () => {
|
|
|
135
138
|
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
|
136
139
|
// Call api
|
|
137
140
|
callApi(DummyUserData)
|
|
138
|
-
.end((_: Error, res:
|
|
141
|
+
.end((_: Error, res: TRes) => {
|
|
139
142
|
expect(res.status).toBe(OK);
|
|
140
143
|
expect(res.body.error).toBeUndefined();
|
|
141
144
|
done();
|
|
@@ -148,7 +151,7 @@ describe('UserRouter', () => {
|
|
|
148
151
|
'param was missing.', (done) => {
|
|
149
152
|
// Call api
|
|
150
153
|
callApi({})
|
|
151
|
-
.end((_: Error, res:
|
|
154
|
+
.end((_: Error, res: TRes) => {
|
|
152
155
|
expect(res.status).toBe(BAD_REQUEST);
|
|
153
156
|
expect(res.body.error).toBe(ERROR_MSG);
|
|
154
157
|
done();
|
|
@@ -161,7 +164,7 @@ describe('UserRouter', () => {
|
|
|
161
164
|
'was not found.', (done) => {
|
|
162
165
|
// Call api
|
|
163
166
|
callApi(DummyUserData)
|
|
164
|
-
.end((_: Error, res:
|
|
167
|
+
.end((_: Error, res: TRes) => {
|
|
165
168
|
expect(res.status).toBe(NOT_FOUND);
|
|
166
169
|
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
167
170
|
done();
|
|
@@ -170,13 +173,13 @@ describe('UserRouter', () => {
|
|
|
170
173
|
});
|
|
171
174
|
|
|
172
175
|
// ** Delete user ** //
|
|
173
|
-
describe(`"DELETE:${Delete}"`, () => {
|
|
176
|
+
describe(`"DELETE:${Paths.Users.Delete}"`, () => {
|
|
174
177
|
|
|
175
178
|
const VALIDATOR_ERR = `${ValidatorErr}"id".`;
|
|
176
179
|
|
|
177
180
|
const callApi = (id: number) =>
|
|
178
181
|
agent
|
|
179
|
-
.delete(insertUrlParams(Delete, { id }));
|
|
182
|
+
.delete(insertUrlParams(Paths.Users.Delete, { id }));
|
|
180
183
|
|
|
181
184
|
// Success
|
|
182
185
|
it(`should return a status code of "${OK}" if the request was successful.`,
|
|
@@ -186,7 +189,7 @@ describe('UserRouter', () => {
|
|
|
186
189
|
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
|
187
190
|
// Call api
|
|
188
191
|
callApi(5)
|
|
189
|
-
.end((_: Error, res:
|
|
192
|
+
.end((_: Error, res: TRes) => {
|
|
190
193
|
expect(res.status).toBe(OK);
|
|
191
194
|
expect(res.body.error).toBeUndefined();
|
|
192
195
|
done();
|
|
@@ -198,7 +201,7 @@ describe('UserRouter', () => {
|
|
|
198
201
|
`"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
|
|
199
202
|
'was not found.', (done) => {
|
|
200
203
|
callApi(-1)
|
|
201
|
-
.end((_: Error, res:
|
|
204
|
+
.end((_: Error, res: TRes) => {
|
|
202
205
|
expect(res.status).toBe(NOT_FOUND);
|
|
203
206
|
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
204
207
|
done();
|
|
@@ -207,9 +210,10 @@ describe('UserRouter', () => {
|
|
|
207
210
|
|
|
208
211
|
// Invalid param
|
|
209
212
|
it(`should return a status code of "${BAD_REQUEST}" and return an error ` +
|
|
210
|
-
|
|
213
|
+
`message of "${VALIDATOR_ERR}" if the id was not a valid number`,
|
|
214
|
+
(done) => {
|
|
211
215
|
callApi('horse' as unknown as number)
|
|
212
|
-
.end((_: Error, res:
|
|
216
|
+
.end((_: Error, res: TRes) => {
|
|
213
217
|
expect(res.status).toBe(BAD_REQUEST);
|
|
214
218
|
expect(res.body.error).toBe(VALIDATOR_ERR);
|
|
215
219
|
done();
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* Express router paths go here.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { Immutable } from '@src/other/types';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const Paths = {
|
|
6
|
+
export default {
|
|
9
7
|
Base: '/api',
|
|
10
8
|
Users: {
|
|
11
9
|
Base: '/users',
|
|
@@ -14,10 +12,4 @@ const Paths = {
|
|
|
14
12
|
Update: '/update',
|
|
15
13
|
Delete: '/delete/:id',
|
|
16
14
|
},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// **** Export **** //
|
|
21
|
-
|
|
22
|
-
export type TPaths = Immutable<typeof Paths>;
|
|
23
|
-
export default Paths as TPaths;
|
|
15
|
+
} as const;
|
|
@@ -12,7 +12,7 @@ import logger from 'jet-logger';
|
|
|
12
12
|
import 'express-async-errors';
|
|
13
13
|
|
|
14
14
|
import BaseRouter from '@src/routes/api';
|
|
15
|
-
import Paths from '@src/
|
|
15
|
+
import Paths from '@src/constants/Paths';
|
|
16
16
|
|
|
17
17
|
import EnvVars from '@src/constants/EnvVars';
|
|
18
18
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"inserturlparams": "^1.0.1",
|
|
37
37
|
"jet-logger": "^1.3.1",
|
|
38
38
|
"jet-validator": "^1.0.3",
|
|
39
|
+
"jet-paths": "^1.0.5",
|
|
39
40
|
"jsonfile": "^6.1.0",
|
|
40
41
|
"jsonwebtoken": "^8.5.1",
|
|
41
42
|
"module-alias": "^2.2.2",
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
"@types/jsonwebtoken": "^8.5.9",
|
|
54
55
|
"@types/morgan": "^1.9.3",
|
|
55
56
|
"@types/node": "^18.7.14",
|
|
56
|
-
"@types/supertest": "^
|
|
57
|
+
"@types/supertest": "^6.0.2",
|
|
57
58
|
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
|
58
59
|
"@typescript-eslint/parser": "^5.36.1",
|
|
59
60
|
"eslint": "^8.23.0",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"fs-extra": "^10.1.0",
|
|
63
64
|
"jasmine": "^4.3.0",
|
|
64
65
|
"nodemon": "^2.0.19",
|
|
65
|
-
"supertest": "^6.
|
|
66
|
+
"supertest": "^6.3.4",
|
|
66
67
|
"ts-node": "^10.9.1",
|
|
67
68
|
"tsconfig-paths": "^4.1.0",
|
|
68
69
|
"typescript": "^4.8.2"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Test, Response } from 'supertest';
|
|
2
|
+
import TestAgent from 'supertest/lib/agent';
|
|
2
3
|
|
|
3
4
|
import User, { UserRoles } from '@src/models/User';
|
|
4
5
|
import UserRepo from '@src/repos/UserRepo';
|
|
5
6
|
import PwdUtil from '@src/util/PwdUtil';
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
import Paths from './Paths';
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
// **** Variables **** //
|
|
@@ -19,7 +21,7 @@ const LoginCreds = {
|
|
|
19
21
|
/**
|
|
20
22
|
* Login a user.
|
|
21
23
|
*/
|
|
22
|
-
function login(beforeAgent:
|
|
24
|
+
function login(beforeAgent: TestAgent<Test>, done: (arg: string) => void) {
|
|
23
25
|
// Setup dummy data
|
|
24
26
|
const role = UserRoles.Admin,
|
|
25
27
|
pwdHash = PwdUtil.hashSync(LoginCreds.password),
|
|
@@ -28,7 +30,7 @@ function login(beforeAgent: SuperTest<Test>, done: (arg: string) => void) {
|
|
|
28
30
|
spyOn(UserRepo, 'getOne').and.resolveTo(loginUser);
|
|
29
31
|
// Call Login API
|
|
30
32
|
beforeAgent
|
|
31
|
-
.post(
|
|
33
|
+
.post(Paths.Auth.Login)
|
|
32
34
|
.type('form')
|
|
33
35
|
.send(LoginCreds)
|
|
34
36
|
.end((_: Error, res: Response) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import supertest, {
|
|
1
|
+
import supertest, { Test, Response } from 'supertest';
|
|
2
2
|
|
|
3
3
|
import app from '@src/server';
|
|
4
4
|
|
|
@@ -7,21 +7,16 @@ import PwdUtil from '@src/util/PwdUtil';
|
|
|
7
7
|
import User, { UserRoles } from '@src/models/User';
|
|
8
8
|
import { Errors } from '@src/services/AuthService';
|
|
9
9
|
|
|
10
|
-
import FullPaths from '@src/routes/constants/FullPaths';
|
|
11
10
|
import EnvVars from '@src/constants/EnvVars';
|
|
12
11
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
13
12
|
|
|
13
|
+
import Paths from 'spec/support/Paths';
|
|
14
14
|
import { TReqBody } from 'spec/support/types';
|
|
15
|
+
import TestAgent from 'supertest/lib/agent';
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
// **** Variables **** //
|
|
18
19
|
|
|
19
|
-
// Paths
|
|
20
|
-
const {
|
|
21
|
-
Login,
|
|
22
|
-
Logout,
|
|
23
|
-
} = FullPaths.Auth;
|
|
24
|
-
|
|
25
20
|
// StatusCodes
|
|
26
21
|
const {
|
|
27
22
|
OK,
|
|
@@ -35,11 +30,20 @@ const LoginCreds = {
|
|
|
35
30
|
} as const;
|
|
36
31
|
|
|
37
32
|
|
|
33
|
+
// **** Types **** //
|
|
34
|
+
|
|
35
|
+
type TRes = Omit<Response, 'body'> & {
|
|
36
|
+
body: {
|
|
37
|
+
error: string;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
|
|
38
42
|
// **** Tests **** //
|
|
39
43
|
|
|
40
44
|
describe('AuthRouter', () => {
|
|
41
45
|
|
|
42
|
-
let agent:
|
|
46
|
+
let agent: TestAgent<Test>;
|
|
43
47
|
|
|
44
48
|
// Run before all tests
|
|
45
49
|
beforeAll((done) => {
|
|
@@ -48,13 +52,13 @@ describe('AuthRouter', () => {
|
|
|
48
52
|
});
|
|
49
53
|
|
|
50
54
|
// ** Test login ** //
|
|
51
|
-
describe(`"POST:${Login}"`, () => {
|
|
55
|
+
describe(`"POST:${Paths.Auth.Login}"`, () => {
|
|
52
56
|
|
|
53
57
|
const EMAIL_NOT_FOUND_ERR = Errors.EmailNotFound(LoginCreds.email);
|
|
54
58
|
|
|
55
59
|
const callApi = (reqBody: TReqBody) =>
|
|
56
60
|
agent
|
|
57
|
-
.post(Login)
|
|
61
|
+
.post(Paths.Auth.Login)
|
|
58
62
|
.type('form')
|
|
59
63
|
.send(reqBody);
|
|
60
64
|
|
|
@@ -85,7 +89,7 @@ describe('AuthRouter', () => {
|
|
|
85
89
|
spyOn(UserRepo, 'getOne').and.resolveTo(null);
|
|
86
90
|
// Call
|
|
87
91
|
callApi(LoginCreds)
|
|
88
|
-
.end((_: Error, res:
|
|
92
|
+
.end((_: Error, res: TRes) => {
|
|
89
93
|
expect(res.status).toBe(UNAUTHORIZED);
|
|
90
94
|
expect(res.body.error).toBe(EMAIL_NOT_FOUND_ERR);
|
|
91
95
|
done();
|
|
@@ -104,7 +108,7 @@ describe('AuthRouter', () => {
|
|
|
104
108
|
spyOn(UserRepo, 'getOne').and.resolveTo(loginUser);
|
|
105
109
|
// Call API
|
|
106
110
|
callApi(LoginCreds)
|
|
107
|
-
.end((_: Error, res:
|
|
111
|
+
.end((_: Error, res: TRes) => {
|
|
108
112
|
expect(res.status).toBe(UNAUTHORIZED);
|
|
109
113
|
expect(res.body.error).toBe(Errors.Unauth);
|
|
110
114
|
done();
|
|
@@ -114,11 +118,11 @@ describe('AuthRouter', () => {
|
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
// ** Test logout ** //
|
|
117
|
-
describe(`"GET:${Logout}"`, () => {
|
|
121
|
+
describe(`"GET:${Paths.Auth.Logout}"`, () => {
|
|
118
122
|
|
|
119
123
|
// Successful logout
|
|
120
124
|
it(`should return a response with a status of ${OK}`, (done) => {
|
|
121
|
-
agent.get(Logout)
|
|
125
|
+
agent.get(Paths.Auth.Logout)
|
|
122
126
|
.end((_: Error, res: Response) => {
|
|
123
127
|
expect(res.status).toBe(HttpStatusCodes.OK);
|
|
124
128
|
done();
|
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
import supertest, {
|
|
1
|
+
import supertest, { Test, Response } from 'supertest';
|
|
2
|
+
import TestAgent from 'supertest/lib/agent';
|
|
2
3
|
import { defaultErrMsg as ValidatorErr } from 'jet-validator';
|
|
3
4
|
import insertUrlParams from 'inserturlparams';
|
|
4
5
|
|
|
5
6
|
import app from '@src/server';
|
|
6
7
|
|
|
7
8
|
import UserRepo from '@src/repos/UserRepo';
|
|
8
|
-
import User from '@src/models/User';
|
|
9
|
+
import User, { IUser } from '@src/models/User';
|
|
9
10
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
10
11
|
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
|
11
|
-
import FullPaths from '@src/routes/constants/FullPaths';
|
|
12
12
|
|
|
13
13
|
import login from '../support/login';
|
|
14
|
+
import Paths from 'spec/support/Paths';
|
|
14
15
|
import { TReqBody } from 'spec/support/types';
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
// **** Variables **** //
|
|
18
19
|
|
|
19
|
-
// Paths
|
|
20
|
-
const {
|
|
21
|
-
Get,
|
|
22
|
-
Add,
|
|
23
|
-
Update,
|
|
24
|
-
Delete,
|
|
25
|
-
} = FullPaths.Users;
|
|
26
|
-
|
|
27
20
|
// StatusCodes
|
|
28
21
|
const {
|
|
29
22
|
OK,
|
|
@@ -45,11 +38,21 @@ const DummyUserData = {
|
|
|
45
38
|
} as const;
|
|
46
39
|
|
|
47
40
|
|
|
41
|
+
// **** Types **** //
|
|
42
|
+
|
|
43
|
+
type TRes = Omit<Response, 'body'> & {
|
|
44
|
+
body: {
|
|
45
|
+
users: IUser[];
|
|
46
|
+
error: string;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
|
|
48
51
|
// **** Tests **** //
|
|
49
52
|
|
|
50
53
|
describe('UserRouter', () => {
|
|
51
54
|
|
|
52
|
-
let agent:
|
|
55
|
+
let agent: TestAgent<Test>,
|
|
53
56
|
jwtCookie: string;
|
|
54
57
|
|
|
55
58
|
// Run before all tests
|
|
@@ -62,11 +65,11 @@ describe('UserRouter', () => {
|
|
|
62
65
|
});
|
|
63
66
|
|
|
64
67
|
// ** Get all users ** //
|
|
65
|
-
describe(`"GET:${Get}"`, () => {
|
|
68
|
+
describe(`"GET:${Paths.Users.Get}"`, () => {
|
|
66
69
|
|
|
67
70
|
const callApi = () =>
|
|
68
71
|
agent
|
|
69
|
-
.get(Get)
|
|
72
|
+
.get(Paths.Users.Get)
|
|
70
73
|
.set('Cookie', jwtCookie);
|
|
71
74
|
|
|
72
75
|
// Success
|
|
@@ -76,7 +79,7 @@ describe('UserRouter', () => {
|
|
|
76
79
|
spyOn(UserRepo, 'getAll').and.resolveTo([...DummyGetAllUsers]);
|
|
77
80
|
// Call API
|
|
78
81
|
callApi()
|
|
79
|
-
.end((_: Error, res:
|
|
82
|
+
.end((_: Error, res: TRes) => {
|
|
80
83
|
expect(res.status).toBe(OK);
|
|
81
84
|
for (let i = 0; i < res.body.users.length; i++) {
|
|
82
85
|
const user = res.body.users[i];
|
|
@@ -88,13 +91,13 @@ describe('UserRouter', () => {
|
|
|
88
91
|
});
|
|
89
92
|
|
|
90
93
|
// Test add user
|
|
91
|
-
describe(`"POST:${Add}"`, () => {
|
|
94
|
+
describe(`"POST:${Paths.Users.Add}"`, () => {
|
|
92
95
|
|
|
93
96
|
const ERROR_MSG = `${ValidatorErr}"user".`;
|
|
94
97
|
|
|
95
98
|
const callApi = (reqBody: TReqBody) =>
|
|
96
99
|
agent
|
|
97
|
-
.post(Add)
|
|
100
|
+
.post(Paths.Users.Add)
|
|
98
101
|
.set('Cookie', jwtCookie)
|
|
99
102
|
.type('form').send(reqBody);
|
|
100
103
|
|
|
@@ -105,7 +108,7 @@ describe('UserRouter', () => {
|
|
|
105
108
|
spyOn(UserRepo, 'add').and.resolveTo();
|
|
106
109
|
// Call api
|
|
107
110
|
callApi(DummyUserData)
|
|
108
|
-
.end((_: Error, res:
|
|
111
|
+
.end((_: Error, res: TRes) => {
|
|
109
112
|
expect(res.status).toBe(CREATED);
|
|
110
113
|
expect(res.body.error).toBeUndefined();
|
|
111
114
|
done();
|
|
@@ -118,7 +121,7 @@ describe('UserRouter', () => {
|
|
|
118
121
|
'param was missing.', (done) => {
|
|
119
122
|
// Call api
|
|
120
123
|
callApi({})
|
|
121
|
-
.end((_: Error, res:
|
|
124
|
+
.end((_: Error, res: TRes) => {
|
|
122
125
|
expect(res.status).toBe(BAD_REQUEST);
|
|
123
126
|
expect(res.body.error).toBe(ERROR_MSG);
|
|
124
127
|
done();
|
|
@@ -127,13 +130,13 @@ describe('UserRouter', () => {
|
|
|
127
130
|
});
|
|
128
131
|
|
|
129
132
|
// ** Update users ** //
|
|
130
|
-
describe(`"PUT:${Update}"`, () => {
|
|
133
|
+
describe(`"PUT:${Paths.Users.Update}"`, () => {
|
|
131
134
|
|
|
132
135
|
const ERROR_MSG = `${ValidatorErr}"user".`;
|
|
133
136
|
|
|
134
137
|
const callApi = (reqBody: TReqBody) =>
|
|
135
138
|
agent
|
|
136
|
-
.put(Update)
|
|
139
|
+
.put(Paths.Users.Update)
|
|
137
140
|
.set('Cookie', jwtCookie)
|
|
138
141
|
.type('form').send(reqBody);
|
|
139
142
|
|
|
@@ -145,7 +148,7 @@ describe('UserRouter', () => {
|
|
|
145
148
|
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
|
146
149
|
// Call api
|
|
147
150
|
callApi(DummyUserData)
|
|
148
|
-
.end((_: Error, res:
|
|
151
|
+
.end((_: Error, res: TRes) => {
|
|
149
152
|
expect(res.status).toBe(OK);
|
|
150
153
|
expect(res.body.error).toBeUndefined();
|
|
151
154
|
done();
|
|
@@ -158,7 +161,7 @@ describe('UserRouter', () => {
|
|
|
158
161
|
'param was missing.', (done) => {
|
|
159
162
|
// Call api
|
|
160
163
|
callApi({})
|
|
161
|
-
.end((_: Error, res:
|
|
164
|
+
.end((_: Error, res: TRes) => {
|
|
162
165
|
expect(res.status).toBe(BAD_REQUEST);
|
|
163
166
|
expect(res.body.error).toBe(ERROR_MSG);
|
|
164
167
|
done();
|
|
@@ -171,7 +174,7 @@ describe('UserRouter', () => {
|
|
|
171
174
|
'was not found.', (done) => {
|
|
172
175
|
// Call api
|
|
173
176
|
callApi(DummyUserData)
|
|
174
|
-
.end((_: Error, res:
|
|
177
|
+
.end((_: Error, res: TRes) => {
|
|
175
178
|
expect(res.status).toBe(NOT_FOUND);
|
|
176
179
|
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
177
180
|
done();
|
|
@@ -180,13 +183,13 @@ describe('UserRouter', () => {
|
|
|
180
183
|
});
|
|
181
184
|
|
|
182
185
|
// ** Delete user ** //
|
|
183
|
-
describe(`"DELETE:${Delete}"`, () => {
|
|
186
|
+
describe(`"DELETE:${Paths.Users.Delete}"`, () => {
|
|
184
187
|
|
|
185
188
|
const VALIDATOR_ERR = `${ValidatorErr}"id".`;
|
|
186
189
|
|
|
187
190
|
const callApi = (id: number) =>
|
|
188
191
|
agent
|
|
189
|
-
.delete(insertUrlParams(Delete, { id }))
|
|
192
|
+
.delete(insertUrlParams(Paths.Users.Delete, { id }))
|
|
190
193
|
.set('Cookie', jwtCookie);
|
|
191
194
|
|
|
192
195
|
// Success
|
|
@@ -197,7 +200,7 @@ describe('UserRouter', () => {
|
|
|
197
200
|
spyOn(UserRepo, 'persists').and.resolveTo(true);
|
|
198
201
|
// Call api
|
|
199
202
|
callApi(5)
|
|
200
|
-
.end((_: Error, res:
|
|
203
|
+
.end((_: Error, res: TRes) => {
|
|
201
204
|
expect(res.status).toBe(OK);
|
|
202
205
|
expect(res.body.error).toBeUndefined();
|
|
203
206
|
done();
|
|
@@ -209,7 +212,7 @@ describe('UserRouter', () => {
|
|
|
209
212
|
`"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
|
|
210
213
|
'was not found.', (done) => {
|
|
211
214
|
callApi(-1)
|
|
212
|
-
.end((_: Error, res:
|
|
215
|
+
.end((_: Error, res: TRes) => {
|
|
213
216
|
expect(res.status).toBe(NOT_FOUND);
|
|
214
217
|
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
215
218
|
done();
|
|
@@ -218,9 +221,10 @@ describe('UserRouter', () => {
|
|
|
218
221
|
|
|
219
222
|
// Invalid param
|
|
220
223
|
it(`should return a status code of "${BAD_REQUEST}" and return an error ` +
|
|
221
|
-
|
|
224
|
+
`message of "${VALIDATOR_ERR}" if the id was not a valid number`,
|
|
225
|
+
(done) => {
|
|
222
226
|
callApi('horse' as unknown as number)
|
|
223
|
-
.end((_: Error, res:
|
|
227
|
+
.end((_: Error, res: TRes) => {
|
|
224
228
|
expect(res.status).toBe(BAD_REQUEST);
|
|
225
229
|
expect(res.body.error).toBe(VALIDATOR_ERR);
|
|
226
230
|
done();
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* Express router paths go here.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { Immutable } from '@src/other/types';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const Paths = {
|
|
6
|
+
export default {
|
|
9
7
|
Base: '/api',
|
|
10
8
|
Auth: {
|
|
11
9
|
Base: '/auth',
|
|
@@ -19,10 +17,4 @@ const Paths = {
|
|
|
19
17
|
Update: '/update',
|
|
20
18
|
Delete: '/delete/:id',
|
|
21
19
|
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// **** Export **** //
|
|
26
|
-
|
|
27
|
-
export type TPaths = Immutable<typeof Paths>;
|
|
28
|
-
export default Paths as TPaths;
|
|
20
|
+
} as const;
|
|
@@ -2,7 +2,7 @@ import { Router } from 'express';
|
|
|
2
2
|
import jetValidator from 'jet-validator';
|
|
3
3
|
|
|
4
4
|
import adminMw from './middleware/adminMw';
|
|
5
|
-
import Paths from '
|
|
5
|
+
import Paths from '../constants/Paths';
|
|
6
6
|
import User from '@src/models/User';
|
|
7
7
|
import AuthRoutes from './AuthRoutes';
|
|
8
8
|
import UserRoutes from './UserRoutes';
|
|
@@ -12,7 +12,7 @@ import logger from 'jet-logger';
|
|
|
12
12
|
import 'express-async-errors';
|
|
13
13
|
|
|
14
14
|
import BaseRouter from '@src/routes/api';
|
|
15
|
-
import Paths from '@src/
|
|
15
|
+
import Paths from '@src/constants/Paths';
|
|
16
16
|
|
|
17
17
|
import EnvVars from '@src/constants/EnvVars';
|
|
18
18
|
import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.7",
|
|
4
4
|
"description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"express-generator-typescript": "node bin/cli.js",
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Convert paths to full paths.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import Paths, { TPaths } from './Paths';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
interface IPathObj {
|
|
10
|
-
Base: string;
|
|
11
|
-
[key: string]: string | IPathObj;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The recursive function.
|
|
16
|
-
*/
|
|
17
|
-
function getFullPaths(
|
|
18
|
-
parent: IPathObj,
|
|
19
|
-
baseUrl: string,
|
|
20
|
-
): IPathObj {
|
|
21
|
-
const url = (baseUrl + parent.Base),
|
|
22
|
-
keys = Object.keys(parent),
|
|
23
|
-
retVal: IPathObj = { Base: url };
|
|
24
|
-
// Iterate keys
|
|
25
|
-
for (const key of keys) {
|
|
26
|
-
const pval = parent[key];
|
|
27
|
-
if (key !== 'Base' && typeof pval === 'string') {
|
|
28
|
-
retVal[key] = (url + pval);
|
|
29
|
-
} else if (typeof pval === 'object') {
|
|
30
|
-
retVal[key] = getFullPaths(pval, url);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
// Return
|
|
34
|
-
return retVal;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// **** Export default **** //
|
|
39
|
-
|
|
40
|
-
export default getFullPaths(Paths, '') as TPaths;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Convert paths to full paths.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import Paths, { TPaths } from './Paths';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
interface IPathObj {
|
|
10
|
-
Base: string;
|
|
11
|
-
[key: string]: string | IPathObj;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The recursive function.
|
|
16
|
-
*/
|
|
17
|
-
function getFullPaths(
|
|
18
|
-
parent: IPathObj,
|
|
19
|
-
baseUrl: string,
|
|
20
|
-
): IPathObj {
|
|
21
|
-
const url = (baseUrl + parent.Base),
|
|
22
|
-
keys = Object.keys(parent),
|
|
23
|
-
retVal: IPathObj = { Base: url };
|
|
24
|
-
// Iterate keys
|
|
25
|
-
for (const key of keys) {
|
|
26
|
-
const pval = parent[key];
|
|
27
|
-
if (key !== 'Base' && typeof pval === 'string') {
|
|
28
|
-
retVal[key] = (url + pval);
|
|
29
|
-
} else if (typeof pval === 'object') {
|
|
30
|
-
retVal[key] = getFullPaths(pval, url);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
// Return
|
|
34
|
-
return retVal;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// **** Export default **** //
|
|
39
|
-
|
|
40
|
-
export default getFullPaths(Paths, '') as TPaths;
|