@adaptivestone/framework 4.7.0 → 4.8.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.
- package/CHANGELOG.md +9 -1
- package/Cli.js +1 -0
- package/commands/SyncIndexes.js +1 -1
- package/controllers/Auth.js +3 -5
- package/controllers/index.js +0 -2
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +3542 -0
- package/coverage/coverage-final.json +44 -0
- package/coverage/favicon.png +0 -0
- package/coverage/framework/config/auth.js.html +100 -0
- package/coverage/framework/config/http.js.html +112 -0
- package/coverage/framework/config/i18n.js.html +121 -0
- package/coverage/framework/config/index.html +236 -0
- package/coverage/framework/config/log.js.html +151 -0
- package/coverage/framework/config/mail.js.html +172 -0
- package/coverage/framework/config/mongo.js.html +94 -0
- package/coverage/framework/config/rateLimiter.js.html +133 -0
- package/coverage/framework/config/redis.js.html +97 -0
- package/coverage/framework/config/validate.js.html +94 -0
- package/coverage/framework/controllers/Auth.js.html +715 -0
- package/coverage/framework/controllers/Home.js.html +169 -0
- package/coverage/framework/controllers/index.html +146 -0
- package/coverage/framework/controllers/index.js.html +259 -0
- package/coverage/framework/controllers/test/SomeController.js.html +571 -0
- package/coverage/framework/controllers/test/index.html +116 -0
- package/coverage/framework/helpers/files.js.html +310 -0
- package/coverage/framework/helpers/index.html +131 -0
- package/coverage/framework/helpers/logger.js.html +142 -0
- package/coverage/framework/helpers/redis/clearNamespace.js.html +127 -0
- package/coverage/framework/helpers/redis/index.html +116 -0
- package/coverage/framework/index.html +116 -0
- package/coverage/framework/models/Migration.js.html +130 -0
- package/coverage/framework/models/Sequence.js.html +151 -0
- package/coverage/framework/models/User.js.html +859 -0
- package/coverage/framework/models/index.html +146 -0
- package/coverage/framework/modules/AbstractController.js.html +1309 -0
- package/coverage/framework/modules/AbstractModel.js.html +268 -0
- package/coverage/framework/modules/Base.js.html +244 -0
- package/coverage/framework/modules/index.html +146 -0
- package/coverage/framework/server.js.html +1186 -0
- package/coverage/framework/services/cache/Cache.js.html +445 -0
- package/coverage/framework/services/cache/index.html +116 -0
- package/coverage/framework/services/documentation/DocumentationGenerator.js.html +592 -0
- package/coverage/framework/services/documentation/index.html +116 -0
- package/coverage/framework/services/http/HttpServer.js.html +373 -0
- package/coverage/framework/services/http/index.html +116 -0
- package/coverage/framework/services/http/middleware/AbstractMiddleware.js.html +238 -0
- package/coverage/framework/services/http/middleware/Auth.js.html +145 -0
- package/coverage/framework/services/http/middleware/GetUserByToken.js.html +223 -0
- package/coverage/framework/services/http/middleware/I18n.js.html +442 -0
- package/coverage/framework/services/http/middleware/Pagination.js.html +253 -0
- package/coverage/framework/services/http/middleware/PrepareAppInfo.js.html +139 -0
- package/coverage/framework/services/http/middleware/RateLimiter.js.html +472 -0
- package/coverage/framework/services/http/middleware/RequestLogger.js.html +151 -0
- package/coverage/framework/services/http/middleware/RequestParser.js.html +199 -0
- package/coverage/framework/services/http/middleware/Role.js.html +172 -0
- package/coverage/framework/services/http/middleware/index.html +251 -0
- package/coverage/framework/services/http/middleware/test/CheckFlag.js.html +139 -0
- package/coverage/framework/services/http/middleware/test/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.js.html +739 -0
- package/coverage/framework/services/messaging/index.html +116 -0
- package/coverage/framework/services/messaging/index.js.html +100 -0
- package/coverage/framework/services/validate/ValidateService.js.html +556 -0
- package/coverage/framework/services/validate/drivers/AbstractValidator.js.html +196 -0
- package/coverage/framework/services/validate/drivers/CustomValidator.js.html +241 -0
- package/coverage/framework/services/validate/drivers/YupValidator.js.html +394 -0
- package/coverage/framework/services/validate/drivers/index.html +146 -0
- package/coverage/framework/services/validate/index.html +116 -0
- package/coverage/index.html +356 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/helpers/files.js +75 -0
- package/helpers/logger.js +19 -0
- package/models/Migration.test.js +19 -0
- package/modules/AbstractController.js +1 -3
- package/modules/Base.js +6 -56
- package/modules/BaseCli.js +0 -3
- package/package.json +2 -2
- package/server.d.ts +6 -0
- package/server.js +126 -78
- package/services/cache/Cache.js +10 -5
- package/services/cache/Cache.test.js +81 -0
- package/services/http/middleware/Auth.test.js +57 -0
- package/services/http/middleware/I18n.test.js +15 -3
- package/services/http/middleware/PrepareAppInfo.test.js +1 -1
- package/services/http/middleware/Role.test.js +93 -0
- package/tests/setup.js +1 -0
- package/tests/setupVitest.js +1 -0
package/server.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
const EventEmitter = require('node:events');
|
|
3
|
+
const { hrtime } = require('node:process');
|
|
3
4
|
|
|
4
5
|
require('dotenv').config();
|
|
5
6
|
const merge = require('deepmerge');
|
|
6
7
|
const winston = require('winston');
|
|
8
|
+
const { getFilesPathWithInheritance } = require('./helpers/files');
|
|
9
|
+
const { consoleLogger } = require('./helpers/logger');
|
|
10
|
+
|
|
11
|
+
const Cache = require('./services/cache/Cache');
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
14
|
* Main framework class.
|
|
@@ -11,6 +16,8 @@ const winston = require('winston');
|
|
|
11
16
|
class Server {
|
|
12
17
|
#realLogger = null;
|
|
13
18
|
|
|
19
|
+
#isInited = false;
|
|
20
|
+
|
|
14
21
|
/**
|
|
15
22
|
* Construct new server
|
|
16
23
|
* @param {Object} config main config object
|
|
@@ -46,6 +53,7 @@ class Server {
|
|
|
46
53
|
this.cache = {
|
|
47
54
|
configs: new Map(),
|
|
48
55
|
models: new Map(),
|
|
56
|
+
modelConstructors: new Map(),
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
this.cli = false;
|
|
@@ -57,13 +65,11 @@ class Server {
|
|
|
57
65
|
* @returns {Promise}
|
|
58
66
|
*/
|
|
59
67
|
async startServer(callbackBefore404 = async () => Promise.resolve()) {
|
|
60
|
-
// const HttpServer = require('./services/http/HttpServer');
|
|
61
|
-
// const ControllerManager = require('./controllers/index');
|
|
62
|
-
// TODO wait until https://github.com/nodejs/node/issues/35889
|
|
63
68
|
const [{ default: HttpServer }, { default: ControllerManager }] =
|
|
64
69
|
await Promise.all([
|
|
65
70
|
import('./services/http/HttpServer.js'), // Speed optimisation
|
|
66
71
|
import('./controllers/index.js'), // Speed optimisation
|
|
72
|
+
this.init(),
|
|
67
73
|
]);
|
|
68
74
|
|
|
69
75
|
this.addErrorHandling();
|
|
@@ -78,20 +84,115 @@ class Server {
|
|
|
78
84
|
this.app.httpServer.add404Page();
|
|
79
85
|
}
|
|
80
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Do an initialization (config reading, etc)
|
|
89
|
+
* @returns {Promise}
|
|
90
|
+
*/
|
|
91
|
+
async init() {
|
|
92
|
+
if (this.#isInited) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.time('Server init. Done');
|
|
97
|
+
await Promise.all([this.#initConfigFiles(), this.#loadModelFiles()]);
|
|
98
|
+
|
|
99
|
+
this.#isInited = true;
|
|
100
|
+
|
|
101
|
+
console.timeEnd('Server init. Done');
|
|
102
|
+
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async #initConfigFiles() {
|
|
107
|
+
const files = await getFilesPathWithInheritance({
|
|
108
|
+
internalFolder: `${__dirname}/config`,
|
|
109
|
+
externalFolder: this.app.foldersConfig.config,
|
|
110
|
+
loggerFileType: 'CONFIG',
|
|
111
|
+
logger: (m) => consoleLogger('info', m),
|
|
112
|
+
filter: {
|
|
113
|
+
startWithCapital: false,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const configFiles = {};
|
|
118
|
+
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
const config = file.file.split('.');
|
|
121
|
+
if (!configFiles[config[0]]) {
|
|
122
|
+
configFiles[config[0]] = {};
|
|
123
|
+
}
|
|
124
|
+
if (config.length === 2) {
|
|
125
|
+
configFiles[config[0]].default = file.path;
|
|
126
|
+
} else {
|
|
127
|
+
configFiles[config[0]][config[1]] = file.path;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const loadConfig = async (configName, values) => {
|
|
132
|
+
const promises = [import(values.default)];
|
|
133
|
+
if (process.env.NODE_ENV && values[process.env.NODE_ENV]) {
|
|
134
|
+
promises.push(import(values[process.env.NODE_ENV]));
|
|
135
|
+
}
|
|
136
|
+
const result = await Promise.all(promises);
|
|
137
|
+
return {
|
|
138
|
+
name: configName,
|
|
139
|
+
finalValue: merge(result[0].default, result[1]?.default || {}, {
|
|
140
|
+
arrayMerge: (destinationArray, sourceArray) => sourceArray,
|
|
141
|
+
}),
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const loadingPromises = [];
|
|
146
|
+
|
|
147
|
+
for (const [configFile, value] of Object.entries(configFiles)) {
|
|
148
|
+
loadingPromises.push(loadConfig(configFile, value));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const configs = await Promise.all(loadingPromises);
|
|
152
|
+
|
|
153
|
+
for (const config of configs) {
|
|
154
|
+
this.cache.configs.set(config.name, config.finalValue);
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async #loadModelFiles() {
|
|
160
|
+
const files = await getFilesPathWithInheritance({
|
|
161
|
+
internalFolder: `${__dirname}/models`,
|
|
162
|
+
externalFolder: this.app.foldersConfig.models,
|
|
163
|
+
loggerFileType: 'MODEL',
|
|
164
|
+
logger: (m) => consoleLogger('info', m),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const promises = [];
|
|
168
|
+
for (const file of files) {
|
|
169
|
+
const t = hrtime.bigint();
|
|
170
|
+
promises.push(
|
|
171
|
+
import(file.path).then((f) => ({
|
|
172
|
+
name: file.file.split('.')[0],
|
|
173
|
+
file: f,
|
|
174
|
+
took: hrtime.bigint() - t,
|
|
175
|
+
})),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const loadedModels = await Promise.all(promises);
|
|
180
|
+
|
|
181
|
+
for (const model of loadedModels) {
|
|
182
|
+
this.cache.modelConstructors.set(model.name, model.file.default);
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
81
187
|
/**
|
|
82
188
|
* Add error logging on promise reject
|
|
83
189
|
*/
|
|
84
|
-
// eslint-disable-next-line class-methods-use-this
|
|
85
190
|
addErrorHandling() {
|
|
86
|
-
process.on('uncaughtException',
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
' reason: ',
|
|
92
|
-
reason,
|
|
93
|
-
);
|
|
94
|
-
console.trace('unhandledRejection');
|
|
191
|
+
process.on('uncaughtException', (e) =>
|
|
192
|
+
this.app.logger.error('uncaughtException', e),
|
|
193
|
+
);
|
|
194
|
+
process.on('unhandledRejection', (e) => {
|
|
195
|
+
this.app.logger.error('unhandledRejection', e);
|
|
95
196
|
});
|
|
96
197
|
}
|
|
97
198
|
|
|
@@ -106,24 +207,15 @@ class Server {
|
|
|
106
207
|
* @returns {Object} config object. Structure depends of config file
|
|
107
208
|
*/
|
|
108
209
|
getConfig(configName) {
|
|
109
|
-
|
|
210
|
+
if (!this.#isInited) {
|
|
211
|
+
throw new Error('You should call Server.init() before using it');
|
|
212
|
+
}
|
|
213
|
+
|
|
110
214
|
if (!this.cache.configs.has(configName)) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
envConfig =
|
|
114
|
-
this.getFileWithExtendingInhirence(
|
|
115
|
-
'config',
|
|
116
|
-
`${configName}.${process.env.NODE_ENV}.js`,
|
|
117
|
-
) || envConfig;
|
|
118
|
-
}
|
|
119
|
-
this.cache.configs.set(
|
|
120
|
-
configName,
|
|
121
|
-
merge(
|
|
122
|
-
this.getFileWithExtendingInhirence('config', configName),
|
|
123
|
-
envConfig,
|
|
124
|
-
{ arrayMerge: (destinationArray, sourceArray) => sourceArray },
|
|
125
|
-
),
|
|
215
|
+
this.logger.warn(
|
|
216
|
+
`You asked for config ${configName} that not exists. Please check you codebase `,
|
|
126
217
|
);
|
|
218
|
+
return {};
|
|
127
219
|
}
|
|
128
220
|
return this.cache.configs.get(configName);
|
|
129
221
|
}
|
|
@@ -225,14 +317,14 @@ class Server {
|
|
|
225
317
|
*/
|
|
226
318
|
getModel(modelName) {
|
|
227
319
|
if (modelName.endsWith('s')) {
|
|
228
|
-
|
|
320
|
+
this.app.logger.warn(
|
|
229
321
|
`Probably your model name '${modelName}' in plural from. Try to avoid plural form`,
|
|
230
322
|
);
|
|
231
323
|
}
|
|
232
324
|
if (!this.cache.models.has(modelName)) {
|
|
233
|
-
const Model = this.
|
|
325
|
+
const Model = this.cache.modelConstructors.get(modelName);
|
|
234
326
|
if (!Model) {
|
|
235
|
-
|
|
327
|
+
this.app.logger.error(`Model not found: ${modelName}`);
|
|
236
328
|
return false;
|
|
237
329
|
}
|
|
238
330
|
try {
|
|
@@ -240,8 +332,8 @@ class Server {
|
|
|
240
332
|
|
|
241
333
|
this.cache.models.set(modelName, model.mongooseModel);
|
|
242
334
|
} catch (e) {
|
|
243
|
-
|
|
244
|
-
|
|
335
|
+
this.app.logger.error(`Problem with model ${modelName}, ${e.message}`);
|
|
336
|
+
this.app.logger.error(e);
|
|
245
337
|
}
|
|
246
338
|
}
|
|
247
339
|
return this.cache.models.get(modelName);
|
|
@@ -254,9 +346,7 @@ class Server {
|
|
|
254
346
|
*/
|
|
255
347
|
async runCliCommand(commandName, args) {
|
|
256
348
|
if (!this.cli) {
|
|
257
|
-
// TODO wait until https://github.com/nodejs/node/issues/35889
|
|
258
349
|
const { default: BaseCli } = await import('./modules/BaseCli.js'); // Speed optimisation
|
|
259
|
-
// const BaseCli = require('./modules/BaseCli');
|
|
260
350
|
this.cli = new BaseCli(this);
|
|
261
351
|
}
|
|
262
352
|
return this.cli.run(commandName, args);
|
|
@@ -268,52 +358,10 @@ class Server {
|
|
|
268
358
|
*/
|
|
269
359
|
getCache() {
|
|
270
360
|
if (!this.cacheService) {
|
|
271
|
-
// eslint-disable-next-line global-require
|
|
272
|
-
const Cache = require('./services/cache/Cache'); // Speed optimisation
|
|
273
361
|
this.cacheService = new Cache(this.app);
|
|
274
362
|
}
|
|
275
363
|
return this.cacheService;
|
|
276
364
|
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Get file using Inhirence (ability to overrite models, configs, etc)
|
|
280
|
-
* @param {('models'|'config')} fileType type of file to load
|
|
281
|
-
* @param {string} fileName name of file to load
|
|
282
|
-
*/
|
|
283
|
-
getFileWithExtendingInhirence(fileType, fileName) {
|
|
284
|
-
let file;
|
|
285
|
-
try {
|
|
286
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
287
|
-
file = require(`${this.config.folders[fileType]}/${fileName}`);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
try {
|
|
290
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
291
|
-
file = require(`./${fileType}/${fileName}`);
|
|
292
|
-
} catch (e2) {
|
|
293
|
-
const levels = [
|
|
294
|
-
'error',
|
|
295
|
-
'warn',
|
|
296
|
-
'info',
|
|
297
|
-
'http',
|
|
298
|
-
'verbose',
|
|
299
|
-
'debug',
|
|
300
|
-
'silly',
|
|
301
|
-
];
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
!process.env.LOGGER_CONSOLE_LEVEL ||
|
|
305
|
-
levels.indexOf(process.env.LOGGER_CONSOLE_LEVEL) > 0 // as a warn level
|
|
306
|
-
) {
|
|
307
|
-
console.warn(
|
|
308
|
-
`Config not found '${fileName}'. This can be a normal (in case this an environment config)`,
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
file = false;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return file;
|
|
316
|
-
}
|
|
317
365
|
}
|
|
318
366
|
|
|
319
367
|
module.exports = Server;
|
package/services/cache/Cache.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
const redis = require('redis');
|
|
2
1
|
const Base = require('../../modules/Base');
|
|
3
2
|
|
|
4
3
|
class Cache extends Base {
|
|
5
4
|
constructor(app) {
|
|
5
|
+
super(app);
|
|
6
|
+
this.whenReady = this.#init();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async #init() {
|
|
6
10
|
// todo for now only redis. refactor for drives support in future
|
|
7
11
|
// at least memory and redis drivers should be presented
|
|
8
12
|
// memory drives should works on master process level
|
|
9
13
|
// we should support multiple cashe same time
|
|
10
|
-
|
|
14
|
+
const redis = await import('redis');
|
|
11
15
|
const conf = this.app.getConfig('redis');
|
|
12
16
|
this.redisClient = redis.createClient({
|
|
13
17
|
url: conf.url,
|
|
@@ -33,6 +37,7 @@ class Cache extends Base {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
async getSetValue(keyValue, onNotFound, storeTime = 60 * 5) {
|
|
40
|
+
await this.whenReady;
|
|
36
41
|
if (!this.redisClient.isOpen) {
|
|
37
42
|
await this.redisClient.connect();
|
|
38
43
|
}
|
|
@@ -58,9 +63,7 @@ class Cache extends Base {
|
|
|
58
63
|
try {
|
|
59
64
|
result = await onNotFound();
|
|
60
65
|
} catch (e) {
|
|
61
|
-
this.logger.error(
|
|
62
|
-
`Cache onNotFound for key '${key}' error: ${e.message}`,
|
|
63
|
-
);
|
|
66
|
+
this.logger.error(`Cache onNotFound for key '${key}' error: ${e}`);
|
|
64
67
|
this.promiseMapping.delete(key);
|
|
65
68
|
reject(e);
|
|
66
69
|
return Promise.reject(e);
|
|
@@ -100,6 +103,8 @@ class Cache extends Base {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
async removeKey(keyValue) {
|
|
106
|
+
await this.whenReady;
|
|
107
|
+
|
|
103
108
|
if (!this.redisClient.isOpen) {
|
|
104
109
|
await this.redisClient.connect();
|
|
105
110
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { setTimeout } from 'node:timers/promises';
|
|
3
|
+
|
|
4
|
+
describe('cache', () => {
|
|
5
|
+
const time = Date.now();
|
|
6
|
+
|
|
7
|
+
it('can get set values', async () => {
|
|
8
|
+
expect.assertions(2);
|
|
9
|
+
|
|
10
|
+
const { cache } = global.server.app;
|
|
11
|
+
|
|
12
|
+
const res = await cache.getSetValue('TEST_TIME', () => time);
|
|
13
|
+
expect(res).toStrictEqual(time);
|
|
14
|
+
|
|
15
|
+
const res2 = await cache.getSetValue('TEST_TIME', () => '123');
|
|
16
|
+
expect(res2).toStrictEqual(time);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('can delete values', async () => {
|
|
20
|
+
expect.assertions(1);
|
|
21
|
+
const { cache } = global.server.app;
|
|
22
|
+
|
|
23
|
+
await cache.removeKey('TEST_TIME');
|
|
24
|
+
|
|
25
|
+
const res2 = await cache.getSetValue('TEST_TIME', () => '123');
|
|
26
|
+
expect(res2).toBe('123');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('can works with big int', async () => {
|
|
30
|
+
expect.assertions(2);
|
|
31
|
+
const { cache } = global.server.app;
|
|
32
|
+
|
|
33
|
+
const res = await cache.getSetValue('BIN_INT', () => 1n);
|
|
34
|
+
expect(res).toBe(1n);
|
|
35
|
+
|
|
36
|
+
const res2 = await cache.getSetValue('BIN_INT', () => '1111');
|
|
37
|
+
expect(res2).toBe(1n);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('can execute only one request per time', async () => {
|
|
41
|
+
expect.assertions(3);
|
|
42
|
+
const { cache } = global.server.app;
|
|
43
|
+
let counter = 0;
|
|
44
|
+
|
|
45
|
+
const f = async () => {
|
|
46
|
+
await setTimeout(10);
|
|
47
|
+
counter += 1;
|
|
48
|
+
return 1;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const [res, res1] = await Promise.all([
|
|
52
|
+
cache.getSetValue('T', f),
|
|
53
|
+
cache.getSetValue('T', f),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
expect(counter).toBe(1);
|
|
57
|
+
|
|
58
|
+
expect(res).toBe(1);
|
|
59
|
+
expect(res1).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('can handle problems on onNotFound', async () => {
|
|
63
|
+
expect.assertions(1);
|
|
64
|
+
const getAsyncThrow = async () => {
|
|
65
|
+
throw new Error('err');
|
|
66
|
+
};
|
|
67
|
+
let err;
|
|
68
|
+
|
|
69
|
+
const { cache } = global.server.app;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await Promise.all([
|
|
73
|
+
cache.getSetValue('THROW', getAsyncThrow),
|
|
74
|
+
cache.getSetValue('THROW', getAsyncThrow),
|
|
75
|
+
]);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
err = e;
|
|
78
|
+
}
|
|
79
|
+
expect(err.message).toBe('err');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { beforeAll, describe, it, expect } from 'vitest';
|
|
2
|
+
import Auth from './Auth';
|
|
3
|
+
|
|
4
|
+
describe('atuh middleware methods', () => {
|
|
5
|
+
let middleware;
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
middleware = new Auth(global.server.app);
|
|
8
|
+
});
|
|
9
|
+
it('have description fields', async () => {
|
|
10
|
+
expect.assertions(1);
|
|
11
|
+
expect(middleware.constructor.description).toBeDefined();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('middleware pass when user presented', async () => {
|
|
15
|
+
expect.assertions(1);
|
|
16
|
+
let isCalled = false;
|
|
17
|
+
const nextFunction = () => {
|
|
18
|
+
isCalled = true;
|
|
19
|
+
};
|
|
20
|
+
const req = {
|
|
21
|
+
appInfo: {
|
|
22
|
+
user: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
await middleware.middleware(req, {}, nextFunction);
|
|
26
|
+
expect(isCalled).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('middleware NOT pass when user NOT presented', async () => {
|
|
30
|
+
expect.assertions(3);
|
|
31
|
+
let isCalled = false;
|
|
32
|
+
let status;
|
|
33
|
+
let isSend;
|
|
34
|
+
const nextFunction = () => {
|
|
35
|
+
isCalled = true;
|
|
36
|
+
};
|
|
37
|
+
const req = {
|
|
38
|
+
appInfo: {}, // no user
|
|
39
|
+
};
|
|
40
|
+
await middleware.middleware(
|
|
41
|
+
req,
|
|
42
|
+
{
|
|
43
|
+
status(statusCode) {
|
|
44
|
+
status = statusCode;
|
|
45
|
+
return this;
|
|
46
|
+
},
|
|
47
|
+
json() {
|
|
48
|
+
isSend = true;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
nextFunction,
|
|
52
|
+
);
|
|
53
|
+
expect(isCalled).toBeFalsy();
|
|
54
|
+
expect(status).toBe(401);
|
|
55
|
+
expect(isSend).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -12,7 +12,7 @@ describe('i18n middleware methods', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('detectors should works correctly', async () => {
|
|
15
|
-
expect.assertions(
|
|
15
|
+
expect.assertions(6);
|
|
16
16
|
const request = {
|
|
17
17
|
get: () => 'en',
|
|
18
18
|
query: {
|
|
@@ -42,10 +42,13 @@ describe('i18n middleware methods', () => {
|
|
|
42
42
|
};
|
|
43
43
|
lang = await middleware.detectLang(request);
|
|
44
44
|
expect(lang).toBe('en');
|
|
45
|
+
|
|
46
|
+
lang = await middleware.detectLang(request, false);
|
|
47
|
+
expect(lang).toBe('en-GB');
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
it('middleware that works', async () => {
|
|
48
|
-
expect.assertions(
|
|
51
|
+
expect.assertions(6);
|
|
49
52
|
let isCalled = false;
|
|
50
53
|
const nextFunction = () => {
|
|
51
54
|
isCalled = true;
|
|
@@ -55,10 +58,19 @@ describe('i18n middleware methods', () => {
|
|
|
55
58
|
appInfo: {},
|
|
56
59
|
};
|
|
57
60
|
await middleware.middleware(req, {}, nextFunction);
|
|
58
|
-
expect(isCalled).
|
|
61
|
+
expect(isCalled).toBeTruthy();
|
|
59
62
|
expect(req.appInfo.i18n).toBeDefined();
|
|
63
|
+
expect(req.appInfo.i18n.language).toBe('en');
|
|
60
64
|
expect(req.appInfo.i18n.t('aaaaa')).toBe('aaaaa');
|
|
61
65
|
expect(req.i18n.t('aaaaa')).toBe('aaaaa'); // proxy test
|
|
66
|
+
|
|
67
|
+
const req2 = {
|
|
68
|
+
get: () => 'fakeLang',
|
|
69
|
+
appInfo: {},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
await middleware.middleware(req2, {}, nextFunction);
|
|
73
|
+
expect(req2.appInfo.i18n.language).toBe('en');
|
|
62
74
|
});
|
|
63
75
|
|
|
64
76
|
it('middleware disabled', async () => {
|
|
@@ -17,7 +17,7 @@ describe('prepareAppInfo methods', () => {
|
|
|
17
17
|
};
|
|
18
18
|
const req = {};
|
|
19
19
|
await middleware.middleware(req, {}, nextFunction);
|
|
20
|
-
expect(isCalled).
|
|
20
|
+
expect(isCalled).toBeTruthy();
|
|
21
21
|
expect(req.appInfo).toBeDefined();
|
|
22
22
|
req.appInfo.test = 5;
|
|
23
23
|
await middleware.middleware(req, {}, nextFunction);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import Role from './Role';
|
|
3
|
+
|
|
4
|
+
describe('role middleware methods', () => {
|
|
5
|
+
it('have description fields', async () => {
|
|
6
|
+
expect.assertions(1);
|
|
7
|
+
const middleware = new Role(global.server.app);
|
|
8
|
+
expect(middleware.constructor.description).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('middleware pass when user presented with a right role', async () => {
|
|
12
|
+
expect.assertions(1);
|
|
13
|
+
let isCalled = false;
|
|
14
|
+
const nextFunction = () => {
|
|
15
|
+
isCalled = true;
|
|
16
|
+
};
|
|
17
|
+
const req = {
|
|
18
|
+
appInfo: {
|
|
19
|
+
user: {
|
|
20
|
+
roles: ['role1', 'role2'],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const middleware = new Role(global.server.app, {
|
|
25
|
+
roles: ['admin', 'role1'],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await middleware.middleware(req, {}, nextFunction);
|
|
29
|
+
expect(isCalled).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('middleware NOT pass when user NOT presented', async () => {
|
|
33
|
+
expect.assertions(3);
|
|
34
|
+
let isCalled = false;
|
|
35
|
+
let status;
|
|
36
|
+
let isSend;
|
|
37
|
+
const nextFunction = () => {
|
|
38
|
+
isCalled = true;
|
|
39
|
+
};
|
|
40
|
+
const req = {
|
|
41
|
+
appInfo: {}, // no user
|
|
42
|
+
};
|
|
43
|
+
const middleware = new Role(global.server.app);
|
|
44
|
+
await middleware.middleware(
|
|
45
|
+
req,
|
|
46
|
+
{
|
|
47
|
+
status(statusCode) {
|
|
48
|
+
status = statusCode;
|
|
49
|
+
return this;
|
|
50
|
+
},
|
|
51
|
+
send() {
|
|
52
|
+
isSend = true;
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
nextFunction,
|
|
56
|
+
);
|
|
57
|
+
expect(isCalled).toBeFalsy();
|
|
58
|
+
expect(status).toBe(401);
|
|
59
|
+
expect(isSend).toBeTruthy();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('middleware NOT pass when user have a wrong role', async () => {
|
|
63
|
+
expect.assertions(3);
|
|
64
|
+
let isCalled = false;
|
|
65
|
+
let status;
|
|
66
|
+
let isSend;
|
|
67
|
+
const nextFunction = () => {
|
|
68
|
+
isCalled = true;
|
|
69
|
+
};
|
|
70
|
+
const req = {
|
|
71
|
+
appInfo: {
|
|
72
|
+
user: { roles: ['role1', 'role2'] },
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
const middleware = new Role(global.server.app, { roles: ['admin'] });
|
|
76
|
+
await middleware.middleware(
|
|
77
|
+
req,
|
|
78
|
+
{
|
|
79
|
+
status(statusCode) {
|
|
80
|
+
status = statusCode;
|
|
81
|
+
return this;
|
|
82
|
+
},
|
|
83
|
+
json() {
|
|
84
|
+
isSend = true;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
nextFunction,
|
|
88
|
+
);
|
|
89
|
+
expect(isCalled).toBeFalsy();
|
|
90
|
+
expect(status).toBe(403);
|
|
91
|
+
expect(isSend).toBeTruthy();
|
|
92
|
+
});
|
|
93
|
+
});
|
package/tests/setup.js
CHANGED
package/tests/setupVitest.js
CHANGED