mocha-qase-reporter 1.0.0-beta.4 → 1.0.0-beta.5
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 +1 -1
- package/changelog.md +8 -0
- package/dist/interceptor.d.ts +12 -0
- package/dist/interceptor.js +16 -0
- package/dist/mocha.d.ts +12 -0
- package/dist/mocha.js +32 -0
- package/dist/reporter.d.ts +20 -0
- package/dist/reporter.js +72 -7
- package/dist/types.d.ts +4 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ QASE_MODE=testops mocha --parallel
|
|
|
89
89
|
After the tests are finished, you can complete the run:
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
qli testops run complete --project DEMO --token token --
|
|
92
|
+
qli testops run complete --project DEMO --token token --id $(echo $QASE_TESTOPS_RUN_ID)
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
## Configuration
|
package/changelog.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# qase-mocha@1.0.0-beta.5
|
|
2
|
+
|
|
3
|
+
## What's new
|
|
4
|
+
|
|
5
|
+
- Added a `qase` function to allow specifying QaseID for tests.
|
|
6
|
+
- Marked the old syntax for QaseID as deprecated.
|
|
7
|
+
- Implemented functionality to capture console logs and include them as attachments in tests.
|
|
8
|
+
|
|
1
9
|
# qase-mocha@1.0.0-beta.4
|
|
2
10
|
|
|
3
11
|
## What's new
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { Writable } from 'stream';
|
|
4
|
+
export interface TestOutput {
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class StreamInterceptor extends Writable {
|
|
9
|
+
private readonly onWrite;
|
|
10
|
+
constructor(onWriteCallback: (data: string) => void);
|
|
11
|
+
_write(chunk: any, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamInterceptor = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
class StreamInterceptor extends stream_1.Writable {
|
|
6
|
+
constructor(onWriteCallback) {
|
|
7
|
+
super();
|
|
8
|
+
this.onWrite = onWriteCallback;
|
|
9
|
+
}
|
|
10
|
+
_write(chunk, _encoding, callback) {
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-call
|
|
12
|
+
this.onWrite(chunk.toString());
|
|
13
|
+
callback();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.StreamInterceptor = StreamInterceptor;
|
package/dist/mocha.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set IDs for the test case
|
|
3
|
+
*
|
|
4
|
+
* @param caseId
|
|
5
|
+
* @param name
|
|
6
|
+
* @example
|
|
7
|
+
* it(qase(1, 'test'), function() => {
|
|
8
|
+
* // test code
|
|
9
|
+
* });
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
export declare const qase: (caseId: number | string | number[] | string[], name: string) => string;
|
package/dist/mocha.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.qase = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Set IDs for the test case
|
|
6
|
+
*
|
|
7
|
+
* @param caseId
|
|
8
|
+
* @param name
|
|
9
|
+
* @example
|
|
10
|
+
* it(qase(1, 'test'), function() => {
|
|
11
|
+
* // test code
|
|
12
|
+
* });
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
const qase = (caseId, name) => {
|
|
16
|
+
const caseIds = Array.isArray(caseId) ? caseId : [caseId];
|
|
17
|
+
const ids = [];
|
|
18
|
+
for (const id of caseIds) {
|
|
19
|
+
if (typeof id === 'number') {
|
|
20
|
+
ids.push(id);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const parsedId = parseInt(id);
|
|
24
|
+
if (!isNaN(parsedId)) {
|
|
25
|
+
ids.push(parsedId);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
console.log(`qase: qase ID ${id} should be a number`);
|
|
29
|
+
}
|
|
30
|
+
return `${name} (Qase ID: ${caseIds.join(',')})`;
|
|
31
|
+
};
|
|
32
|
+
exports.qase = qase;
|
package/dist/reporter.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { MochaOptions, reporters, Runner } from 'mocha';
|
|
|
3
3
|
import { ConfigLoader, TestStatusEnum } from 'qase-javascript-commons';
|
|
4
4
|
type MochaState = 'failed' | 'passed' | 'pending';
|
|
5
5
|
export declare class MochaQaseReporter extends reporters.Base {
|
|
6
|
+
private originalStdoutWrite;
|
|
7
|
+
private originalStderrWrite;
|
|
8
|
+
private testOutputs;
|
|
6
9
|
/**
|
|
7
10
|
* @type {Record<CypressState, TestStatusEnum>}
|
|
8
11
|
*/
|
|
@@ -23,6 +26,7 @@ export declare class MochaQaseReporter extends reporters.Base {
|
|
|
23
26
|
private applyListeners;
|
|
24
27
|
private onStartRun;
|
|
25
28
|
private onEndRun;
|
|
29
|
+
private addMethodsToContext;
|
|
26
30
|
private addMethods;
|
|
27
31
|
private onStartTest;
|
|
28
32
|
private onEndTest;
|
|
@@ -63,5 +67,21 @@ export declare class MochaQaseReporter extends reporters.Base {
|
|
|
63
67
|
}) => void;
|
|
64
68
|
comment: (message: string) => void;
|
|
65
69
|
step: (title: string, func: () => void) => void;
|
|
70
|
+
/**
|
|
71
|
+
* @param {string} title
|
|
72
|
+
* @returns {string}
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
private removeQaseIdsFromTitle;
|
|
76
|
+
/**
|
|
77
|
+
* @type {RegExp}
|
|
78
|
+
*/
|
|
79
|
+
static qaseIdRegExp: RegExp;
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} title
|
|
82
|
+
* @returns {number[]}
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
private static getCaseId;
|
|
66
86
|
}
|
|
67
87
|
export {};
|
package/dist/reporter.js
CHANGED
|
@@ -10,6 +10,7 @@ const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
|
10
10
|
const deasync_promise_1 = __importDefault(require("deasync-promise"));
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
const uuid_1 = require("uuid");
|
|
13
|
+
const interceptor_1 = require("./interceptor");
|
|
13
14
|
const Events = mocha_1.Runner.constants;
|
|
14
15
|
class currentTest {
|
|
15
16
|
constructor() {
|
|
@@ -33,11 +34,11 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
33
34
|
this.applyListeners = () => {
|
|
34
35
|
this.runner.on(Events.EVENT_RUN_BEGIN, () => this.onStartRun());
|
|
35
36
|
this.runner.on(Events.EVENT_RUN_END, () => this.onEndRun());
|
|
36
|
-
this.runner.on(Events.EVENT_TEST_BEGIN, (test) => this.addMethods(test
|
|
37
|
-
this.runner.on(Events.EVENT_HOOK_BEGIN, (hook) => this.
|
|
37
|
+
this.runner.on(Events.EVENT_TEST_BEGIN, (test) => this.addMethods(test));
|
|
38
|
+
this.runner.on(Events.EVENT_HOOK_BEGIN, (hook) => this.addMethodsToContext(hook.ctx));
|
|
38
39
|
this.runner.on(Events.EVENT_TEST_BEGIN, () => this.onStartTest());
|
|
39
40
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
40
|
-
this.runner.on(Events.EVENT_TEST_END,
|
|
41
|
+
this.runner.on(Events.EVENT_TEST_END, (test) => this.onEndTest(test));
|
|
41
42
|
};
|
|
42
43
|
this.qaseId = (id) => {
|
|
43
44
|
this.metadata.addQaseId(id);
|
|
@@ -123,6 +124,9 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
123
124
|
else {
|
|
124
125
|
this.applyListeners();
|
|
125
126
|
}
|
|
127
|
+
this.originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
128
|
+
this.originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
129
|
+
this.testOutputs = new Map();
|
|
126
130
|
}
|
|
127
131
|
onStartRun() {
|
|
128
132
|
this.reporter.startTestRun();
|
|
@@ -130,7 +134,7 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
130
134
|
onEndRun() {
|
|
131
135
|
(0, deasync_promise_1.default)(this.reporter.publish());
|
|
132
136
|
}
|
|
133
|
-
|
|
137
|
+
addMethodsToContext(ctx) {
|
|
134
138
|
if (!ctx)
|
|
135
139
|
return;
|
|
136
140
|
ctx.qaseId = this.qaseId;
|
|
@@ -144,14 +148,50 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
144
148
|
ctx.comment = this.comment;
|
|
145
149
|
ctx.step = this.step;
|
|
146
150
|
}
|
|
151
|
+
addMethods(test) {
|
|
152
|
+
const stdoutInterceptor = new interceptor_1.StreamInterceptor((data) => {
|
|
153
|
+
const output = this.testOutputs.get(test.title) ?? { stdout: '', stderr: '' };
|
|
154
|
+
output.stdout += data;
|
|
155
|
+
this.testOutputs.set(test.title, output);
|
|
156
|
+
});
|
|
157
|
+
const stderrInterceptor = new interceptor_1.StreamInterceptor((data) => {
|
|
158
|
+
const output = this.testOutputs.get(test.title) ?? { stdout: '', stderr: '' };
|
|
159
|
+
output.stderr += data;
|
|
160
|
+
this.testOutputs.set(test.title, output);
|
|
161
|
+
});
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
163
|
+
// @ts-ignore
|
|
164
|
+
process.stdout.write = stdoutInterceptor.write.bind(stdoutInterceptor);
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
166
|
+
// @ts-ignore
|
|
167
|
+
process.stderr.write = stderrInterceptor.write.bind(stderrInterceptor);
|
|
168
|
+
this.testOutputs.set(test.title, { stdout: '', stderr: '' });
|
|
169
|
+
this.addMethodsToContext(test.ctx);
|
|
170
|
+
}
|
|
147
171
|
onStartTest() {
|
|
148
172
|
this.currentType = 'test';
|
|
149
173
|
}
|
|
150
|
-
|
|
174
|
+
onEndTest(test) {
|
|
175
|
+
process.stdout.write = this.originalStdoutWrite;
|
|
176
|
+
process.stderr.write = this.originalStderrWrite;
|
|
177
|
+
if (this.reporter.isCaptureLogs()) {
|
|
178
|
+
const output = this.testOutputs.get(test.title);
|
|
179
|
+
if (output?.stdout) {
|
|
180
|
+
this.attach({ name: 'stdout.txt', content: output.stdout, contentType: 'text/plain' });
|
|
181
|
+
}
|
|
182
|
+
if (output?.stderr) {
|
|
183
|
+
this.attach({ name: 'stderr.txt', content: output.stderr, contentType: 'text/plain' });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
151
186
|
if (this.metadata.ignore) {
|
|
187
|
+
this.metadata.clear();
|
|
188
|
+
this.currentTest = new currentTest();
|
|
152
189
|
return;
|
|
153
190
|
}
|
|
154
191
|
const ids = this.getQaseId();
|
|
192
|
+
if (ids.length === 0) {
|
|
193
|
+
ids.push(...MochaQaseReporter.getCaseId(test.title));
|
|
194
|
+
}
|
|
155
195
|
const suites = this.getSuites(test);
|
|
156
196
|
let relations = {};
|
|
157
197
|
if (suites.length > 0) {
|
|
@@ -196,9 +236,9 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
196
236
|
thread: null,
|
|
197
237
|
},
|
|
198
238
|
testops_id: ids.length > 0 ? ids : null,
|
|
199
|
-
title: this.metadata.title && this.metadata.title != '' ? this.metadata.title : test.title,
|
|
239
|
+
title: this.metadata.title && this.metadata.title != '' ? this.metadata.title : this.removeQaseIdsFromTitle(test.title),
|
|
200
240
|
};
|
|
201
|
-
|
|
241
|
+
(0, deasync_promise_1.default)(this.reporter.addTestResult(result));
|
|
202
242
|
this.metadata.clear();
|
|
203
243
|
this.currentTest = new currentTest();
|
|
204
244
|
}
|
|
@@ -264,6 +304,27 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
264
304
|
}
|
|
265
305
|
return suites;
|
|
266
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* @param {string} title
|
|
309
|
+
* @returns {string}
|
|
310
|
+
* @private
|
|
311
|
+
*/
|
|
312
|
+
removeQaseIdsFromTitle(title) {
|
|
313
|
+
const matches = title.match(MochaQaseReporter.qaseIdRegExp);
|
|
314
|
+
if (matches) {
|
|
315
|
+
return title.replace(matches[0], '').trimEnd();
|
|
316
|
+
}
|
|
317
|
+
return title;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* @param {string} title
|
|
321
|
+
* @returns {number[]}
|
|
322
|
+
* @private
|
|
323
|
+
*/
|
|
324
|
+
static getCaseId(title) {
|
|
325
|
+
const [, ids] = title.match(MochaQaseReporter.qaseIdRegExp) ?? [];
|
|
326
|
+
return ids ? ids.split(',').map((id) => Number(id)) : [];
|
|
327
|
+
}
|
|
267
328
|
}
|
|
268
329
|
exports.MochaQaseReporter = MochaQaseReporter;
|
|
269
330
|
/**
|
|
@@ -274,3 +335,7 @@ MochaQaseReporter.statusMap = {
|
|
|
274
335
|
passed: qase_javascript_commons_1.TestStatusEnum.passed,
|
|
275
336
|
pending: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
276
337
|
};
|
|
338
|
+
/**
|
|
339
|
+
* @type {RegExp}
|
|
340
|
+
*/
|
|
341
|
+
MochaQaseReporter.qaseIdRegExp = /\(Qase ID: ([\d,]+)\)/;
|
package/dist/types.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface Hook extends Mocha.Hook {
|
|
|
13
13
|
ctx?: Context;
|
|
14
14
|
}
|
|
15
15
|
export interface Methods {
|
|
16
|
+
/**
|
|
17
|
+
* Set IDs for the test case
|
|
18
|
+
* Use `qase()` instead. This method is deprecated and kept for reverse compatibility.
|
|
19
|
+
*/
|
|
16
20
|
qaseId(id: number | number[]): void;
|
|
17
21
|
title(title: string): void;
|
|
18
22
|
parameters(values: Record<string, string>): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mocha-qase-reporter",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "Mocha Cypress Reporter",
|
|
5
5
|
"homepage": "https://github.com/qase-tms/qase-javascript",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./dist/index.js",
|
|
11
11
|
"./reporter": "./dist/reporter.js",
|
|
12
|
-
"./package.json": "./package.json"
|
|
12
|
+
"./package.json": "./package.json",
|
|
13
|
+
"./mocha": "./dist/mocha.js"
|
|
13
14
|
},
|
|
14
15
|
"typesVersions": {
|
|
15
16
|
"*": {
|