@vida-global/core 2.0.6 → 2.0.8
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/activeRecord/baseRecord.js +17 -2
- package/lib/activeRecord/db/connection.js +42 -17
- package/lib/activeRecord/db/schema.js +47 -16
- package/lib/jobQueue/abstractJob.js +19 -4
- package/lib/jobQueue/queue.js +8 -4
- package/lib/jobQueue/worker.js +35 -20
- package/lib/logger/index.js +10 -6
- package/lib/logger/serverMiddleware.js +41 -26
- package/lib/server/controllerMixins/renderer.js +4 -2
- package/lib/server/server.js +25 -10
- package/package.json +1 -1
- package/test/activeRecord/baseRecord.test.js +52 -10
- package/test/activeRecord/db/connection.test.js +16 -19
- package/test/activeRecord/db/queryInterface.test.js +1 -9
- package/test/activeRecord/db/schema.test.js +76 -58
- package/test/activeRecord/helpers/fixtures.js +10 -1
- package/test/activeRecord/helpers/queryInterface.js +14 -3
- package/test/jobQueue/abstractJob.test.js +15 -43
- package/test/jobQueue/helpers/abstractJob.js +14 -3
- package/test/jobQueue/helpers/queue.js +26 -0
- package/test/jobQueue/helpers/worker.js +13 -0
- package/test/jobQueue/queue.test.js +7 -26
- package/test/jobQueue/worker.test.js +28 -48
- package/test/logger/index.test.js +26 -0
- package/test/logger/serverMiddleware.test.js +6 -15
- package/test/server/helpers/server.js +40 -6
- package/test/server/server.test.js +6 -35
- package/test/server/serverController.test.js +3 -3
|
@@ -7,11 +7,24 @@ const FIXTURE_JOBS_DIR = path.join(__dirname, 'fixtureJobs');
|
|
|
7
7
|
|
|
8
8
|
/***************************************************************************************************
|
|
9
9
|
* WORKER FACTORY
|
|
10
|
+
* bullmqMock/loggerMock/apmMock are required lazily so the mock instances align with whatever the
|
|
11
|
+
* test re-requires after jest.resetModules() (used to reset the worker's module-level registeredJobs).
|
|
10
12
|
***************************************************************************************************/
|
|
11
13
|
function buildWorker(Worker, queueName) {
|
|
14
|
+
const bullmqMock = require('./bullmqMock');
|
|
15
|
+
const { buildLoggerMock } = require('./loggerMock');
|
|
16
|
+
const { buildApmMock } = require('./apmMock');
|
|
17
|
+
|
|
18
|
+
const loggerMock = buildLoggerMock();
|
|
19
|
+
const apmMock = buildApmMock();
|
|
20
|
+
|
|
12
21
|
class TestWorker extends Worker {
|
|
13
22
|
get jobDirectories() { return [FIXTURE_JOBS_DIR]; }
|
|
23
|
+
get workerClass() { return bullmqMock.Worker; }
|
|
24
|
+
get loggerLibrary() { return loggerMock; }
|
|
25
|
+
get apm() { return apmMock; }
|
|
14
26
|
}
|
|
27
|
+
|
|
15
28
|
return new TestWorker(queueName || TestHelpers.Faker.Text.randomString());
|
|
16
29
|
}
|
|
17
30
|
|
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
const TestHelpers
|
|
1
|
+
const TestHelpers = require('@vida-global/test-helpers');
|
|
2
2
|
const { setupJobQueueEnv } = require('./helpers/env');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
jest.mock('bullmq', () => {
|
|
6
|
-
const mock = require('./helpers/bullmqMock');
|
|
7
|
-
return { Queue: mock.Queue, Worker: mock.Worker };
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
jest.mock('../../lib/logger', () => {
|
|
11
|
-
const { buildLoggerMock } = require('./helpers/loggerMock');
|
|
12
|
-
return { logger: buildLoggerMock() };
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
jest.mock('crypto', () => {
|
|
16
|
-
const actual = jest.requireActual('crypto');
|
|
17
|
-
return { ...actual, randomUUID: jest.fn() };
|
|
18
|
-
});
|
|
3
|
+
const { buildQueue } = require('./helpers/queue');
|
|
19
4
|
|
|
20
5
|
|
|
21
6
|
let bullmqMock;
|
|
22
7
|
let getQueue;
|
|
23
|
-
let logger;
|
|
24
|
-
let randomUUID;
|
|
25
8
|
let restoreEnv;
|
|
26
9
|
|
|
27
10
|
beforeEach(() => {
|
|
@@ -30,8 +13,6 @@ beforeEach(() => {
|
|
|
30
13
|
|
|
31
14
|
bullmqMock = require('./helpers/bullmqMock');
|
|
32
15
|
({ getQueue } = require('../../lib/jobQueue/queue'));
|
|
33
|
-
({ logger } = require('../../lib/logger'));
|
|
34
|
-
({ randomUUID } = require('crypto'));
|
|
35
16
|
});
|
|
36
17
|
|
|
37
18
|
|
|
@@ -95,7 +76,7 @@ describe('Queue', () => {
|
|
|
95
76
|
|
|
96
77
|
beforeEach(() => {
|
|
97
78
|
queueName = TestHelpers.Faker.Text.randomString();
|
|
98
|
-
queue =
|
|
79
|
+
queue = buildQueue(queueName);
|
|
99
80
|
});
|
|
100
81
|
|
|
101
82
|
|
|
@@ -117,8 +98,8 @@ describe('Queue', () => {
|
|
|
117
98
|
it ('uses the queue scope keyed by fullQueueName', () => {
|
|
118
99
|
const child = queue.logger;
|
|
119
100
|
|
|
120
|
-
expect(
|
|
121
|
-
expect(child).toBe(
|
|
101
|
+
expect(queue.loggerLibrary.queue.child).toHaveBeenCalledWith(`${queueName}-test`);
|
|
102
|
+
expect(child).toBe(queue.loggerLibrary.queue.child.mock.results[0].value);
|
|
122
103
|
});
|
|
123
104
|
});
|
|
124
105
|
|
|
@@ -157,7 +138,7 @@ describe('Queue', () => {
|
|
|
157
138
|
describe('#queueJob', () => {
|
|
158
139
|
it ('adds the job to the BullMQ queue with a generated UUID, args, and settings', async () => {
|
|
159
140
|
const id = TestHelpers.Faker.Text.randomString();
|
|
160
|
-
|
|
141
|
+
queue.idGenerator.mockReturnValue(id);
|
|
161
142
|
const args = [TestHelpers.Faker.Text.randomString(), TestHelpers.Faker.Math.randomNumber()];
|
|
162
143
|
const settings = { attempts: TestHelpers.Faker.Math.randomNumber(10) };
|
|
163
144
|
const jobClass = { name: TestHelpers.Faker.Text.randomString() };
|
|
@@ -313,7 +294,7 @@ describe('Queue', () => {
|
|
|
313
294
|
|
|
314
295
|
errorListener(err);
|
|
315
296
|
|
|
316
|
-
const child =
|
|
297
|
+
const child = queue.loggerLibrary.queue.child.mock.results[0].value;
|
|
317
298
|
expect(child.error).toHaveBeenCalledWith(err);
|
|
318
299
|
});
|
|
319
300
|
});
|
|
@@ -3,26 +3,8 @@ const { setupJobQueueEnv } = require('./helpers/env');
|
|
|
3
3
|
const { buildFakeBullJob, buildWorker } = require('./helpers/worker');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
jest.mock('bullmq', () => {
|
|
7
|
-
const mock = require('./helpers/bullmqMock');
|
|
8
|
-
return { Queue: mock.Queue, Worker: mock.Worker };
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
jest.mock('../../lib/logger', () => {
|
|
12
|
-
const { buildLoggerMock } = require('./helpers/loggerMock');
|
|
13
|
-
return { logger: buildLoggerMock() };
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
jest.mock('../../lib/apm', () => {
|
|
17
|
-
const { buildApmMock } = require('./helpers/apmMock');
|
|
18
|
-
return buildApmMock();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
|
|
22
6
|
let bullmqMock;
|
|
23
7
|
let Worker;
|
|
24
|
-
let logger;
|
|
25
|
-
let APM;
|
|
26
8
|
let TestJobA;
|
|
27
9
|
let TestJobB;
|
|
28
10
|
let restoreEnv;
|
|
@@ -33,8 +15,6 @@ beforeEach(() => {
|
|
|
33
15
|
|
|
34
16
|
bullmqMock = require('./helpers/bullmqMock');
|
|
35
17
|
({ Worker } = require('../../lib/jobQueue/worker'));
|
|
36
|
-
({ logger } = require('../../lib/logger'));
|
|
37
|
-
APM = require('../../lib/apm');
|
|
38
18
|
({ TestJobA } = require('./helpers/fixtureJobs/testJobA'));
|
|
39
19
|
({ TestJobB } = require('./helpers/fixtureJobs/testJobB'));
|
|
40
20
|
});
|
|
@@ -110,9 +90,9 @@ describe('Worker', () => {
|
|
|
110
90
|
|
|
111
91
|
describe('#logger', () => {
|
|
112
92
|
it ('returns the worker scope', () => {
|
|
113
|
-
const worker =
|
|
93
|
+
const worker = buildWorker(Worker);
|
|
114
94
|
|
|
115
|
-
expect(worker.logger).toBe(
|
|
95
|
+
expect(worker.logger).toBe(worker.loggerLibrary.worker);
|
|
116
96
|
});
|
|
117
97
|
});
|
|
118
98
|
|
|
@@ -203,8 +183,8 @@ describe('Worker', () => {
|
|
|
203
183
|
|
|
204
184
|
await worker.listen();
|
|
205
185
|
|
|
206
|
-
expect(
|
|
207
|
-
expect(
|
|
186
|
+
expect(worker.loggerLibrary.worker.verbose).toHaveBeenCalledWith('JOB: TestJobA');
|
|
187
|
+
expect(worker.loggerLibrary.worker.verbose).toHaveBeenCalledWith('JOB: TestJobB');
|
|
208
188
|
});
|
|
209
189
|
|
|
210
190
|
it ('skips per-job verbose logging when NODE_ENV is test', async () => {
|
|
@@ -213,7 +193,7 @@ describe('Worker', () => {
|
|
|
213
193
|
|
|
214
194
|
await worker.listen();
|
|
215
195
|
|
|
216
|
-
const verboseCalls =
|
|
196
|
+
const verboseCalls = worker.loggerLibrary.worker.verbose.mock.calls.filter(
|
|
217
197
|
([msg]) => typeof msg === 'string' && msg.startsWith('JOB:')
|
|
218
198
|
);
|
|
219
199
|
expect(verboseCalls).toHaveLength(0);
|
|
@@ -288,8 +268,8 @@ describe('Worker', () => {
|
|
|
288
268
|
|
|
289
269
|
await processor(fakeBull);
|
|
290
270
|
|
|
291
|
-
expect(
|
|
292
|
-
expect(
|
|
271
|
+
expect(worker.apm.startBackgroundTransaction).toHaveBeenCalledTimes(1);
|
|
272
|
+
expect(worker.apm.startBackgroundTransaction).toHaveBeenCalledWith(
|
|
293
273
|
'TestJobA',
|
|
294
274
|
`${queueName}-test`,
|
|
295
275
|
expect.any(Function),
|
|
@@ -304,8 +284,8 @@ describe('Worker', () => {
|
|
|
304
284
|
|
|
305
285
|
await processor(fakeBull);
|
|
306
286
|
|
|
307
|
-
expect(
|
|
308
|
-
expect(
|
|
287
|
+
expect(worker.apm.startSegment).toHaveBeenCalledTimes(1);
|
|
288
|
+
expect(worker.apm.startSegment).toHaveBeenCalledWith('job:TestJobA', true, expect.any(Function));
|
|
309
289
|
});
|
|
310
290
|
|
|
311
291
|
it ('adds jobId, jobName, queueName, attempt, and maxAttempts as custom attributes', async () => {
|
|
@@ -323,11 +303,11 @@ describe('Worker', () => {
|
|
|
323
303
|
|
|
324
304
|
await processor(fakeBull);
|
|
325
305
|
|
|
326
|
-
expect(
|
|
327
|
-
expect(
|
|
328
|
-
expect(
|
|
329
|
-
expect(
|
|
330
|
-
expect(
|
|
306
|
+
expect(worker.apm.addCustomAttribute).toHaveBeenCalledWith('jobId', id);
|
|
307
|
+
expect(worker.apm.addCustomAttribute).toHaveBeenCalledWith('jobName', 'TestJobA');
|
|
308
|
+
expect(worker.apm.addCustomAttribute).toHaveBeenCalledWith('queueName', queueName);
|
|
309
|
+
expect(worker.apm.addCustomAttribute).toHaveBeenCalledWith('attempt', 2);
|
|
310
|
+
expect(worker.apm.addCustomAttribute).toHaveBeenCalledWith('maxAttempts', 5);
|
|
331
311
|
});
|
|
332
312
|
|
|
333
313
|
it ('records a JobCompleted custom event and a duration metric on success', async () => {
|
|
@@ -344,13 +324,13 @@ describe('Worker', () => {
|
|
|
344
324
|
|
|
345
325
|
await processor(fakeBull);
|
|
346
326
|
|
|
347
|
-
expect(
|
|
327
|
+
expect(worker.apm.recordCustomEvent).toHaveBeenCalledWith('JobCompleted', {
|
|
348
328
|
jobName: 'TestJobA',
|
|
349
329
|
queueName,
|
|
350
330
|
durationMs: finishedAt - startedAt,
|
|
351
331
|
attempts: 1,
|
|
352
332
|
});
|
|
353
|
-
expect(
|
|
333
|
+
expect(worker.apm.recordMetric).toHaveBeenCalledWith(
|
|
354
334
|
`Custom/Worker/${queueName}/TestJobA/duration`,
|
|
355
335
|
finishedAt - startedAt,
|
|
356
336
|
);
|
|
@@ -372,8 +352,8 @@ describe('Worker', () => {
|
|
|
372
352
|
|
|
373
353
|
await expect(processor(fakeBull)).rejects.toBe(err);
|
|
374
354
|
|
|
375
|
-
expect(
|
|
376
|
-
expect(
|
|
355
|
+
expect(worker.apm.reportError).toHaveBeenCalledTimes(1);
|
|
356
|
+
expect(worker.apm.reportError).toHaveBeenCalledWith(err, {
|
|
377
357
|
jobId: id,
|
|
378
358
|
jobName: 'TestJobA',
|
|
379
359
|
queueName,
|
|
@@ -381,7 +361,7 @@ describe('Worker', () => {
|
|
|
381
361
|
maxAttempts: 3,
|
|
382
362
|
isFinalRetry: false,
|
|
383
363
|
});
|
|
384
|
-
expect(
|
|
364
|
+
expect(worker.apm.recordCustomEvent).not.toHaveBeenCalledWith('JobFailed', expect.anything());
|
|
385
365
|
});
|
|
386
366
|
|
|
387
367
|
it ('records a JobFailed custom event on the final retry', async () => {
|
|
@@ -398,13 +378,13 @@ describe('Worker', () => {
|
|
|
398
378
|
|
|
399
379
|
await expect(processor(fakeBull)).rejects.toBe(err);
|
|
400
380
|
|
|
401
|
-
expect(
|
|
381
|
+
expect(worker.apm.recordCustomEvent).toHaveBeenCalledWith('JobFailed', {
|
|
402
382
|
jobName: 'TestJobA',
|
|
403
383
|
queueName,
|
|
404
384
|
attempts: 3,
|
|
405
385
|
error: err.message,
|
|
406
386
|
});
|
|
407
|
-
expect(
|
|
387
|
+
expect(worker.apm.reportError).toHaveBeenCalledWith(err, expect.objectContaining({
|
|
408
388
|
isFinalRetry: true,
|
|
409
389
|
}));
|
|
410
390
|
});
|
|
@@ -418,8 +398,8 @@ describe('Worker', () => {
|
|
|
418
398
|
|
|
419
399
|
await expect(processor(fakeBull)).rejects.toBe(err);
|
|
420
400
|
|
|
421
|
-
expect(
|
|
422
|
-
expect(
|
|
401
|
+
expect(worker.apm.recordCustomEvent).not.toHaveBeenCalledWith('JobCompleted', expect.anything());
|
|
402
|
+
expect(worker.apm.recordMetric).not.toHaveBeenCalled();
|
|
423
403
|
});
|
|
424
404
|
|
|
425
405
|
/*
|
|
@@ -453,7 +433,7 @@ describe('Worker', () => {
|
|
|
453
433
|
|
|
454
434
|
handler({ name: 'TestJobA', data: { id } }, duration);
|
|
455
435
|
|
|
456
|
-
const child =
|
|
436
|
+
const child = worker.loggerLibrary.worker.child.mock.results[0].value;
|
|
457
437
|
expect(child.debug).toHaveBeenCalledWith(`Completed in ${duration}ms`);
|
|
458
438
|
});
|
|
459
439
|
|
|
@@ -466,7 +446,7 @@ describe('Worker', () => {
|
|
|
466
446
|
|
|
467
447
|
handler({ name: 'TestJobA', data: { id } }, payload);
|
|
468
448
|
|
|
469
|
-
const child =
|
|
449
|
+
const child = worker.loggerLibrary.worker.child.mock.results[0].value;
|
|
470
450
|
expect(child.debug).toHaveBeenCalledWith(payload);
|
|
471
451
|
});
|
|
472
452
|
|
|
@@ -483,7 +463,7 @@ describe('Worker', () => {
|
|
|
483
463
|
const err = new Error('boom');
|
|
484
464
|
|
|
485
465
|
expect(() => handler(job, err)).not.toThrow();
|
|
486
|
-
const child =
|
|
466
|
+
const child = worker.loggerLibrary.worker.child.mock.results[0].value;
|
|
487
467
|
expect(child.debug).toHaveBeenCalledWith('ERROR (1/3) Error: boom');
|
|
488
468
|
});
|
|
489
469
|
|
|
@@ -510,7 +490,7 @@ describe('Worker', () => {
|
|
|
510
490
|
const err = new Error(TestHelpers.Faker.Text.randomString());
|
|
511
491
|
|
|
512
492
|
expect(() => handler(err)).toThrow(err);
|
|
513
|
-
expect(
|
|
493
|
+
expect(worker.loggerLibrary.worker.error).toHaveBeenCalledWith(err);
|
|
514
494
|
});
|
|
515
495
|
|
|
516
496
|
it ('"error" handler logs and does NOT throw outside development', async () => {
|
|
@@ -520,7 +500,7 @@ describe('Worker', () => {
|
|
|
520
500
|
const err = new Error(TestHelpers.Faker.Text.randomString());
|
|
521
501
|
|
|
522
502
|
expect(() => handler(err)).not.toThrow();
|
|
523
|
-
expect(
|
|
503
|
+
expect(worker.loggerLibrary.worker.error).toHaveBeenCalledWith(err);
|
|
524
504
|
});
|
|
525
505
|
});
|
|
526
506
|
});
|
|
@@ -46,6 +46,32 @@ describe('Logger', () => {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
describe('#child', () => {
|
|
50
|
+
it ('returns a fresh, uncached logger for an id so per-request loggers are not retained', () => {
|
|
51
|
+
const scope = randomScope();
|
|
52
|
+
const id = TestHelpers.Faker.Text.randomString();
|
|
53
|
+
const root = new Logger(scope);
|
|
54
|
+
|
|
55
|
+
const first = root.child(id);
|
|
56
|
+
const second = root.child(id);
|
|
57
|
+
|
|
58
|
+
expect(first).not.toBe(second);
|
|
59
|
+
expect(first.id).toEqual(id);
|
|
60
|
+
expect(first.scopes).toEqual([scope]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it ('caches and reuses the logger when no id is provided', () => {
|
|
64
|
+
const scope = randomScope();
|
|
65
|
+
const root = new Logger(scope);
|
|
66
|
+
|
|
67
|
+
const first = root.child();
|
|
68
|
+
const second = root.child();
|
|
69
|
+
|
|
70
|
+
expect(first).toBe(second);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
|
|
49
75
|
describe('#messageFormatter', () => {
|
|
50
76
|
it ('renders every nested scope in the prefix in order', () => {
|
|
51
77
|
const scopeA = randomScope();
|
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
return {
|
|
3
|
-
logger: jest.fn(() => jest.fn()) // returns a noop middleware
|
|
4
|
-
};
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
const expressWinston = require('express-winston');
|
|
1
|
+
const { LoggingMiddleware } = require('../../lib/logger/serverMiddleware');
|
|
8
2
|
|
|
9
|
-
// Invoking middleware() triggers expressWinston.logger(options) — capturing options gives us
|
|
10
|
-
// access to the otherwise-unexported msgFormatter
|
|
11
|
-
const { middleware } = require('../../lib/logger/serverMiddleware');
|
|
12
|
-
middleware({ _winstonLogger: {} });
|
|
13
3
|
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
// msgFormatter is an instance method, so we exercise it directly — no need to mock express-winston
|
|
5
|
+
// or build the middleware (the logger collaborator is only read lazily when middleware is built).
|
|
6
|
+
const msgFormatter = (req, res) => new LoggingMiddleware({}).msgFormatter(req, res);
|
|
16
7
|
|
|
17
8
|
|
|
18
|
-
describe('
|
|
19
|
-
describe('msgFormatter', () => {
|
|
9
|
+
describe('LoggingMiddleware', () => {
|
|
10
|
+
describe('#msgFormatter', () => {
|
|
20
11
|
const baseRes = (overrides = {}) => ({
|
|
21
12
|
statusCode: 200,
|
|
22
13
|
responseTime: 12,
|
|
@@ -1,14 +1,48 @@
|
|
|
1
|
-
const { VidaServer }
|
|
1
|
+
const { VidaServer } = require('../../../lib/server');
|
|
2
|
+
const jestExpress = require('jest-express');
|
|
3
|
+
const { Response } = require('jest-express/lib/response');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
// missing function in mock express
|
|
7
|
+
Response.prototype.on = jest.fn();
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function buildServerEngineFactory() {
|
|
11
|
+
const instances = [];
|
|
12
|
+
const factory = (...args) => {
|
|
13
|
+
const app = jestExpress(...args);
|
|
14
|
+
instances.push(app);
|
|
15
|
+
return app;
|
|
16
|
+
};
|
|
17
|
+
Object.assign(factory, jestExpress);
|
|
18
|
+
factory.raw = jest.fn();
|
|
19
|
+
factory.__instances = instances;
|
|
20
|
+
return factory;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const serverEngineDouble = buildServerEngineFactory();
|
|
25
|
+
const socketServerDouble = jest.fn();
|
|
26
|
+
const httpServerDouble = jest.fn();
|
|
2
27
|
|
|
3
28
|
|
|
4
29
|
class TestServer extends VidaServer {
|
|
5
|
-
get controllerDirectories() {
|
|
6
|
-
|
|
7
|
-
}
|
|
30
|
+
get controllerDirectories() { return [`${__dirname}/controllers`]; }
|
|
31
|
+
get serverEngineFactory() { return serverEngineDouble; }
|
|
32
|
+
get socketServerFactory() { return socketServerDouble; }
|
|
33
|
+
get httpServerFactory() { return httpServerDouble; }
|
|
8
34
|
}
|
|
9
35
|
|
|
10
36
|
|
|
11
|
-
|
|
12
|
-
|
|
37
|
+
function lastApp() {
|
|
38
|
+
return serverEngineDouble.__instances[serverEngineDouble.__instances.length - 1];
|
|
13
39
|
}
|
|
14
40
|
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
TestServer,
|
|
44
|
+
lastApp,
|
|
45
|
+
serverEngineDouble,
|
|
46
|
+
socketServerDouble,
|
|
47
|
+
httpServerDouble,
|
|
48
|
+
}
|
|
@@ -3,42 +3,13 @@ const { BazController } = require('./helpers/controllers/sub/bazController');
|
|
|
3
3
|
const { FooController } = require('./helpers/controllers/fooController');
|
|
4
4
|
const { Request } = require('jest-express/lib/request');
|
|
5
5
|
const { Response } = require('jest-express/lib/response');
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
TestServer,
|
|
8
|
+
lastApp,
|
|
9
|
+
socketServerDouble: IoServer,
|
|
10
|
+
httpServerDouble: HttpServer,
|
|
11
|
+
} = require('./helpers/server');
|
|
7
12
|
const { VidaServer } = require('../../lib/server');
|
|
8
|
-
const express = require('express');
|
|
9
|
-
const IoServer = require('socket.io');
|
|
10
|
-
const { Server: HttpServer } = require('http');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const lastApp = () => express.__instances[express.__instances.length - 1];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
jest.mock('express', () => {
|
|
17
|
-
const jestExpress = require('jest-express');
|
|
18
|
-
const { Response } = require('jest-express/lib/response');
|
|
19
|
-
|
|
20
|
-
// missing functions in mock express
|
|
21
|
-
Response.prototype.on = jest.fn();
|
|
22
|
-
|
|
23
|
-
// Wrap the factory so tests can inspect the most recently created Express app.
|
|
24
|
-
const instances = [];
|
|
25
|
-
const wrapped = (...args) => {
|
|
26
|
-
const app = jestExpress(...args);
|
|
27
|
-
instances.push(app);
|
|
28
|
-
return app;
|
|
29
|
-
};
|
|
30
|
-
Object.assign(wrapped, jestExpress);
|
|
31
|
-
wrapped.raw = jest.fn();
|
|
32
|
-
wrapped.__instances = instances;
|
|
33
|
-
|
|
34
|
-
return wrapped;
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
jest.mock('socket.io', () => jest.fn());
|
|
38
|
-
jest.mock('http', () => {
|
|
39
|
-
const actual = jest.requireActual('http');
|
|
40
|
-
return { ...actual, Server: jest.fn() };
|
|
41
|
-
});
|
|
42
13
|
|
|
43
14
|
|
|
44
15
|
afterEach(() => {
|
|
@@ -1786,12 +1786,12 @@ describe('VidaServerController', () => {
|
|
|
1786
1786
|
.toThrow(NoActiveStreamError);
|
|
1787
1787
|
});
|
|
1788
1788
|
|
|
1789
|
-
it ('writes
|
|
1789
|
+
it ('writes the event and data lines as a single atomic frame when an event name is provided', async () => {
|
|
1790
1790
|
await controller.streamSseResponse(async () => {
|
|
1791
1791
|
response.write.mockClear();
|
|
1792
1792
|
controller.writeStreamEvent('progress', 'halfway');
|
|
1793
|
-
expect(response.write).
|
|
1794
|
-
expect(response.write).
|
|
1793
|
+
expect(response.write).toHaveBeenCalledTimes(1);
|
|
1794
|
+
expect(response.write).toHaveBeenCalledWith('event: progress\ndata: halfway\n\n');
|
|
1795
1795
|
}, jest.fn());
|
|
1796
1796
|
});
|
|
1797
1797
|
|