express-generator-typescript 2.3.7 → 2.4.0

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.
Files changed (64) hide show
  1. package/README.md +5 -34
  2. package/bin/cli.js +22 -7
  3. package/lib/cli.js +22 -7
  4. package/lib/express-generator-typescript.js +38 -28
  5. package/lib/project-files/spec/tests/users.spec.ts +9 -20
  6. package/lib/project-files/src/models/User.ts +50 -53
  7. package/lib/project-files/src/repos/database.json +1 -1
  8. package/lib/project-files/src/routes/api.ts +1 -24
  9. package/lib/project-files/src/routes/constants/Paths.ts +0 -5
  10. package/lib/project-files/src/server.ts +4 -9
  11. package/lib/project-files/src/views/users.html +0 -5
  12. package/lib/project-files-auth/.eslintignore +1 -0
  13. package/lib/project-files-auth/.eslintrc.json +44 -0
  14. package/lib/project-files-auth/README.md +43 -0
  15. package/lib/project-files-auth/build.ts +64 -0
  16. package/lib/project-files-auth/env/development.env +24 -0
  17. package/lib/project-files-auth/env/production.env +25 -0
  18. package/lib/project-files-auth/env/test.env +24 -0
  19. package/lib/project-files-auth/gitignore +3 -0
  20. package/lib/project-files-auth/package.json +70 -0
  21. package/lib/project-files-auth/spec/index.ts +77 -0
  22. package/lib/project-files-auth/spec/nodemon.json +6 -0
  23. package/lib/project-files-auth/spec/support/jasmine.json +11 -0
  24. package/lib/{project-files → project-files-auth}/spec/support/login.ts +1 -1
  25. package/lib/project-files-auth/spec/support/types.ts +1 -0
  26. package/lib/{project-files → project-files-auth}/spec/tests/auth.spec.ts +2 -2
  27. package/lib/project-files-auth/spec/tests/users.spec.ts +224 -0
  28. package/lib/project-files-auth/spec/types/supertest/index.d.ts +14 -0
  29. package/lib/project-files-auth/src/constants/EnvVars.ts +28 -0
  30. package/lib/project-files-auth/src/constants/HttpStatusCodes.ts +386 -0
  31. package/lib/project-files-auth/src/constants/misc.ts +5 -0
  32. package/lib/project-files-auth/src/index.ts +13 -0
  33. package/lib/project-files-auth/src/models/User.ts +85 -0
  34. package/lib/project-files-auth/src/other/classes.ts +17 -0
  35. package/lib/project-files-auth/src/other/types.ts +4 -0
  36. package/lib/project-files-auth/src/pre-start.ts +37 -0
  37. package/lib/project-files-auth/src/public/scripts/http.js +24 -0
  38. package/lib/project-files-auth/src/public/scripts/users.js +164 -0
  39. package/lib/project-files-auth/src/public/stylesheets/users.css +50 -0
  40. package/lib/project-files-auth/src/repos/MockOrm.ts +42 -0
  41. package/lib/project-files-auth/src/repos/UserRepo.ts +88 -0
  42. package/lib/project-files-auth/src/repos/database.json +1 -0
  43. package/lib/project-files-auth/src/routes/UserRoutes.ts +53 -0
  44. package/lib/project-files-auth/src/routes/api.ts +75 -0
  45. package/lib/project-files-auth/src/routes/constants/FullPaths.ts +40 -0
  46. package/lib/project-files-auth/src/routes/constants/Paths.ts +28 -0
  47. package/lib/project-files-auth/src/routes/types/express/index.d.ts +11 -0
  48. package/lib/project-files-auth/src/routes/types/express/misc.ts +16 -0
  49. package/lib/project-files-auth/src/routes/types/types.ts +22 -0
  50. package/lib/project-files-auth/src/server.ts +96 -0
  51. package/lib/project-files-auth/src/services/AuthService.ts +56 -0
  52. package/lib/project-files-auth/src/services/UserService.ts +66 -0
  53. package/lib/project-files-auth/src/util/PwdUtil.ts +39 -0
  54. package/lib/project-files-auth/src/util/SessionUtil.ts +92 -0
  55. package/lib/project-files-auth/src/util/misc.ts +22 -0
  56. package/lib/project-files-auth/src/views/users.html +42 -0
  57. package/lib/project-files-auth/tsconfig.json +83 -0
  58. package/lib/project-files-auth/tsconfig.prod.json +12 -0
  59. package/package.json +1 -1
  60. /package/lib/{project-files → project-files-auth}/src/public/scripts/login.js +0 -0
  61. /package/lib/{project-files → project-files-auth}/src/public/stylesheets/login.css +0 -0
  62. /package/lib/{project-files → project-files-auth}/src/routes/AuthRoutes.ts +0 -0
  63. /package/lib/{project-files → project-files-auth}/src/routes/middleware/adminMw.ts +0 -0
  64. /package/lib/{project-files → project-files-auth}/src/views/login.html +0 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Remove old files, copy front-end ones.
3
+ */
4
+
5
+ import fs from 'fs-extra';
6
+ import logger from 'jet-logger';
7
+ import childProcess from 'child_process';
8
+
9
+
10
+ /**
11
+ * Start
12
+ */
13
+ (async () => {
14
+ try {
15
+ // Remove current build
16
+ await remove('./dist/');
17
+ // Copy front-end files
18
+ await copy('./src/public', './dist/public');
19
+ await copy('./src/views', './dist/views');
20
+ // Copy back-end files
21
+ await exec('tsc --build tsconfig.prod.json', './');
22
+ } catch (err) {
23
+ logger.err(err);
24
+ }
25
+ })();
26
+
27
+ /**
28
+ * Remove file
29
+ */
30
+ function remove(loc: string): Promise<void> {
31
+ return new Promise((res, rej) => {
32
+ return fs.remove(loc, (err) => {
33
+ return (!!err ? rej(err) : res());
34
+ });
35
+ });
36
+ }
37
+
38
+ /**
39
+ * Copy file.
40
+ */
41
+ function copy(src: string, dest: string): Promise<void> {
42
+ return new Promise((res, rej) => {
43
+ return fs.copy(src, dest, (err) => {
44
+ return (!!err ? rej(err) : res());
45
+ });
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Do command line command.
51
+ */
52
+ function exec(cmd: string, loc: string): Promise<void> {
53
+ return new Promise((res, rej) => {
54
+ return childProcess.exec(cmd, {cwd: loc}, (err, stdout, stderr) => {
55
+ if (!!stdout) {
56
+ logger.info(stdout);
57
+ }
58
+ if (!!stderr) {
59
+ logger.warn(stderr);
60
+ }
61
+ return (!!err ? rej(err) : res());
62
+ });
63
+ });
64
+ }
@@ -0,0 +1,24 @@
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
+
17
+ ## Authentication ##
18
+ COOKIE_DOMAIN=localhost
19
+ COOKIE_PATH=/
20
+ SECURE_COOKIE=false
21
+ JWT_SECRET=xxxxxxxxxxxxxx
22
+ COOKIE_SECRET=xxxxxxxxxxxxxx
23
+ # expires in 3 days
24
+ COOKIE_EXP=259200000
@@ -0,0 +1,25 @@
1
+ ## Environment ##
2
+ NODE_ENV=production
3
+
4
+
5
+ ## Server ##
6
+ PORT=8081
7
+ HOST=localhost
8
+
9
+
10
+ ## Setup jet-logger ##
11
+ JET_LOGGER_MODE=FILE
12
+ JET_LOGGER_FILEPATH=jet-logger.log
13
+ JET_LOGGER_TIMESTAMP=TRUE
14
+ JET_LOGGER_FORMAT=LINE
15
+
16
+
17
+ ## Authentication ##
18
+ # SECURE_COOKIE 'false' here for demo-ing. But ideally should be true.
19
+ COOKIE_DOMAIN=localhost
20
+ COOKIE_PATH=/
21
+ SECURE_COOKIE=false
22
+ JWT_SECRET=xxxxxxxxxxxxxx
23
+ COOKIE_SECRET=xxxxxxxxxxxxxx
24
+ # expires in 3 days
25
+ COOKIE_EXP=259200000
@@ -0,0 +1,24 @@
1
+ ## Environment ##
2
+ NODE_ENV=test
3
+
4
+
5
+ ## Server ##
6
+ PORT=4000
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
+
17
+ ## Authentication ##
18
+ COOKIE_DOMAIN=localhost
19
+ COOKIE_PATH=/
20
+ SECURE_COOKIE=false
21
+ JWT_SECRET=xxxxxxxxxxxxxx
22
+ COOKIE_SECRET=xxxxxxxxxxxxxx
23
+ # expires in 3 days
24
+ COOKIE_EXP=259200000
@@ -0,0 +1,3 @@
1
+ **/node_modules
2
+ dist/
3
+ **/**/*.log
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "express-typescript-example",
3
+ "version": "0.0.0",
4
+ "scripts": {
5
+ "build": "npx ts-node build.ts",
6
+ "lint": "npx eslint --ext .ts src/",
7
+ "lint:tests": "npx eslint --ext .ts spec/",
8
+ "start": "node -r module-alias/register ./dist --env=production",
9
+ "dev": "nodemon",
10
+ "test": "nodemon --config ./spec/nodemon.json",
11
+ "test:no-reloading": "npx ts-node --files -r tsconfig-paths/register ./spec"
12
+ },
13
+ "nodemonConfig": {
14
+ "watch": [
15
+ "src"
16
+ ],
17
+ "ext": "ts, html",
18
+ "ignore": [
19
+ "src/public"
20
+ ],
21
+ "exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./src"
22
+ },
23
+ "_moduleAliases": {
24
+ "@src": "dist"
25
+ },
26
+ "engines": {
27
+ "node": ">=8.10.0"
28
+ },
29
+ "dependencies": {
30
+ "bcrypt": "^5.0.1",
31
+ "cookie-parser": "^1.4.6",
32
+ "dotenv": "^16.0.2",
33
+ "express": "^4.18.1",
34
+ "express-async-errors": "^3.1.1",
35
+ "helmet": "^6.0.0",
36
+ "inserturlparams": "^1.0.1",
37
+ "jet-logger": "^1.3.1",
38
+ "jet-validator": "^1.0.3",
39
+ "jsonfile": "^6.1.0",
40
+ "jsonwebtoken": "^8.5.1",
41
+ "module-alias": "^2.2.2",
42
+ "morgan": "^1.10.0",
43
+ "ts-command-line-args": "^2.4.2"
44
+ },
45
+ "devDependencies": {
46
+ "@types/bcrypt": "^5.0.0",
47
+ "@types/cookie-parser": "^1.4.3",
48
+ "@types/express": "^4.17.13",
49
+ "@types/find": "^0.2.1",
50
+ "@types/fs-extra": "^9.0.13",
51
+ "@types/jasmine": "^4.3.0",
52
+ "@types/jsonfile": "^6.1.0",
53
+ "@types/jsonwebtoken": "^8.5.9",
54
+ "@types/morgan": "^1.9.3",
55
+ "@types/node": "^18.7.14",
56
+ "@types/supertest": "^2.0.12",
57
+ "@typescript-eslint/eslint-plugin": "^5.36.1",
58
+ "@typescript-eslint/parser": "^5.36.1",
59
+ "eslint": "^8.23.0",
60
+ "eslint-plugin-node": "^11.1.0",
61
+ "find": "^0.3.0",
62
+ "fs-extra": "^10.1.0",
63
+ "jasmine": "^4.3.0",
64
+ "nodemon": "^2.0.19",
65
+ "supertest": "^6.2.4",
66
+ "ts-node": "^10.9.1",
67
+ "tsconfig-paths": "^4.1.0",
68
+ "typescript": "^4.8.2"
69
+ }
70
+ }
@@ -0,0 +1,77 @@
1
+ import dotenv from 'dotenv';
2
+ import find from 'find';
3
+ import Jasmine from 'jasmine';
4
+ import { parse } from 'ts-command-line-args';
5
+ import logger from 'jet-logger';
6
+
7
+
8
+ // **** Types **** //
9
+
10
+ interface IArgs {
11
+ testFile: string;
12
+ }
13
+
14
+
15
+ // **** Setup **** //
16
+
17
+ // ** Init ** //
18
+
19
+ // NOTE: MUST BE FIRST!! Load env vars
20
+ const result2 = dotenv.config({
21
+ path: './env/test.env',
22
+ });
23
+ if (result2.error) {
24
+ throw result2.error;
25
+ }
26
+
27
+ // Setup command line options.
28
+ const args = parse<IArgs>({
29
+ testFile: {
30
+ type: String,
31
+ defaultValue: '',
32
+ },
33
+ });
34
+
35
+
36
+ // ** Start Jasmine ** //
37
+
38
+ // Init Jasmine
39
+ const jasmine = new Jasmine();
40
+ jasmine.exitOnCompletion = false;
41
+
42
+ // Set location of test files
43
+ jasmine.loadConfig({
44
+ random: true,
45
+ spec_dir: 'spec',
46
+ spec_files: [
47
+ './tests/**/*.spec.ts',
48
+ ],
49
+ stopSpecOnExpectationFailure: false,
50
+ });
51
+
52
+ // Run all or a single unit-test
53
+ let execResp: Promise<jasmine.JasmineDoneInfo> | undefined;
54
+ if (args.testFile) {
55
+ const testFile = args.testFile;
56
+ find.file(testFile + '.spec.ts', './spec', (files: string[]) => {
57
+ if (files.length === 1) {
58
+ jasmine.execute([files[0]]);
59
+ } else {
60
+ logger.err('Test file not found!');
61
+ }
62
+ });
63
+ } else {
64
+ execResp = jasmine.execute();
65
+ }
66
+
67
+ // Wait for tests to finish
68
+ (async () => {
69
+ if (!!execResp) {
70
+ const info = await execResp;
71
+ if (info.overallStatus === 'passed') {
72
+ logger.info('All tests have passed :)');
73
+ } else {
74
+ logger.err('At least one test has failed :(');
75
+ }
76
+ }
77
+ })();
@@ -0,0 +1,6 @@
1
+ {
2
+ "watch": ["spec"],
3
+ "ext": "spec.ts",
4
+ "ignore": ["spec/support"],
5
+ "exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./spec"
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "spec_dir": "spec",
3
+ "spec_files": [
4
+ "**/*[sS]pec.ts"
5
+ ],
6
+ "helpers": [
7
+ "helpers/**/*.js"
8
+ ],
9
+ "stopSpecOnExpectationFailure": false,
10
+ "random": true
11
+ }
@@ -23,7 +23,7 @@ function login(beforeAgent: SuperTest<Test>, done: (arg: string) => void) {
23
23
  // Setup dummy data
24
24
  const role = UserRoles.Admin,
25
25
  pwdHash = PwdUtil.hashSync(LoginCreds.password),
26
- loginUser = new User('john smith', LoginCreds.email, role, pwdHash);
26
+ loginUser = User.new('john smith', LoginCreds.email, role, pwdHash);
27
27
  // Add spy
28
28
  spyOn(UserRepo, 'getOne').and.resolveTo(loginUser);
29
29
  // Call Login API
@@ -0,0 +1 @@
1
+ export type TReqBody = string | object | undefined;
@@ -64,7 +64,7 @@ describe('AuthRouter', () => {
64
64
  // Setup data
65
65
  const role = UserRoles.Standard,
66
66
  pwdHash = PwdUtil.hashSync(LoginCreds.password),
67
- loginUser = new User('john smith', LoginCreds.email, role, pwdHash);
67
+ loginUser = User.new('john smith', LoginCreds.email, role, pwdHash);
68
68
  // Add spy
69
69
  spyOn(UserRepo, 'getOne').and.resolveTo(loginUser);
70
70
  // Call API
@@ -99,7 +99,7 @@ describe('AuthRouter', () => {
99
99
  // Setup data
100
100
  const role = UserRoles.Standard,
101
101
  pwdHash = PwdUtil.hashSync('bad password'),
102
- loginUser = new User('john smith', LoginCreds.email, role, pwdHash);
102
+ loginUser = User.new('john smith', LoginCreds.email, role, pwdHash);
103
103
  // Add spy
104
104
  spyOn(UserRepo, 'getOne').and.resolveTo(loginUser);
105
105
  // Call API
@@ -0,0 +1,224 @@
1
+ import supertest, { SuperTest, Test, Response } from 'supertest';
2
+ import { defaultErrMsg as ValidatorErr } from 'jet-validator';
3
+ import insertUrlParams from 'inserturlparams';
4
+
5
+ import app from '@src/server';
6
+
7
+ import UserRepo from '@src/repos/UserRepo';
8
+ import User from '@src/models/User';
9
+ import HttpStatusCodes from '@src/constants/HttpStatusCodes';
10
+ import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
11
+ import FullPaths from '@src/routes/constants/FullPaths';
12
+
13
+ import login from '../support/login';
14
+ import { TReqBody } from 'spec/support/types';
15
+
16
+
17
+ // **** Variables **** //
18
+
19
+ // Paths
20
+ const {
21
+ Get,
22
+ Add,
23
+ Update,
24
+ Delete,
25
+ } = FullPaths.Users;
26
+
27
+ // StatusCodes
28
+ const {
29
+ OK,
30
+ CREATED,
31
+ NOT_FOUND,
32
+ BAD_REQUEST,
33
+ } = HttpStatusCodes;
34
+
35
+ // Dummy users for GET req
36
+ const DummyGetAllUsers = [
37
+ User.new('Sean Maxwell', 'sean.maxwell@gmail.com'),
38
+ User.new('John Smith', 'john.smith@gmail.com'),
39
+ User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
40
+ ] as const;
41
+
42
+ // Dummy update user
43
+ const DummyUserData = {
44
+ user: User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
45
+ } as const;
46
+
47
+
48
+ // **** Tests **** //
49
+
50
+ describe('UserRouter', () => {
51
+
52
+ let agent: SuperTest<Test>,
53
+ jwtCookie: string;
54
+
55
+ // Run before all tests
56
+ beforeAll((done) => {
57
+ agent = supertest.agent(app);
58
+ login(agent, (cookie: string) => {
59
+ jwtCookie = cookie;
60
+ done();
61
+ });
62
+ });
63
+
64
+ // ** Get all users ** //
65
+ describe(`"GET:${Get}"`, () => {
66
+
67
+ const callApi = () =>
68
+ agent
69
+ .get(Get)
70
+ .set('Cookie', jwtCookie);
71
+
72
+ // Success
73
+ it('should return a JSON object with all the users and a status code ' +
74
+ `of "${OK}" if the request was successful.`, (done) => {
75
+ // Add spy
76
+ spyOn(UserRepo, 'getAll').and.resolveTo([...DummyGetAllUsers]);
77
+ // Call API
78
+ callApi()
79
+ .end((_: Error, res: Response) => {
80
+ expect(res.status).toBe(OK);
81
+ for (let i = 0; i < res.body.users.length; i++) {
82
+ const user = res.body.users[i];
83
+ expect(user).toEqual(DummyGetAllUsers[i]);
84
+ }
85
+ done();
86
+ });
87
+ });
88
+ });
89
+
90
+ // Test add user
91
+ describe(`"POST:${Add}"`, () => {
92
+
93
+ const callApi = (reqBody: TReqBody) =>
94
+ agent
95
+ .post(Add)
96
+ .set('Cookie', jwtCookie)
97
+ .type('form').send(reqBody);
98
+
99
+ // Test add user success
100
+ it(`should return a status code of "${CREATED}" if the request was ` +
101
+ 'successful.', (done) => {
102
+ // Spy
103
+ spyOn(UserRepo, 'add').and.resolveTo();
104
+ // Call api
105
+ callApi(DummyUserData)
106
+ .end((_: Error, res: Response) => {
107
+ expect(res.status).toBe(CREATED);
108
+ expect(res.body.error).toBeUndefined();
109
+ done();
110
+ });
111
+ });
112
+
113
+ // Missing param
114
+ it('should return a JSON object with an error message of ' +
115
+ `"${ValidatorErr}" and a status code of "${BAD_REQUEST}" if the user ` +
116
+ 'param was missing.', (done) => {
117
+ // Call api
118
+ callApi({})
119
+ .end((_: Error, res: Response) => {
120
+ expect(res.status).toBe(BAD_REQUEST);
121
+ expect(res.body.error).toBe(ValidatorErr);
122
+ done();
123
+ });
124
+ });
125
+ });
126
+
127
+ // ** Update users ** //
128
+ describe(`"PUT:${Update}"`, () => {
129
+
130
+ const callApi = (reqBody: TReqBody) =>
131
+ agent
132
+ .put(Update)
133
+ .set('Cookie', jwtCookie)
134
+ .type('form').send(reqBody);
135
+
136
+ // Success
137
+ it(`should return a status code of "${OK}" if the request was successful.`,
138
+ (done) => {
139
+ // Setup spies
140
+ spyOn(UserRepo, 'update').and.resolveTo();
141
+ spyOn(UserRepo, 'persists').and.resolveTo(true);
142
+ // Call api
143
+ callApi(DummyUserData)
144
+ .end((_: Error, res: Response) => {
145
+ expect(res.status).toBe(OK);
146
+ expect(res.body.error).toBeUndefined();
147
+ done();
148
+ });
149
+ });
150
+
151
+ // Param missing
152
+ it('should return a JSON object with an error message of ' +
153
+ `"${ValidatorErr}" and a status code of "${BAD_REQUEST}" if the user ` +
154
+ 'param was missing.', (done) => {
155
+ // Call api
156
+ callApi({})
157
+ .end((_: Error, res: Response) => {
158
+ expect(res.status).toBe(BAD_REQUEST);
159
+ expect(res.body.error).toBe(ValidatorErr);
160
+ done();
161
+ });
162
+ });
163
+
164
+ // User not found
165
+ it('should return a JSON object with the error message of ' +
166
+ `"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
167
+ 'was not found.', (done) => {
168
+ // Call api
169
+ callApi(DummyUserData)
170
+ .end((_: Error, res: Response) => {
171
+ expect(res.status).toBe(NOT_FOUND);
172
+ expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
173
+ done();
174
+ });
175
+ });
176
+ });
177
+
178
+ // ** Delete user ** //
179
+ describe(`"DELETE:${Delete}"`, () => {
180
+
181
+ const callApi = (id: number) =>
182
+ agent
183
+ .delete(insertUrlParams(Delete, { id }))
184
+ .set('Cookie', jwtCookie);
185
+
186
+ // Success
187
+ it(`should return a status code of "${OK}" if the request was successful.`,
188
+ (done) => {
189
+ // Setup spies
190
+ spyOn(UserRepo, 'delete').and.resolveTo();
191
+ spyOn(UserRepo, 'persists').and.resolveTo(true);
192
+ // Call api
193
+ callApi(5)
194
+ .end((_: Error, res: Response) => {
195
+ expect(res.status).toBe(OK);
196
+ expect(res.body.error).toBeUndefined();
197
+ done();
198
+ });
199
+ });
200
+
201
+ // User not found
202
+ it('should return a JSON object with the error message of ' +
203
+ `"${USER_NOT_FOUND_ERR}" and a status code of "${NOT_FOUND}" if the id ` +
204
+ 'was not found.', (done) => {
205
+ callApi(-1)
206
+ .end((_: Error, res: Response) => {
207
+ expect(res.status).toBe(NOT_FOUND);
208
+ expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
209
+ done();
210
+ });
211
+ });
212
+
213
+ // Invalid param
214
+ it(`should return a status code of "${BAD_REQUEST}" and return an error ` +
215
+ `message of "${ValidatorErr}" if the id was not a valid number`, (done) => {
216
+ callApi('horse' as unknown as number)
217
+ .end((_: Error, res: Response) => {
218
+ expect(res.status).toBe(BAD_REQUEST);
219
+ expect(res.body.error).toBe(ValidatorErr);
220
+ done();
221
+ });
222
+ });
223
+ });
224
+ });
@@ -0,0 +1,14 @@
1
+ import { IUser } from '@src/models/User';
2
+ import 'supertest';
3
+
4
+
5
+ declare module 'supertest' {
6
+
7
+ export interface Response {
8
+ headers: Record<string, string[]>;
9
+ body: {
10
+ error: string;
11
+ users: IUser[];
12
+ };
13
+ }
14
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Environments variables declared here.
3
+ */
4
+
5
+ /* eslint-disable node/no-process-env */
6
+
7
+
8
+ export default {
9
+ NodeEnv: (process.env.NODE_ENV ?? ''),
10
+ Port: (process.env.PORT ?? 0),
11
+ CookieProps: {
12
+ Key: 'ExpressGeneratorTs',
13
+ Secret: (process.env.COOKIE_SECRET ?? ''),
14
+ // Casing to match express cookie options
15
+ Options: {
16
+ httpOnly: true,
17
+ signed: true,
18
+ path: (process.env.COOKIE_PATH ?? ''),
19
+ maxAge: Number(process.env.COOKIE_EXP ?? 0),
20
+ domain: (process.env.COOKIE_DOMAIN ?? ''),
21
+ secure: (process.env.SECURE_COOKIE === 'true'),
22
+ },
23
+ },
24
+ Jwt: {
25
+ Secret: (process.env.JWT_SECRET ?? ''),
26
+ Exp: (process.env.COOKIE_EXP ?? ''), // exp at the same time as the cookie
27
+ },
28
+ } as const;