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/src/test.js CHANGED
@@ -1,5 +1,5 @@
1
- import { S as keepAssets, a as HANDS, c as PICTURE, d as STOPPED_ON, f as UNMET, i as GLIMPSES, l as READINGS, m as firstLine, n as ASSETS, o as HOLD, p as WROTE, s as PERSON, t as ACTIONS, u as RECORDING, v as pathOf, x as seconds } from "./reporter-BEodHYRI.js";
2
- import { C as make, E as repo, T as setupIn, b as changes, n as REACHES_OUTSIDE, r as WALKED, t as ALONGSIDE, w as personIn, x as firstOf } from "./flows-BcISV1M-.js";
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(() => underway && (underway.unmet = (underway.unmet ?? 0) + 1));
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
- if (flow.unmet) await testInfo.attach(UNMET, {
264
- body: String(flow.unmet),
265
- contentType: "text/plain"
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()));
@@ -14,8 +14,13 @@ export type Run = {
14
14
  taken: string[];
15
15
  started: string;
16
16
  walk?: Walk;
17
- stops?: Record<string, string>;
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 runFlows(repo: Repo, id: string, round: number, { later, first }: {
83
- later?: {
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: (flow: string) => boolean;
94
+ first?: (flow: string) => boolean;
88
95
  }): Promise<Ran>;
89
- export declare function keepFailed(repo: Repo, id: string, round: number, failed: Failed[]): Promise<void>;
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 UNMET = "playthrough unmet";
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;
@@ -1,2 +1,3 @@
1
1
  import type { Repo } from "./repo.js";
2
2
  export declare function trySetup(repo: Repo, again: string): Promise<void>;
3
+ export declare function writtenNow(repo: Repo): Promise<string>;
@@ -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[];
@@ -29,7 +29,6 @@ export declare class Reviews {
29
29
  name: string;
30
30
  bytes: Uint8Array;
31
31
  }[];
32
- commit?: string;
33
32
  gone?: string[];
34
33
  }): Promise<void>;
35
34
  saveComparison(id: string, comparison: Comparison): Promise<void>;