mocha-qase-reporter 1.0.0-beta.3 → 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 +14 -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 +70 -4
- 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,17 @@
|
|
|
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
|
+
|
|
9
|
+
# qase-mocha@1.0.0-beta.4
|
|
10
|
+
|
|
11
|
+
## What's new
|
|
12
|
+
|
|
13
|
+
Fixed the issue with async tests not being reported correctly.
|
|
14
|
+
|
|
1
15
|
# qase-mocha@1.0.0-beta.3
|
|
2
16
|
|
|
3
17
|
## 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,9 +34,10 @@ 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());
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
39
41
|
this.runner.on(Events.EVENT_TEST_END, (test) => this.onEndTest(test));
|
|
40
42
|
};
|
|
41
43
|
this.qaseId = (id) => {
|
|
@@ -122,6 +124,9 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
122
124
|
else {
|
|
123
125
|
this.applyListeners();
|
|
124
126
|
}
|
|
127
|
+
this.originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
128
|
+
this.originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
129
|
+
this.testOutputs = new Map();
|
|
125
130
|
}
|
|
126
131
|
onStartRun() {
|
|
127
132
|
this.reporter.startTestRun();
|
|
@@ -129,7 +134,7 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
129
134
|
onEndRun() {
|
|
130
135
|
(0, deasync_promise_1.default)(this.reporter.publish());
|
|
131
136
|
}
|
|
132
|
-
|
|
137
|
+
addMethodsToContext(ctx) {
|
|
133
138
|
if (!ctx)
|
|
134
139
|
return;
|
|
135
140
|
ctx.qaseId = this.qaseId;
|
|
@@ -143,14 +148,50 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
143
148
|
ctx.comment = this.comment;
|
|
144
149
|
ctx.step = this.step;
|
|
145
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
|
+
}
|
|
146
171
|
onStartTest() {
|
|
147
172
|
this.currentType = 'test';
|
|
148
173
|
}
|
|
149
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
|
+
}
|
|
150
186
|
if (this.metadata.ignore) {
|
|
187
|
+
this.metadata.clear();
|
|
188
|
+
this.currentTest = new currentTest();
|
|
151
189
|
return;
|
|
152
190
|
}
|
|
153
191
|
const ids = this.getQaseId();
|
|
192
|
+
if (ids.length === 0) {
|
|
193
|
+
ids.push(...MochaQaseReporter.getCaseId(test.title));
|
|
194
|
+
}
|
|
154
195
|
const suites = this.getSuites(test);
|
|
155
196
|
let relations = {};
|
|
156
197
|
if (suites.length > 0) {
|
|
@@ -195,7 +236,7 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
195
236
|
thread: null,
|
|
196
237
|
},
|
|
197
238
|
testops_id: ids.length > 0 ? ids : null,
|
|
198
|
-
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),
|
|
199
240
|
};
|
|
200
241
|
(0, deasync_promise_1.default)(this.reporter.addTestResult(result));
|
|
201
242
|
this.metadata.clear();
|
|
@@ -263,6 +304,27 @@ class MochaQaseReporter extends mocha_1.reporters.Base {
|
|
|
263
304
|
}
|
|
264
305
|
return suites;
|
|
265
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
|
+
}
|
|
266
328
|
}
|
|
267
329
|
exports.MochaQaseReporter = MochaQaseReporter;
|
|
268
330
|
/**
|
|
@@ -273,3 +335,7 @@ MochaQaseReporter.statusMap = {
|
|
|
273
335
|
passed: qase_javascript_commons_1.TestStatusEnum.passed,
|
|
274
336
|
pending: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
275
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
|
"*": {
|