@datadog/datadog-ci 1.7.2 → 1.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/README.md +26 -0
- package/dist/commands/junit/__tests__/upload.test.js +12 -0
- package/dist/commands/junit/__tests__/upload.test.js.map +1 -1
- package/dist/commands/junit/api.js +1 -1
- package/dist/commands/junit/api.js.map +1 -1
- package/dist/commands/junit/interfaces.d.ts +1 -0
- package/dist/commands/junit/upload.js +2 -0
- package/dist/commands/junit/upload.js.map +1 -1
- package/dist/commands/synthetics/__tests__/api.test.js +5 -13
- package/dist/commands/synthetics/__tests__/api.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/cli.test.js +49 -211
- package/dist/commands/synthetics/__tests__/cli.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/fixtures.d.ts +10 -15
- package/dist/commands/synthetics/__tests__/fixtures.js +99 -56
- package/dist/commands/synthetics/__tests__/fixtures.js.map +1 -1
- package/dist/commands/synthetics/__tests__/reporters/default.test.js +21 -24
- package/dist/commands/synthetics/__tests__/reporters/default.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/reporters/junit.test.js +1 -2
- package/dist/commands/synthetics/__tests__/reporters/junit.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/run-test.test.js +5 -3
- package/dist/commands/synthetics/__tests__/run-test.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/utils.test.js +289 -225
- package/dist/commands/synthetics/__tests__/utils.test.js.map +1 -1
- package/dist/commands/synthetics/__tests__/websocket.test.js +2 -0
- package/dist/commands/synthetics/__tests__/websocket.test.js.map +1 -1
- package/dist/commands/synthetics/api.d.ts +3 -4
- package/dist/commands/synthetics/api.js +13 -3
- package/dist/commands/synthetics/api.js.map +1 -1
- package/dist/commands/synthetics/command.d.ts +1 -9
- package/dist/commands/synthetics/command.js +7 -66
- package/dist/commands/synthetics/command.js.map +1 -1
- package/dist/commands/synthetics/errors.d.ts +1 -1
- package/dist/commands/synthetics/errors.js +1 -1
- package/dist/commands/synthetics/errors.js.map +1 -1
- package/dist/commands/synthetics/interfaces.d.ts +28 -31
- package/dist/commands/synthetics/interfaces.js +1 -7
- package/dist/commands/synthetics/interfaces.js.map +1 -1
- package/dist/commands/synthetics/reporters/default.d.ts +3 -3
- package/dist/commands/synthetics/reporters/default.js +35 -19
- package/dist/commands/synthetics/reporters/default.js.map +1 -1
- package/dist/commands/synthetics/reporters/junit.js +4 -5
- package/dist/commands/synthetics/reporters/junit.js.map +1 -1
- package/dist/commands/synthetics/run-test.d.ts +2 -3
- package/dist/commands/synthetics/run-test.js +6 -8
- package/dist/commands/synthetics/run-test.js.map +1 -1
- package/dist/commands/synthetics/utils.d.ts +19 -5
- package/dist/commands/synthetics/utils.js +118 -104
- package/dist/commands/synthetics/utils.js.map +1 -1
- package/package.json +2 -1
|
@@ -42,7 +42,11 @@ const api_1 = require("../api");
|
|
|
42
42
|
const errors_1 = require("../errors");
|
|
43
43
|
const interfaces_1 = require("../interfaces");
|
|
44
44
|
const utils = __importStar(require("../utils"));
|
|
45
|
+
const command_1 = require("../command");
|
|
45
46
|
const fixtures_1 = require("./fixtures");
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
jest.restoreAllMocks();
|
|
49
|
+
});
|
|
46
50
|
describe('utils', () => {
|
|
47
51
|
const apiConfiguration = {
|
|
48
52
|
apiKey: '123',
|
|
@@ -69,19 +73,11 @@ describe('utils', () => {
|
|
|
69
73
|
describe('runTest', () => {
|
|
70
74
|
const fakeId = '123-456-789';
|
|
71
75
|
const fakeTrigger = {
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
batch_id: 'bid',
|
|
77
|
+
locations: [],
|
|
74
78
|
};
|
|
75
|
-
afterAll(() => {
|
|
76
|
-
jest.clearAllMocks();
|
|
77
|
-
});
|
|
78
79
|
test('should run test', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
|
-
|
|
80
|
-
axiosMock.mockImplementation((() => (e) => {
|
|
81
|
-
if (e.url === '/synthetics/tests/trigger/ci') {
|
|
82
|
-
return { data: fakeTrigger };
|
|
83
|
-
}
|
|
84
|
-
}));
|
|
80
|
+
jest.spyOn(api, 'triggerTests').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return fakeTrigger; }));
|
|
85
81
|
const output = yield utils.runTests(api, [{ public_id: fakeId, executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }]);
|
|
86
82
|
expect(output).toEqual(fakeTrigger);
|
|
87
83
|
}));
|
|
@@ -120,12 +116,7 @@ describe('utils', () => {
|
|
|
120
116
|
expect(headersMetadataSpy).toHaveBeenCalledWith(expect.objectContaining({ 'X-Trigger-App': 'unit_test' }));
|
|
121
117
|
}));
|
|
122
118
|
test('should run test with publicId from url', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
-
|
|
124
|
-
axiosMock.mockImplementation((() => (e) => {
|
|
125
|
-
if (e.url === '/synthetics/tests/trigger/ci') {
|
|
126
|
-
return { data: fakeTrigger };
|
|
127
|
-
}
|
|
128
|
-
}));
|
|
119
|
+
jest.spyOn(api, 'triggerTests').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return fakeTrigger; }));
|
|
129
120
|
const output = yield utils.runTests(api, [
|
|
130
121
|
{
|
|
131
122
|
executionRule: interfaces_1.ExecutionRule.NON_BLOCKING,
|
|
@@ -143,11 +134,9 @@ describe('utils', () => {
|
|
|
143
134
|
status: 502,
|
|
144
135
|
},
|
|
145
136
|
});
|
|
146
|
-
|
|
147
|
-
requestMock.mockImplementation(() => {
|
|
137
|
+
jest.spyOn(api, 'triggerTests').mockImplementation(() => {
|
|
148
138
|
throw serverError;
|
|
149
139
|
});
|
|
150
|
-
jest.spyOn(axios_1.default, 'create').mockImplementation((() => requestMock));
|
|
151
140
|
yield expect(utils.runTests(api, [{ public_id: fakeId, executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }])).rejects.toThrow(/Failed to trigger tests:/);
|
|
152
141
|
}));
|
|
153
142
|
});
|
|
@@ -167,7 +156,7 @@ describe('utils', () => {
|
|
|
167
156
|
suite: 'Suite 3',
|
|
168
157
|
},
|
|
169
158
|
};
|
|
170
|
-
|
|
159
|
+
beforeEach(() => {
|
|
171
160
|
const axiosMock = jest.spyOn(axios_1.default, 'create');
|
|
172
161
|
axiosMock.mockImplementation((() => (e) => {
|
|
173
162
|
const publicId = e.url.slice(18);
|
|
@@ -179,9 +168,6 @@ describe('utils', () => {
|
|
|
179
168
|
throw error;
|
|
180
169
|
}));
|
|
181
170
|
});
|
|
182
|
-
afterAll(() => {
|
|
183
|
-
jest.clearAllMocks();
|
|
184
|
-
});
|
|
185
171
|
test('only existing tests are returned', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
186
172
|
const triggerConfigs = [
|
|
187
173
|
{ suite: 'Suite 1', config: {}, id: '123-456-789' },
|
|
@@ -344,71 +330,59 @@ describe('utils', () => {
|
|
|
344
330
|
const result = {
|
|
345
331
|
device: { height: 0, id: 'laptop_large', width: 0 },
|
|
346
332
|
duration: 0,
|
|
347
|
-
eventType: 'finished',
|
|
348
333
|
passed: true,
|
|
349
334
|
startUrl: '',
|
|
350
335
|
stepDetails: [],
|
|
351
336
|
};
|
|
352
|
-
expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
|
|
353
|
-
expect(utils.hasResultPassed(result, true, true)).toBeTruthy();
|
|
337
|
+
expect(utils.hasResultPassed(result, false, false, true)).toBeTruthy();
|
|
338
|
+
expect(utils.hasResultPassed(result, false, true, true)).toBeTruthy();
|
|
354
339
|
result.passed = false;
|
|
355
|
-
expect(utils.hasResultPassed(result, false, true)).toBeFalsy();
|
|
356
|
-
expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
|
|
340
|
+
expect(utils.hasResultPassed(result, false, false, true)).toBeFalsy();
|
|
341
|
+
expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
|
|
357
342
|
});
|
|
358
343
|
test('result with error', () => {
|
|
359
344
|
const result = {
|
|
360
345
|
device: { height: 0, id: 'laptop_large', width: 0 },
|
|
361
346
|
duration: 0,
|
|
362
|
-
|
|
363
|
-
|
|
347
|
+
failure: {
|
|
348
|
+
code: 'ERRABORTED',
|
|
349
|
+
message: 'Connection aborted',
|
|
350
|
+
},
|
|
364
351
|
passed: false,
|
|
365
352
|
startUrl: '',
|
|
366
353
|
stepDetails: [],
|
|
367
354
|
};
|
|
368
|
-
expect(utils.hasResultPassed(result, false, true)).toBeFalsy();
|
|
369
|
-
expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
|
|
355
|
+
expect(utils.hasResultPassed(result, false, false, true)).toBeFalsy();
|
|
356
|
+
expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
|
|
370
357
|
});
|
|
371
358
|
test('result with unhealthy result', () => {
|
|
372
359
|
const result = {
|
|
373
360
|
device: { height: 0, id: 'laptop_large', width: 0 },
|
|
374
361
|
duration: 0,
|
|
375
|
-
|
|
376
|
-
|
|
362
|
+
failure: {
|
|
363
|
+
code: 'ERRABORTED',
|
|
364
|
+
message: 'Connection aborted',
|
|
365
|
+
},
|
|
377
366
|
passed: false,
|
|
378
367
|
startUrl: '',
|
|
379
368
|
stepDetails: [],
|
|
380
369
|
unhealthy: true,
|
|
381
370
|
};
|
|
382
|
-
expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
|
|
383
|
-
expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
|
|
371
|
+
expect(utils.hasResultPassed(result, false, false, true)).toBeTruthy();
|
|
372
|
+
expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
|
|
384
373
|
});
|
|
385
374
|
test('result with timeout result', () => {
|
|
386
375
|
const result = {
|
|
387
376
|
device: { height: 0, id: 'laptop_large', width: 0 },
|
|
388
377
|
duration: 0,
|
|
389
|
-
error: interfaces_1.ERRORS.TIMEOUT,
|
|
390
|
-
eventType: 'finished',
|
|
391
378
|
passed: false,
|
|
392
379
|
startUrl: '',
|
|
393
380
|
stepDetails: [],
|
|
394
381
|
};
|
|
395
|
-
expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
|
|
396
|
-
expect(utils.hasResultPassed(result, true, false)).toBeTruthy();
|
|
382
|
+
expect(utils.hasResultPassed(result, true, true, true)).toBeFalsy();
|
|
383
|
+
expect(utils.hasResultPassed(result, true, true, false)).toBeTruthy();
|
|
397
384
|
});
|
|
398
385
|
});
|
|
399
|
-
test('result with endpoint failure result', () => {
|
|
400
|
-
const result = {
|
|
401
|
-
device: { height: 0, id: 'laptop_large', width: 0 },
|
|
402
|
-
duration: 0,
|
|
403
|
-
error: interfaces_1.ERRORS.ENDPOINT,
|
|
404
|
-
eventType: 'finished',
|
|
405
|
-
passed: false,
|
|
406
|
-
startUrl: '',
|
|
407
|
-
stepDetails: [],
|
|
408
|
-
};
|
|
409
|
-
expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
|
|
410
|
-
expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
|
|
411
|
-
});
|
|
412
386
|
describe('getExecutionRule', () => {
|
|
413
387
|
const cases = [
|
|
414
388
|
[undefined, undefined, interfaces_1.ExecutionRule.BLOCKING],
|
|
@@ -437,211 +411,162 @@ describe('utils', () => {
|
|
|
437
411
|
jest.spyOn(utils, 'getExecutionRule').mockReturnValue(resultRule);
|
|
438
412
|
const test = fixtures_1.getApiTest('abc-def-ghi');
|
|
439
413
|
const result = fixtures_1.getApiResult('1', test);
|
|
414
|
+
result.executionRule = resultRule;
|
|
440
415
|
result.passed = resultPassed;
|
|
441
416
|
expect(utils.getResultOutcome(result)).toEqual(expectedOutcome);
|
|
442
417
|
});
|
|
443
418
|
});
|
|
444
419
|
describe('waitForResults', () => {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
.filter((resultId) => resultId !== 'timingOutTest')
|
|
450
|
-
.map((resultId) => getPassingPollResult(resultId));
|
|
451
|
-
return { data: { results } };
|
|
452
|
-
})));
|
|
453
|
-
};
|
|
454
|
-
afterAll(() => {
|
|
455
|
-
jest.clearAllMocks();
|
|
420
|
+
beforeAll(() => {
|
|
421
|
+
// We still wait a few milliseconds to avoid the test going crazy on a infinite loop
|
|
422
|
+
// if case of mistakes in the code or test.
|
|
423
|
+
jest.spyOn(utils, 'wait').mockImplementation(() => new Promise((r) => setTimeout(r, 10)));
|
|
456
424
|
});
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
check: result.test,
|
|
462
|
-
enrichment: result.enrichment,
|
|
463
|
-
result: result.result,
|
|
464
|
-
resultID: result.resultId,
|
|
465
|
-
timestamp: result.timestamp,
|
|
466
|
-
};
|
|
467
|
-
};
|
|
468
|
-
const getPassingResult = (resultId) => ({
|
|
425
|
+
const batch = fixtures_1.getBatch();
|
|
426
|
+
const apiTest = fixtures_1.getApiTest(batch.results[0].test_public_id);
|
|
427
|
+
const result = {
|
|
428
|
+
executionRule: interfaces_1.ExecutionRule.BLOCKING,
|
|
469
429
|
location: fixtures_1.mockLocation.display_name,
|
|
470
430
|
passed: true,
|
|
471
|
-
result: fixtures_1.getBrowserServerResult({
|
|
472
|
-
resultId,
|
|
473
|
-
test:
|
|
431
|
+
result: fixtures_1.getBrowserServerResult({ passed: true }),
|
|
432
|
+
resultId: batch.results[0].result_id,
|
|
433
|
+
test: apiTest,
|
|
434
|
+
timedOut: false,
|
|
474
435
|
timestamp: 0,
|
|
475
|
-
}
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
test: passingResult.test,
|
|
492
|
-
trigger: { locations: [fixtures_1.mockLocation], results: [triggerResult] },
|
|
493
|
-
triggerConfig,
|
|
494
|
-
triggerResult,
|
|
495
|
-
};
|
|
436
|
+
};
|
|
437
|
+
const pollResult = {
|
|
438
|
+
check: result.test,
|
|
439
|
+
result: result.result,
|
|
440
|
+
resultID: result.resultId,
|
|
441
|
+
timestamp: result.timestamp,
|
|
442
|
+
};
|
|
443
|
+
const trigger = { batch_id: 'bid', locations: [fixtures_1.mockLocation] };
|
|
444
|
+
const mockApi = ({ getBatchImplementation, pollResultsImplementation, } = {}) => {
|
|
445
|
+
const getBatchMock = jest
|
|
446
|
+
.spyOn(api, 'getBatch')
|
|
447
|
+
.mockImplementation(getBatchImplementation || (() => __awaiter(void 0, void 0, void 0, function* () { return JSON.parse(JSON.stringify(batch)); })));
|
|
448
|
+
const pollResultsMock = jest
|
|
449
|
+
.spyOn(api, 'pollResults')
|
|
450
|
+
.mockImplementation(pollResultsImplementation || (() => __awaiter(void 0, void 0, void 0, function* () { return JSON.parse(JSON.stringify([pollResult])); })));
|
|
451
|
+
return { getBatchMock, pollResultsMock };
|
|
496
452
|
};
|
|
497
453
|
test('should poll result ids', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
waitMock.mockImplementation();
|
|
502
|
-
const expectedResults = [passingResult];
|
|
503
|
-
expect(yield utils.waitForResults(api, trigger, [triggerConfig], [test], { defaultTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
|
|
504
|
-
expect(fixtures_1.mockReporter.resultReceived).toHaveBeenCalledWith(passingResult);
|
|
454
|
+
mockApi();
|
|
455
|
+
expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([result]);
|
|
456
|
+
expect(fixtures_1.mockReporter.resultReceived).toHaveBeenCalledWith(batch.results[0]);
|
|
505
457
|
}));
|
|
506
|
-
test('results should be timed
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
]
|
|
522
|
-
|
|
458
|
+
test('results should be timed out if global pollingTimeout is exceeded', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
459
|
+
mockApi({
|
|
460
|
+
getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
461
|
+
return ({
|
|
462
|
+
results: [batch.results[0], Object.assign(Object.assign({}, batch.results[0]), { result_id: '3', timed_out: undefined })],
|
|
463
|
+
status: 'in_progress',
|
|
464
|
+
});
|
|
465
|
+
}),
|
|
466
|
+
pollResultsImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
467
|
+
return [
|
|
468
|
+
Object.assign(Object.assign({}, pollResult), { result: Object.assign({}, pollResult.result) }),
|
|
469
|
+
Object.assign(Object.assign({}, pollResult), { result: Object.assign({}, pollResult.result), resultID: '3' }),
|
|
470
|
+
];
|
|
471
|
+
}),
|
|
472
|
+
});
|
|
473
|
+
expect(yield utils.waitForResults(api, trigger, [result.test, result.test], { maxPollingTimeout: 0, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([
|
|
474
|
+
result,
|
|
475
|
+
Object.assign(Object.assign({}, result), { result: Object.assign(Object.assign({}, result.result), { failure: { code: 'TIMEOUT', message: 'Result timed out' }, passed: false }), resultId: '3', timedOut: true }),
|
|
476
|
+
]);
|
|
523
477
|
}));
|
|
524
|
-
test('results should
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
},
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
478
|
+
test('results failure should ignore if timed-out', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
479
|
+
// The original failure of a result received between timing-out in batch poll
|
|
480
|
+
// and retrieving it should be ignored in favor of timeout.
|
|
481
|
+
mockApi({
|
|
482
|
+
getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
483
|
+
return ({
|
|
484
|
+
results: [Object.assign(Object.assign({}, batch.results[0]), { timed_out: undefined })],
|
|
485
|
+
status: 'in_progress',
|
|
486
|
+
});
|
|
487
|
+
}),
|
|
488
|
+
pollResultsImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
489
|
+
return [
|
|
490
|
+
Object.assign(Object.assign({}, pollResult), { passed: false, result: Object.assign(Object.assign({}, pollResult.result), { failure: { code: 'FAILURE', message: 'Original failure, should be ignored' }, passed: false }) }),
|
|
491
|
+
];
|
|
492
|
+
}),
|
|
493
|
+
});
|
|
494
|
+
expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 0, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toStrictEqual([
|
|
495
|
+
Object.assign(Object.assign({}, result), { result: Object.assign(Object.assign({}, result.result), { failure: { code: 'TIMEOUT', message: 'Result timed out' }, passed: false }), timedOut: true }),
|
|
496
|
+
]);
|
|
497
|
+
}));
|
|
498
|
+
test('results should be timed out if batch result is timed out', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
499
|
+
const batchWithTimeoutResult = Object.assign(Object.assign({}, batch), { results: [Object.assign(Object.assign({}, batch.results[0]), { timed_out: true })] });
|
|
500
|
+
mockApi({ getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return batchWithTimeoutResult; }) });
|
|
501
|
+
expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([
|
|
502
|
+
Object.assign(Object.assign({}, result), { result: Object.assign(Object.assign({}, result.result), { failure: { code: 'TIMEOUT', message: 'Result timed out' }, passed: false }), timedOut: true }),
|
|
503
|
+
]);
|
|
504
|
+
}));
|
|
505
|
+
test('wait between batch polling', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
506
|
+
jest.restoreAllMocks();
|
|
507
|
+
const waitMock = jest.spyOn(utils, 'wait').mockImplementation(() => new Promise((r) => setTimeout(r, 10)));
|
|
508
|
+
let counter = 0;
|
|
509
|
+
mockApi({
|
|
510
|
+
getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
511
|
+
counter += 1;
|
|
512
|
+
return counter === 3 ? batch : Object.assign(Object.assign({}, batch), { status: 'in_progress' });
|
|
513
|
+
}),
|
|
514
|
+
});
|
|
515
|
+
expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([result]);
|
|
516
|
+
expect(counter).toBe(3);
|
|
517
|
+
expect(waitMock).toHaveBeenCalledTimes(2);
|
|
546
518
|
}));
|
|
547
519
|
test('correct number of pass and timeout results', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
548
|
-
|
|
549
|
-
const {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
{
|
|
556
|
-
location: fixtures_1.mockLocation.display_name,
|
|
557
|
-
passed: true,
|
|
558
|
-
result: fixtures_1.getBrowserServerResult({
|
|
559
|
-
device: { height: 0, id: triggerResultTimeOut.device, width: 0 },
|
|
560
|
-
error: interfaces_1.ERRORS.TIMEOUT,
|
|
561
|
-
passed: false,
|
|
562
|
-
}),
|
|
563
|
-
resultId: triggerResultTimeOut.result_id,
|
|
564
|
-
test,
|
|
565
|
-
timestamp: 0,
|
|
566
|
-
},
|
|
567
|
-
];
|
|
568
|
-
trigger.results = [triggerResult, triggerResultTimeOut];
|
|
569
|
-
expect(yield utils.waitForResults(api, trigger, [], [test], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
|
|
520
|
+
const pollTimeoutResult = Object.assign(Object.assign({}, pollResult), { resultID: 'another-id' });
|
|
521
|
+
const batchWithTimeoutResult = Object.assign(Object.assign({}, batch), { results: [batch.results[0], Object.assign(Object.assign({}, batch.results[0]), { timed_out: true, result_id: pollTimeoutResult.resultID })] });
|
|
522
|
+
mockApi({
|
|
523
|
+
getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return batchWithTimeoutResult; }),
|
|
524
|
+
pollResultsImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return [pollResult, pollTimeoutResult]; }),
|
|
525
|
+
});
|
|
526
|
+
expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([result, Object.assign(Object.assign({}, result), { resultId: pollTimeoutResult.resultID, timedOut: true })]);
|
|
570
527
|
}));
|
|
571
528
|
test('tunnel failure', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
572
|
-
|
|
573
|
-
waitMock.mockImplementation();
|
|
574
|
-
const { test, trigger, triggerResult } = getTestAndResult();
|
|
575
|
-
// Fake pollResults to not update results and iterate until the isTunnelConnected is equal to false
|
|
576
|
-
jest
|
|
577
|
-
.spyOn(axios_1.default, 'create')
|
|
578
|
-
.mockImplementation((() => (r) => __awaiter(void 0, void 0, void 0, function* () { return ({ data: { results: [] } }); })));
|
|
529
|
+
mockApi();
|
|
579
530
|
const mockTunnel = {
|
|
580
531
|
keepAlive: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
581
532
|
throw new Error('keepAlive failed');
|
|
582
533
|
}),
|
|
583
534
|
};
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
location: 'Tunneled',
|
|
587
|
-
passed: false,
|
|
588
|
-
result: fixtures_1.getBrowserServerResult({
|
|
589
|
-
device: { height: 0, id: triggerResult.device, width: 0 },
|
|
590
|
-
error: interfaces_1.ERRORS.TUNNEL,
|
|
591
|
-
passed: false,
|
|
592
|
-
}),
|
|
593
|
-
resultId: triggerResult.result_id,
|
|
594
|
-
test,
|
|
595
|
-
timestamp: 0,
|
|
596
|
-
},
|
|
597
|
-
];
|
|
598
|
-
expect(yield utils.waitForResults(api, trigger, [], [test], { defaultTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel)).toEqual(expectedResults);
|
|
599
|
-
expect(yield utils.waitForResults(api, trigger, [], [test], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter, mockTunnel)).toEqual(expectedResults);
|
|
535
|
+
yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
|
|
536
|
+
expect(fixtures_1.mockReporter.error).toBeCalledWith('The tunnel has stopped working, this may have affected the results.');
|
|
600
537
|
}));
|
|
601
538
|
test('location when tunnel', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const mockTunnel = {
|
|
606
|
-
keepAlive: () => __awaiter(void 0, void 0, void 0, function* () { return true; }),
|
|
607
|
-
};
|
|
608
|
-
let results = yield utils.waitForResults(api, trigger, [], [test], { defaultTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
|
|
539
|
+
mockApi();
|
|
540
|
+
const mockTunnel = { keepAlive: () => __awaiter(void 0, void 0, void 0, function* () { return true; }) };
|
|
541
|
+
let results = yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
|
|
609
542
|
expect(results[0].location).toBe('Tunneled');
|
|
610
|
-
const newTest = Object.assign({}, test);
|
|
543
|
+
const newTest = Object.assign({}, result.test);
|
|
611
544
|
newTest.type = 'api';
|
|
612
545
|
newTest.subtype = 'http';
|
|
613
|
-
results = yield utils.waitForResults(api, trigger, [
|
|
546
|
+
results = yield utils.waitForResults(api, trigger, [newTest], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
|
|
614
547
|
expect(results[0].location).toBe('Tunneled');
|
|
615
548
|
newTest.type = 'api';
|
|
616
549
|
newTest.subtype = 'ssl';
|
|
617
|
-
results = yield utils.waitForResults(api, trigger, [
|
|
550
|
+
results = yield utils.waitForResults(api, trigger, [newTest], { failOnCriticalErrors: true, maxPollingTimeout: 2000 }, fixtures_1.mockReporter, mockTunnel);
|
|
618
551
|
expect(results[0].location).toBe('Frankfurt (AWS)');
|
|
619
552
|
}));
|
|
620
553
|
test('pollResults throws', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
621
|
-
const {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
const serverError = new Error('Server Error');
|
|
625
|
-
serverError.response = { status: 502 };
|
|
626
|
-
axiosMock.mockImplementation((() => (r) => __awaiter(void 0, void 0, void 0, function* () {
|
|
627
|
-
throw serverError;
|
|
628
|
-
})));
|
|
629
|
-
const mockTunnel = { keepAlive: () => __awaiter(void 0, void 0, void 0, function* () { return Promise.reject(); }) };
|
|
630
|
-
expect(yield utils.waitForResults(api, trigger, [], [test], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter, mockTunnel)).toEqual([
|
|
631
|
-
{
|
|
632
|
-
location: 'Tunneled',
|
|
633
|
-
passed: true,
|
|
634
|
-
result: fixtures_1.getBrowserServerResult({
|
|
635
|
-
device: { height: 0, id: triggerResult.device, width: 0 },
|
|
636
|
-
error: interfaces_1.ERRORS.ENDPOINT,
|
|
637
|
-
passed: false,
|
|
638
|
-
}),
|
|
639
|
-
resultId: triggerResult.result_id,
|
|
640
|
-
test,
|
|
641
|
-
timestamp: 0,
|
|
554
|
+
const { pollResultsMock } = mockApi({
|
|
555
|
+
pollResultsImplementation: () => {
|
|
556
|
+
throw new Error('Poll results server error');
|
|
642
557
|
},
|
|
643
|
-
|
|
644
|
-
yield expect(utils.waitForResults(api, trigger, [
|
|
558
|
+
});
|
|
559
|
+
yield expect(utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000 }, fixtures_1.mockReporter)).rejects.toThrowError('Failed to poll results: Poll results server error');
|
|
560
|
+
expect(pollResultsMock).toHaveBeenCalledWith([result.resultId]);
|
|
561
|
+
}));
|
|
562
|
+
test('getBatch throws', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
563
|
+
const { getBatchMock } = mockApi({
|
|
564
|
+
getBatchImplementation: () => {
|
|
565
|
+
throw new Error('Get batch server error');
|
|
566
|
+
},
|
|
567
|
+
});
|
|
568
|
+
yield expect(utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000 }, fixtures_1.mockReporter)).rejects.toThrowError('Failed to get batch: Get batch server error');
|
|
569
|
+
expect(getBatchMock).toHaveBeenCalledWith(trigger.batch_id);
|
|
645
570
|
}));
|
|
646
571
|
});
|
|
647
572
|
test('getStrictestExecutionRule', () => {
|
|
@@ -699,5 +624,144 @@ describe('utils', () => {
|
|
|
699
624
|
expect(utils.parseVariablesFromCli([''], mockLogFunction)).toBeUndefined();
|
|
700
625
|
expect(utils.parseVariablesFromCli(undefined, mockLogFunction)).toBeUndefined();
|
|
701
626
|
});
|
|
627
|
+
test('getAppBaseURL', () => {
|
|
628
|
+
expect(utils.getAppBaseURL({ datadogSite: 'datadoghq.eu', subdomain: 'custom' })).toBe('https://custom.datadoghq.eu/');
|
|
629
|
+
});
|
|
630
|
+
describe('sortResultsByOutcome', () => {
|
|
631
|
+
const results = fixtures_1.getResults([
|
|
632
|
+
{ executionRule: interfaces_1.ExecutionRule.NON_BLOCKING, passed: false },
|
|
633
|
+
{ executionRule: interfaces_1.ExecutionRule.BLOCKING, passed: true },
|
|
634
|
+
{ executionRule: interfaces_1.ExecutionRule.BLOCKING, passed: false },
|
|
635
|
+
{ executionRule: interfaces_1.ExecutionRule.NON_BLOCKING, passed: true },
|
|
636
|
+
]);
|
|
637
|
+
test('should sort tests with success, non_blocking failures then failures', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
638
|
+
const sortedResults = [...results];
|
|
639
|
+
sortedResults.sort(utils.sortResultsByOutcome());
|
|
640
|
+
expect(sortedResults.map((r) => r.resultId)).toStrictEqual(['3', '1', '0', '2']);
|
|
641
|
+
}));
|
|
642
|
+
});
|
|
643
|
+
describe('Render results', () => {
|
|
644
|
+
const emptySummary = utils.createSummary();
|
|
645
|
+
const cases = [
|
|
646
|
+
{
|
|
647
|
+
description: '1 API test with 1 config override, 1 result (passed)',
|
|
648
|
+
expected: {
|
|
649
|
+
exitCode: 0,
|
|
650
|
+
summary: Object.assign(Object.assign({}, emptySummary), { passed: 1 }),
|
|
651
|
+
},
|
|
652
|
+
failOnCriticalErrors: false,
|
|
653
|
+
failOnTimeout: false,
|
|
654
|
+
results: fixtures_1.getResults([{ passed: true }]),
|
|
655
|
+
summary: Object.assign({}, emptySummary),
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
description: '1 API test with 1 config override, 1 result (failed timeout), no fail on timeout, no fail on critical errors',
|
|
659
|
+
expected: {
|
|
660
|
+
exitCode: 0,
|
|
661
|
+
summary: Object.assign(Object.assign({}, emptySummary), { passed: 1, timedOut: 1 }),
|
|
662
|
+
},
|
|
663
|
+
failOnCriticalErrors: false,
|
|
664
|
+
failOnTimeout: false,
|
|
665
|
+
results: fixtures_1.getResults([{ timedOut: true }]),
|
|
666
|
+
summary: Object.assign({}, emptySummary),
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
description: '1 API test with 1 config override, 1 result (failed timeout), fail on timeout, no fail on critical errors',
|
|
670
|
+
expected: {
|
|
671
|
+
exitCode: 1,
|
|
672
|
+
summary: Object.assign(Object.assign({}, emptySummary), { failed: 1 }),
|
|
673
|
+
},
|
|
674
|
+
failOnCriticalErrors: false,
|
|
675
|
+
failOnTimeout: true,
|
|
676
|
+
results: fixtures_1.getResults([{ timedOut: true }]),
|
|
677
|
+
summary: Object.assign({}, emptySummary),
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
description: '1 API test with 1 config override, 1 result (failed critical error), no fail on timeout, no fail on critical errors',
|
|
681
|
+
expected: {
|
|
682
|
+
exitCode: 0,
|
|
683
|
+
summary: Object.assign(Object.assign({}, emptySummary), { passed: 1, criticalErrors: 1 }),
|
|
684
|
+
},
|
|
685
|
+
failOnCriticalErrors: false,
|
|
686
|
+
failOnTimeout: false,
|
|
687
|
+
results: fixtures_1.getResults([{ unhealthy: true }]),
|
|
688
|
+
summary: Object.assign({}, emptySummary),
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
description: '1 API test with 1 config override, 1 result (failed critical error), no fail on timeout, fail on critical errors',
|
|
692
|
+
expected: {
|
|
693
|
+
exitCode: 1,
|
|
694
|
+
summary: Object.assign(Object.assign({}, emptySummary), { criticalErrors: 0, failed: 1 }),
|
|
695
|
+
},
|
|
696
|
+
failOnCriticalErrors: true,
|
|
697
|
+
failOnTimeout: false,
|
|
698
|
+
results: fixtures_1.getResults([{ unhealthy: true }]),
|
|
699
|
+
summary: Object.assign({}, emptySummary),
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
description: '1 API test (blocking) with 4 config overrides (1 skipped), 3 results (1 passed, 1 failed, 1 failed non-blocking)',
|
|
703
|
+
expected: {
|
|
704
|
+
exitCode: 1,
|
|
705
|
+
summary: Object.assign(Object.assign({}, emptySummary), { failed: 1, failedNonBlocking: 1, passed: 1, skipped: 1 }),
|
|
706
|
+
},
|
|
707
|
+
failOnCriticalErrors: false,
|
|
708
|
+
failOnTimeout: false,
|
|
709
|
+
results: fixtures_1.getResults([{ passed: true }, { executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }, {}]),
|
|
710
|
+
summary: Object.assign(Object.assign({}, emptySummary), { skipped: 1 }),
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
description: '1 API test (non-blocking) with 4 config overrides (1 skipped), 3 results (1 passed, 1 failed, 1 failed non-blocking)',
|
|
714
|
+
expected: {
|
|
715
|
+
exitCode: 0,
|
|
716
|
+
summary: Object.assign(Object.assign({}, emptySummary), { failedNonBlocking: 2, passed: 1, skipped: 1 }),
|
|
717
|
+
},
|
|
718
|
+
failOnCriticalErrors: false,
|
|
719
|
+
failOnTimeout: false,
|
|
720
|
+
results: fixtures_1.getResults([
|
|
721
|
+
{
|
|
722
|
+
executionRule: interfaces_1.ExecutionRule.NON_BLOCKING,
|
|
723
|
+
testExecutionRule: interfaces_1.ExecutionRule.NON_BLOCKING,
|
|
724
|
+
},
|
|
725
|
+
{ passed: true, testExecutionRule: interfaces_1.ExecutionRule.NON_BLOCKING },
|
|
726
|
+
{
|
|
727
|
+
testExecutionRule: interfaces_1.ExecutionRule.NON_BLOCKING,
|
|
728
|
+
},
|
|
729
|
+
]),
|
|
730
|
+
summary: Object.assign(Object.assign({}, emptySummary), { skipped: 1 }),
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
description: '3 API tests (blocking) with 1 config override each, 3 results (1 failed non-blocking, 1 failed, 1 passed)',
|
|
734
|
+
expected: {
|
|
735
|
+
exitCode: 1,
|
|
736
|
+
summary: Object.assign(Object.assign({}, emptySummary), { failed: 1, failedNonBlocking: 1, passed: 1 }),
|
|
737
|
+
},
|
|
738
|
+
failOnCriticalErrors: false,
|
|
739
|
+
failOnTimeout: false,
|
|
740
|
+
results: fixtures_1.getResults([{}, { passed: true }, { executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }]),
|
|
741
|
+
summary: Object.assign({}, emptySummary),
|
|
742
|
+
},
|
|
743
|
+
];
|
|
744
|
+
test.each(cases)('$description', (testCase) => __awaiter(void 0, void 0, void 0, function* () {
|
|
745
|
+
testCase.results.forEach((result) => (result.passed = utils.hasResultPassed(result.result, result.timedOut, testCase.failOnCriticalErrors, testCase.failOnTimeout)));
|
|
746
|
+
const config = Object.assign(Object.assign({}, command_1.DEFAULT_COMMAND_CONFIG), { failOnCriticalErrors: testCase.failOnCriticalErrors, failOnTimeout: testCase.failOnTimeout });
|
|
747
|
+
const startTime = Date.now();
|
|
748
|
+
const exitCode = utils.renderResults({
|
|
749
|
+
config,
|
|
750
|
+
reporter: fixtures_1.mockReporter,
|
|
751
|
+
results: testCase.results,
|
|
752
|
+
startTime,
|
|
753
|
+
summary: testCase.summary,
|
|
754
|
+
});
|
|
755
|
+
expect(fixtures_1.mockReporter.reportStart).toHaveBeenCalledWith({ startTime });
|
|
756
|
+
expect(fixtures_1.mockReporter.resultEnd).toHaveBeenCalledTimes(testCase.results.length);
|
|
757
|
+
const baseUrl = `https://${command_1.DEFAULT_COMMAND_CONFIG.subdomain}.${command_1.DEFAULT_COMMAND_CONFIG.datadogSite}/`;
|
|
758
|
+
for (const result of testCase.results) {
|
|
759
|
+
expect(fixtures_1.mockReporter.resultEnd).toHaveBeenCalledWith(result, baseUrl);
|
|
760
|
+
}
|
|
761
|
+
expect(testCase.summary).toEqual(testCase.expected.summary);
|
|
762
|
+
expect(fixtures_1.mockReporter.runEnd).toHaveBeenCalledWith(testCase.expected.summary, baseUrl);
|
|
763
|
+
expect(exitCode).toBe(testCase.expected.exitCode);
|
|
764
|
+
}));
|
|
765
|
+
});
|
|
702
766
|
});
|
|
703
767
|
//# sourceMappingURL=utils.test.js.map
|