testit-adapter-playwright 4.0.5 → 4.1.1-TMS-5.7
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 +7 -0
- package/dist/labels.d.ts +3 -0
- package/dist/labels.js +38 -1
- package/dist/metadata-store.d.ts +24 -0
- package/dist/metadata-store.js +107 -0
- package/dist/reporter.d.ts +9 -0
- package/dist/reporter.js +112 -68
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@ npm install testit-adapter-playwright
|
|
|
12
12
|
|
|
13
13
|
### Configuration
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
#### Log level
|
|
17
|
+
|
|
18
|
+
The adapter includes a custom logger; the default level is `warn`. Set another level at runtime with the `LOG_LEVEL` environment variable: `error`, `warn`, `info`, or `debug`.
|
|
19
|
+
|
|
20
|
+
|
|
15
21
|
| Description | File property | Environment variable |
|
|
16
22
|
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|--------------------------------------------|
|
|
17
23
|
| Location of the TMS instance | url | TMS_URL |
|
|
@@ -24,6 +30,7 @@ npm install testit-adapter-playwright
|
|
|
24
30
|
| It enables/disables certificate validation (**It's optional**). Default value - true | certValidation | TMS_CERT_VALIDATION |
|
|
25
31
|
| Mode of automatic creation test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will create a test case linked to the created autotest (not to the updated autotest)<br/>false - in this mode, the adapter will not create a test case | automaticCreationTestCases | TMS_AUTOMATIC_CREATION_TEST_CASES |
|
|
26
32
|
| Mode of automatic updation links to test cases (**It's optional**). Default value - false. The adapter supports following modes:<br/>true - in this mode, the adapter will update links to test cases<br/>false - in this mode, the adapter will not update link to test cases | automaticUpdationLinksToTestCases | TMS_AUTOMATIC_UPDATION_LINKS_TO_TEST_CASES |
|
|
33
|
+
| Logger level, default value is `warn`, available values: [`error`, `warn`, `info`, `debug`] | | LOG_LEVEL |
|
|
27
34
|
|
|
28
35
|
Add Adapter to Playwright file configuration:
|
|
29
36
|
|
package/dist/labels.d.ts
CHANGED
|
@@ -46,6 +46,9 @@ export declare enum Extensions {
|
|
|
46
46
|
}
|
|
47
47
|
type Parameters = Record<string, string>;
|
|
48
48
|
export declare class testit {
|
|
49
|
+
private static isMetadataAttachment;
|
|
50
|
+
private static readAttachmentBuffer;
|
|
51
|
+
private static mergeMetadataAttachments;
|
|
49
52
|
private static addMetadataAttachment;
|
|
50
53
|
static addAttachment(name: string, content: Buffer | string, options: ContentType | string | Pick<AttachmentOptions, "contentType">): Promise<void>;
|
|
51
54
|
private static mapParams;
|
package/dist/labels.js
CHANGED
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.testit = exports.Extensions = exports.ContentType = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
8
|
const test_1 = __importDefault(require("@playwright/test"));
|
|
9
|
+
const testit_js_commons_1 = require("testit-js-commons");
|
|
10
|
+
const metadata_store_1 = require("./metadata-store");
|
|
9
11
|
const utils_1 = require("./utils");
|
|
10
12
|
var ContentType;
|
|
11
13
|
(function (ContentType) {
|
|
@@ -34,10 +36,45 @@ var Extensions;
|
|
|
34
36
|
Extensions["MD"] = ".md";
|
|
35
37
|
})(Extensions || (exports.Extensions = Extensions = {}));
|
|
36
38
|
class testit {
|
|
39
|
+
static isMetadataAttachment(attachment) {
|
|
40
|
+
return (attachment.contentType === "application/vnd.tms.metadata+json" ||
|
|
41
|
+
attachment.name === "tms-metadata.json");
|
|
42
|
+
}
|
|
43
|
+
static readAttachmentBuffer(attachment) {
|
|
44
|
+
if (attachment.body) {
|
|
45
|
+
return attachment.body;
|
|
46
|
+
}
|
|
47
|
+
if (!attachment.path) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return testit_js_commons_1.Utils.readBufferSync(attachment.path);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
static mergeMetadataAttachments() {
|
|
58
|
+
let merged = {};
|
|
59
|
+
for (const attachment of test_1.default.info().attachments) {
|
|
60
|
+
if (!this.isMetadataAttachment(attachment)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const body = this.readAttachmentBuffer(attachment);
|
|
64
|
+
if (!body) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
merged = { ...merged, ...JSON.parse(body.toString()) };
|
|
68
|
+
}
|
|
69
|
+
return merged;
|
|
70
|
+
}
|
|
37
71
|
static async addMetadataAttachment(metadata) {
|
|
72
|
+
const info = test_1.default.info();
|
|
73
|
+
(0, metadata_store_1.patchTestMetadataForRun)({ testId: info.testId, file: info.file, titlePath: info.titlePath, title: info.title }, metadata);
|
|
74
|
+
const merged = { ...this.mergeMetadataAttachments(), ...metadata };
|
|
38
75
|
await test_1.default.info().attach("tms-metadata.json", {
|
|
39
76
|
contentType: "application/vnd.tms.metadata+json",
|
|
40
|
-
body: Buffer.from(JSON.stringify(
|
|
77
|
+
body: Buffer.from(JSON.stringify(merged), "utf8"),
|
|
41
78
|
});
|
|
42
79
|
}
|
|
43
80
|
static async addAttachment(name, content, options) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MetadataMessage } from "./labels";
|
|
2
|
+
export declare function metadataKey(file: string, titlePath: string[]): string;
|
|
3
|
+
export type MetadataRunContext = {
|
|
4
|
+
testId: string;
|
|
5
|
+
file: string;
|
|
6
|
+
titlePath: string[];
|
|
7
|
+
title: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function metadataKeys(ctx: MetadataRunContext): string[];
|
|
10
|
+
/** In-process metadata from testit.*(); attachments alone are unreliable in the reporter. */
|
|
11
|
+
export declare function patchTestMetadataForRun(ctx: MetadataRunContext, patch: MetadataMessage): void;
|
|
12
|
+
export declare function resolveTestMetadata(ctx: {
|
|
13
|
+
testId: string;
|
|
14
|
+
file: string;
|
|
15
|
+
titlePath: string[];
|
|
16
|
+
title: string;
|
|
17
|
+
}): MetadataMessage | undefined;
|
|
18
|
+
export declare function releaseTestMetadata(ctx: {
|
|
19
|
+
testId: string;
|
|
20
|
+
file: string;
|
|
21
|
+
titlePath: string[];
|
|
22
|
+
title: string;
|
|
23
|
+
}): void;
|
|
24
|
+
export declare function applyMetadataTo(target: MetadataMessage, source: MetadataMessage): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.metadataKey = metadataKey;
|
|
7
|
+
exports.metadataKeys = metadataKeys;
|
|
8
|
+
exports.patchTestMetadataForRun = patchTestMetadataForRun;
|
|
9
|
+
exports.resolveTestMetadata = resolveTestMetadata;
|
|
10
|
+
exports.releaseTestMetadata = releaseTestMetadata;
|
|
11
|
+
exports.applyMetadataTo = applyMetadataTo;
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const testit_js_commons_1 = require("testit-js-commons");
|
|
14
|
+
const STORE_KEY = Symbol.for("testit.playwright.metadata");
|
|
15
|
+
function metadataMap() {
|
|
16
|
+
const g = globalThis;
|
|
17
|
+
if (!g[STORE_KEY]) {
|
|
18
|
+
g[STORE_KEY] = new Map();
|
|
19
|
+
}
|
|
20
|
+
return g[STORE_KEY];
|
|
21
|
+
}
|
|
22
|
+
function metadataKey(file, titlePath) {
|
|
23
|
+
return `${path_1.default.resolve(file)}\0${titlePath.join("\0")}`;
|
|
24
|
+
}
|
|
25
|
+
function metadataKeys(ctx) {
|
|
26
|
+
const fullTitle = ctx.titlePath.join(" › ");
|
|
27
|
+
return [
|
|
28
|
+
ctx.testId,
|
|
29
|
+
metadataKey(ctx.file, ctx.titlePath),
|
|
30
|
+
metadataKey(ctx.file, [ctx.title]),
|
|
31
|
+
`hash:${testit_js_commons_1.Utils.getHash(ctx.title)}`,
|
|
32
|
+
`hash:${testit_js_commons_1.Utils.getHash(fullTitle)}`,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
/** In-process metadata from testit.*(); attachments alone are unreliable in the reporter. */
|
|
36
|
+
function patchTestMetadataForRun(ctx, patch) {
|
|
37
|
+
for (const key of metadataKeys(ctx)) {
|
|
38
|
+
const map = metadataMap();
|
|
39
|
+
map.set(key, { ...(map.get(key) ?? {}), ...patch });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function peekTestMetadata(key) {
|
|
43
|
+
return metadataMap().get(key);
|
|
44
|
+
}
|
|
45
|
+
function resolveTestMetadata(ctx) {
|
|
46
|
+
let merged = {};
|
|
47
|
+
let found = false;
|
|
48
|
+
for (const key of metadataKeys(ctx)) {
|
|
49
|
+
const chunk = peekTestMetadata(key);
|
|
50
|
+
if (!chunk) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
merged = { ...merged, ...chunk };
|
|
54
|
+
found = true;
|
|
55
|
+
}
|
|
56
|
+
return found ? merged : undefined;
|
|
57
|
+
}
|
|
58
|
+
function releaseTestMetadata(ctx) {
|
|
59
|
+
const map = metadataMap();
|
|
60
|
+
for (const key of metadataKeys(ctx)) {
|
|
61
|
+
map.delete(key);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function applyMetadataTo(target, source) {
|
|
65
|
+
if (source.externalId) {
|
|
66
|
+
target.externalId = source.externalId;
|
|
67
|
+
}
|
|
68
|
+
if (source.displayName) {
|
|
69
|
+
target.displayName = source.displayName;
|
|
70
|
+
}
|
|
71
|
+
if (source.title) {
|
|
72
|
+
target.title = source.title;
|
|
73
|
+
}
|
|
74
|
+
if (source.description) {
|
|
75
|
+
target.description = source.description;
|
|
76
|
+
}
|
|
77
|
+
if (source.labels) {
|
|
78
|
+
target.labels = source.labels;
|
|
79
|
+
}
|
|
80
|
+
if (source.tags) {
|
|
81
|
+
target.tags = source.tags;
|
|
82
|
+
}
|
|
83
|
+
if (source.links) {
|
|
84
|
+
target.links = source.links;
|
|
85
|
+
}
|
|
86
|
+
if (source.namespace) {
|
|
87
|
+
target.namespace = source.namespace;
|
|
88
|
+
}
|
|
89
|
+
if (source.classname) {
|
|
90
|
+
target.classname = source.classname;
|
|
91
|
+
}
|
|
92
|
+
if (source.addLinks) {
|
|
93
|
+
target.addLinks = source.addLinks;
|
|
94
|
+
}
|
|
95
|
+
if (source.addMessage) {
|
|
96
|
+
target.addMessage = source.addMessage;
|
|
97
|
+
}
|
|
98
|
+
if (source.params) {
|
|
99
|
+
target.params = source.params;
|
|
100
|
+
}
|
|
101
|
+
if (source.workItemIds) {
|
|
102
|
+
target.workItemIds = source.workItemIds;
|
|
103
|
+
}
|
|
104
|
+
if (source.externalKey) {
|
|
105
|
+
target.externalKey = source.externalKey;
|
|
106
|
+
}
|
|
107
|
+
}
|
package/dist/reporter.d.ts
CHANGED
|
@@ -20,17 +20,26 @@ declare class TmsReporter implements Reporter {
|
|
|
20
20
|
private attachmentsMap;
|
|
21
21
|
private loadTestPromises;
|
|
22
22
|
private setupPromise;
|
|
23
|
+
private readonly adapterConfig;
|
|
24
|
+
private bufferedResults;
|
|
23
25
|
constructor(options: ReporterOptions);
|
|
24
26
|
onBegin(config: FullConfig, suite: Suite): void;
|
|
25
27
|
onTestBegin(test: TestCase): void;
|
|
26
28
|
onTestEnd(test: TestCase, result: TestResult): void;
|
|
27
29
|
private _processAttachmentsWithExtensions;
|
|
30
|
+
private metadataContext;
|
|
28
31
|
onStepBegin(test: TestCase, _result: TestResult, step: TestStep): void;
|
|
29
32
|
onEnd(): Promise<void>;
|
|
30
33
|
addSkippedResults(): Promise<void>;
|
|
34
|
+
private runLoadTest;
|
|
31
35
|
printsToStdio(): boolean;
|
|
32
36
|
private getDictionariesByTest;
|
|
33
37
|
private getAutotestData;
|
|
38
|
+
private isMetadataAttachment;
|
|
39
|
+
/** Playwright copies inline attach to disk — reporter often gets path only, not body. */
|
|
40
|
+
private readAttachmentBuffer;
|
|
41
|
+
/** Each testit.*() call may add a separate tms-metadata.json; merge all of them. */
|
|
42
|
+
private applyMetadataAttachments;
|
|
34
43
|
private loadTest;
|
|
35
44
|
}
|
|
36
45
|
export default TmsReporter;
|
package/dist/reporter.js
CHANGED
|
@@ -19,8 +19,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
const testit_js_commons_1 = require("testit-js-commons");
|
|
21
21
|
const converter_1 = require("./converter");
|
|
22
|
+
const metadata_store_1 = require("./metadata-store");
|
|
22
23
|
const utils_1 = require("./utils");
|
|
23
24
|
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const testit_js_commons_2 = require("testit-js-commons");
|
|
24
26
|
class TmsReporter {
|
|
25
27
|
constructor(options) {
|
|
26
28
|
this.testCache = new Array();
|
|
@@ -29,10 +31,13 @@ class TmsReporter {
|
|
|
29
31
|
this.attachmentsMap = new Map();
|
|
30
32
|
this.loadTestPromises = new Array();
|
|
31
33
|
this.setupPromise = Promise.resolve();
|
|
34
|
+
this.bufferedResults = [];
|
|
32
35
|
this.options = { suiteTitle: true, detail: true, ...options };
|
|
33
36
|
const config = new testit_js_commons_1.ConfigComposer().compose(options.tmsOptions);
|
|
37
|
+
this.adapterConfig = config;
|
|
34
38
|
this.strategy = testit_js_commons_1.StrategyFactory.create(config);
|
|
35
39
|
this.additions = new testit_js_commons_1.Additions(config);
|
|
40
|
+
testit_js_commons_2.logger.debug("[playwright] reporter init", { importRealtime: Boolean(config.importRealtime) });
|
|
36
41
|
}
|
|
37
42
|
onBegin(config, suite) {
|
|
38
43
|
this.config = config;
|
|
@@ -43,21 +48,36 @@ class TmsReporter {
|
|
|
43
48
|
this.testCache.push(test);
|
|
44
49
|
}
|
|
45
50
|
onTestEnd(test, result) {
|
|
46
|
-
|
|
51
|
+
const currentResult = {
|
|
47
52
|
status: result.status,
|
|
48
53
|
attachments: this._processAttachmentsWithExtensions(result),
|
|
49
54
|
duration: result.duration,
|
|
50
55
|
errors: result.errors,
|
|
51
56
|
error: result.error,
|
|
52
57
|
steps: result.steps,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
};
|
|
59
|
+
if (this.adapterConfig.importRealtime) {
|
|
60
|
+
testit_js_commons_2.logger.debug("[playwright] onTestEnd realtime", { title: test.title, status: result.status });
|
|
61
|
+
this.loadTestPromises.push(this.runLoadTest(test, currentResult));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.bufferedResults.push({ test, result: currentResult });
|
|
56
65
|
}
|
|
57
66
|
// fix issues with trace and video files on playwright
|
|
58
67
|
_processAttachmentsWithExtensions(result) {
|
|
59
68
|
return result.attachments.map(utils_1.processAttachmentExtensions);
|
|
60
69
|
}
|
|
70
|
+
metadataContext(test) {
|
|
71
|
+
const titlePath = typeof test.titlePath === "function"
|
|
72
|
+
? test.titlePath()
|
|
73
|
+
: [test.title];
|
|
74
|
+
return {
|
|
75
|
+
testId: test.id,
|
|
76
|
+
file: test.location.file,
|
|
77
|
+
titlePath,
|
|
78
|
+
title: test.title,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
61
81
|
onStepBegin(test, _result, step) {
|
|
62
82
|
if (!this.testCache.includes(test)) {
|
|
63
83
|
return;
|
|
@@ -80,17 +100,24 @@ class TmsReporter {
|
|
|
80
100
|
async onEnd() {
|
|
81
101
|
try {
|
|
82
102
|
await this.setupPromise.catch((err) => {
|
|
83
|
-
|
|
103
|
+
testit_js_commons_2.logger.error("TMS Playwright setup failed:", err?.body ?? err?.error ?? err);
|
|
84
104
|
});
|
|
105
|
+
if (!this.adapterConfig.importRealtime) {
|
|
106
|
+
testit_js_commons_2.logger.debug("[playwright] onEnd batch flush", { count: this.bufferedResults.length });
|
|
107
|
+
await Promise.allSettled(this.bufferedResults.map(({ test, result }) => this.runLoadTest(test, result)));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
testit_js_commons_2.logger.debug("[playwright] onEnd await realtime", { pending: this.loadTestPromises.length });
|
|
111
|
+
}
|
|
85
112
|
await Promise.allSettled(this.loadTestPromises);
|
|
86
113
|
await this.addSkippedResults();
|
|
87
114
|
}
|
|
88
115
|
catch (err) {
|
|
89
|
-
|
|
116
|
+
testit_js_commons_2.logger.error("TMS Playwright onEnd failed:", err?.body ?? err?.error ?? err);
|
|
90
117
|
}
|
|
91
118
|
finally {
|
|
92
119
|
await this.strategy.teardown().catch((err) => {
|
|
93
|
-
|
|
120
|
+
testit_js_commons_2.logger.error("TMS Playwright teardown failed:", err?.body ?? err?.error ?? err);
|
|
94
121
|
});
|
|
95
122
|
}
|
|
96
123
|
}
|
|
@@ -105,9 +132,16 @@ class TmsReporter {
|
|
|
105
132
|
errors: [],
|
|
106
133
|
steps: [],
|
|
107
134
|
}).catch((err) => {
|
|
108
|
-
|
|
135
|
+
testit_js_commons_2.logger.error("TMS Playwright loadTest (skipped) failed:", testCase?.title, err?.body ?? err?.error ?? err);
|
|
109
136
|
})));
|
|
110
137
|
}
|
|
138
|
+
runLoadTest(test, result) {
|
|
139
|
+
return this.setupPromise
|
|
140
|
+
.then(() => this.loadTest(test, result))
|
|
141
|
+
.catch((err) => {
|
|
142
|
+
testit_js_commons_2.logger.log("Error processing test result. \n", err?.body ?? err?.error ?? err);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
111
145
|
printsToStdio() {
|
|
112
146
|
return false;
|
|
113
147
|
}
|
|
@@ -126,6 +160,9 @@ class TmsReporter {
|
|
|
126
160
|
externalKey: test.title,
|
|
127
161
|
};
|
|
128
162
|
for (const attachment of result.attachments) {
|
|
163
|
+
if (this.isMetadataAttachment(attachment)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
129
166
|
if (!attachment.body) {
|
|
130
167
|
if (attachment.path && attachment.name !== "screenshot") {
|
|
131
168
|
let content;
|
|
@@ -143,54 +180,11 @@ class TmsReporter {
|
|
|
143
180
|
autotestData.addAttachments?.push(...ids);
|
|
144
181
|
}
|
|
145
182
|
catch (err) {
|
|
146
|
-
|
|
183
|
+
testit_js_commons_2.logger.log("Error uploading file attachment. \n", err?.body ?? err?.error ?? err);
|
|
147
184
|
}
|
|
148
185
|
}
|
|
149
186
|
continue;
|
|
150
187
|
}
|
|
151
|
-
if (attachment.contentType === "application/vnd.tms.metadata+json") {
|
|
152
|
-
const metadata = JSON.parse(attachment.body.toString());
|
|
153
|
-
if (metadata.externalId) {
|
|
154
|
-
autotestData.externalId = metadata.externalId;
|
|
155
|
-
}
|
|
156
|
-
if (metadata.displayName) {
|
|
157
|
-
autotestData.displayName = metadata.displayName;
|
|
158
|
-
}
|
|
159
|
-
if (metadata.title) {
|
|
160
|
-
autotestData.title = metadata.title;
|
|
161
|
-
}
|
|
162
|
-
if (metadata.description) {
|
|
163
|
-
autotestData.description = metadata.description;
|
|
164
|
-
}
|
|
165
|
-
if (metadata.labels) {
|
|
166
|
-
autotestData.labels = metadata.labels;
|
|
167
|
-
}
|
|
168
|
-
if (metadata.tags) {
|
|
169
|
-
autotestData.tags = metadata.tags;
|
|
170
|
-
}
|
|
171
|
-
if (metadata.links) {
|
|
172
|
-
autotestData.links = metadata.links;
|
|
173
|
-
}
|
|
174
|
-
if (metadata.namespace) {
|
|
175
|
-
autotestData.namespace = metadata.namespace;
|
|
176
|
-
}
|
|
177
|
-
if (metadata.classname) {
|
|
178
|
-
autotestData.classname = metadata.classname;
|
|
179
|
-
}
|
|
180
|
-
if (metadata.addLinks) {
|
|
181
|
-
autotestData.addLinks = metadata.addLinks;
|
|
182
|
-
}
|
|
183
|
-
if (metadata.addMessage) {
|
|
184
|
-
autotestData.addMessage = metadata.addMessage;
|
|
185
|
-
}
|
|
186
|
-
if (metadata.params) {
|
|
187
|
-
autotestData.params = metadata.params;
|
|
188
|
-
}
|
|
189
|
-
if (metadata.workItemIds) {
|
|
190
|
-
autotestData.workItemIds = metadata.workItemIds;
|
|
191
|
-
}
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
188
|
if (attachment.name.match(utils_1.stepAttachRegexp)) {
|
|
195
189
|
const step = this.attachmentStepsCache.find((step) => step.title === attachment.name);
|
|
196
190
|
try {
|
|
@@ -202,38 +196,88 @@ class TmsReporter {
|
|
|
202
196
|
autotestData.addAttachments?.push(...ids);
|
|
203
197
|
}
|
|
204
198
|
catch (err) {
|
|
205
|
-
|
|
199
|
+
testit_js_commons_2.logger.log("Error uploading text attachment. \n", err?.body ?? err?.error ?? err);
|
|
206
200
|
}
|
|
207
201
|
}
|
|
208
202
|
}
|
|
203
|
+
this.applyMetadataAttachments(autotestData, result.attachments);
|
|
204
|
+
const stored = (0, metadata_store_1.resolveTestMetadata)(this.metadataContext(test));
|
|
205
|
+
if (stored) {
|
|
206
|
+
(0, metadata_store_1.applyMetadataTo)(autotestData, stored);
|
|
207
|
+
testit_js_commons_2.logger.debug("[playwright] metadata from store", {
|
|
208
|
+
title: test.title,
|
|
209
|
+
namespace: autotestData.namespace,
|
|
210
|
+
classname: autotestData.classname,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
209
213
|
return autotestData;
|
|
210
214
|
}
|
|
215
|
+
isMetadataAttachment(attachment) {
|
|
216
|
+
return (attachment.contentType === "application/vnd.tms.metadata+json" ||
|
|
217
|
+
attachment.name === "tms-metadata.json");
|
|
218
|
+
}
|
|
219
|
+
/** Playwright copies inline attach to disk — reporter often gets path only, not body. */
|
|
220
|
+
readAttachmentBuffer(attachment) {
|
|
221
|
+
if (attachment.body) {
|
|
222
|
+
return attachment.body;
|
|
223
|
+
}
|
|
224
|
+
if (!attachment.path) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
return testit_js_commons_1.Utils.readBufferSync(attachment.path);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
if (err?.code === "ENOENT") {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
throw err;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** Each testit.*() call may add a separate tms-metadata.json; merge all of them. */
|
|
238
|
+
applyMetadataAttachments(autotestData, attachments) {
|
|
239
|
+
let merged = {};
|
|
240
|
+
for (const attachment of attachments) {
|
|
241
|
+
if (!this.isMetadataAttachment(attachment)) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const body = this.readAttachmentBuffer(attachment);
|
|
245
|
+
if (!body) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
merged = { ...merged, ...JSON.parse(body.toString()) };
|
|
249
|
+
}
|
|
250
|
+
(0, metadata_store_1.applyMetadataTo)(autotestData, merged);
|
|
251
|
+
}
|
|
211
252
|
async loadTest(test, result) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
253
|
+
testit_js_commons_2.logger.debug("[playwright] loadTest", { title: test.title, status: result.status });
|
|
254
|
+
try {
|
|
255
|
+
const autotestData = await this.getAutotestData(test, result);
|
|
215
256
|
const dictionaries = this.getDictionariesByTest(test);
|
|
216
257
|
const pathNamespace = dictionaries.slice(0, -1).join(path_1.default.sep);
|
|
217
258
|
const pathClassname = dictionaries[dictionaries.length - 1];
|
|
218
|
-
// Prefer testit.namespace / testit.classname from
|
|
259
|
+
// Prefer testit.namespace / testit.classname from metadata; file path only when missing.
|
|
219
260
|
if (pathNamespace.length > 0 && autotestData.namespace == null) {
|
|
220
261
|
autotestData.namespace = pathNamespace;
|
|
221
262
|
}
|
|
222
263
|
if (pathClassname?.length && autotestData.classname == null) {
|
|
223
264
|
autotestData.classname = pathClassname;
|
|
224
265
|
}
|
|
266
|
+
const autotest = converter_1.Converter.convertTestCaseToAutotestPost(autotestData);
|
|
267
|
+
const rawSteps = result.steps?.length
|
|
268
|
+
? result.steps
|
|
269
|
+
: [...this.stepsMap.keys()].filter((step) => this.stepsMap.get(step) === test);
|
|
270
|
+
const stepResults = converter_1.Converter.convertTestStepsToSteps(rawSteps, this.attachmentsMap);
|
|
271
|
+
result.status = (0, utils_1.getTestStatus)(test);
|
|
272
|
+
autotest.steps = converter_1.Converter.convertTestStepsToShortSteps(rawSteps);
|
|
273
|
+
await this.strategy.loadAutotest(autotest, converter_1.Converter.convertStatus(result.status, test.expectedStatus));
|
|
274
|
+
const autotestResult = converter_1.Converter.convertAutotestPostToAutotestResult(autotestData, test, result);
|
|
275
|
+
autotestResult.stepResults = stepResults;
|
|
276
|
+
await this.strategy.loadTestRun([autotestResult]);
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
(0, metadata_store_1.releaseTestMetadata)(this.metadataContext(test));
|
|
225
280
|
}
|
|
226
|
-
const autotest = converter_1.Converter.convertTestCaseToAutotestPost(autotestData);
|
|
227
|
-
const rawSteps = result.steps?.length
|
|
228
|
-
? result.steps
|
|
229
|
-
: [...this.stepsMap.keys()].filter((step) => this.stepsMap.get(step) === test);
|
|
230
|
-
const stepResults = converter_1.Converter.convertTestStepsToSteps(rawSteps, this.attachmentsMap);
|
|
231
|
-
result.status = (0, utils_1.getTestStatus)(test);
|
|
232
|
-
autotest.steps = converter_1.Converter.convertTestStepsToShortSteps(rawSteps);
|
|
233
|
-
await this.strategy.loadAutotest(autotest, converter_1.Converter.convertStatus(result.status, test.expectedStatus));
|
|
234
|
-
const autotestResult = converter_1.Converter.convertAutotestPostToAutotestResult(autotestData, test, result);
|
|
235
|
-
autotestResult.stepResults = stepResults;
|
|
236
|
-
await this.strategy.loadTestRun([autotestResult]);
|
|
237
281
|
}
|
|
238
282
|
}
|
|
239
283
|
exports.default = TmsReporter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testit-adapter-playwright",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1-TMS-5.7",
|
|
4
4
|
"description": "Playwright adapter for Test IT",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"prettier": "^3.0.1"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"testit-js-commons": "4.
|
|
43
|
+
"testit-js-commons": "4.1.1-TMS-5.7"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"dist"
|