playthrough 0.3.1 → 0.4.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/INSTRUCTIONS.md +11 -10
- package/README.md +2 -2
- package/package.json +2 -2
- package/src/{flows-BcISV1M-.js → flows-BkG0TgHA.js} +42 -35
- package/src/playthrough.js +121 -210
- package/src/playwright.config.js +1 -1
- package/src/{reporter-BEodHYRI.js → reporter-DE8aueAO.js} +15 -24
- package/src/reporter.js +1 -1
- package/src/test.js +29 -12
- package/types/cli/src/flows.d.ts +13 -5
- package/types/cli/src/reporter.d.ts +3 -5
- package/types/cli/src/try-setup.d.ts +1 -0
- package/types/review/src/model.d.ts +3 -0
- package/types/review/src/rules.d.ts +46 -0
- package/types/review/src/store.d.ts +0 -1
- package/viewer/assets/{index-D64VrgNj.js → index-Ds2iot3O.js} +23 -23
- package/viewer/index.html +1 -1
package/src/test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as
|
|
1
|
+
import { a as GLIMPSES, c as PERSON, d as RECORDING, f as WROTE, l as PICTURE, n as ASSETS, o as HANDS, p as firstLine, r as DONE_ON, s as HOLD, t as ACTIONS, u as READINGS, v as seconds, y as keepAssets } from "./reporter-DE8aueAO.js";
|
|
2
|
+
import { C as firstOf, D as setupIn, E as personIn, O as repo, S as changes, T as make, n as REACHES_OUTSIDE, r as WALKED, t as ALONGSIDE } from "./flows-BkG0TgHA.js";
|
|
3
3
|
import { n as readPage, r as unhovered } from "./read-Bg9XVTtn.js";
|
|
4
4
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
@@ -83,7 +83,7 @@ function onlyWaits(expect) {
|
|
|
83
83
|
if (typeof check !== "function") return check;
|
|
84
84
|
return (...args) => {
|
|
85
85
|
try {
|
|
86
|
-
return Promise.resolve(check.apply(target, args)).catch(() =>
|
|
86
|
+
return Promise.resolve(check.apply(target, args)).catch(() => {});
|
|
87
87
|
} catch {}
|
|
88
88
|
};
|
|
89
89
|
} });
|
|
@@ -185,7 +185,8 @@ const recorded = test$1.extend({
|
|
|
185
185
|
actions: [],
|
|
186
186
|
inStep: 0,
|
|
187
187
|
hands: [],
|
|
188
|
-
assets: []
|
|
188
|
+
assets: [],
|
|
189
|
+
doneOn: {}
|
|
189
190
|
};
|
|
190
191
|
await page.exposeFunction("__playthrough", (event) => void (flow.page === page && flow.events.push(event)));
|
|
191
192
|
flow.assets.push(keepAssets(page, run.folder));
|
|
@@ -260,13 +261,9 @@ const recorded = test$1.extend({
|
|
|
260
261
|
body: flow.wrote,
|
|
261
262
|
contentType: "text/plain"
|
|
262
263
|
});
|
|
263
|
-
|
|
264
|
-
body:
|
|
265
|
-
contentType: "
|
|
266
|
-
});
|
|
267
|
-
if (!ended && last.url() !== "about:blank") await testInfo.attach(STOPPED_ON, {
|
|
268
|
-
body: pathOf(last.url()),
|
|
269
|
-
contentType: "text/plain"
|
|
264
|
+
await testInfo.attach(DONE_ON, {
|
|
265
|
+
body: JSON.stringify(flow.doneOn),
|
|
266
|
+
contentType: "application/json"
|
|
270
267
|
});
|
|
271
268
|
for (const picture of pictures) await testInfo.attach(PICTURE, {
|
|
272
269
|
body: picture,
|
|
@@ -596,7 +593,6 @@ const step = Object.assign(async (title, body, options) => {
|
|
|
596
593
|
const flow = underway;
|
|
597
594
|
if (!flow || flow.depth) return playwrightStep(title, body, options);
|
|
598
595
|
return playwrightStep(title, async (info) => {
|
|
599
|
-
if (run?.stops?.[test$1.info().title] === title) throw new Error("It stopped here the first time it was recorded.");
|
|
600
596
|
Object.assign(flow, {
|
|
601
597
|
step: title,
|
|
602
598
|
inStep: 0
|
|
@@ -692,6 +688,7 @@ function pace(page) {
|
|
|
692
688
|
}
|
|
693
689
|
const timeout = args.findLast((arg) => !!arg && typeof arg === "object" && typeof arg.timeout === "number")?.timeout;
|
|
694
690
|
if (pointer) await approach(this, pointer, timeout).catch((error) => Promise.reject(asAction(error, action)));
|
|
691
|
+
if (underway?.depth) await follow(underway, this);
|
|
695
692
|
const [text, options] = args;
|
|
696
693
|
const typed = pointer && action === "fill" && typeof text === "string" && text && await typedInto(this) ? text : void 0;
|
|
697
694
|
const result = await acted(action, () => pathTo(this), typed ? async () => {
|
|
@@ -763,6 +760,26 @@ async function acted(does, target, act, given) {
|
|
|
763
760
|
if (keeping) await reached(keeping, keeping.step, ++keeping.actions);
|
|
764
761
|
return result;
|
|
765
762
|
}
|
|
763
|
+
async function follow(flow, target) {
|
|
764
|
+
const on = await doneOn(target);
|
|
765
|
+
const done = flow.doneOn[flow.step ?? ""] ??= [];
|
|
766
|
+
const inRound = run?.before && run.doneInRound?.[test$1.info().title]?.[flow.step ?? ""]?.[done.length];
|
|
767
|
+
done.push(on ?? null);
|
|
768
|
+
if (on && inRound && !alike(on, inRound)) throw new Error(`The app as it was has ${on.role} “${on.name}” here, where the round has ${inRound.role} “${inRound.name}”.`);
|
|
769
|
+
}
|
|
770
|
+
const doneOn = (target) => target.ariaSnapshot({ timeout: 1e3 }).then((snapshot) => {
|
|
771
|
+
const [, role, name, words] = snapshot.match(/^- ([\w-]+)(?: "((?:[^"\\]|\\.)*)")?[^:\n]*(?::\s*(.*))?/) ?? [];
|
|
772
|
+
return role ? {
|
|
773
|
+
role,
|
|
774
|
+
name: name ?? (role === "text" ? words ?? "" : "")
|
|
775
|
+
} : void 0;
|
|
776
|
+
}, () => void 0);
|
|
777
|
+
function alike(one, other) {
|
|
778
|
+
if (one.role !== other.role) return false;
|
|
779
|
+
const words = (name) => name.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
|
|
780
|
+
const [few, many] = [words(one.name), words(other.name)].sort((a, b) => a.length - b.length);
|
|
781
|
+
return !few.length || few.filter((word) => many.includes(word)).length * 2 >= few.length;
|
|
782
|
+
}
|
|
766
783
|
async function walkOn(flow, walk) {
|
|
767
784
|
await flow.rest();
|
|
768
785
|
const since = () => seconds(Date.now() - (flow.events[0]?.timestamp ?? Date.now()));
|
package/types/cli/src/flows.d.ts
CHANGED
|
@@ -14,8 +14,13 @@ export type Run = {
|
|
|
14
14
|
taken: string[];
|
|
15
15
|
started: string;
|
|
16
16
|
walk?: Walk;
|
|
17
|
-
|
|
17
|
+
doneInRound?: Record<string, DoneOn>;
|
|
18
18
|
};
|
|
19
|
+
export type On = {
|
|
20
|
+
role: string;
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
export type DoneOn = Record<string, (On | null)[]>;
|
|
19
24
|
export type Walk = {
|
|
20
25
|
flow: string;
|
|
21
26
|
step: string;
|
|
@@ -79,14 +84,16 @@ export declare function makeFlowsFolder(repo: Repo, id: string): Promise<void>;
|
|
|
79
84
|
export declare const called: (names: string[]) => string;
|
|
80
85
|
export declare const isFlow: (name: string) => boolean;
|
|
81
86
|
export declare function howToWriteFlows(repo: Repo, id: string): string;
|
|
82
|
-
export declare function
|
|
83
|
-
|
|
87
|
+
export declare function flowsOf(repo: Repo, id: string): Promise<string>;
|
|
88
|
+
export declare function runFlows(repo: Repo, id: string, round: number, { before, first }: {
|
|
89
|
+
before?: {
|
|
84
90
|
flows: string[];
|
|
85
91
|
taken: string[];
|
|
92
|
+
doneInRound: Record<string, DoneOn>;
|
|
86
93
|
};
|
|
87
|
-
first
|
|
94
|
+
first?: (flow: string) => boolean;
|
|
88
95
|
}): Promise<Ran>;
|
|
89
|
-
export declare function keepFailed(repo: Repo, id: string,
|
|
96
|
+
export declare function keepFailed(repo: Repo, id: string, failed: Failed[]): Promise<void>;
|
|
90
97
|
export declare const failedLastTime: (repo: Repo, id: string) => Promise<string[]>;
|
|
91
98
|
export declare const whereItStopped: (repo: Repo, id: string, failed: Failed[]) => string;
|
|
92
99
|
export type Ran = {
|
|
@@ -97,6 +104,7 @@ export type Ran = {
|
|
|
97
104
|
bytes: Buffer;
|
|
98
105
|
}[];
|
|
99
106
|
wrote?: string;
|
|
107
|
+
doneOn?: DoneOn;
|
|
100
108
|
}[];
|
|
101
109
|
failed: Failed[];
|
|
102
110
|
written: Record<string, Written>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Reporter, TestCase, TestError, TestResult } from "@playwright/test/reporter";
|
|
2
2
|
import type { Reading } from "../../page/src/index.js";
|
|
3
3
|
import { type Flow, type Reviews } from "../../review/src/index.js";
|
|
4
|
+
import type { DoneOn } from "./flows.js";
|
|
4
5
|
export declare const RECORDING = "playthrough recording";
|
|
5
6
|
export declare const READINGS = "playthrough readings";
|
|
6
7
|
export declare const GLIMPSES = "playthrough glimpses";
|
|
@@ -10,8 +11,7 @@ export declare const PERSON = "playthrough person";
|
|
|
10
11
|
export declare const HANDS = "playthrough hands";
|
|
11
12
|
export declare const ACTIONS = "playthrough actions";
|
|
12
13
|
export declare const WROTE = "playthrough wrote";
|
|
13
|
-
export declare const
|
|
14
|
-
export declare const STOPPED_ON = "playthrough stopped on";
|
|
14
|
+
export declare const DONE_ON = "playthrough done on";
|
|
15
15
|
export declare const HOLD = 1500;
|
|
16
16
|
export declare const readingsOf: (flow: Flow) => string;
|
|
17
17
|
export declare function readingsOn(reviews: Reviews, review: string, round: number, flow: Flow): Promise<Reading[]>;
|
|
@@ -22,14 +22,12 @@ export type Failed = {
|
|
|
22
22
|
at?: string;
|
|
23
23
|
why?: string;
|
|
24
24
|
broken?: true;
|
|
25
|
-
on?: string;
|
|
26
25
|
};
|
|
27
|
-
export declare const pathOf: (address: string) => string;
|
|
28
|
-
export declare const onPage: (on?: string) => string;
|
|
29
26
|
export type Recorded = {
|
|
30
27
|
flow: Flow;
|
|
31
28
|
files: string[];
|
|
32
29
|
wrote?: string;
|
|
30
|
+
doneOn?: DoneOn;
|
|
33
31
|
};
|
|
34
32
|
export type Hand = {
|
|
35
33
|
at: number;
|
|
@@ -128,6 +128,7 @@ export declare const Change: z.ZodObject<{
|
|
|
128
128
|
length: z.ZodNumber;
|
|
129
129
|
}, z.core.$strict>>;
|
|
130
130
|
}, z.core.$strict>>;
|
|
131
|
+
pictureOnly: z.ZodOptional<z.ZodLiteral<true>>;
|
|
131
132
|
}, z.core.$strict>;
|
|
132
133
|
export declare const Comparison: z.ZodObject<{
|
|
133
134
|
round: z.ZodNumber;
|
|
@@ -176,6 +177,7 @@ export declare const Comparison: z.ZodObject<{
|
|
|
176
177
|
length: z.ZodNumber;
|
|
177
178
|
}, z.core.$strict>>;
|
|
178
179
|
}, z.core.$strict>>;
|
|
180
|
+
pictureOnly: z.ZodOptional<z.ZodLiteral<true>>;
|
|
179
181
|
}, z.core.$strict>>;
|
|
180
182
|
}, z.core.$strict>;
|
|
181
183
|
export declare const Account: z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -556,6 +558,7 @@ export declare const Review: z.ZodObject<{
|
|
|
556
558
|
length: z.ZodNumber;
|
|
557
559
|
}, z.core.$strict>>;
|
|
558
560
|
}, z.core.$strict>>;
|
|
561
|
+
pictureOnly: z.ZodOptional<z.ZodLiteral<true>>;
|
|
559
562
|
}, z.core.$strict>>;
|
|
560
563
|
}, z.core.$strict>>;
|
|
561
564
|
sends: z.ZodArray<z.ZodObject<{
|
|
@@ -28,6 +28,52 @@ export declare function problemsAddingToBefore(review: Review, flows: Flow[], ca
|
|
|
28
28
|
export declare function withInBefore(before: Round, flows: Flow[], cantStart: string[], gone?: string[]): Round;
|
|
29
29
|
export declare function problemsWithComparison(review: Review, comparison: Comparison): string[];
|
|
30
30
|
export declare const LONGEST_LINE = 140;
|
|
31
|
+
export declare const toAccountFor: (comparison?: Comparison) => {
|
|
32
|
+
id: string;
|
|
33
|
+
words: string;
|
|
34
|
+
seen: {
|
|
35
|
+
flow: string;
|
|
36
|
+
at?: number | undefined;
|
|
37
|
+
until?: number | undefined;
|
|
38
|
+
element?: {
|
|
39
|
+
role: string;
|
|
40
|
+
name: string;
|
|
41
|
+
css?: string | undefined;
|
|
42
|
+
node?: number | undefined;
|
|
43
|
+
} | undefined;
|
|
44
|
+
alike?: {
|
|
45
|
+
role: string;
|
|
46
|
+
name: string;
|
|
47
|
+
css?: string | undefined;
|
|
48
|
+
node?: number | undefined;
|
|
49
|
+
}[] | undefined;
|
|
50
|
+
box?: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
width: number;
|
|
54
|
+
height: number;
|
|
55
|
+
} | undefined;
|
|
56
|
+
point?: {
|
|
57
|
+
x: number;
|
|
58
|
+
y: number;
|
|
59
|
+
} | undefined;
|
|
60
|
+
app?: {
|
|
61
|
+
from: {
|
|
62
|
+
flow: string;
|
|
63
|
+
at: number;
|
|
64
|
+
};
|
|
65
|
+
did: {
|
|
66
|
+
does: string;
|
|
67
|
+
on: string;
|
|
68
|
+
with?: string | boolean | string[] | undefined;
|
|
69
|
+
what?: string | undefined;
|
|
70
|
+
}[];
|
|
71
|
+
recording: string;
|
|
72
|
+
length: number;
|
|
73
|
+
} | undefined;
|
|
74
|
+
}[];
|
|
75
|
+
pictureOnly?: true | undefined;
|
|
76
|
+
}[];
|
|
31
77
|
export declare function problemsFinishing(review: Review, number: number): string[];
|
|
32
78
|
export declare function problemsWithFile(review: Review, round: number, name: string): string[];
|
|
33
79
|
export declare function problemsWithFileName(name: string): string[];
|