@testomatio/reporter 0.8.0-beta.1 → 0.8.0-beta.11
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/codecept.js +0 -5
- package/lib/adapter/cucumber/current.js +1 -7
- package/lib/adapter/jasmine.js +1 -8
- package/lib/adapter/jest.js +1 -7
- package/lib/adapter/mocha.js +5 -10
- package/lib/adapter/playwright.js +1 -7
- package/lib/adapter/webdriver.js +1 -4
- package/lib/client.js +12 -5
- package/lib/pipe/github.js +29 -12
- package/lib/pipe/index.js +6 -2
- package/lib/pipe/testomatio.js +12 -3
- package/lib/util.js +1 -3
- package/lib/xmlReader.js +4 -1
- package/package.json +3 -2
package/lib/adapter/codecept.js
CHANGED
|
@@ -35,11 +35,6 @@ function CodeceptReporter(config) {
|
|
|
35
35
|
const testTimeMap = {};
|
|
36
36
|
const { apiKey } = config;
|
|
37
37
|
|
|
38
|
-
if (!apiKey) {
|
|
39
|
-
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
const getDuration = test => {
|
|
44
39
|
if (testTimeMap[test.id]) {
|
|
45
40
|
return Date.now() - testTimeMap[test.id];
|
|
@@ -18,13 +18,7 @@ class CucumberReporter extends Formatter {
|
|
|
18
18
|
this.failures = [];
|
|
19
19
|
this.cases = [];
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
if (!apiKey || apiKey === '') {
|
|
23
|
-
console.log(chalk.red('TESTOMATIO key is empty, ignoring reports'));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
this.client = new TestomatClient({ apiKey });
|
|
21
|
+
this.client = new TestomatClient();
|
|
28
22
|
this.status = TRConstants.PASSED;
|
|
29
23
|
|
|
30
24
|
}
|
package/lib/adapter/jasmine.js
CHANGED
|
@@ -5,14 +5,7 @@ const { PASSED, FAILED } = require('../constants');
|
|
|
5
5
|
class JasmineReporter {
|
|
6
6
|
constructor(options) {
|
|
7
7
|
this.testTimeMap = {};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (!apiKey) {
|
|
11
|
-
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
this.client = new TestomatClient({ apiKey });
|
|
8
|
+
this.client = new TestomatClient({ apiKey: options?.apiKey });
|
|
16
9
|
this.client.createRun();
|
|
17
10
|
}
|
|
18
11
|
|
package/lib/adapter/jest.js
CHANGED
|
@@ -6,14 +6,8 @@ class JestReporter {
|
|
|
6
6
|
constructor(globalConfig, options) {
|
|
7
7
|
this._globalConfig = globalConfig;
|
|
8
8
|
this._options = options;
|
|
9
|
-
const { apiKey } = options;
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
this.client = new TestomatClient({ apiKey });
|
|
10
|
+
this.client = new TestomatClient({ apiKey: options?.apiKey });
|
|
17
11
|
this.client.createRun();
|
|
18
12
|
}
|
|
19
13
|
|
package/lib/adapter/mocha.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
2
2
|
const Mocha = require('mocha');
|
|
3
|
+
const chalk = require('chalk');
|
|
3
4
|
const TestomatClient = require('../client');
|
|
4
5
|
const TRConstants = require('../constants');
|
|
5
6
|
const { parseTest } = require('../util');
|
|
@@ -11,13 +12,7 @@ function MochaReporter(runner, opts) {
|
|
|
11
12
|
let passes = 0;
|
|
12
13
|
let failures = 0;
|
|
13
14
|
|
|
14
|
-
const { apiKey
|
|
15
|
-
|
|
16
|
-
if (!apiKey) {
|
|
17
|
-
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const client = new TestomatClient({ apiKey });
|
|
15
|
+
const client = new TestomatClient({ apiKey: opts?.reporterOptions?.apiKey });
|
|
21
16
|
|
|
22
17
|
runner.on(EVENT_RUN_BEGIN, () => {
|
|
23
18
|
client.createRun();
|
|
@@ -25,7 +20,7 @@ function MochaReporter(runner, opts) {
|
|
|
25
20
|
|
|
26
21
|
runner.on(EVENT_TEST_PASS, test => {
|
|
27
22
|
passes += 1;
|
|
28
|
-
console.log('
|
|
23
|
+
console.log(chalk.bold.green('✔'), test.fullTitle());
|
|
29
24
|
const testId = parseTest(test.title);
|
|
30
25
|
client.addTestRun(testId, TRConstants.PASSED, {
|
|
31
26
|
title: test.title,
|
|
@@ -35,7 +30,7 @@ function MochaReporter(runner, opts) {
|
|
|
35
30
|
|
|
36
31
|
runner.on(EVENT_TEST_FAIL, (test, err) => {
|
|
37
32
|
failures += 1;
|
|
38
|
-
console.log('
|
|
33
|
+
console.log(chalk.bold.red('✖'), test.fullTitle(), chalk.gray(err.message));
|
|
39
34
|
const testId = parseTest(test.title);
|
|
40
35
|
client.addTestRun(testId, TRConstants.FAILED, {
|
|
41
36
|
error: err,
|
|
@@ -45,8 +40,8 @@ function MochaReporter(runner, opts) {
|
|
|
45
40
|
});
|
|
46
41
|
|
|
47
42
|
runner.on(EVENT_RUN_END, () => {
|
|
48
|
-
console.log('end: %d/%d', passes, passes + failures);
|
|
49
43
|
const status = failures === 0 ? TRConstants.PASSED : TRConstants.FAILED;
|
|
44
|
+
console.log(chalk.bold(status), `${passes} passed, ${failures} failed`);
|
|
50
45
|
client.updateRunStatus(status);
|
|
51
46
|
});
|
|
52
47
|
}
|
|
@@ -10,13 +10,7 @@ const { parseTest } = require('../util');
|
|
|
10
10
|
|
|
11
11
|
class TestomatioReporter {
|
|
12
12
|
constructor(config = {}) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!apiKey) {
|
|
16
|
-
console.log('API Key is not provided. Testomat.io report is disabled');
|
|
17
|
-
} else {
|
|
18
|
-
this.client = new TestomatioClient({ apiKey });
|
|
19
|
-
}
|
|
13
|
+
this.client = new TestomatioClient({ apiKey: config?.apiKey });
|
|
20
14
|
|
|
21
15
|
this.videos = [];
|
|
22
16
|
}
|
package/lib/adapter/webdriver.js
CHANGED
|
@@ -7,10 +7,7 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
7
7
|
constructor(options) {
|
|
8
8
|
super(options);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
if (!apiKey) return;
|
|
12
|
-
|
|
13
|
-
this.client = new TestomatClient({ apiKey });
|
|
10
|
+
this.client = new TestomatClient({ apiKey: options?.apiKey });
|
|
14
11
|
options = Object.assign(options, { stdout: true });
|
|
15
12
|
|
|
16
13
|
this._addTestPromises = [];
|
package/lib/client.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const axios = require('axios');
|
|
2
1
|
const createCallsiteRecord = require('callsite-record');
|
|
3
2
|
const { sep, join } = require('path');
|
|
4
3
|
const fs = require('fs');
|
|
@@ -6,6 +5,7 @@ const chalk = require('chalk');
|
|
|
6
5
|
const upload = require('./fileUploader');
|
|
7
6
|
const { PASSED, FAILED, FINISHED, APP_PREFIX } = require('./constants');
|
|
8
7
|
const pipesFactory = require('./pipe');
|
|
8
|
+
|
|
9
9
|
const { TESTOMATIO_ENV } = process.env;
|
|
10
10
|
|
|
11
11
|
|
|
@@ -15,17 +15,16 @@ class TestomatClient {
|
|
|
15
15
|
*
|
|
16
16
|
* @param {*} params
|
|
17
17
|
*/
|
|
18
|
-
constructor(params) {
|
|
19
|
-
this.apiKey = params.apiKey || process.env.TESTOMATIO;
|
|
18
|
+
constructor(params = {}) {
|
|
20
19
|
this.title = params.title || process.env.TESTOMATIO_TITLE;
|
|
21
20
|
this.env = TESTOMATIO_ENV;
|
|
22
21
|
this.parallel = params.parallel;
|
|
23
22
|
const store = {}
|
|
24
23
|
this.pipes = pipesFactory(params, store);
|
|
25
24
|
this.queue = Promise.resolve();
|
|
26
|
-
this.axios = axios.create();
|
|
27
25
|
this.totalUploaded = 0;
|
|
28
26
|
this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
|
|
27
|
+
console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
/**
|
|
@@ -34,7 +33,9 @@ class TestomatClient {
|
|
|
34
33
|
* @returns {Promise} - resolves to Run id which should be used to update / add test
|
|
35
34
|
*/
|
|
36
35
|
createRun() {
|
|
37
|
-
|
|
36
|
+
// all pipes disabled, skipping
|
|
37
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
38
|
+
|
|
38
39
|
const runParams = {
|
|
39
40
|
title: this.title,
|
|
40
41
|
parallel: this.parallel,
|
|
@@ -54,6 +55,9 @@ class TestomatClient {
|
|
|
54
55
|
* @returns {Promise}
|
|
55
56
|
*/
|
|
56
57
|
async addTestRun(testId, status, testData = {}) {
|
|
58
|
+
// all pipes disabled, skipping
|
|
59
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
60
|
+
|
|
57
61
|
const {
|
|
58
62
|
error = '',
|
|
59
63
|
time = '',
|
|
@@ -127,6 +131,9 @@ class TestomatClient {
|
|
|
127
131
|
* @returns {Promise}
|
|
128
132
|
*/
|
|
129
133
|
updateRunStatus(status, isParallel) {
|
|
134
|
+
// all pipes disabled, skipping
|
|
135
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
136
|
+
|
|
130
137
|
let statusEvent;
|
|
131
138
|
if (status === FINISHED) statusEvent = 'finish';
|
|
132
139
|
if (status === PASSED) statusEvent = 'pass';
|
package/lib/pipe/github.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
const path = require('path');
|
|
1
2
|
const chalk = require('chalk');
|
|
3
|
+
const merge = require('lodash.merge');
|
|
2
4
|
const { Octokit } = require("@octokit/rest");
|
|
3
5
|
const { APP_PREFIX } = require('../constants');
|
|
4
6
|
const { ansiRegExp, isSameTest } = require('../util');
|
|
5
|
-
const merge = require('lodash.merge');
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class GitHubPipe {
|
|
@@ -14,11 +15,22 @@ class GitHubPipe {
|
|
|
14
15
|
this.tests = []
|
|
15
16
|
this.token = params.GH_PAT || process.env.GH_PAT;
|
|
16
17
|
this.ref = process.env.GITHUB_REF
|
|
17
|
-
this.repo = process.env.
|
|
18
|
+
this.repo = process.env.GITHUB_REPOSITORY
|
|
19
|
+
|
|
20
|
+
if (process.env.DEBUG) {
|
|
21
|
+
console.log(APP_PREFIX, 'GitHub Pipe: ', this.token ? 'TOKEN' : '*no token*', this.ref, this.repo);
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
if (!this.token || !this.ref || !this.repo) return;
|
|
19
25
|
this.isEnabled = true;
|
|
20
|
-
|
|
26
|
+
const matchedIssue = this.ref.match(/refs\/pull\/(\d+)\/merge/);
|
|
27
|
+
if (!matchedIssue) return;
|
|
28
|
+
this.issue = matchedIssue[1]
|
|
21
29
|
this.start = new Date();
|
|
30
|
+
|
|
31
|
+
if (process.env.DEBUG) {
|
|
32
|
+
console.log(APP_PREFIX, 'GitHub Pipe: Enabled');
|
|
33
|
+
}
|
|
22
34
|
}
|
|
23
35
|
|
|
24
36
|
async createRun() {}
|
|
@@ -27,7 +39,7 @@ class GitHubPipe {
|
|
|
27
39
|
|
|
28
40
|
addTest(test) {
|
|
29
41
|
if (!this.isEnabled) return;
|
|
30
|
-
|
|
42
|
+
|
|
31
43
|
const index = this.tests.findIndex(t => isSameTest(t, test))
|
|
32
44
|
// update if they were already added
|
|
33
45
|
if (index >= 0) {
|
|
@@ -92,8 +104,9 @@ class GitHubPipe {
|
|
|
92
104
|
if (t.stack) text += "```diff\n" + t.stack.replace(ansiRegExp(), '').trim() + "\n```\n";
|
|
93
105
|
|
|
94
106
|
if (t.artifacts && t.artifacts.length && !process.env.TESTOMATIO_PRIVATE_ARTIFACTS) {
|
|
95
|
-
t.artifacts.filter(f => f.endsWith('.png')).forEach(f => {
|
|
107
|
+
t.artifacts.filter(f => !!f).filter(f => f.endsWith('.png')).forEach(f => {
|
|
96
108
|
if (f.endsWith('.png')) return text+= `\n`
|
|
109
|
+
return text+= `[📄 ${path.basename(f)}](${f})\n`
|
|
97
110
|
});
|
|
98
111
|
}
|
|
99
112
|
|
|
@@ -105,19 +118,19 @@ class GitHubPipe {
|
|
|
105
118
|
let body = summary;
|
|
106
119
|
|
|
107
120
|
if (failures.length) {
|
|
108
|
-
body += `\n
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
body += "\n
|
|
121
|
+
body += `\n<details>\n<summary><h3>🟥 Failures (${failures.length})</h4></summary>\n\n${failures.join('\n')}\n`;
|
|
122
|
+
if (failures.length > 20) {
|
|
123
|
+
body += "\n> Notice\n> Only first 20 failures shown*"
|
|
124
|
+
}
|
|
125
|
+
body += "\n\n</details>\n";
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
if (this.tests.length > 0) {
|
|
116
|
-
body += "\n
|
|
117
|
-
|
|
129
|
+
body += "\n<details>\n<summary><h3>🐢 Slowest Tests</h3>\n\n"
|
|
118
130
|
body += this.tests.sort((a, b) => b?.run_time - a?.run_time).slice(0, 5).map(t => {
|
|
119
131
|
return `* ${fullName(t)} (${parseFloat(t.run_time).toFixed(2)}ms)`
|
|
120
132
|
}).join('\n')
|
|
133
|
+
body += "\n</details>"
|
|
121
134
|
}
|
|
122
135
|
|
|
123
136
|
try {
|
|
@@ -144,6 +157,10 @@ class GitHubPipe {
|
|
|
144
157
|
);
|
|
145
158
|
}
|
|
146
159
|
}
|
|
160
|
+
|
|
161
|
+
toString() {
|
|
162
|
+
return 'GitHub Reporter'
|
|
163
|
+
}
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
function statusEmoji(status) {
|
package/lib/pipe/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
3
4
|
const { APP_PREFIX } = require('../constants');
|
|
4
5
|
const TestomatioPipe = require('./testomatio');
|
|
5
6
|
const GitHubPipe = require('./github');
|
|
@@ -36,10 +37,13 @@ module.exports = function(params, opts) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
|
|
39
|
-
const
|
|
40
|
+
const pipes = [
|
|
40
41
|
new TestomatioPipe(params, opts),
|
|
41
42
|
new GitHubPipe(params, opts),
|
|
43
|
+
...extraPipes
|
|
42
44
|
];
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
console.log(APP_PREFIX, chalk.cyan('Pipes:'), chalk.cyan(pipes.filter(p => p.isEnabled).map(p => p.toString()).join(', ') || "No pipes enabled"));
|
|
47
|
+
|
|
48
|
+
return pipes;
|
|
45
49
|
}
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -15,9 +15,15 @@ class TestomatioPipe {
|
|
|
15
15
|
constructor(params, store = {}) {
|
|
16
16
|
this.url = params.testomatioUrl || process.env.TESTOMATIO_URL || 'https://app.testomat.io';
|
|
17
17
|
this.apiKey = params.apiKey || process.env.TESTOMATIO;
|
|
18
|
+
if (process.env.DEBUG) {
|
|
19
|
+
console.log(APP_PREFIX, 'Testomatio Pipe: ', this.apiKey ? 'API KEY' : '*no api key*');
|
|
20
|
+
}
|
|
18
21
|
if (!this.apiKey) {
|
|
19
22
|
return;
|
|
20
23
|
}
|
|
24
|
+
if (process.env.DEBUG) {
|
|
25
|
+
console.log(APP_PREFIX, 'Testomatio Pipe: Enabled');
|
|
26
|
+
}
|
|
21
27
|
this.store = store;
|
|
22
28
|
this.title = params.title || process.env.TESTOMATIO_TITLE;
|
|
23
29
|
this.axios = axios.create();
|
|
@@ -26,7 +32,6 @@ class TestomatioPipe {
|
|
|
26
32
|
this.runId = params.runId || process.env.runId;
|
|
27
33
|
this.createNewTests = !!process.env.TESTOMATIO_CREATE;
|
|
28
34
|
|
|
29
|
-
|
|
30
35
|
if (!isValidUrl(this.url.trim())) {
|
|
31
36
|
this.isEnabled = false;
|
|
32
37
|
console.log(
|
|
@@ -56,7 +61,7 @@ class TestomatioPipe {
|
|
|
56
61
|
this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
|
|
57
62
|
this.store.runUrl = this.runUrl;
|
|
58
63
|
this.store.runId = this.runId;
|
|
59
|
-
console.log(APP_PREFIX, '📊 Report created. Report ID:', this.runId
|
|
64
|
+
console.log(APP_PREFIX, '📊 Report created. Report ID:', this.runId);
|
|
60
65
|
process.env.runId = this.runId;
|
|
61
66
|
} catch (err) {
|
|
62
67
|
console.log(
|
|
@@ -122,7 +127,11 @@ class TestomatioPipe {
|
|
|
122
127
|
} catch (err) {
|
|
123
128
|
console.log(APP_PREFIX, 'Error updating status, skipping...', err);
|
|
124
129
|
}
|
|
125
|
-
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
toString() {
|
|
133
|
+
return 'Testomatio Reporter';
|
|
134
|
+
}
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
module.exports = TestomatioPipe;
|
package/lib/util.js
CHANGED
|
@@ -137,9 +137,7 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
const isSameTest = (test, t) =>
|
|
141
|
-
return t.title == test.title && t.suite_title == test.suite_title && Object.values(t.example) == Object.values(test.example) && t.test_id == test.test_id;
|
|
142
|
-
}
|
|
140
|
+
const isSameTest = (test, t) => t.title == test.title && t.suite_title == test.suite_title && Object.values(t.example) == Object.values(test.example) && t.test_id == test.test_id
|
|
143
141
|
|
|
144
142
|
module.exports = {
|
|
145
143
|
parseTest,
|
package/lib/xmlReader.js
CHANGED
|
@@ -4,7 +4,7 @@ const fs = require("fs");
|
|
|
4
4
|
|
|
5
5
|
// const util = require("util"); // you can see a result
|
|
6
6
|
const { XMLParser } = require("fast-xml-parser");
|
|
7
|
-
const { PASSED, FAILED, SKIPPED } = require('./constants');
|
|
7
|
+
const { APP_PREFIX, PASSED, FAILED, SKIPPED } = require('./constants');
|
|
8
8
|
const { fetchFilesFromStackTrace, fetchSourceCode, fetchSourceCodeFromStackTrace } = require('./util');
|
|
9
9
|
const upload = require('./fileUploader');
|
|
10
10
|
const pipesFactory = require('./pipe');
|
|
@@ -45,6 +45,9 @@ class XmlReader {
|
|
|
45
45
|
this.stats = {}
|
|
46
46
|
this.stats.language = opts.lang?.toLowerCase();
|
|
47
47
|
this.filesToUpload = {}
|
|
48
|
+
|
|
49
|
+
this.version = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json')).toString()).version;
|
|
50
|
+
console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
connectAdapter() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "0.8.0-beta.
|
|
3
|
+
"version": "0.8.0-beta.11",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"main": "./lib/reporter.js",
|
|
6
6
|
"repository": "git@github.com:testomatio/reporter.git",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"has-flag": "^5.0.1",
|
|
20
20
|
"is-valid-path": "^0.1.1",
|
|
21
21
|
"json-cycle": "^1.3.0",
|
|
22
|
-
"lodash.memoize": "^4.1.2"
|
|
22
|
+
"lodash.memoize": "^4.1.2",
|
|
23
|
+
"lodash.merge": "^4.6.2"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"bin",
|