@datadog/datadog-ci 1.6.0 → 1.7.2-alpha

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 (58) hide show
  1. package/README.md +30 -0
  2. package/dist/commands/dsyms/interfaces.d.ts +1 -0
  3. package/dist/commands/dsyms/interfaces.js +15 -4
  4. package/dist/commands/dsyms/interfaces.js.map +1 -1
  5. package/dist/commands/git-metadata/interfaces.d.ts +1 -0
  6. package/dist/commands/git-metadata/interfaces.js +15 -4
  7. package/dist/commands/git-metadata/interfaces.js.map +1 -1
  8. package/dist/commands/lambda/__tests__/functions/commons.test.js +8 -0
  9. package/dist/commands/lambda/__tests__/functions/commons.test.js.map +1 -1
  10. package/dist/commands/lambda/__tests__/instrument.test.js +22 -0
  11. package/dist/commands/lambda/__tests__/instrument.test.js.map +1 -1
  12. package/dist/commands/lambda/constants.d.ts +2 -0
  13. package/dist/commands/lambda/constants.js +2 -0
  14. package/dist/commands/lambda/constants.js.map +1 -1
  15. package/dist/commands/lambda/functions/commons.d.ts +2 -2
  16. package/dist/commands/sourcemaps/interfaces.d.ts +1 -0
  17. package/dist/commands/sourcemaps/interfaces.js +32 -20
  18. package/dist/commands/sourcemaps/interfaces.js.map +1 -1
  19. package/dist/commands/synthetics/__tests__/api.test.js +5 -16
  20. package/dist/commands/synthetics/__tests__/api.test.js.map +1 -1
  21. package/dist/commands/synthetics/__tests__/cli.test.js +137 -39
  22. package/dist/commands/synthetics/__tests__/cli.test.js.map +1 -1
  23. package/dist/commands/synthetics/__tests__/fixtures.d.ts +34 -45
  24. package/dist/commands/synthetics/__tests__/fixtures.js +108 -42
  25. package/dist/commands/synthetics/__tests__/fixtures.js.map +1 -1
  26. package/dist/commands/synthetics/__tests__/reporters/default.test.js +148 -3
  27. package/dist/commands/synthetics/__tests__/reporters/default.test.js.map +1 -1
  28. package/dist/commands/synthetics/__tests__/reporters/junit.test.js +16 -16
  29. package/dist/commands/synthetics/__tests__/reporters/junit.test.js.map +1 -1
  30. package/dist/commands/synthetics/__tests__/run-test.test.js +40 -23
  31. package/dist/commands/synthetics/__tests__/run-test.test.js.map +1 -1
  32. package/dist/commands/synthetics/__tests__/utils.test.js +150 -245
  33. package/dist/commands/synthetics/__tests__/utils.test.js.map +1 -1
  34. package/dist/commands/synthetics/api.d.ts +12 -2
  35. package/dist/commands/synthetics/api.js +13 -3
  36. package/dist/commands/synthetics/api.js.map +1 -1
  37. package/dist/commands/synthetics/command.d.ts +7 -1
  38. package/dist/commands/synthetics/command.js +41 -56
  39. package/dist/commands/synthetics/command.js.map +1 -1
  40. package/dist/commands/synthetics/errors.d.ts +3 -3
  41. package/dist/commands/synthetics/errors.js +5 -5
  42. package/dist/commands/synthetics/errors.js.map +1 -1
  43. package/dist/commands/synthetics/interfaces.d.ts +49 -47
  44. package/dist/commands/synthetics/interfaces.js +1 -7
  45. package/dist/commands/synthetics/interfaces.js.map +1 -1
  46. package/dist/commands/synthetics/reporters/default.d.ts +5 -5
  47. package/dist/commands/synthetics/reporters/default.js +89 -76
  48. package/dist/commands/synthetics/reporters/default.js.map +1 -1
  49. package/dist/commands/synthetics/reporters/junit.d.ts +2 -3
  50. package/dist/commands/synthetics/reporters/junit.js +48 -56
  51. package/dist/commands/synthetics/reporters/junit.js.map +1 -1
  52. package/dist/commands/synthetics/run-test.d.ts +14 -8
  53. package/dist/commands/synthetics/run-test.js +23 -18
  54. package/dist/commands/synthetics/run-test.js.map +1 -1
  55. package/dist/commands/synthetics/utils.d.ts +18 -14
  56. package/dist/commands/synthetics/utils.js +93 -99
  57. package/dist/commands/synthetics/utils.js.map +1 -1
  58. package/package.json +4 -3
@@ -43,6 +43,9 @@ const errors_1 = require("../errors");
43
43
  const interfaces_1 = require("../interfaces");
44
44
  const utils = __importStar(require("../utils"));
45
45
  const fixtures_1 = require("./fixtures");
46
+ beforeEach(() => {
47
+ jest.restoreAllMocks();
48
+ });
46
49
  describe('utils', () => {
47
50
  const apiConfiguration = {
48
51
  apiKey: '123',
@@ -69,19 +72,11 @@ describe('utils', () => {
69
72
  describe('runTest', () => {
70
73
  const fakeId = '123-456-789';
71
74
  const fakeTrigger = {
72
- results: [],
73
- triggered_check_ids: [fakeId],
75
+ batch_id: 'bid',
76
+ locations: [],
74
77
  };
75
- afterAll(() => {
76
- jest.clearAllMocks();
77
- });
78
78
  test('should run test', () => __awaiter(void 0, void 0, void 0, function* () {
79
- const axiosMock = jest.spyOn(axios_1.default, 'create');
80
- axiosMock.mockImplementation((() => (e) => {
81
- if (e.url === '/synthetics/tests/trigger/ci') {
82
- return { data: fakeTrigger };
83
- }
84
- }));
79
+ jest.spyOn(api, 'triggerTests').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return fakeTrigger; }));
85
80
  const output = yield utils.runTests(api, [{ public_id: fakeId, executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }]);
86
81
  expect(output).toEqual(fakeTrigger);
87
82
  }));
@@ -120,12 +115,7 @@ describe('utils', () => {
120
115
  expect(headersMetadataSpy).toHaveBeenCalledWith(expect.objectContaining({ 'X-Trigger-App': 'unit_test' }));
121
116
  }));
122
117
  test('should run test with publicId from url', () => __awaiter(void 0, void 0, void 0, function* () {
123
- const axiosMock = jest.spyOn(axios_1.default, 'create');
124
- axiosMock.mockImplementation((() => (e) => {
125
- if (e.url === '/synthetics/tests/trigger/ci') {
126
- return { data: fakeTrigger };
127
- }
128
- }));
118
+ jest.spyOn(api, 'triggerTests').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return fakeTrigger; }));
129
119
  const output = yield utils.runTests(api, [
130
120
  {
131
121
  executionRule: interfaces_1.ExecutionRule.NON_BLOCKING,
@@ -143,11 +133,9 @@ describe('utils', () => {
143
133
  status: 502,
144
134
  },
145
135
  });
146
- const requestMock = jest.fn();
147
- requestMock.mockImplementation(() => {
136
+ jest.spyOn(api, 'triggerTests').mockImplementation(() => {
148
137
  throw serverError;
149
138
  });
150
- jest.spyOn(axios_1.default, 'create').mockImplementation((() => requestMock));
151
139
  yield expect(utils.runTests(api, [{ public_id: fakeId, executionRule: interfaces_1.ExecutionRule.NON_BLOCKING }])).rejects.toThrow(/Failed to trigger tests:/);
152
140
  }));
153
141
  });
@@ -167,7 +155,7 @@ describe('utils', () => {
167
155
  suite: 'Suite 3',
168
156
  },
169
157
  };
170
- beforeAll(() => {
158
+ beforeEach(() => {
171
159
  const axiosMock = jest.spyOn(axios_1.default, 'create');
172
160
  axiosMock.mockImplementation((() => (e) => {
173
161
  const publicId = e.url.slice(18);
@@ -179,9 +167,6 @@ describe('utils', () => {
179
167
  throw error;
180
168
  }));
181
169
  });
182
- afterAll(() => {
183
- jest.clearAllMocks();
184
- });
185
170
  test('only existing tests are returned', () => __awaiter(void 0, void 0, void 0, function* () {
186
171
  const triggerConfigs = [
187
172
  { suite: 'Suite 1', config: {}, id: '123-456-789' },
@@ -197,6 +182,7 @@ describe('utils', () => {
197
182
  const expectedSummary = {
198
183
  criticalErrors: 0,
199
184
  failed: 0,
185
+ failedNonBlocking: 0,
200
186
  passed: 0,
201
187
  skipped: 1,
202
188
  testsNotFound: new Set(['987-654-321']),
@@ -343,284 +329,203 @@ describe('utils', () => {
343
329
  const result = {
344
330
  device: { height: 0, id: 'laptop_large', width: 0 },
345
331
  duration: 0,
346
- eventType: 'finished',
347
332
  passed: true,
348
333
  startUrl: '',
349
334
  stepDetails: [],
350
335
  };
351
- expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
352
- expect(utils.hasResultPassed(result, true, true)).toBeTruthy();
336
+ expect(utils.hasResultPassed(result, false, false, true)).toBeTruthy();
337
+ expect(utils.hasResultPassed(result, false, true, true)).toBeTruthy();
353
338
  result.passed = false;
354
- expect(utils.hasResultPassed(result, false, true)).toBeFalsy();
355
- expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
339
+ expect(utils.hasResultPassed(result, false, false, true)).toBeFalsy();
340
+ expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
356
341
  });
357
342
  test('result with error', () => {
358
343
  const result = {
359
344
  device: { height: 0, id: 'laptop_large', width: 0 },
360
345
  duration: 0,
361
346
  errorCode: 'ERRABORTED',
362
- eventType: 'finished',
363
347
  passed: false,
364
348
  startUrl: '',
365
349
  stepDetails: [],
366
350
  };
367
- expect(utils.hasResultPassed(result, false, true)).toBeFalsy();
368
- expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
351
+ expect(utils.hasResultPassed(result, false, false, true)).toBeFalsy();
352
+ expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
369
353
  });
370
354
  test('result with unhealthy result', () => {
371
355
  const result = {
372
356
  device: { height: 0, id: 'laptop_large', width: 0 },
373
357
  duration: 0,
374
358
  errorCode: 'ERRABORTED',
375
- eventType: 'finished',
376
359
  passed: false,
377
360
  startUrl: '',
378
361
  stepDetails: [],
379
362
  unhealthy: true,
380
363
  };
381
- expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
382
- expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
364
+ expect(utils.hasResultPassed(result, false, false, true)).toBeTruthy();
365
+ expect(utils.hasResultPassed(result, false, true, true)).toBeFalsy();
383
366
  });
384
367
  test('result with timeout result', () => {
385
368
  const result = {
386
369
  device: { height: 0, id: 'laptop_large', width: 0 },
387
370
  duration: 0,
388
- error: interfaces_1.ERRORS.TIMEOUT,
389
- eventType: 'finished',
390
371
  passed: false,
391
372
  startUrl: '',
392
373
  stepDetails: [],
393
374
  };
394
- expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
395
- expect(utils.hasResultPassed(result, true, false)).toBeTruthy();
375
+ expect(utils.hasResultPassed(result, true, true, true)).toBeFalsy();
376
+ expect(utils.hasResultPassed(result, true, true, false)).toBeTruthy();
396
377
  });
397
378
  });
398
- test('result with endpoint failure result', () => {
399
- const result = {
400
- device: { height: 0, id: 'laptop_large', width: 0 },
401
- duration: 0,
402
- error: interfaces_1.ERRORS.ENDPOINT,
403
- eventType: 'finished',
404
- passed: false,
405
- startUrl: '',
406
- stepDetails: [],
407
- };
408
- expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
409
- expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
379
+ describe('getExecutionRule', () => {
380
+ const cases = [
381
+ [undefined, undefined, interfaces_1.ExecutionRule.BLOCKING],
382
+ [undefined, interfaces_1.ExecutionRule.BLOCKING, interfaces_1.ExecutionRule.BLOCKING],
383
+ [undefined, interfaces_1.ExecutionRule.NON_BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING],
384
+ [interfaces_1.ExecutionRule.BLOCKING, undefined, interfaces_1.ExecutionRule.BLOCKING],
385
+ [interfaces_1.ExecutionRule.BLOCKING, interfaces_1.ExecutionRule.BLOCKING, interfaces_1.ExecutionRule.BLOCKING],
386
+ [interfaces_1.ExecutionRule.BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING],
387
+ [interfaces_1.ExecutionRule.NON_BLOCKING, undefined, interfaces_1.ExecutionRule.NON_BLOCKING],
388
+ [interfaces_1.ExecutionRule.NON_BLOCKING, interfaces_1.ExecutionRule.BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING],
389
+ [interfaces_1.ExecutionRule.NON_BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING, interfaces_1.ExecutionRule.NON_BLOCKING],
390
+ ];
391
+ test.each(cases)('Test execution rule: %s, result execution rule: %s. Expected rule: %s', (testRule, resultRule, expectedRule) => {
392
+ const test = fixtures_1.getApiTest('abc-def-ghi');
393
+ expect(utils.getExecutionRule(testRule ? Object.assign(Object.assign({}, test), { options: Object.assign(Object.assign({}, test.options), { ci: { executionRule: testRule } }) }) : test, resultRule ? { executionRule: resultRule } : {})).toEqual(expectedRule);
394
+ });
410
395
  });
411
- test('hasTestSucceeded', () => {
412
- const testConfiguration = fixtures_1.getApiTest('abc-def-ghi');
413
- const passingResult = fixtures_1.getBrowserResult();
414
- const passingPollResult = {
415
- check: testConfiguration,
416
- dc_id: 42,
417
- result: passingResult,
418
- resultID: '0123456789',
419
- timestamp: 0,
420
- };
421
- const failingPollResult = {
422
- check: testConfiguration,
423
- dc_id: 42,
424
- result: Object.assign(Object.assign({}, passingResult), { passed: false }),
425
- resultID: '0123456789',
426
- timestamp: 0,
427
- };
428
- const unhealthyPollResult = {
429
- check: testConfiguration,
430
- dc_id: 42,
431
- result: Object.assign(Object.assign({}, passingResult), { passed: false, unhealthy: true }),
432
- resultID: '0123456789',
433
- timestamp: 0,
434
- };
435
- const endpointFailurePollResult = {
436
- check: testConfiguration,
437
- dc_id: 42,
438
- result: Object.assign(Object.assign({}, passingResult), { passed: false, error: interfaces_1.ERRORS.ENDPOINT }),
439
- resultID: '0123456789',
440
- timestamp: 0,
441
- };
442
- const timeoutPollResult = {
443
- check: testConfiguration,
444
- dc_id: 42,
445
- result: Object.assign(Object.assign({}, passingResult), { passed: false, error: interfaces_1.ERRORS.TIMEOUT }),
446
- resultID: '0123456789',
447
- timestamp: 0,
448
- };
449
- expect(utils.hasTestSucceeded([passingPollResult, failingPollResult], false, true)).toBeFalsy();
450
- expect(utils.hasTestSucceeded([passingPollResult, unhealthyPollResult], true, true)).toBeFalsy();
451
- expect(utils.hasTestSucceeded([passingPollResult, unhealthyPollResult], false, true)).toBeTruthy();
452
- expect(utils.hasTestSucceeded([passingPollResult, endpointFailurePollResult], true, true)).toBeFalsy();
453
- expect(utils.hasTestSucceeded([passingPollResult, endpointFailurePollResult], false, true)).toBeTruthy();
454
- expect(utils.hasTestSucceeded([passingPollResult, passingPollResult], false, true)).toBeTruthy();
455
- expect(utils.hasTestSucceeded([passingPollResult, timeoutPollResult], false, true)).toBeFalsy();
456
- expect(utils.hasTestSucceeded([passingPollResult, timeoutPollResult], false, false)).toBeTruthy();
396
+ describe('getResultOutcome', () => {
397
+ const cases = [
398
+ [true, interfaces_1.ExecutionRule.BLOCKING, "passed" /* Passed */],
399
+ [true, interfaces_1.ExecutionRule.NON_BLOCKING, "passed-non-blocking" /* PassedNonBlocking */],
400
+ [false, interfaces_1.ExecutionRule.BLOCKING, "failed" /* Failed */],
401
+ [false, interfaces_1.ExecutionRule.NON_BLOCKING, "failed-non-blocking" /* FailedNonBlocking */],
402
+ ];
403
+ test.each(cases)('Result passed: %s, execution rule: %s. Expected outcome: %s', (resultPassed, resultRule, expectedOutcome) => {
404
+ jest.spyOn(utils, 'getExecutionRule').mockReturnValue(resultRule);
405
+ const test = fixtures_1.getApiTest('abc-def-ghi');
406
+ const result = fixtures_1.getApiResult('1', test);
407
+ result.executionRule = resultRule;
408
+ result.passed = resultPassed;
409
+ expect(utils.getResultOutcome(result)).toEqual(expectedOutcome);
410
+ });
457
411
  });
458
412
  describe('waitForResults', () => {
459
- const mockAxiosWithDefaultResult = () => {
460
- jest.spyOn(axios_1.default, 'create').mockImplementation((() => (r) => __awaiter(void 0, void 0, void 0, function* () {
461
- yield utils.wait(100);
462
- const results = JSON.parse(r.params.result_ids)
463
- .filter((resultId) => resultId !== 'timingOutTest')
464
- .map((resultId) => getPassingPollResult(resultId));
465
- return { data: { results } };
466
- })));
467
- };
468
- afterAll(() => {
469
- jest.clearAllMocks();
413
+ beforeAll(() => {
414
+ // We still wait a few milliseconds to avoid the test going crazy on a infinite loop
415
+ // if case of mistakes in the code or test.
416
+ jest.spyOn(utils, 'wait').mockImplementation(() => new Promise((r) => setTimeout(r, 10)));
470
417
  });
471
- const getTestConfig = (publicId = 'abc-def-ghi') => fixtures_1.getApiTest(publicId);
472
- const getPassingPollResult = (resultId) => ({
473
- check: getTestConfig(),
474
- dc_id: 42,
475
- result: fixtures_1.getBrowserResult({ error: interfaces_1.ERRORS.TIMEOUT, passed: false }),
476
- resultID: resultId,
418
+ const batch = fixtures_1.getBatch();
419
+ const apiTest = fixtures_1.getApiTest(batch.results[0].test_public_id);
420
+ const result = {
421
+ executionRule: interfaces_1.ExecutionRule.BLOCKING,
422
+ location: fixtures_1.mockLocation.display_name,
423
+ passed: true,
424
+ result: fixtures_1.getBrowserServerResult({ passed: true }),
425
+ resultId: batch.results[0].result_id,
426
+ test: apiTest,
427
+ timedOut: false,
477
428
  timestamp: 0,
478
- });
479
- const getTestAndResult = (publicId = 'abc-def-ghi', resultId = '0123456789') => {
480
- const triggerResult = {
481
- device: 'laptop_large',
482
- location: 42,
483
- public_id: publicId,
484
- result_id: resultId,
485
- };
486
- const triggerConfig = {
487
- config: {},
488
- id: publicId,
489
- suite: 'Suite 1',
490
- };
491
- const passingPollResult = getPassingPollResult(resultId);
492
- return { passingPollResult, triggerConfig, triggerResult };
429
+ };
430
+ const pollResult = {
431
+ check: result.test,
432
+ result: result.result,
433
+ resultID: result.resultId,
434
+ timestamp: result.timestamp,
435
+ };
436
+ const trigger = { batch_id: 'bid', locations: [fixtures_1.mockLocation] };
437
+ const mockApi = ({ getBatchImplementation, pollResultsImplementation, } = {}) => {
438
+ const getBatchMock = jest
439
+ .spyOn(api, 'getBatch')
440
+ .mockImplementation(getBatchImplementation || (() => __awaiter(void 0, void 0, void 0, function* () { return JSON.parse(JSON.stringify(batch)); })));
441
+ const pollResultsMock = jest
442
+ .spyOn(api, 'pollResults')
443
+ .mockImplementation(pollResultsImplementation || (() => __awaiter(void 0, void 0, void 0, function* () { return JSON.parse(JSON.stringify([pollResult])); })));
444
+ return { getBatchMock, pollResultsMock };
493
445
  };
494
446
  test('should poll result ids', () => __awaiter(void 0, void 0, void 0, function* () {
495
- mockAxiosWithDefaultResult();
496
- const { triggerResult, passingPollResult, triggerConfig } = getTestAndResult();
497
- const waitMock = jest.spyOn(utils, 'wait');
498
- waitMock.mockImplementation();
499
- const expectedResults = {};
500
- expectedResults[triggerResult.public_id] = [passingPollResult];
501
- expect(yield utils.waitForResults(api, [triggerResult], [triggerConfig], { defaultTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
502
- expect(fixtures_1.mockReporter.testResult).toHaveBeenCalledWith(triggerResult, passingPollResult);
447
+ mockApi();
448
+ expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([result]);
449
+ expect(fixtures_1.mockReporter.resultReceived).toHaveBeenCalledWith(batch.results[0]);
503
450
  }));
504
- test('results should be timed-out if global pollingTimeout is exceeded', () => __awaiter(void 0, void 0, void 0, function* () {
505
- const { triggerResult } = getTestAndResult();
506
- const expectedResults = {};
507
- expectedResults[triggerResult.public_id] = [
508
- {
509
- dc_id: triggerResult.location,
510
- result: fixtures_1.getBrowserResult({
511
- device: { height: 0, id: triggerResult.device, width: 0 },
512
- error: interfaces_1.ERRORS.TIMEOUT,
513
- passed: false,
514
- }),
515
- resultID: triggerResult.result_id,
516
- timestamp: 0,
517
- },
518
- ];
519
- expect(yield utils.waitForResults(api, [triggerResult], [], { defaultTimeout: 0, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
451
+ test('results should be timed out if global pollingTimeout is exceeded', () => __awaiter(void 0, void 0, void 0, function* () {
452
+ mockApi({ getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, batch), { status: 'in_progress' })); }) });
453
+ expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 0, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([
454
+ Object.assign(Object.assign({}, result), { result: Object.assign(Object.assign({}, result.result), { error: 'Timeout', passed: false }), timedOut: true }),
455
+ ]);
520
456
  }));
521
- test('results should be timeout-ed if test pollingTimeout is exceeded', () => __awaiter(void 0, void 0, void 0, function* () {
522
- const { triggerResult } = getTestAndResult();
523
- const expectedResults = {};
524
- expectedResults[triggerResult.public_id] = [
525
- {
526
- dc_id: triggerResult.location,
527
- result: fixtures_1.getBrowserResult({
528
- device: { height: 0, id: triggerResult.device, width: 0 },
529
- error: interfaces_1.ERRORS.TIMEOUT,
530
- passed: false,
531
- }),
532
- resultID: triggerResult.result_id,
533
- timestamp: 0,
534
- },
535
- ];
536
- const testTriggerConfig = {
537
- config: { pollingTimeout: 0 },
538
- id: triggerResult.public_id,
539
- suite: 'Suite 1',
540
- };
541
- expect(yield utils.waitForResults(api, [triggerResult], [testTriggerConfig], { defaultTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
457
+ test('results should be timed out if batch result is timed out', () => __awaiter(void 0, void 0, void 0, function* () {
458
+ const batchWithTimeoutResult = Object.assign(Object.assign({}, batch), { results: [Object.assign(Object.assign({}, batch.results[0]), { timed_out: true })] });
459
+ mockApi({ getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return batchWithTimeoutResult; }) });
460
+ expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([
461
+ Object.assign(Object.assign({}, result), { result: Object.assign(Object.assign({}, result.result), { error: 'Timeout', passed: false }), timedOut: true }),
462
+ ]);
463
+ }));
464
+ test('wait between batch polling', () => __awaiter(void 0, void 0, void 0, function* () {
465
+ jest.restoreAllMocks();
466
+ const waitMock = jest.spyOn(utils, 'wait').mockImplementation(() => new Promise((r) => setTimeout(r, 10)));
467
+ let counter = 0;
468
+ mockApi({
469
+ getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () {
470
+ counter += 1;
471
+ return counter === 3 ? batch : Object.assign(Object.assign({}, batch), { status: 'in_progress' });
472
+ }),
473
+ });
474
+ expect(yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 120000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual([result]);
475
+ expect(counter).toBe(3);
476
+ expect(waitMock).toHaveBeenCalledTimes(2);
542
477
  }));
543
478
  test('correct number of pass and timeout results', () => __awaiter(void 0, void 0, void 0, function* () {
544
- mockAxiosWithDefaultResult();
545
- const { triggerResult, passingPollResult } = getTestAndResult();
546
- const waitMock = jest.spyOn(utils, 'wait');
547
- waitMock.mockImplementation();
548
- const expectedResults = {};
549
- const triggerResultPass = triggerResult;
550
- const triggerResultTimeOut = Object.assign(Object.assign({}, triggerResult), { result_id: 'timingOutTest' });
551
- expectedResults[triggerResult.public_id] = [
552
- passingPollResult,
553
- {
554
- dc_id: triggerResultTimeOut.location,
555
- result: fixtures_1.getBrowserResult({
556
- device: { height: 0, id: triggerResultTimeOut.device, width: 0 },
557
- error: interfaces_1.ERRORS.TIMEOUT,
558
- passed: false,
559
- }),
560
- resultID: triggerResultTimeOut.result_id,
561
- timestamp: 0,
562
- },
563
- ];
564
- expect(yield utils.waitForResults(api, [triggerResultPass, triggerResultTimeOut], [], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter)).toEqual(expectedResults);
479
+ const pollTimeoutResult = Object.assign(Object.assign({}, pollResult), { resultID: 'another-id' });
480
+ 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 })] });
481
+ mockApi({
482
+ getBatchImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return batchWithTimeoutResult; }),
483
+ pollResultsImplementation: () => __awaiter(void 0, void 0, void 0, function* () { return [pollResult, pollTimeoutResult]; }),
484
+ });
485
+ 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 })]);
565
486
  }));
566
487
  test('tunnel failure', () => __awaiter(void 0, void 0, void 0, function* () {
567
- const waitMock = jest.spyOn(utils, 'wait');
568
- waitMock.mockImplementation();
569
- const { triggerResult } = getTestAndResult();
570
- // Fake pollResults to not update results and iterate until the isTunnelConnected is equal to false
571
- jest
572
- .spyOn(axios_1.default, 'create')
573
- .mockImplementation((() => (r) => __awaiter(void 0, void 0, void 0, function* () { return ({ data: { results: [] } }); })));
488
+ mockApi();
574
489
  const mockTunnel = {
575
490
  keepAlive: () => __awaiter(void 0, void 0, void 0, function* () {
576
491
  throw new Error('keepAlive failed');
577
492
  }),
578
493
  };
579
- const expectedResults = {
580
- [triggerResult.public_id]: [
581
- {
582
- dc_id: triggerResult.location,
583
- result: fixtures_1.getBrowserResult({
584
- device: { height: 0, id: triggerResult.device, width: 0 },
585
- error: interfaces_1.ERRORS.TUNNEL,
586
- passed: false,
587
- tunnel: true,
588
- }),
589
- resultID: triggerResult.result_id,
590
- timestamp: 0,
591
- },
592
- ],
593
- };
594
- expect(yield utils.waitForResults(api, [triggerResult], [], { defaultTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel)).toEqual(expectedResults);
595
- expect(yield utils.waitForResults(api, [triggerResult], [], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter, mockTunnel)).toEqual(expectedResults);
494
+ yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
495
+ expect(fixtures_1.mockReporter.error).toBeCalledWith('The tunnel has stopped working, this may have affected the results.');
496
+ }));
497
+ test('location when tunnel', () => __awaiter(void 0, void 0, void 0, function* () {
498
+ mockApi();
499
+ const mockTunnel = { keepAlive: () => __awaiter(void 0, void 0, void 0, function* () { return true; }) };
500
+ let results = yield utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
501
+ expect(results[0].location).toBe('Tunneled');
502
+ const newTest = Object.assign({}, result.test);
503
+ newTest.type = 'api';
504
+ newTest.subtype = 'http';
505
+ results = yield utils.waitForResults(api, trigger, [newTest], { maxPollingTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel);
506
+ expect(results[0].location).toBe('Tunneled');
507
+ newTest.type = 'api';
508
+ newTest.subtype = 'ssl';
509
+ results = yield utils.waitForResults(api, trigger, [newTest], { failOnCriticalErrors: true, maxPollingTimeout: 2000 }, fixtures_1.mockReporter, mockTunnel);
510
+ expect(results[0].location).toBe('Frankfurt (AWS)');
596
511
  }));
597
512
  test('pollResults throws', () => __awaiter(void 0, void 0, void 0, function* () {
598
- const { triggerResult } = getTestAndResult();
599
- jest.spyOn(utils, 'wait').mockImplementation();
600
- const axiosMock = jest.spyOn(axios_1.default, 'create');
601
- const serverError = new Error('Server Error');
602
- serverError.response = { status: 502 };
603
- axiosMock.mockImplementation((() => (r) => __awaiter(void 0, void 0, void 0, function* () {
604
- throw serverError;
605
- })));
606
- const mockTunnel = { keepAlive: () => __awaiter(void 0, void 0, void 0, function* () { return Promise.reject(); }) };
607
- const expectedResults = {
608
- [triggerResult.public_id]: [
609
- {
610
- dc_id: triggerResult.location,
611
- result: fixtures_1.getBrowserResult({
612
- device: { height: 0, id: triggerResult.device, width: 0 },
613
- error: interfaces_1.ERRORS.ENDPOINT,
614
- passed: false,
615
- tunnel: true,
616
- }),
617
- resultID: triggerResult.result_id,
618
- timestamp: 0,
619
- },
620
- ],
621
- };
622
- expect(yield utils.waitForResults(api, [triggerResult], [], { defaultTimeout: 2000, failOnCriticalErrors: false }, fixtures_1.mockReporter, mockTunnel)).toEqual(expectedResults);
623
- yield expect(utils.waitForResults(api, [triggerResult], [], { defaultTimeout: 2000, failOnCriticalErrors: true }, fixtures_1.mockReporter, mockTunnel)).rejects.toThrow();
513
+ const { pollResultsMock } = mockApi({
514
+ pollResultsImplementation: () => {
515
+ throw new Error('Poll results server error');
516
+ },
517
+ });
518
+ yield expect(utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000 }, fixtures_1.mockReporter)).rejects.toThrowError('Failed to poll results: Poll results server error');
519
+ expect(pollResultsMock).toHaveBeenCalledWith([result.resultId]);
520
+ }));
521
+ test('getBatch throws', () => __awaiter(void 0, void 0, void 0, function* () {
522
+ const { getBatchMock } = mockApi({
523
+ getBatchImplementation: () => {
524
+ throw new Error('Get batch server error');
525
+ },
526
+ });
527
+ yield expect(utils.waitForResults(api, trigger, [result.test], { maxPollingTimeout: 2000 }, fixtures_1.mockReporter)).rejects.toThrowError('Failed to get batch: Get batch server error');
528
+ expect(getBatchMock).toHaveBeenCalledWith(trigger.batch_id);
624
529
  }));
625
530
  });
626
531
  test('getStrictestExecutionRule', () => {