@qualflare/playwright 0.1.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/LICENSE +190 -0
- package/README.md +139 -0
- package/dist/index.cjs +139 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +79 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter/index.cjs +949 -0
- package/dist/reporter/index.cjs.map +1 -0
- package/dist/reporter/index.d.cts +66 -0
- package/dist/reporter/index.d.ts +66 -0
- package/dist/reporter/index.js +916 -0
- package/dist/reporter/index.js.map +1 -0
- package/dist/resolve-config-CSjXFl7v.d.cts +292 -0
- package/dist/resolve-config-CSjXFl7v.d.ts +292 -0
- package/package.json +81 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Qualflare `/api/v1/collect` wire contract.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces mirror `api-service/internal/core/domain/launch/launch.go`
|
|
5
|
+
* field-for-field (JSON key names, optionality, and string-union values) as
|
|
6
|
+
* verified against the live, deployed source. Do not add, rename, or change
|
|
7
|
+
* the optionality of a field here without re-verifying against that file —
|
|
8
|
+
* a mismatch either 400s the request or silently drops data server-side.
|
|
9
|
+
*
|
|
10
|
+
* Kept identical to `@qualflare/cypress`'s copy of this file — the two
|
|
11
|
+
* packages report to the same backend, so this file should stay in sync
|
|
12
|
+
* across both.
|
|
13
|
+
*/
|
|
14
|
+
/** Every `duration` field in this contract is a raw integer number of
|
|
15
|
+
* NANOSECONDS, with no unit marker on the wire. Playwright reports
|
|
16
|
+
* `{seconds, nanos}` — convert directly to nanoseconds (see `./duration.ts`)
|
|
17
|
+
* before assigning into one of these fields. */
|
|
18
|
+
type NanosecondDuration = number;
|
|
19
|
+
type Platform = 'android' | 'ios' | 'desktop' | 'web' | 'api';
|
|
20
|
+
type CaseStatus = 'passed' | 'failed' | 'skipped' | 'error' | 'timeout' | 'aborted' | 'pending';
|
|
21
|
+
/**
|
|
22
|
+
* The server's oneof accepts a value named after any of the ~23 frameworks it
|
|
23
|
+
* auto-detects (e.g. "playwright"), not just the six coarse buckets below — a
|
|
24
|
+
* suite's category is meant to say exactly which tool produced it, which is
|
|
25
|
+
* what lets the UI show that tool's own logo. This reporter only ever emits
|
|
26
|
+
* 'playwright' (see suite-builder.ts), so that's the only
|
|
27
|
+
* tool-specific value listed here; the six buckets remain for backward
|
|
28
|
+
* compatibility / servers that haven't been upgraded.
|
|
29
|
+
*/
|
|
30
|
+
type FrameworkCategory = 'playwright' | 'unit' | 'bdd' | 'e2e' | 'api' | 'security' | 'generic';
|
|
31
|
+
type CasePriority = 'low' | 'medium' | 'high' | 'critical';
|
|
32
|
+
type LinkType = 'issue' | 'tms' | 'custom';
|
|
33
|
+
interface Metadata {
|
|
34
|
+
version: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
cliName: string;
|
|
37
|
+
}
|
|
38
|
+
interface Label {
|
|
39
|
+
/** Required, max 128 chars. Allure-style arbitrary label name — epic/feature/story/owner/severity
|
|
40
|
+
* are just conventional names, not separate fields. */
|
|
41
|
+
name: string;
|
|
42
|
+
/** Required, max 512 chars. */
|
|
43
|
+
value: string;
|
|
44
|
+
}
|
|
45
|
+
interface Link {
|
|
46
|
+
/** Required. A small, server-owned closed taxonomy — not open text. */
|
|
47
|
+
type: LinkType;
|
|
48
|
+
/** Optional, max 255 chars. */
|
|
49
|
+
name?: string;
|
|
50
|
+
/** Required, must be a valid URL, max 2048 chars. */
|
|
51
|
+
url: string;
|
|
52
|
+
}
|
|
53
|
+
interface Parameter {
|
|
54
|
+
name: string;
|
|
55
|
+
value?: string;
|
|
56
|
+
/** Display hint ONLY — the server does not redact this value. Do not treat
|
|
57
|
+
* this as real secret protection. */
|
|
58
|
+
masked?: boolean;
|
|
59
|
+
}
|
|
60
|
+
interface Step {
|
|
61
|
+
name: string;
|
|
62
|
+
keyword?: string;
|
|
63
|
+
/** Reuses the Case status vocabulary. */
|
|
64
|
+
status: CaseStatus | string;
|
|
65
|
+
/** NANOSECONDS — see `NanosecondDuration`. */
|
|
66
|
+
duration: NanosecondDuration;
|
|
67
|
+
error?: string;
|
|
68
|
+
location?: string;
|
|
69
|
+
/** 0-based index into the SAME Case's `steps[]` array identifying this
|
|
70
|
+
* step's parent, for nested/hierarchical steps. Omit for a root step.
|
|
71
|
+
* The server drops an out-of-range or cycle-forming value to root rather
|
|
72
|
+
* than rejecting the request — but a well-behaved client shouldn't rely
|
|
73
|
+
* on that. Server caps total steps per case at 1000. */
|
|
74
|
+
parentIndex?: number;
|
|
75
|
+
/** Server caps at 50 parameters per step. */
|
|
76
|
+
parameters?: Parameter[];
|
|
77
|
+
}
|
|
78
|
+
interface Attachment {
|
|
79
|
+
/** Required, max 255 chars. */
|
|
80
|
+
name: string;
|
|
81
|
+
/** Optional, max 1024 chars — informational only, never fetched server-side. */
|
|
82
|
+
path?: string;
|
|
83
|
+
/** Optional, max 255 chars. */
|
|
84
|
+
mimeType?: string;
|
|
85
|
+
/** Base64-encoded content, max 2,097,152 characters (~1.5MB decoded binary).
|
|
86
|
+
* Mutually exclusive with `storageKey` — used for small inline attachments. */
|
|
87
|
+
content?: string;
|
|
88
|
+
/** R2 object key from a prior `POST /api/v1/attachments/upload-url` call —
|
|
89
|
+
* mutually exclusive with `content`. Used for attachments too large to
|
|
90
|
+
* inline (video); if both are set, `storageKey` wins server-side. Max 1024
|
|
91
|
+
* chars. */
|
|
92
|
+
storageKey?: string;
|
|
93
|
+
/** Set when this is a video the reporter copied into the same output
|
|
94
|
+
* directory as the report file, rather than uploading it itself —
|
|
95
|
+
* `qualflare-cli` resolves this into a real `storageKey` at collect time.
|
|
96
|
+
* Relative to the report file's own directory. Never sent to `/collect`
|
|
97
|
+
* directly; mutually exclusive with `content`/`storageKey`. */
|
|
98
|
+
localVideoPath?: string;
|
|
99
|
+
/** Byte size of the object at `storageKey`. Ignored when `storageKey` is
|
|
100
|
+
* unset. */
|
|
101
|
+
fileSize?: number;
|
|
102
|
+
/** 0-based index into the Case's `steps[]` this attachment belongs to.
|
|
103
|
+
* Omit for a case-level (not step-level) attachment. */
|
|
104
|
+
stepIndex?: number;
|
|
105
|
+
}
|
|
106
|
+
interface Case {
|
|
107
|
+
/** Required. A stable per-test identifier used for flaky-history matching
|
|
108
|
+
* across separate runs — must stay the same for what a human would call
|
|
109
|
+
* "the same test" across renames you want tracked together. */
|
|
110
|
+
id: string;
|
|
111
|
+
/** Required, 1-255 chars. */
|
|
112
|
+
name: string;
|
|
113
|
+
/** Max 255 chars. */
|
|
114
|
+
className?: string;
|
|
115
|
+
/** Max 10000 chars. */
|
|
116
|
+
description?: string;
|
|
117
|
+
status: CaseStatus;
|
|
118
|
+
/** NANOSECONDS — see `NanosecondDuration`. */
|
|
119
|
+
duration: NanosecondDuration;
|
|
120
|
+
retryCount?: number;
|
|
121
|
+
isFlaky?: boolean;
|
|
122
|
+
/** Truncated server-side at 65536 runes, never validation-rejected — send
|
|
123
|
+
* the full error/stack text, don't pre-truncate. */
|
|
124
|
+
error?: string;
|
|
125
|
+
/** Unrecognized values are silently normalized/dropped server-side, never
|
|
126
|
+
* rejects the request. */
|
|
127
|
+
priority?: CasePriority;
|
|
128
|
+
/** Max 64 items, each max 255 chars. */
|
|
129
|
+
tags?: string[];
|
|
130
|
+
properties?: Record<string, string>;
|
|
131
|
+
/** Max 50 items. */
|
|
132
|
+
attachments?: Attachment[];
|
|
133
|
+
/** Server caps at 1000 items and truncates individual fields — never
|
|
134
|
+
* validation-rejected, send freely. */
|
|
135
|
+
steps?: Step[];
|
|
136
|
+
/** Not validated; the server drops an out-of-range value rather than
|
|
137
|
+
* rejecting the request. */
|
|
138
|
+
shardIndex?: number;
|
|
139
|
+
/** RFC3339. */
|
|
140
|
+
startedAt?: string;
|
|
141
|
+
/** Max 100 items. */
|
|
142
|
+
labels?: Label[];
|
|
143
|
+
/** Max 20 items. */
|
|
144
|
+
links?: Link[];
|
|
145
|
+
}
|
|
146
|
+
interface Suite {
|
|
147
|
+
/** Required, 1-255 chars. One Suite per Playwright spec file. */
|
|
148
|
+
name: string;
|
|
149
|
+
category?: FrameworkCategory;
|
|
150
|
+
assertions?: number;
|
|
151
|
+
/** NANOSECONDS — see `NanosecondDuration`. */
|
|
152
|
+
duration: NanosecondDuration;
|
|
153
|
+
/** RFC3339. */
|
|
154
|
+
timestamp?: string;
|
|
155
|
+
/** Max 64 chars. Per-suite override of the launch-level `browser` — omit
|
|
156
|
+
* to inherit the launch value. */
|
|
157
|
+
browser?: string;
|
|
158
|
+
/** Max 64 chars. Per-suite override of the launch-level `os`. */
|
|
159
|
+
os?: string;
|
|
160
|
+
properties?: Record<string, string>;
|
|
161
|
+
/** Max 5000 items. */
|
|
162
|
+
cases: Case[];
|
|
163
|
+
}
|
|
164
|
+
interface Collect {
|
|
165
|
+
/** Required, 1-100 chars. */
|
|
166
|
+
framework: string;
|
|
167
|
+
platform: Platform;
|
|
168
|
+
/** Required, 1-100 chars. */
|
|
169
|
+
os: string;
|
|
170
|
+
/** Max 64 chars. */
|
|
171
|
+
browser: string;
|
|
172
|
+
/** ALWAYS present as value-or-null on the wire — never omit this key. */
|
|
173
|
+
branch: string | null;
|
|
174
|
+
/** ALWAYS present as value-or-null on the wire — never omit this key. */
|
|
175
|
+
commit: string | null;
|
|
176
|
+
/** Required, 1-100 chars. Must already exist server-side (404 if not) —
|
|
177
|
+
* every project seeds `development`/`staging`/`production`/`qa` by
|
|
178
|
+
* default. */
|
|
179
|
+
environment: string;
|
|
180
|
+
/** Required, BCP47 (e.g. "en-US"). */
|
|
181
|
+
language: string;
|
|
182
|
+
/** ALWAYS present as value-or-null on the wire — never omit this key. */
|
|
183
|
+
milestone: number | null;
|
|
184
|
+
metadata: Metadata | null;
|
|
185
|
+
properties?: Record<string, string>;
|
|
186
|
+
/** Max 2000 items. */
|
|
187
|
+
suites: Suite[];
|
|
188
|
+
/** Max 64 chars. Free text, no enum — an unrecognized CI provider must
|
|
189
|
+
* never reject the request. */
|
|
190
|
+
ciProvider?: string;
|
|
191
|
+
/** Max 128 chars. */
|
|
192
|
+
ciBuildNumber?: string;
|
|
193
|
+
/** Must be a valid URL, max 2048 chars. */
|
|
194
|
+
ciRunUrl?: string;
|
|
195
|
+
/** Must be >= 1. */
|
|
196
|
+
ciPrNumber?: number;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Options for the reporter, passed as the second element of its entry in
|
|
200
|
+
* `playwright.config.ts`'s `reporter` array:
|
|
201
|
+
* `['@qualflare/playwright/reporter', { ... }]`. Every field here also has an
|
|
202
|
+
* environment-variable override — see the precedence table in
|
|
203
|
+
* `docs/CONFIGURATION.md`. */
|
|
204
|
+
interface QualflarePlaywrightOptions {
|
|
205
|
+
environment?: string;
|
|
206
|
+
language?: string;
|
|
207
|
+
milestone?: number | null;
|
|
208
|
+
branch?: string | null;
|
|
209
|
+
commit?: string | null;
|
|
210
|
+
platform?: Platform;
|
|
211
|
+
framework?: string;
|
|
212
|
+
os?: string;
|
|
213
|
+
browser?: string;
|
|
214
|
+
properties?: Record<string, string>;
|
|
215
|
+
/** Max 64 chars. Free text, no enum — an unrecognized CI provider must
|
|
216
|
+
* never be rejected. Auto-detected via `ci-detect.ts` when omitted. */
|
|
217
|
+
ciProvider?: string;
|
|
218
|
+
ciBuildNumber?: string;
|
|
219
|
+
ciRunUrl?: string;
|
|
220
|
+
ciPrNumber?: number;
|
|
221
|
+
attachScreenshots?: boolean;
|
|
222
|
+
/** Include Playwright's runner-internal steps — `pw:api` (every
|
|
223
|
+
* `page.click()`, `locator.fill()`, ...) and `fixture` (the implicit
|
|
224
|
+
* `browser`/`context`/`page` setup every browser test opens with) — as
|
|
225
|
+
* reported Steps.
|
|
226
|
+
*
|
|
227
|
+
* Off by default: a single browser test routinely produces hundreds of
|
|
228
|
+
* them, which buries the user-authored `test.step()`/`expect` boundaries
|
|
229
|
+
* that are actually legible in a report and blows through
|
|
230
|
+
* MAX_STEPS_PER_TEST_ATTEMPT on noise. A step that FAILED is always kept
|
|
231
|
+
* regardless of this setting, since a failing API call or fixture is
|
|
232
|
+
* usually the single most useful line in the trace. */
|
|
233
|
+
includeApiSteps?: boolean;
|
|
234
|
+
maxAttachmentBytes?: number;
|
|
235
|
+
maxTotalAttachmentBytes?: number;
|
|
236
|
+
/** Per-video byte cap, checked before the file is written. Default 50MB,
|
|
237
|
+
* matching the server's own hard cap. */
|
|
238
|
+
maxVideoBytes?: number;
|
|
239
|
+
debug?: boolean;
|
|
240
|
+
/** `false` fully disables accumulation/upload (a complete no-op) but the
|
|
241
|
+
* reporter still no-ops cleanly rather than throwing. */
|
|
242
|
+
enabled?: boolean;
|
|
243
|
+
/** Directory `onEnd()` writes this process's report file (and any
|
|
244
|
+
* video attachments) into. Default `./qualflare-results`. Always active —
|
|
245
|
+
* this reporter never uploads anything itself; `qualflare-cli` reads
|
|
246
|
+
* whatever ends up in this directory. Every JSON file this process writes
|
|
247
|
+
* is uniquely named, so multiple shards can safely share one `outputDir`
|
|
248
|
+
* without colliding — see docs/LIMITATIONS.md. */
|
|
249
|
+
outputDir?: string;
|
|
250
|
+
/** This process's 0-based position among parallel shards of the same CI
|
|
251
|
+
* run, stamped onto every case it reports. Purely a label: `qualflare-cli`
|
|
252
|
+
* merges by "every file in the directory", not by this value, so an
|
|
253
|
+
* unset shardIndex costs attribution, never correctness.
|
|
254
|
+
*
|
|
255
|
+
* Auto-detected, in order: `QUALFLARE_SHARD_INDEX`, then Playwright's own
|
|
256
|
+
* `--shard i/N`, which it exposes to reporters as `FullConfig.shard`
|
|
257
|
+
* ({ current, total }). Playwright's `current` is 1-BASED, so the reporter
|
|
258
|
+
* converts it before passing it here as `deps.detectedShardIndex`.
|
|
259
|
+
*
|
|
260
|
+
* This is the one place Playwright is markedly better than its siblings:
|
|
261
|
+
* Cypress has no shard concept at all, and cucumber-js hides its `--shard`
|
|
262
|
+
* from formatters entirely (forcing an argv scrape). Here the runner just
|
|
263
|
+
* tells us. */
|
|
264
|
+
shardIndex?: number;
|
|
265
|
+
}
|
|
266
|
+
interface ResolvedReporterConfig {
|
|
267
|
+
environment: string;
|
|
268
|
+
language: string;
|
|
269
|
+
milestone: number | null;
|
|
270
|
+
branch: string | null;
|
|
271
|
+
commit: string | null;
|
|
272
|
+
platform: Platform;
|
|
273
|
+
framework: string;
|
|
274
|
+
os?: string;
|
|
275
|
+
browser?: string;
|
|
276
|
+
properties?: Record<string, string>;
|
|
277
|
+
ciProvider?: string;
|
|
278
|
+
ciBuildNumber?: string;
|
|
279
|
+
ciRunUrl?: string;
|
|
280
|
+
ciPrNumber?: number;
|
|
281
|
+
attachScreenshots: boolean;
|
|
282
|
+
includeApiSteps: boolean;
|
|
283
|
+
maxAttachmentBytes: number;
|
|
284
|
+
maxTotalAttachmentBytes: number;
|
|
285
|
+
maxVideoBytes: number;
|
|
286
|
+
debug: boolean;
|
|
287
|
+
enabled: boolean;
|
|
288
|
+
outputDir: string;
|
|
289
|
+
shardIndex?: number;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export type { Attachment as A, CasePriority as C, FrameworkCategory as F, LinkType as L, Metadata as M, NanosecondDuration as N, Parameter as P, QualflarePlaywrightOptions as Q, ResolvedReporterConfig as R, Step as S, Case as a, CaseStatus as b, Collect as c, Label as d, Link as e, Platform as f, Suite as g };
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qualflare/playwright",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Native Playwright reporter for the Qualflare test-management platform.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"qualflare",
|
|
7
|
+
"playwright",
|
|
8
|
+
"playwright-reporter",
|
|
9
|
+
"test-reporter",
|
|
10
|
+
"e2e",
|
|
11
|
+
"test-results",
|
|
12
|
+
"flaky-tests",
|
|
13
|
+
"test-reporting"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://qualflare.com",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/Qualflare/qualflare-playwright/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Qualflare/qualflare-playwright.git"
|
|
22
|
+
},
|
|
23
|
+
"license": "Apache-2.0",
|
|
24
|
+
"author": "Qualflare",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"require": "./dist/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./reporter": {
|
|
36
|
+
"types": "./dist/reporter/index.d.ts",
|
|
37
|
+
"import": "./dist/reporter/index.js",
|
|
38
|
+
"require": "./dist/reporter/index.cjs"
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"provenance": true
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@playwright/test": ">=1.40.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"ci-info": "^4.0.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@playwright/test": "^1.56.0",
|
|
62
|
+
"@types/node": "^18.19.50",
|
|
63
|
+
"eslint": "^9.9.1",
|
|
64
|
+
"execa": "^9.3.1",
|
|
65
|
+
"prettier": "^3.3.3",
|
|
66
|
+
"tsup": "^8.2.4",
|
|
67
|
+
"typescript": "^5.6.2",
|
|
68
|
+
"typescript-eslint": "^8.5.0",
|
|
69
|
+
"vitest": "^2.0.5"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsup",
|
|
73
|
+
"dev": "tsup --watch",
|
|
74
|
+
"typecheck": "tsc --noEmit",
|
|
75
|
+
"lint": "eslint .",
|
|
76
|
+
"test": "vitest run test/unit",
|
|
77
|
+
"test:integration": "vitest run test/integration --pool=forks --testTimeout=120000",
|
|
78
|
+
"test:all": "npm run test && npm run test:integration",
|
|
79
|
+
"prepublishOnly": "npm run build"
|
|
80
|
+
}
|
|
81
|
+
}
|