@testomatio/reporter 2.5.1 → 2.6.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/lib/adapter/playwright.d.ts +15 -2
- package/lib/adapter/playwright.js +108 -21
- package/lib/bin/cli.js +35 -7
- package/lib/pipe/coverage.js +63 -5
- package/lib/pipe/github.js +15 -0
- package/lib/pipe/testomatio.js +71 -35
- package/lib/reporter-functions.js +8 -0
- package/lib/services/links.d.ts +4 -2
- package/lib/services/links.js +1 -1
- package/package.json +1 -1
- package/src/adapter/playwright.js +119 -23
- package/src/bin/cli.js +37 -11
- package/src/pipe/coverage.js +90 -32
- package/src/pipe/github.js +14 -0
- package/src/pipe/testomatio.js +86 -52
- package/src/reporter-functions.js +8 -0
- package/src/services/links.js +1 -1
- package/types/types.d.ts +1 -1
package/src/pipe/testomatio.js
CHANGED
|
@@ -3,11 +3,12 @@ import pc from 'picocolors';
|
|
|
3
3
|
import { Gaxios } from 'gaxios';
|
|
4
4
|
import JsonCycle from 'json-cycle';
|
|
5
5
|
import { APP_PREFIX, STATUS, AXIOS_TIMEOUT, REPORTER_REQUEST_RETRIES } from '../constants.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import {
|
|
7
|
+
isValidUrl,
|
|
8
|
+
foundedTestLog,
|
|
9
|
+
readLatestRunId,
|
|
10
|
+
transformEnvVarToBoolean,
|
|
11
|
+
getGitCommitSha,
|
|
11
12
|
} from '../utils/utils.js';
|
|
12
13
|
import { parseFilterParams, generateFilterRequestParams, setS3Credentials } from '../utils/pipe_utils.js';
|
|
13
14
|
import { config } from '../config.js';
|
|
@@ -198,6 +199,9 @@ class TestomatioPipe {
|
|
|
198
199
|
if (!this.isEnabled) return;
|
|
199
200
|
if (this.batch.isEnabled && this.isEnabled)
|
|
200
201
|
this.batch.intervalFunction = setInterval(this.#batchUpload, this.batch.intervalTime);
|
|
202
|
+
if (this.store) {
|
|
203
|
+
this.store.runKind = params.kind;
|
|
204
|
+
}
|
|
201
205
|
|
|
202
206
|
let buildUrl = process.env.BUILD_URL || process.env.CI_JOB_URL || process.env.CIRCLE_BUILD_URL;
|
|
203
207
|
|
|
@@ -219,6 +223,16 @@ class TestomatioPipe {
|
|
|
219
223
|
|
|
220
224
|
const accessEvent = process.env.TESTOMATIO_PUBLISH ? 'publish' : null;
|
|
221
225
|
|
|
226
|
+
const coverageConfiguration = this.store?.coverageConfiguration;
|
|
227
|
+
let description = null;
|
|
228
|
+
let configuration = null;
|
|
229
|
+
if (coverageConfiguration && (coverageConfiguration.tests?.length || coverageConfiguration.suites?.length)) {
|
|
230
|
+
description = this.store?.coverageDescription || null;
|
|
231
|
+
configuration = {
|
|
232
|
+
tests: coverageConfiguration.tests?.map(id => id.replace(/^T/, '')) || [],
|
|
233
|
+
suites: coverageConfiguration.suites?.map(id => id.replace(/^S/, '')) || [],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
222
236
|
const runParams = Object.fromEntries(
|
|
223
237
|
Object.entries({
|
|
224
238
|
ci_build_url: buildUrl,
|
|
@@ -232,6 +246,8 @@ class TestomatioPipe {
|
|
|
232
246
|
shared_run: this.sharedRun,
|
|
233
247
|
shared_run_timeout: this.sharedRunTimeout,
|
|
234
248
|
kind: params.kind,
|
|
249
|
+
configuration,
|
|
250
|
+
description,
|
|
235
251
|
}).filter(([, value]) => !!value),
|
|
236
252
|
);
|
|
237
253
|
debug(' >>>>>> Run params', JSON.stringify(runParams, null, 2));
|
|
@@ -278,11 +294,13 @@ class TestomatioPipe {
|
|
|
278
294
|
if (!this.apiKey) console.error('Testomat.io API key is not set');
|
|
279
295
|
if (!this.apiKey?.startsWith('tstmt')) console.error('Testomat.io API key is invalid');
|
|
280
296
|
|
|
297
|
+
if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) this.#logFailedResponse(err);
|
|
298
|
+
|
|
281
299
|
console.error(
|
|
282
300
|
APP_PREFIX,
|
|
283
301
|
'Error creating Testomat.io report (see details above), please check if your API key is valid. Skipping report',
|
|
284
302
|
);
|
|
285
|
-
printCreateIssue(
|
|
303
|
+
printCreateIssue();
|
|
286
304
|
}
|
|
287
305
|
debug('"createRun" function finished');
|
|
288
306
|
}
|
|
@@ -329,24 +347,8 @@ class TestomatioPipe {
|
|
|
329
347
|
this.requestFailures++;
|
|
330
348
|
this.notReportedTestsCount++;
|
|
331
349
|
if (err.response) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
console.log(
|
|
335
|
-
APP_PREFIX,
|
|
336
|
-
pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
|
|
337
|
-
pc.gray(data?.title || ''),
|
|
338
|
-
);
|
|
339
|
-
if (err.response?.data?.message?.includes('could not be matched')) {
|
|
340
|
-
this.hasUnmatchedTests = true;
|
|
341
|
-
}
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
console.log(
|
|
345
|
-
APP_PREFIX,
|
|
346
|
-
pc.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
|
|
347
|
-
`Report couldn't be processed: ${err?.response?.data?.message}`,
|
|
348
|
-
);
|
|
349
|
-
printCreateIssue(err);
|
|
350
|
+
this.#logFailedResponse(err);
|
|
351
|
+
printCreateIssue();
|
|
350
352
|
} else {
|
|
351
353
|
console.log(APP_PREFIX, pc.blue(data?.title || ''), "Report couldn't be processed", err);
|
|
352
354
|
}
|
|
@@ -395,20 +397,8 @@ class TestomatioPipe {
|
|
|
395
397
|
this.requestFailures++;
|
|
396
398
|
this.notReportedTestsCount += testsToSend.length;
|
|
397
399
|
if (err.response) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
console.log(APP_PREFIX, pc.yellow(`Warning: ${responseData.message} (${err.response.status})`));
|
|
401
|
-
if (err.response?.data?.message?.includes('could not be matched')) {
|
|
402
|
-
this.hasUnmatchedTests = true;
|
|
403
|
-
}
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
console.log(
|
|
407
|
-
APP_PREFIX,
|
|
408
|
-
pc.yellow(`Warning: (${err.response?.status})`),
|
|
409
|
-
`Report couldn't be processed: ${err?.response?.data?.message}`,
|
|
410
|
-
);
|
|
411
|
-
printCreateIssue(err);
|
|
400
|
+
this.#logFailedResponse(err);
|
|
401
|
+
printCreateIssue();
|
|
412
402
|
} else {
|
|
413
403
|
console.log(APP_PREFIX, "Report couldn't be processed", err);
|
|
414
404
|
}
|
|
@@ -521,37 +511,81 @@ class TestomatioPipe {
|
|
|
521
511
|
}
|
|
522
512
|
} catch (err) {
|
|
523
513
|
console.log(APP_PREFIX, 'Error updating status, skipping...', err);
|
|
524
|
-
|
|
514
|
+
if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) this.#logFailedResponse(err);
|
|
515
|
+
printCreateIssue();
|
|
525
516
|
}
|
|
526
517
|
debug('Run finished');
|
|
527
518
|
}
|
|
528
519
|
|
|
520
|
+
#logFailedResponse(error) {
|
|
521
|
+
let responseBody = stringify(error.response?.data ?? error.response ?? error, { pretty: true });
|
|
522
|
+
if (!responseBody) responseBody = '<empty>';
|
|
523
|
+
responseBody = hideTestomatioToken(responseBody);
|
|
524
|
+
|
|
525
|
+
const statusCode = error.status || error.code || error.response?.status || '<unknown status code>';
|
|
526
|
+
const method = error.response?.config.method || '<unknown method>';
|
|
527
|
+
const url = error.response?.config.url || '<unknown url>';
|
|
528
|
+
|
|
529
|
+
let message = pc.yellow('\n⚠️ Request to Testomat.io failed:\n');
|
|
530
|
+
message += pc.bold(`${pc.red(statusCode)} ${method} ${url}\n`);
|
|
531
|
+
message += `\t${pc.bold('response: ')}${pc.gray(responseBody)}\n`;
|
|
532
|
+
|
|
533
|
+
const requestBody = hideTestomatioToken(stringify(error.response?.config?.data));
|
|
534
|
+
if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) {
|
|
535
|
+
message += `\t${pc.bold('request: ')}${pc.gray(requestBody)}\n`;
|
|
536
|
+
} else {
|
|
537
|
+
const requestBodyCut = requestBody.slice(0, 1000);
|
|
538
|
+
message += `\t${pc.bold('request: ')}${pc.gray(`${requestBodyCut}.....`)}\n`;
|
|
539
|
+
message += '\trequest body is cut, run with TESTOMATIO_DEBUG=1 to see full body\n';
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
console.log(message);
|
|
543
|
+
|
|
544
|
+
if (error.response?.data?.message?.includes('could not be matched')) {
|
|
545
|
+
this.hasUnmatchedTests = true;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
529
549
|
toString() {
|
|
530
550
|
return 'Testomatio Reporter';
|
|
531
551
|
}
|
|
532
552
|
}
|
|
533
553
|
|
|
534
554
|
let registeredErrorHints = false;
|
|
535
|
-
function printCreateIssue(
|
|
555
|
+
function printCreateIssue() {
|
|
536
556
|
if (registeredErrorHints) return;
|
|
537
557
|
registeredErrorHints = true;
|
|
538
558
|
process.on('exit', () => {
|
|
539
|
-
console.log();
|
|
540
|
-
console.log(APP_PREFIX, 'There was an error reporting to Testomat.io:');
|
|
541
559
|
console.log(
|
|
542
560
|
APP_PREFIX,
|
|
543
|
-
'
|
|
561
|
+
'There was an error reporting to Testomat.io.\n',
|
|
562
|
+
pc.yellow(
|
|
563
|
+
'If you think this is a bug please create an issue: https://github.com/testomatio/reporter/issues/new.',
|
|
564
|
+
),
|
|
565
|
+
pc.yellow('Provide the logs from above'),
|
|
544
566
|
);
|
|
545
|
-
console.log(APP_PREFIX, 'Provide this information:');
|
|
546
|
-
console.log('Error:', err.message || err.code);
|
|
547
|
-
if (!err.config) return;
|
|
548
|
-
|
|
549
|
-
const time = new Date().toUTCString();
|
|
550
|
-
const { body, url, baseURL, method } = err?.config || {};
|
|
551
|
-
console.log('```js');
|
|
552
|
-
console.log({ body: body?.replace(/"(tstmt_[^"]+)"/g, 'tstmt_*'), url, baseURL, method, time });
|
|
553
|
-
console.log('```');
|
|
554
567
|
});
|
|
555
568
|
}
|
|
556
569
|
|
|
570
|
+
/**
|
|
571
|
+
* Removes Testomatio token from string data
|
|
572
|
+
*
|
|
573
|
+
* @param {string} data
|
|
574
|
+
* @returns {string}
|
|
575
|
+
*/
|
|
576
|
+
function hideTestomatioToken(data) {
|
|
577
|
+
return data.replace(/"api_key": "[^"]+"/g, '"api_key": "<hidden>"').replace(/"(tstmt_[^"]+)"/g, 'tstmt_***');
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Stringifies provided data
|
|
582
|
+
*
|
|
583
|
+
* @param {any} anything
|
|
584
|
+
* @param {{ pretty: boolean }} opts
|
|
585
|
+
* @returns {string}
|
|
586
|
+
*/
|
|
587
|
+
function stringify(anything, opts = { pretty: false }) {
|
|
588
|
+
return typeof anything === 'string' ? anything : JSON.stringify(anything, null, opts.pretty ? 2 : undefined);
|
|
589
|
+
}
|
|
590
|
+
|
|
557
591
|
export default TestomatioPipe;
|
|
@@ -76,6 +76,10 @@ function setLabel(key, value = null) {
|
|
|
76
76
|
* @returns {void}
|
|
77
77
|
*/
|
|
78
78
|
function linkTest(...testIds) {
|
|
79
|
+
if (isPlaywright) {
|
|
80
|
+
console.log(`[TESTOMATIO-LINK-TESTS] ${JSON.stringify(testIds)}`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
79
83
|
const links = testIds.map(testId => ({ test: testId }));
|
|
80
84
|
services.links.put(links);
|
|
81
85
|
}
|
|
@@ -86,6 +90,10 @@ function linkTest(...testIds) {
|
|
|
86
90
|
* @returns {void}
|
|
87
91
|
*/
|
|
88
92
|
function linkJira(...jiraIds) {
|
|
93
|
+
if (isPlaywright) {
|
|
94
|
+
console.log(`[TESTOMATIO-LINK-JIRA] ${JSON.stringify(jiraIds)}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
89
97
|
const links = jiraIds.map(jiraId => ({ jira: jiraId }));
|
|
90
98
|
services.links.put(links);
|
|
91
99
|
}
|
package/src/services/links.js
CHANGED
|
@@ -30,7 +30,7 @@ class LinkStorage {
|
|
|
30
30
|
/**
|
|
31
31
|
* Returns links array for the test
|
|
32
32
|
* @param {*} context testId or test context from test runner
|
|
33
|
-
* @returns {
|
|
33
|
+
* @returns {{[key: 'test' | 'jira']: string}[]} links array, e.g. [{test: 'TEST-123'}, {jira: 'JIRA-456'}]
|
|
34
34
|
*/
|
|
35
35
|
get(context = null) {
|
|
36
36
|
const linksList = dataStorage.getData('links', context);
|
package/types/types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ declare module '@testomatio/reporter' {
|
|
|
17
17
|
* @param message - step message
|
|
18
18
|
* @param logs - optional key-value object with additional info (e.g. logs)
|
|
19
19
|
*/
|
|
20
|
-
export function step(message: string, logs?: {[key: string]: any}): void;
|
|
20
|
+
export function step(message: string, logs?: { [key: string]: any }): void;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Add key-value pair(s) to the test report
|