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
package/src/project.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, relative } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { configPath, ensureWalkwrightDir, projectDir, tryGit } from "./paths.js";
|
|
5
|
+
|
|
6
|
+
export const defaultReportsUrl = "https://app.walkwright.dev";
|
|
7
|
+
|
|
8
|
+
export interface WalkwrightConfig {
|
|
9
|
+
url: string;
|
|
10
|
+
project: string;
|
|
11
|
+
token: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function describeConfigPath(cwd = process.cwd()): string {
|
|
15
|
+
return relative(cwd, configPath(cwd)) || configPath(cwd);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function readWalkwrightConfig(
|
|
19
|
+
cwd = process.cwd(),
|
|
20
|
+
): WalkwrightConfig | undefined {
|
|
21
|
+
const path = configPath(cwd);
|
|
22
|
+
|
|
23
|
+
if (!existsSync(path)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const raw = JSON.parse(
|
|
28
|
+
readFileSync(path, "utf8"),
|
|
29
|
+
) as Partial<WalkwrightConfig>;
|
|
30
|
+
|
|
31
|
+
if (typeof raw.project !== "string" || typeof raw.token !== "string") {
|
|
32
|
+
throw new Error(`${path} is missing "project" or "token"`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (raw.url !== undefined && typeof raw.url !== "string") {
|
|
36
|
+
throw new Error(`${path} has a non-string "url"`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
url: raw.url ?? defaultReportsUrl,
|
|
41
|
+
project: raw.project,
|
|
42
|
+
token: raw.token,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function writeWalkwrightConfig(
|
|
47
|
+
config: WalkwrightConfig,
|
|
48
|
+
cwd = process.cwd(),
|
|
49
|
+
): string {
|
|
50
|
+
ensureWalkwrightDir(cwd);
|
|
51
|
+
|
|
52
|
+
const path = configPath(cwd);
|
|
53
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`);
|
|
54
|
+
|
|
55
|
+
return path;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function currentBranch(cwd = process.cwd()): string {
|
|
59
|
+
const override = process.env["WALKWRIGHT_BRANCH"];
|
|
60
|
+
|
|
61
|
+
if (override !== undefined && override !== "") {
|
|
62
|
+
return override;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const branch = tryGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
66
|
+
|
|
67
|
+
return branch === undefined || branch === "HEAD" ? "unknown" : branch;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function repoName(cwd = process.cwd()): string {
|
|
71
|
+
const url = tryGit(cwd, ["remote", "get-url", "origin"]);
|
|
72
|
+
const match = url === undefined ? null : /([^/:]+?)(\.git)?\/?$/.exec(url);
|
|
73
|
+
|
|
74
|
+
return match?.[1] !== undefined && match[1] !== ""
|
|
75
|
+
? match[1]
|
|
76
|
+
: basename(projectDir(cwd));
|
|
77
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { createStore } from "./store.js";
|
|
5
|
+
|
|
6
|
+
export type Use = <D extends AnyProvision>(
|
|
7
|
+
provision: D,
|
|
8
|
+
...input: ProvisionArgs<InputOf<D>>
|
|
9
|
+
) => Promise<ResultOf<D>>;
|
|
10
|
+
|
|
11
|
+
export interface Provision<Name extends string, Input, Result> {
|
|
12
|
+
name: Name;
|
|
13
|
+
create: (page: Page, input: Input, use: Use) => Promise<Result>;
|
|
14
|
+
dispose?: (page: Page, result: Result) => Promise<void>;
|
|
15
|
+
schema?: z.ZodType<Result>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AnyProvision {
|
|
19
|
+
name: string;
|
|
20
|
+
create: (page: Page, input: never, use: Use) => Promise<unknown>;
|
|
21
|
+
dispose?: (page: Page, result: never) => Promise<void>;
|
|
22
|
+
schema?: z.ZodType;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type InputOf<D extends AnyProvision> = D extends {
|
|
26
|
+
create: (page: Page, input: infer Input, use: Use) => Promise<unknown>;
|
|
27
|
+
}
|
|
28
|
+
? Input
|
|
29
|
+
: never;
|
|
30
|
+
|
|
31
|
+
export type ResultOf<D extends AnyProvision> = D extends {
|
|
32
|
+
create: (page: Page, input: never, use: Use) => Promise<infer Result>;
|
|
33
|
+
}
|
|
34
|
+
? Result
|
|
35
|
+
: never;
|
|
36
|
+
|
|
37
|
+
export function createProvision<Name extends string, Input, Result>(
|
|
38
|
+
name: Name,
|
|
39
|
+
create: (page: Page, input: Input, use: Use) => Promise<Result>,
|
|
40
|
+
dispose?: (page: Page, result: Result) => Promise<void>,
|
|
41
|
+
): Provision<Name, Input, Result> {
|
|
42
|
+
return {
|
|
43
|
+
name,
|
|
44
|
+
create,
|
|
45
|
+
...(dispose === undefined ? {} : { dispose }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function createPersistentProvision<Name extends string, Input, Result>(
|
|
50
|
+
name: Name,
|
|
51
|
+
schema: z.ZodType<Result>,
|
|
52
|
+
create: (page: Page, input: Input, use: Use) => Promise<Result>,
|
|
53
|
+
dispose?: (page: Page, result: Result) => Promise<void>,
|
|
54
|
+
): Provision<Name, Input, Result> {
|
|
55
|
+
return {
|
|
56
|
+
name,
|
|
57
|
+
create,
|
|
58
|
+
schema,
|
|
59
|
+
...(dispose === undefined ? {} : { dispose }),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type ProvisionMap<Defs extends readonly AnyProvision[]> = {
|
|
64
|
+
[D in Defs[number] as D["name"]]: (
|
|
65
|
+
...input: ProvisionArgs<InputOf<D>>
|
|
66
|
+
) => Promise<ResultOf<D>>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export interface Provisioner<
|
|
70
|
+
Defs extends readonly AnyProvision[],
|
|
71
|
+
> extends AsyncDisposable {
|
|
72
|
+
provision: ProvisionMap<Defs>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createProvisioner<Defs extends readonly AnyProvision[]>(
|
|
76
|
+
page: Page,
|
|
77
|
+
provisions: Defs,
|
|
78
|
+
): Provisioner<Defs> {
|
|
79
|
+
const disposals: Disposal[] = [];
|
|
80
|
+
const named = new Set<string>();
|
|
81
|
+
|
|
82
|
+
for (const def of provisions) {
|
|
83
|
+
if (named.has(def.name)) {
|
|
84
|
+
throw new Error(`two provisions are both named "${def.name}"`);
|
|
85
|
+
}
|
|
86
|
+
named.add(def.name);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const pending = new Map<AnyProvision, Promise<unknown>>();
|
|
90
|
+
|
|
91
|
+
const rawUse = async (
|
|
92
|
+
def: AnyProvision,
|
|
93
|
+
input: unknown,
|
|
94
|
+
): Promise<unknown> => {
|
|
95
|
+
if (def.schema === undefined) {
|
|
96
|
+
const result = await def.create(page, input as never, use);
|
|
97
|
+
|
|
98
|
+
if (def.dispose !== undefined) {
|
|
99
|
+
const dispose = def.dispose;
|
|
100
|
+
disposals.push(async (): Promise<void> => {
|
|
101
|
+
await dispose(page, result as never);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const schema = def.schema;
|
|
109
|
+
const cached = pending.get(def);
|
|
110
|
+
if (cached !== undefined) {
|
|
111
|
+
return await cached;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const promise = (async (): Promise<unknown> => {
|
|
115
|
+
const store = createStore<unknown>(def.name, { schema });
|
|
116
|
+
const cached = store.read();
|
|
117
|
+
|
|
118
|
+
if (cached !== undefined) {
|
|
119
|
+
return cached;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const result = await def.create(page, input as never, use);
|
|
123
|
+
store.persist(result);
|
|
124
|
+
return result;
|
|
125
|
+
})();
|
|
126
|
+
|
|
127
|
+
pending.set(def, promise);
|
|
128
|
+
return await promise;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const use = (async (
|
|
132
|
+
def: AnyProvision,
|
|
133
|
+
...input: unknown[]
|
|
134
|
+
): Promise<unknown> => await rawUse(def, input[0])) as Use;
|
|
135
|
+
|
|
136
|
+
const provision: Record<string, (...input: unknown[]) => Promise<unknown>> =
|
|
137
|
+
{};
|
|
138
|
+
|
|
139
|
+
for (const def of provisions) {
|
|
140
|
+
provision[def.name] = async (...input: unknown[]): Promise<unknown> =>
|
|
141
|
+
await rawUse(def, input[0]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
provision: provision as unknown as ProvisionMap<Defs>,
|
|
146
|
+
[Symbol.asyncDispose]: async (): Promise<void> => {
|
|
147
|
+
await disposeAll(disposals);
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type ProvisionArgs<Input> = undefined extends Input
|
|
153
|
+
? [input?: Input]
|
|
154
|
+
: [input: Input];
|
|
155
|
+
|
|
156
|
+
type Disposal = () => Promise<void>;
|
|
157
|
+
|
|
158
|
+
async function disposeAll(disposals: Disposal[]): Promise<void> {
|
|
159
|
+
const failures: unknown[] = [];
|
|
160
|
+
|
|
161
|
+
for (const dispose of [...disposals].reverse()) {
|
|
162
|
+
try {
|
|
163
|
+
await dispose();
|
|
164
|
+
} catch (error) {
|
|
165
|
+
failures.push(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
disposals.length = 0;
|
|
170
|
+
|
|
171
|
+
if (failures.length > 0) {
|
|
172
|
+
throw new AggregateError(
|
|
173
|
+
failures,
|
|
174
|
+
`provisioner clean-up failed: ${failures
|
|
175
|
+
.map((failure) =>
|
|
176
|
+
failure instanceof Error
|
|
177
|
+
? failure.message.split("\n")[0]
|
|
178
|
+
: String(failure),
|
|
179
|
+
)
|
|
180
|
+
.join("; ")}`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|