walkwright 0.0.1
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 +21 -0
- package/README.md +276 -0
- package/bin/walkwright.js +3 -0
- package/build/aria.d.ts +92 -0
- package/build/aria.js +215 -0
- package/build/aria.js.map +1 -0
- package/build/browser.d.ts +3 -0
- package/build/browser.js +18 -0
- package/build/browser.js.map +1 -0
- package/build/chunk-5CHKYNP7.js +507 -0
- package/build/chunk-5CHKYNP7.js.map +1 -0
- package/build/chunk-6YRKPGUO.js +1197 -0
- package/build/chunk-6YRKPGUO.js.map +1 -0
- package/build/chunk-A452S7R3.js +35 -0
- package/build/chunk-A452S7R3.js.map +1 -0
- package/build/chunk-BODO6HIH.js +60 -0
- package/build/chunk-BODO6HIH.js.map +1 -0
- package/build/chunk-FJI2CMCE.js +439 -0
- package/build/chunk-FJI2CMCE.js.map +1 -0
- package/build/chunk-JYHZVRB2.js +80 -0
- package/build/chunk-JYHZVRB2.js.map +1 -0
- package/build/chunk-KQN5IYN6.js +97 -0
- package/build/chunk-KQN5IYN6.js.map +1 -0
- package/build/chunk-KTXNERHT.js +72 -0
- package/build/chunk-KTXNERHT.js.map +1 -0
- package/build/chunk-MFTC7XL2.js +141 -0
- package/build/chunk-MFTC7XL2.js.map +1 -0
- package/build/chunk-N4SSLHMP.js +108 -0
- package/build/chunk-N4SSLHMP.js.map +1 -0
- package/build/chunk-RNNW7OW2.js +270 -0
- package/build/chunk-RNNW7OW2.js.map +1 -0
- package/build/chunk-UAWBPTDW.js +51 -0
- package/build/chunk-UAWBPTDW.js.map +1 -0
- package/build/chunk-Z7CW5CAY.js +64 -0
- package/build/chunk-Z7CW5CAY.js.map +1 -0
- package/build/cli.d.ts +1 -0
- package/build/cli.js +253 -0
- package/build/cli.js.map +1 -0
- package/build/config.d.ts +13 -0
- package/build/config.js +15 -0
- package/build/config.js.map +1 -0
- package/build/descriptor.d.ts +96 -0
- package/build/descriptor.js +27 -0
- package/build/descriptor.js.map +1 -0
- package/build/device-auth.d.ts +6 -0
- package/build/device-auth.js +11 -0
- package/build/device-auth.js.map +1 -0
- package/build/locator.d.ts +140 -0
- package/build/locator.js +92 -0
- package/build/locator.js.map +1 -0
- package/build/paths.d.ts +11 -0
- package/build/paths.js +22 -0
- package/build/paths.js.map +1 -0
- package/build/pom-kcSMxwX2.d.ts +349 -0
- package/build/pom.d.ts +6 -0
- package/build/pom.js +37 -0
- package/build/pom.js.map +1 -0
- package/build/project.d.ts +13 -0
- package/build/project.js +19 -0
- package/build/project.js.map +1 -0
- package/build/provisioner.d.ts +34 -0
- package/build/provisioner.js +14 -0
- package/build/provisioner.js.map +1 -0
- package/build/recorder.d.ts +6 -0
- package/build/recorder.js +15 -0
- package/build/recorder.js.map +1 -0
- package/build/reporter.d.ts +16 -0
- package/build/reporter.js +426 -0
- package/build/reporter.js.map +1 -0
- package/build/schema.d.ts +49 -0
- package/build/schema.js +16 -0
- package/build/schema.js.map +1 -0
- package/build/storage-state.d.ts +22 -0
- package/build/storage-state.js +42 -0
- package/build/storage-state.js.map +1 -0
- package/build/store.d.ts +17 -0
- package/build/store.js +9 -0
- package/build/store.js.map +1 -0
- package/build/ui.d.ts +49 -0
- package/build/ui.js +56 -0
- package/build/ui.js.map +1 -0
- package/build/upload.d.ts +10 -0
- package/build/upload.js +8 -0
- package/build/upload.js.map +1 -0
- package/build/wait.d.ts +14 -0
- package/build/wait.js +50 -0
- package/build/wait.js.map +1 -0
- package/package.json +52 -0
- package/src/aria.ts +326 -0
- package/src/browser.ts +15 -0
- package/src/cli.ts +295 -0
- package/src/config.ts +16 -0
- package/src/descriptor.ts +179 -0
- package/src/device-auth.ts +188 -0
- package/src/locator.ts +683 -0
- package/src/paths.ts +70 -0
- package/src/pom.ts +2363 -0
- package/src/project.ts +77 -0
- package/src/provisioner.ts +183 -0
- package/src/recorder.ts +877 -0
- package/src/reporter.ts +561 -0
- package/src/schema.ts +37 -0
- package/src/storage-state.ts +71 -0
- package/src/store.ts +96 -0
- package/src/ui.ts +333 -0
- package/src/upload.ts +116 -0
- package/src/wait.ts +63 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import {
|
|
2
|
+
uploadRun
|
|
3
|
+
} from "./chunk-JYHZVRB2.js";
|
|
4
|
+
import {
|
|
5
|
+
manifestSchema,
|
|
6
|
+
manifestVersion
|
|
7
|
+
} from "./chunk-A452S7R3.js";
|
|
8
|
+
import {
|
|
9
|
+
describeError,
|
|
10
|
+
runDirVariable,
|
|
11
|
+
shotsAttachment
|
|
12
|
+
} from "./chunk-5CHKYNP7.js";
|
|
13
|
+
import {
|
|
14
|
+
currentBranch,
|
|
15
|
+
describeConfigPath,
|
|
16
|
+
readWalkwrightConfig,
|
|
17
|
+
repoName
|
|
18
|
+
} from "./chunk-Z7CW5CAY.js";
|
|
19
|
+
import {
|
|
20
|
+
blank,
|
|
21
|
+
bold,
|
|
22
|
+
box,
|
|
23
|
+
columns,
|
|
24
|
+
count,
|
|
25
|
+
duration,
|
|
26
|
+
failure,
|
|
27
|
+
glyph,
|
|
28
|
+
line,
|
|
29
|
+
pad,
|
|
30
|
+
paint,
|
|
31
|
+
progress,
|
|
32
|
+
status,
|
|
33
|
+
transient,
|
|
34
|
+
width
|
|
35
|
+
} from "./chunk-RNNW7OW2.js";
|
|
36
|
+
import "./chunk-FJI2CMCE.js";
|
|
37
|
+
import {
|
|
38
|
+
ensureWalkwrightDir,
|
|
39
|
+
reportsDir
|
|
40
|
+
} from "./chunk-BODO6HIH.js";
|
|
41
|
+
import "./chunk-UAWBPTDW.js";
|
|
42
|
+
|
|
43
|
+
// src/reporter.ts
|
|
44
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
45
|
+
import { basename, join, relative } from "path";
|
|
46
|
+
var WalkwrightReporter = class {
|
|
47
|
+
#appUrl;
|
|
48
|
+
#startedAt = /* @__PURE__ */ new Date();
|
|
49
|
+
#runDir;
|
|
50
|
+
#recorded = [];
|
|
51
|
+
#failures = /* @__PURE__ */ new Map();
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this.#appUrl = options.appUrl;
|
|
54
|
+
if (options.reportsDir === void 0) {
|
|
55
|
+
ensureWalkwrightDir();
|
|
56
|
+
}
|
|
57
|
+
this.#runDir = join(
|
|
58
|
+
options.reportsDir ?? reportsDir(),
|
|
59
|
+
`run-${this.#startedAt.toISOString().replace(/[:.]/g, "-")}`
|
|
60
|
+
);
|
|
61
|
+
process.env[runDirVariable] = this.#runDir;
|
|
62
|
+
}
|
|
63
|
+
onTestEnd(test, result) {
|
|
64
|
+
if (result.status !== "passed") {
|
|
65
|
+
if (result.status !== "skipped") {
|
|
66
|
+
this.#failures.set(test.id, {
|
|
67
|
+
step: test.title,
|
|
68
|
+
lane: laneOf(test)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.#failures.delete(test.id);
|
|
74
|
+
for (const attachment of result.attachments) {
|
|
75
|
+
if (attachment.name !== shotsAttachment || attachment.body === void 0) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
this.#recorded.push({
|
|
79
|
+
test: test.title,
|
|
80
|
+
lane: laneOf(test),
|
|
81
|
+
shots: JSON.parse(attachment.body.toString("utf8"))
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async onEnd(result) {
|
|
86
|
+
const failures = [...this.#failures.values()];
|
|
87
|
+
if (this.#recorded.length === 0 && failures.length === 0) {
|
|
88
|
+
blank();
|
|
89
|
+
line(paint("dim", " no pages walked"));
|
|
90
|
+
return void 0;
|
|
91
|
+
}
|
|
92
|
+
const elapsedMs = Date.now() - this.#startedAt.getTime();
|
|
93
|
+
let manifest;
|
|
94
|
+
try {
|
|
95
|
+
manifest = this.#manifest(elapsedMs);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
blank();
|
|
98
|
+
failure(
|
|
99
|
+
describeError(error),
|
|
100
|
+
"fix the lane and run walkwright walk again"
|
|
101
|
+
);
|
|
102
|
+
return { status: "failed" };
|
|
103
|
+
}
|
|
104
|
+
const branch = currentBranch();
|
|
105
|
+
blank();
|
|
106
|
+
for (const row of box(walkRows(treePages(this.#recorded), failures), {
|
|
107
|
+
legend: "walk",
|
|
108
|
+
title: `${repoName()} ${glyph.dot} ${branch}`,
|
|
109
|
+
primary: true
|
|
110
|
+
})) {
|
|
111
|
+
line(row);
|
|
112
|
+
}
|
|
113
|
+
const shots = manifest.subjects.reduce(
|
|
114
|
+
(total, subject) => total + subject.states.reduce(
|
|
115
|
+
(stateTotal, state) => stateTotal + state.captures.length,
|
|
116
|
+
0
|
|
117
|
+
),
|
|
118
|
+
0
|
|
119
|
+
);
|
|
120
|
+
const summary = `${count(shots, "shot")} ${paint("dim", glyph.dot)} ${duration(elapsedMs)}`;
|
|
121
|
+
const failed = result.status !== "passed";
|
|
122
|
+
const walkFailed = paint("fail", `${glyph.fail} walk failed`);
|
|
123
|
+
if (this.#recorded.length === 0) {
|
|
124
|
+
line(status(summary, walkFailed, paint("dim", "nothing to upload")));
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
mkdirSync(this.#runDir, { recursive: true });
|
|
128
|
+
writeFileSync(
|
|
129
|
+
join(this.#runDir, "manifest.json"),
|
|
130
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
131
|
+
`,
|
|
132
|
+
"utf8"
|
|
133
|
+
);
|
|
134
|
+
const runDir = paint("code", relative(process.cwd(), this.#runDir));
|
|
135
|
+
if (shots === 0) {
|
|
136
|
+
line(status(summary, paint("dim", "nothing to upload"), runDir));
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
if (process.env["WALKWRIGHT_NO_UPLOAD"] === "1") {
|
|
140
|
+
line(status(summary, paint("dim", "not uploaded (--no-upload)"), runDir));
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
143
|
+
if (failed && process.env["WALKWRIGHT_UPLOAD_ON_FAIL"] !== "1") {
|
|
144
|
+
line(status(summary, walkFailed, paint("dim", "not uploaded"), runDir));
|
|
145
|
+
line(
|
|
146
|
+
paint(
|
|
147
|
+
"dim",
|
|
148
|
+
" walkwright walk --upload-on-fail uploads the passing lanes"
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
let config;
|
|
154
|
+
try {
|
|
155
|
+
config = readWalkwrightConfig();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
line(
|
|
158
|
+
status(
|
|
159
|
+
summary,
|
|
160
|
+
failed ? walkFailed : "",
|
|
161
|
+
paint("dim", "not uploaded"),
|
|
162
|
+
runDir
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
failure(
|
|
166
|
+
describeError(error),
|
|
167
|
+
`fix ${describeConfigPath()} or delete it and run walkwright login`
|
|
168
|
+
);
|
|
169
|
+
return { status: "failed" };
|
|
170
|
+
}
|
|
171
|
+
if (config === void 0) {
|
|
172
|
+
line(
|
|
173
|
+
status(
|
|
174
|
+
summary,
|
|
175
|
+
failed ? walkFailed : "",
|
|
176
|
+
paint("dim", "not uploaded"),
|
|
177
|
+
runDir
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
line(
|
|
181
|
+
paint(
|
|
182
|
+
"dim",
|
|
183
|
+
` no ${describeConfigPath()} ${glyph.dot} walkwright login to upload`
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
return void 0;
|
|
187
|
+
}
|
|
188
|
+
const kept = failed ? paint("warn", `${glyph.carried} kept ${this.#keptLanes().join(", ")}`) : "";
|
|
189
|
+
if (!process.stdout.isTTY) {
|
|
190
|
+
line(paint("dim", ` uploading ${count(shots, "shot")}`));
|
|
191
|
+
}
|
|
192
|
+
const files = [
|
|
193
|
+
"manifest.json",
|
|
194
|
+
...manifest.subjects.flatMap(
|
|
195
|
+
(subject) => subject.states.flatMap(
|
|
196
|
+
(state) => state.captures.flatMap((capture) => Object.values(capture.files))
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
];
|
|
200
|
+
let uploaded;
|
|
201
|
+
try {
|
|
202
|
+
uploaded = await uploadRun(
|
|
203
|
+
config,
|
|
204
|
+
branch,
|
|
205
|
+
this.#runDir,
|
|
206
|
+
files,
|
|
207
|
+
uploadProgress
|
|
208
|
+
);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
line(status(summary, failed ? walkFailed : "", kept));
|
|
211
|
+
failure(
|
|
212
|
+
describeError(error),
|
|
213
|
+
"run walkwright walk again to retry the upload"
|
|
214
|
+
);
|
|
215
|
+
return { status: "failed" };
|
|
216
|
+
}
|
|
217
|
+
const as = uploaded.number === void 0 ? "uploaded" : `uploaded as ${bold(`#${String(uploaded.number)}`)}`;
|
|
218
|
+
const url = paint("accent", uploaded.url);
|
|
219
|
+
const room = process.stdout.isTTY ? columns() - 1 : Infinity;
|
|
220
|
+
for (const candidate of [
|
|
221
|
+
status(summary, failed ? walkFailed : "", kept, as, url),
|
|
222
|
+
status(summary, failed ? walkFailed : "", as, url)
|
|
223
|
+
]) {
|
|
224
|
+
if (width(candidate) <= room) {
|
|
225
|
+
line(candidate);
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const head = status(summary, failed ? walkFailed : "", kept, as);
|
|
230
|
+
line(
|
|
231
|
+
width(head) <= room ? head : status(summary, failed ? walkFailed : "", as)
|
|
232
|
+
);
|
|
233
|
+
line(` ${url}`);
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
#keptLanes() {
|
|
237
|
+
return [
|
|
238
|
+
...new Set(
|
|
239
|
+
this.#recorded.filter(({ shots }) => shots.shots.length > 0).map(({ lane }) => lane)
|
|
240
|
+
)
|
|
241
|
+
];
|
|
242
|
+
}
|
|
243
|
+
#manifest(durationMs) {
|
|
244
|
+
const subjects = [];
|
|
245
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
246
|
+
const captured = /* @__PURE__ */ new Map();
|
|
247
|
+
const files = /* @__PURE__ */ new Map();
|
|
248
|
+
for (const { lane, shots } of this.#recorded) {
|
|
249
|
+
for (const shot of shots.shots) {
|
|
250
|
+
const path = [...shot.group ?? [], shot.page];
|
|
251
|
+
const pathKey = JSON.stringify(path);
|
|
252
|
+
const name = shot.state === "" ? "default" : shot.state;
|
|
253
|
+
const identityKey = `${pathKey}#${name}`;
|
|
254
|
+
const identityLane = captured.get(identityKey);
|
|
255
|
+
if (identityLane !== void 0) {
|
|
256
|
+
if (identityLane !== lane) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`"${identityLane}" and "${lane}" both captured ${describeShot(shot)} \u2014 record it in one lane, or give one of them another state`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
throw new Error(
|
|
262
|
+
`"${lane}" captured ${describeShot(shot)} twice \u2014 record it once, or give one of them another state`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
captured.set(identityKey, lane);
|
|
266
|
+
const fileLane = files.get(shot.file);
|
|
267
|
+
if (fileLane !== void 0 && fileLane !== lane) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
`"${fileLane}" and "${lane}" both wrote ${shot.file} \u2014 rename one of the "${shot.page}" pages`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
files.set(shot.file, lane);
|
|
273
|
+
let subject = byPath.get(pathKey);
|
|
274
|
+
if (subject === void 0) {
|
|
275
|
+
const url = shot.path !== void 0 && !shot.path.includes(":") ? shot.path : void 0;
|
|
276
|
+
subject = {
|
|
277
|
+
path,
|
|
278
|
+
...url === void 0 ? {} : { url },
|
|
279
|
+
states: []
|
|
280
|
+
};
|
|
281
|
+
byPath.set(pathKey, subject);
|
|
282
|
+
subjects.push(subject);
|
|
283
|
+
}
|
|
284
|
+
const state = {
|
|
285
|
+
name,
|
|
286
|
+
captures: [{ files: { image: shot.file } }]
|
|
287
|
+
};
|
|
288
|
+
subject.states.push(state);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return manifestSchema.parse({
|
|
292
|
+
version: manifestVersion,
|
|
293
|
+
tool: "walkwright",
|
|
294
|
+
url: this.#appUrl,
|
|
295
|
+
startedAt: this.#startedAt.toISOString(),
|
|
296
|
+
runStats: {
|
|
297
|
+
duration: duration(durationMs),
|
|
298
|
+
lanes: this.#keptLanes().length
|
|
299
|
+
},
|
|
300
|
+
subjects
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
function describeShot(shot) {
|
|
305
|
+
const page = shot.path === void 0 ? `"${shot.page}"` : `"${shot.page}" (${shot.path})`;
|
|
306
|
+
return shot.state === "" ? page : `the "${shot.state}" state of ${page}`;
|
|
307
|
+
}
|
|
308
|
+
function laneOf(test) {
|
|
309
|
+
return basename(test.location.file).replace(/(\.\w+)?\.ts$/, "");
|
|
310
|
+
}
|
|
311
|
+
function treePages(recorded) {
|
|
312
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
313
|
+
const pages = [];
|
|
314
|
+
const keyOf = (group, name) => JSON.stringify([...group ?? [], name]);
|
|
315
|
+
for (const { shots } of recorded) {
|
|
316
|
+
for (const page of shots.pages) {
|
|
317
|
+
const key = keyOf(page.group, page.name);
|
|
318
|
+
if (!byKey.has(key)) {
|
|
319
|
+
const entry = {
|
|
320
|
+
name: page.name,
|
|
321
|
+
...page.group === void 0 ? {} : { group: page.group },
|
|
322
|
+
shots: 0
|
|
323
|
+
};
|
|
324
|
+
byKey.set(key, entry);
|
|
325
|
+
pages.push(entry);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
for (const { shots } of recorded) {
|
|
330
|
+
for (const shot of shots.shots) {
|
|
331
|
+
const key = keyOf(shot.group, shot.page);
|
|
332
|
+
let entry = byKey.get(key);
|
|
333
|
+
if (entry === void 0) {
|
|
334
|
+
entry = {
|
|
335
|
+
name: shot.page,
|
|
336
|
+
...shot.group === void 0 ? {} : { group: shot.group },
|
|
337
|
+
shots: 0
|
|
338
|
+
};
|
|
339
|
+
byKey.set(key, entry);
|
|
340
|
+
pages.push(entry);
|
|
341
|
+
}
|
|
342
|
+
entry.shots += 1;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return pages;
|
|
346
|
+
}
|
|
347
|
+
function walkRows(pages, failures) {
|
|
348
|
+
const root = buildTree(pages);
|
|
349
|
+
const rows = [];
|
|
350
|
+
const walk = (folder, depth) => {
|
|
351
|
+
const indent = " ".repeat(depth);
|
|
352
|
+
const entries = folder.pages;
|
|
353
|
+
for (const [index, page] of entries.entries()) {
|
|
354
|
+
const last = index === entries.length - 1 && folder.folders.length === 0;
|
|
355
|
+
rows.push([
|
|
356
|
+
`${indent}${paint("faint", last ? glyph.last : glyph.branch)} ${paint("text", page.name)}`,
|
|
357
|
+
page.shots === 0 ? paint("dim", "no shots") : `${paint("ok", glyph.ok)} ${paint("dim", count(page.shots, "shot"))}`
|
|
358
|
+
]);
|
|
359
|
+
}
|
|
360
|
+
for (const child of folder.folders) {
|
|
361
|
+
rows.push([
|
|
362
|
+
`${indent}${paint("accent", glyph.open)} ${bold(paint("text", child.name))}`,
|
|
363
|
+
""
|
|
364
|
+
]);
|
|
365
|
+
walk(child, depth + 1);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
walk(root, 0);
|
|
369
|
+
const labelWidth = rows.reduce(
|
|
370
|
+
(max, [label]) => Math.max(max, width(label)),
|
|
371
|
+
0
|
|
372
|
+
);
|
|
373
|
+
const out = rows.map(
|
|
374
|
+
([label, note]) => note === "" ? label : `${pad(label, labelWidth)} ${note}`
|
|
375
|
+
);
|
|
376
|
+
if (failures.length > 0) {
|
|
377
|
+
if (out.length > 0) {
|
|
378
|
+
out.push("");
|
|
379
|
+
}
|
|
380
|
+
for (const failed of failures) {
|
|
381
|
+
out.push(
|
|
382
|
+
`${paint("fail", `${glyph.fail} ${failed.lane}`)} ${paint("dim", glyph.dot)} ${paint("text", `"${failed.step}"`)} ${paint("fail", "failed")}`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
function buildTree(pages) {
|
|
389
|
+
const root = { name: "", folders: [], pages: [] };
|
|
390
|
+
for (const page of pages) {
|
|
391
|
+
let folder = root;
|
|
392
|
+
for (const name of page.group ?? []) {
|
|
393
|
+
let next = folder.folders.find((child) => child.name === name);
|
|
394
|
+
if (next === void 0) {
|
|
395
|
+
next = { name, folders: [], pages: [] };
|
|
396
|
+
folder.folders.push(next);
|
|
397
|
+
}
|
|
398
|
+
folder = next;
|
|
399
|
+
}
|
|
400
|
+
folder.pages.push(page);
|
|
401
|
+
}
|
|
402
|
+
sortFolder(root);
|
|
403
|
+
return root;
|
|
404
|
+
}
|
|
405
|
+
function sortFolder(folder) {
|
|
406
|
+
folder.pages.sort((a, b) => compare(a.name, b.name));
|
|
407
|
+
folder.folders.sort((a, b) => compare(a.name, b.name));
|
|
408
|
+
for (const child of folder.folders) {
|
|
409
|
+
sortFolder(child);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function compare(a, b) {
|
|
413
|
+
return a.localeCompare(b, void 0, { sensitivity: "base" });
|
|
414
|
+
}
|
|
415
|
+
function uploadProgress(done, total, file) {
|
|
416
|
+
const clear = transient(
|
|
417
|
+
` ${progress(done, total)} ${paint("dim", `uploading ${String(done)}/${String(total)}`)} ${paint("code", file)}`
|
|
418
|
+
);
|
|
419
|
+
if (done === total) {
|
|
420
|
+
clear();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
export {
|
|
424
|
+
WalkwrightReporter as default
|
|
425
|
+
};
|
|
426
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { basename, join, relative } from \"node:path\";\n\nimport type {\n FullResult,\n Reporter,\n TestCase,\n TestResult,\n} from \"@playwright/test/reporter\";\n\nimport { ensureWalkwrightDir, reportsDir } from \"./paths.js\";\nimport type { WalkwrightConfig } from \"./project.js\";\nimport {\n currentBranch,\n describeConfigPath,\n readWalkwrightConfig,\n repoName,\n} from \"./project.js\";\nimport type { RecordedShots, ShotRecord } from \"./recorder.js\";\nimport { describeError, runDirVariable, shotsAttachment } from \"./recorder.js\";\nimport type { Manifest, State, Subject } from \"./schema.js\";\nimport { manifestSchema, manifestVersion } from \"./schema.js\";\nimport {\n blank,\n bold,\n box,\n columns,\n count,\n duration,\n failure,\n glyph,\n line,\n pad,\n paint,\n progress,\n status,\n transient,\n width,\n} from \"./ui.js\";\nimport { uploadRun } from \"./upload.js\";\n\nexport interface ReporterOptions {\n appUrl: string;\n reportsDir?: string;\n}\n\ninterface Recorded {\n test: string;\n lane: string;\n shots: RecordedShots;\n}\n\ninterface WalkFailure {\n step: string;\n lane: string;\n}\n\ninterface TreePage {\n name: string;\n group?: string[];\n shots: number;\n}\n\ninterface Folder {\n name: string;\n folders: Folder[];\n pages: TreePage[];\n}\n\nexport default class WalkwrightReporter implements Reporter {\n readonly #appUrl: string;\n readonly #startedAt = new Date();\n readonly #runDir: string;\n readonly #recorded: Recorded[] = [];\n readonly #failures = new Map<string, WalkFailure>();\n\n public constructor(options: ReporterOptions) {\n this.#appUrl = options.appUrl;\n\n if (options.reportsDir === undefined) {\n ensureWalkwrightDir();\n }\n\n this.#runDir = join(\n options.reportsDir ?? reportsDir(),\n `run-${this.#startedAt.toISOString().replace(/[:.]/g, \"-\")}`,\n );\n\n process.env[runDirVariable] = this.#runDir;\n }\n\n public onTestEnd(test: TestCase, result: TestResult): void {\n if (result.status !== \"passed\") {\n if (result.status !== \"skipped\") {\n this.#failures.set(test.id, {\n step: test.title,\n lane: laneOf(test),\n });\n }\n\n return;\n }\n\n this.#failures.delete(test.id);\n\n for (const attachment of result.attachments) {\n if (\n attachment.name !== shotsAttachment ||\n attachment.body === undefined\n ) {\n continue;\n }\n\n this.#recorded.push({\n test: test.title,\n lane: laneOf(test),\n shots: JSON.parse(attachment.body.toString(\"utf8\")) as RecordedShots,\n });\n }\n }\n\n public async onEnd(\n result: FullResult,\n ): Promise<{ status: FullResult[\"status\"] } | undefined> {\n const failures = [...this.#failures.values()];\n\n if (this.#recorded.length === 0 && failures.length === 0) {\n blank();\n line(paint(\"dim\", \" no pages walked\"));\n return undefined;\n }\n\n const elapsedMs = Date.now() - this.#startedAt.getTime();\n\n let manifest: Manifest;\n\n try {\n manifest = this.#manifest(elapsedMs);\n } catch (error) {\n blank();\n failure(\n describeError(error),\n \"fix the lane and run walkwright walk again\",\n );\n return { status: \"failed\" };\n }\n\n const branch = currentBranch();\n\n blank();\n\n for (const row of box(walkRows(treePages(this.#recorded), failures), {\n legend: \"walk\",\n title: `${repoName()} ${glyph.dot} ${branch}`,\n primary: true,\n })) {\n line(row);\n }\n\n const shots = manifest.subjects.reduce(\n (total, subject) =>\n total +\n subject.states.reduce(\n (stateTotal, state) => stateTotal + state.captures.length,\n 0,\n ),\n 0,\n );\n const summary = `${count(shots, \"shot\")} ${paint(\"dim\", glyph.dot)} ${duration(elapsedMs)}`;\n const failed = result.status !== \"passed\";\n const walkFailed = paint(\"fail\", `${glyph.fail} walk failed`);\n\n if (this.#recorded.length === 0) {\n line(status(summary, walkFailed, paint(\"dim\", \"nothing to upload\")));\n return undefined;\n }\n\n mkdirSync(this.#runDir, { recursive: true });\n\n writeFileSync(\n join(this.#runDir, \"manifest.json\"),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\",\n );\n\n const runDir = paint(\"code\", relative(process.cwd(), this.#runDir));\n\n if (shots === 0) {\n line(status(summary, paint(\"dim\", \"nothing to upload\"), runDir));\n return undefined;\n }\n\n if (process.env[\"WALKWRIGHT_NO_UPLOAD\"] === \"1\") {\n line(status(summary, paint(\"dim\", \"not uploaded (--no-upload)\"), runDir));\n return undefined;\n }\n\n if (failed && process.env[\"WALKWRIGHT_UPLOAD_ON_FAIL\"] !== \"1\") {\n line(status(summary, walkFailed, paint(\"dim\", \"not uploaded\"), runDir));\n line(\n paint(\n \"dim\",\n \" walkwright walk --upload-on-fail uploads the passing lanes\",\n ),\n );\n return undefined;\n }\n\n let config: WalkwrightConfig | undefined;\n\n try {\n config = readWalkwrightConfig();\n } catch (error) {\n line(\n status(\n summary,\n failed ? walkFailed : \"\",\n paint(\"dim\", \"not uploaded\"),\n runDir,\n ),\n );\n failure(\n describeError(error),\n `fix ${describeConfigPath()} or delete it and run walkwright login`,\n );\n return { status: \"failed\" };\n }\n\n if (config === undefined) {\n line(\n status(\n summary,\n failed ? walkFailed : \"\",\n paint(\"dim\", \"not uploaded\"),\n runDir,\n ),\n );\n line(\n paint(\n \"dim\",\n ` no ${describeConfigPath()} ${glyph.dot} walkwright login to upload`,\n ),\n );\n return undefined;\n }\n\n const kept = failed\n ? paint(\"warn\", `${glyph.carried} kept ${this.#keptLanes().join(\", \")}`)\n : \"\";\n\n if (!process.stdout.isTTY) {\n line(paint(\"dim\", ` uploading ${count(shots, \"shot\")}`));\n }\n\n const files = [\n \"manifest.json\",\n ...manifest.subjects.flatMap((subject) =>\n subject.states.flatMap((state) =>\n state.captures.flatMap((capture) => Object.values(capture.files)),\n ),\n ),\n ];\n\n let uploaded: { url: string; number: number | undefined };\n\n try {\n uploaded = await uploadRun(\n config,\n branch,\n this.#runDir,\n files,\n uploadProgress,\n );\n } catch (error) {\n line(status(summary, failed ? walkFailed : \"\", kept));\n failure(\n describeError(error),\n \"run walkwright walk again to retry the upload\",\n );\n return { status: \"failed\" };\n }\n\n const as =\n uploaded.number === undefined\n ? \"uploaded\"\n : `uploaded as ${bold(`#${String(uploaded.number)}`)}`;\n const url = paint(\"accent\", uploaded.url);\n const room = process.stdout.isTTY ? columns() - 1 : Infinity;\n\n for (const candidate of [\n status(summary, failed ? walkFailed : \"\", kept, as, url),\n status(summary, failed ? walkFailed : \"\", as, url),\n ]) {\n if (width(candidate) <= room) {\n line(candidate);\n return undefined;\n }\n }\n\n const head = status(summary, failed ? walkFailed : \"\", kept, as);\n\n line(\n width(head) <= room\n ? head\n : status(summary, failed ? walkFailed : \"\", as),\n );\n line(` ${url}`);\n\n return undefined;\n }\n\n #keptLanes(): string[] {\n return [\n ...new Set(\n this.#recorded\n .filter(({ shots }) => shots.shots.length > 0)\n .map(({ lane }) => lane),\n ),\n ];\n }\n\n #manifest(durationMs: number): Manifest {\n const subjects: Subject[] = [];\n const byPath = new Map<string, Subject>();\n const captured = new Map<string, string>();\n const files = new Map<string, string>();\n\n for (const { lane, shots } of this.#recorded) {\n for (const shot of shots.shots) {\n const path = [...(shot.group ?? []), shot.page];\n const pathKey = JSON.stringify(path);\n const name = shot.state === \"\" ? \"default\" : shot.state;\n const identityKey = `${pathKey}#${name}`;\n\n const identityLane = captured.get(identityKey);\n\n if (identityLane !== undefined) {\n if (identityLane !== lane) {\n throw new Error(\n `\"${identityLane}\" and \"${lane}\" both captured ${describeShot(shot)} — record it in one lane, or give one of them another state`,\n );\n }\n\n throw new Error(\n `\"${lane}\" captured ${describeShot(shot)} twice — record it once, or give one of them another state`,\n );\n }\n\n captured.set(identityKey, lane);\n\n const fileLane = files.get(shot.file);\n\n if (fileLane !== undefined && fileLane !== lane) {\n throw new Error(\n `\"${fileLane}\" and \"${lane}\" both wrote ${shot.file} — rename one of the \"${shot.page}\" pages`,\n );\n }\n\n files.set(shot.file, lane);\n\n let subject = byPath.get(pathKey);\n\n if (subject === undefined) {\n const url =\n shot.path !== undefined && !shot.path.includes(\":\")\n ? shot.path\n : undefined;\n\n subject = {\n path,\n ...(url === undefined ? {} : { url }),\n states: [],\n };\n\n byPath.set(pathKey, subject);\n subjects.push(subject);\n }\n\n const state: State = {\n name,\n captures: [{ files: { image: shot.file } }],\n };\n\n subject.states.push(state);\n }\n }\n\n return manifestSchema.parse({\n version: manifestVersion,\n tool: \"walkwright\",\n url: this.#appUrl,\n startedAt: this.#startedAt.toISOString(),\n runStats: {\n duration: duration(durationMs),\n lanes: this.#keptLanes().length,\n },\n subjects,\n });\n }\n}\n\nfunction describeShot(shot: ShotRecord): string {\n const page =\n shot.path === undefined\n ? `\"${shot.page}\"`\n : `\"${shot.page}\" (${shot.path})`;\n\n return shot.state === \"\" ? page : `the \"${shot.state}\" state of ${page}`;\n}\n\nfunction laneOf(test: TestCase): string {\n return basename(test.location.file).replace(/(\\.\\w+)?\\.ts$/, \"\");\n}\n\nfunction treePages(recorded: Recorded[]): TreePage[] {\n const byKey = new Map<string, TreePage>();\n const pages: TreePage[] = [];\n\n const keyOf = (group: string[] | undefined, name: string): string =>\n JSON.stringify([...(group ?? []), name]);\n\n for (const { shots } of recorded) {\n for (const page of shots.pages) {\n const key = keyOf(page.group, page.name);\n\n if (!byKey.has(key)) {\n const entry: TreePage = {\n name: page.name,\n ...(page.group === undefined ? {} : { group: page.group }),\n shots: 0,\n };\n\n byKey.set(key, entry);\n pages.push(entry);\n }\n }\n }\n\n for (const { shots } of recorded) {\n for (const shot of shots.shots) {\n const key = keyOf(shot.group, shot.page);\n let entry = byKey.get(key);\n\n if (entry === undefined) {\n entry = {\n name: shot.page,\n ...(shot.group === undefined ? {} : { group: shot.group }),\n shots: 0,\n };\n\n byKey.set(key, entry);\n pages.push(entry);\n }\n\n entry.shots += 1;\n }\n }\n\n return pages;\n}\n\nfunction walkRows(pages: TreePage[], failures: WalkFailure[]): string[] {\n const root = buildTree(pages);\n const rows: [label: string, note: string][] = [];\n\n const walk = (folder: Folder, depth: number): void => {\n const indent = \" \".repeat(depth);\n const entries = folder.pages;\n\n for (const [index, page] of entries.entries()) {\n const last = index === entries.length - 1 && folder.folders.length === 0;\n\n rows.push([\n `${indent}${paint(\"faint\", last ? glyph.last : glyph.branch)} ${paint(\"text\", page.name)}`,\n page.shots === 0\n ? paint(\"dim\", \"no shots\")\n : `${paint(\"ok\", glyph.ok)} ${paint(\"dim\", count(page.shots, \"shot\"))}`,\n ]);\n }\n\n for (const child of folder.folders) {\n rows.push([\n `${indent}${paint(\"accent\", glyph.open)} ${bold(paint(\"text\", child.name))}`,\n \"\",\n ]);\n walk(child, depth + 1);\n }\n };\n\n walk(root, 0);\n\n const labelWidth = rows.reduce(\n (max, [label]) => Math.max(max, width(label)),\n 0,\n );\n const out = rows.map(([label, note]) =>\n note === \"\" ? label : `${pad(label, labelWidth)} ${note}`,\n );\n\n if (failures.length > 0) {\n if (out.length > 0) {\n out.push(\"\");\n }\n\n for (const failed of failures) {\n out.push(\n `${paint(\"fail\", `${glyph.fail} ${failed.lane}`)} ${paint(\"dim\", glyph.dot)} ${paint(\"text\", `\"${failed.step}\"`)} ${paint(\"fail\", \"failed\")}`,\n );\n }\n }\n\n return out;\n}\n\nfunction buildTree(pages: TreePage[]): Folder {\n const root: Folder = { name: \"\", folders: [], pages: [] };\n\n for (const page of pages) {\n let folder = root;\n\n for (const name of page.group ?? []) {\n let next = folder.folders.find((child) => child.name === name);\n\n if (next === undefined) {\n next = { name, folders: [], pages: [] };\n folder.folders.push(next);\n }\n\n folder = next;\n }\n\n folder.pages.push(page);\n }\n\n sortFolder(root);\n\n return root;\n}\n\nfunction sortFolder(folder: Folder): void {\n folder.pages.sort((a, b) => compare(a.name, b.name));\n folder.folders.sort((a, b) => compare(a.name, b.name));\n\n for (const child of folder.folders) {\n sortFolder(child);\n }\n}\n\nfunction compare(a: string, b: string): number {\n return a.localeCompare(b, undefined, { sensitivity: \"base\" });\n}\n\nfunction uploadProgress(done: number, total: number, file: string): void {\n const clear = transient(\n ` ${progress(done, total)} ${paint(\"dim\", `uploading ${String(done)}/${String(total)}`)} ${paint(\"code\", file)}`,\n );\n\n if (done === total) {\n clear();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const manifestVersion = 5;
|
|
4
|
+
declare const captureSchema: z.ZodObject<{
|
|
5
|
+
variant: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
6
|
+
files: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
declare const stateSchema: z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
captures: z.ZodArray<z.ZodObject<{
|
|
11
|
+
variant: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
12
|
+
files: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
13
|
+
}, z.core.$strip>>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
declare const subjectSchema: z.ZodObject<{
|
|
16
|
+
path: z.ZodArray<z.ZodString>;
|
|
17
|
+
url: z.ZodOptional<z.ZodString>;
|
|
18
|
+
states: z.ZodArray<z.ZodObject<{
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
captures: z.ZodArray<z.ZodObject<{
|
|
21
|
+
variant: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
22
|
+
files: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
declare const manifestSchema: z.ZodObject<{
|
|
27
|
+
version: z.ZodLiteral<5>;
|
|
28
|
+
tool: z.ZodOptional<z.ZodString>;
|
|
29
|
+
url: z.ZodOptional<z.ZodString>;
|
|
30
|
+
startedAt: z.ZodOptional<z.ZodISODateTime>;
|
|
31
|
+
runStats: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
32
|
+
subjects: z.ZodArray<z.ZodObject<{
|
|
33
|
+
path: z.ZodArray<z.ZodString>;
|
|
34
|
+
url: z.ZodOptional<z.ZodString>;
|
|
35
|
+
states: z.ZodArray<z.ZodObject<{
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
captures: z.ZodArray<z.ZodObject<{
|
|
38
|
+
variant: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
39
|
+
files: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
}, z.core.$strip>>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
type Capture = z.infer<typeof captureSchema>;
|
|
45
|
+
type State = z.infer<typeof stateSchema>;
|
|
46
|
+
type Subject = z.infer<typeof subjectSchema>;
|
|
47
|
+
type Manifest = z.infer<typeof manifestSchema>;
|
|
48
|
+
|
|
49
|
+
export { type Capture, type Manifest, type State, type Subject, captureSchema, manifestSchema, manifestVersion, stateSchema, subjectSchema };
|
package/build/schema.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureSchema,
|
|
3
|
+
manifestSchema,
|
|
4
|
+
manifestVersion,
|
|
5
|
+
stateSchema,
|
|
6
|
+
subjectSchema
|
|
7
|
+
} from "./chunk-A452S7R3.js";
|
|
8
|
+
import "./chunk-UAWBPTDW.js";
|
|
9
|
+
export {
|
|
10
|
+
captureSchema,
|
|
11
|
+
manifestSchema,
|
|
12
|
+
manifestVersion,
|
|
13
|
+
stateSchema,
|
|
14
|
+
subjectSchema
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BrowserContext, BrowserContextOptions } from '@playwright/test';
|
|
2
|
+
import { StoreScope } from './paths.js';
|
|
3
|
+
|
|
4
|
+
type StorageState = Awaited<ReturnType<BrowserContext["storageState"]>>;
|
|
5
|
+
type StorageStateCookie = StorageState["cookies"][number];
|
|
6
|
+
type StorageStateOption = NonNullable<BrowserContextOptions["storageState"]>;
|
|
7
|
+
interface StorageStateStoreOptions {
|
|
8
|
+
scope?: StoreScope;
|
|
9
|
+
cookies?: (cookie: StorageStateCookie) => boolean;
|
|
10
|
+
}
|
|
11
|
+
interface StorageStateStore {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
exists: () => boolean;
|
|
14
|
+
save: (context: BrowserContext) => Promise<void>;
|
|
15
|
+
restore: (context: BrowserContext) => Promise<void>;
|
|
16
|
+
clear: () => void;
|
|
17
|
+
}
|
|
18
|
+
declare const emptyStorageState: StorageStateOption;
|
|
19
|
+
declare function createStorageStateStore(name: string, { scope, cookies }?: StorageStateStoreOptions): StorageStateStore;
|
|
20
|
+
declare function storageStateOf(...stores: StorageStateStore[]): StorageStateOption;
|
|
21
|
+
|
|
22
|
+
export { type StorageState, type StorageStateCookie, type StorageStateOption, type StorageStateStore, type StorageStateStoreOptions, createStorageStateStore, emptyStorageState, storageStateOf };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createStore
|
|
3
|
+
} from "./chunk-KTXNERHT.js";
|
|
4
|
+
import "./chunk-BODO6HIH.js";
|
|
5
|
+
import "./chunk-UAWBPTDW.js";
|
|
6
|
+
|
|
7
|
+
// src/storage-state.ts
|
|
8
|
+
var emptyStorageState = {
|
|
9
|
+
cookies: [],
|
|
10
|
+
origins: []
|
|
11
|
+
};
|
|
12
|
+
function createStorageStateStore(name, { scope = "worker", cookies } = {}) {
|
|
13
|
+
const store = createStore(name, { scope });
|
|
14
|
+
return {
|
|
15
|
+
get path() {
|
|
16
|
+
return store.path;
|
|
17
|
+
},
|
|
18
|
+
exists: store.exists,
|
|
19
|
+
save: async (context) => {
|
|
20
|
+
const state = await context.storageState();
|
|
21
|
+
store.persist(
|
|
22
|
+
cookies === void 0 ? state : { cookies: state.cookies.filter(cookies), origins: [] }
|
|
23
|
+
);
|
|
24
|
+
},
|
|
25
|
+
restore: async (context) => {
|
|
26
|
+
const state = store.read();
|
|
27
|
+
if (state !== void 0 && state.cookies.length > 0) {
|
|
28
|
+
await context.addCookies(state.cookies);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
clear: store.clear
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function storageStateOf(...stores) {
|
|
35
|
+
return stores.find((store) => store.exists())?.path ?? emptyStorageState;
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createStorageStateStore,
|
|
39
|
+
emptyStorageState,
|
|
40
|
+
storageStateOf
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=storage-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage-state.ts"],"sourcesContent":["import type { BrowserContext, BrowserContextOptions } from \"@playwright/test\";\n\nimport type { StoreScope } from \"./paths.js\";\nimport { createStore } from \"./store.js\";\n\nexport type StorageState = Awaited<ReturnType<BrowserContext[\"storageState\"]>>;\n\nexport type StorageStateCookie = StorageState[\"cookies\"][number];\n\nexport type StorageStateOption = NonNullable<\n BrowserContextOptions[\"storageState\"]\n>;\n\nexport interface StorageStateStoreOptions {\n scope?: StoreScope;\n cookies?: (cookie: StorageStateCookie) => boolean;\n}\n\nexport interface StorageStateStore {\n readonly path: string;\n exists: () => boolean;\n save: (context: BrowserContext) => Promise<void>;\n restore: (context: BrowserContext) => Promise<void>;\n clear: () => void;\n}\n\nexport const emptyStorageState: StorageStateOption = {\n cookies: [],\n origins: [],\n};\n\nexport function createStorageStateStore(\n name: string,\n { scope = \"worker\", cookies }: StorageStateStoreOptions = {},\n): StorageStateStore {\n const store = createStore<StorageState>(name, { scope });\n\n return {\n get path(): string {\n return store.path;\n },\n\n exists: store.exists,\n\n save: async (context): Promise<void> => {\n const state = await context.storageState();\n\n store.persist(\n cookies === undefined\n ? state\n : { cookies: state.cookies.filter(cookies), origins: [] },\n );\n },\n\n restore: async (context): Promise<void> => {\n const state = store.read();\n\n if (state !== undefined && state.cookies.length > 0) {\n await context.addCookies(state.cookies);\n }\n },\n\n clear: store.clear,\n };\n}\n\nexport function storageStateOf(\n ...stores: StorageStateStore[]\n): StorageStateOption {\n return stores.find((store) => store.exists())?.path ?? emptyStorageState;\n}\n"],"mappings":";;;;;;;AA0BO,IAAM,oBAAwC;AAAA,EACnD,SAAS,CAAC;AAAA,EACV,SAAS,CAAC;AACZ;AAEO,SAAS,wBACd,MACA,EAAE,QAAQ,UAAU,QAAQ,IAA8B,CAAC,GACxC;AACnB,QAAM,QAAQ,YAA0B,MAAM,EAAE,MAAM,CAAC;AAEvD,SAAO;AAAA,IACL,IAAI,OAAe;AACjB,aAAO,MAAM;AAAA,IACf;AAAA,IAEA,QAAQ,MAAM;AAAA,IAEd,MAAM,OAAO,YAA2B;AACtC,YAAM,QAAQ,MAAM,QAAQ,aAAa;AAEzC,YAAM;AAAA,QACJ,YAAY,SACR,QACA,EAAE,SAAS,MAAM,QAAQ,OAAO,OAAO,GAAG,SAAS,CAAC,EAAE;AAAA,MAC5D;AAAA,IACF;AAAA,IAEA,SAAS,OAAO,YAA2B;AACzC,YAAM,QAAQ,MAAM,KAAK;AAEzB,UAAI,UAAU,UAAa,MAAM,QAAQ,SAAS,GAAG;AACnD,cAAM,QAAQ,WAAW,MAAM,OAAO;AAAA,MACxC;AAAA,IACF;AAAA,IAEA,OAAO,MAAM;AAAA,EACf;AACF;AAEO,SAAS,kBACX,QACiB;AACpB,SAAO,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,CAAC,GAAG,QAAQ;AACzD;","names":[]}
|
package/build/store.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { StoreScope } from './paths.js';
|
|
3
|
+
|
|
4
|
+
interface StoreOptions<Value> {
|
|
5
|
+
scope?: StoreScope;
|
|
6
|
+
schema?: z.ZodType<Value>;
|
|
7
|
+
}
|
|
8
|
+
interface Store<Value> {
|
|
9
|
+
readonly path: string;
|
|
10
|
+
exists: () => boolean;
|
|
11
|
+
read: () => Value | undefined;
|
|
12
|
+
persist: (value: Value) => void;
|
|
13
|
+
clear: () => void;
|
|
14
|
+
}
|
|
15
|
+
declare function createStore<Value>(name: string, { scope, schema }?: StoreOptions<Value>): Store<Value>;
|
|
16
|
+
|
|
17
|
+
export { type Store, type StoreOptions, createStore };
|
package/build/store.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|