playthrough 0.3.0 → 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 { a as HANDS, c as PICTURE, d as UNMET, f as WROTE, i as GLIMPSES, l as READINGS, n as ASSETS, o as HOLD, p as firstLine, s as PERSON, t as ACTIONS, u as RECORDING, v as seconds, y as keepAssets } from "./reporter-4C_7joIm.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-Dt7fcPLt.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,9 +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"
264
+ await testInfo.attach(DONE_ON, {
265
+ body: JSON.stringify(flow.doneOn),
266
+ contentType: "application/json"
266
267
  });
267
268
  for (const picture of pictures) await testInfo.attach(PICTURE, {
268
269
  body: picture,
@@ -592,7 +593,6 @@ const step = Object.assign(async (title, body, options) => {
592
593
  const flow = underway;
593
594
  if (!flow || flow.depth) return playwrightStep(title, body, options);
594
595
  return playwrightStep(title, async (info) => {
595
- if (run?.stops?.[test$1.info().title] === title) throw new Error("It stopped here the first time it was recorded.");
596
596
  Object.assign(flow, {
597
597
  step: title,
598
598
  inStep: 0
@@ -688,6 +688,7 @@ function pace(page) {
688
688
  }
689
689
  const timeout = args.findLast((arg) => !!arg && typeof arg === "object" && typeof arg.timeout === "number")?.timeout;
690
690
  if (pointer) await approach(this, pointer, timeout).catch((error) => Promise.reject(asAction(error, action)));
691
+ if (underway?.depth) await follow(underway, this);
691
692
  const [text, options] = args;
692
693
  const typed = pointer && action === "fill" && typeof text === "string" && text && await typedInto(this) ? text : void 0;
693
694
  const result = await acted(action, () => pathTo(this), typed ? async () => {
@@ -759,6 +760,26 @@ async function acted(does, target, act, given) {
759
760
  if (keeping) await reached(keeping, keeping.step, ++keeping.actions);
760
761
  return result;
761
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
+ }
762
783
  async function walkOn(flow, walk) {
763
784
  await flow.rest();
764
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,7 +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 DONE_ON = "playthrough done on";
14
15
  export declare const HOLD = 1500;
15
16
  export declare const readingsOf: (flow: Flow) => string;
16
17
  export declare function readingsOn(reviews: Reviews, review: string, round: number, flow: Flow): Promise<Reading[]>;
@@ -26,6 +27,7 @@ export type Recorded = {
26
27
  flow: Flow;
27
28
  files: string[];
28
29
  wrote?: string;
30
+ doneOn?: DoneOn;
29
31
  };
30
32
  export type Hand = {
31
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>;
@@ -1,5 +1,5 @@
1
- import { type Element, type Flow, type Place } from "../../review/src/index.js";
2
- import type { Reading, Thing } from "./reading.js";
1
+ import { type Element, type Flow, type Place, type Point } from "../../review/src/index.js";
2
+ import type { Glimpse, Reading, Thing } from "./reading.js";
3
3
  export type Recorded = {
4
4
  flow: Flow;
5
5
  readings: Reading[];
@@ -9,5 +9,7 @@ export type Shown = {
9
9
  thing: Thing;
10
10
  };
11
11
  export declare function placeIn(place: Place, from: Recorded, to: Recorded): Place;
12
+ export declare const HOLDING: RegExp;
13
+ export declare const nearTo: (read: Glimpse[], at: number, point: Point) => Thing | undefined;
12
14
  export declare function shownAt(readings: Reading[], element: Element, at: number): Shown | undefined;
13
15
  export declare const elementOf: (thing: Thing, name: string) => Element;
@@ -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<{
@@ -1,5 +1,6 @@
1
1
  import { Comparison, Round, Send, type Account, type Flow, type Note, type Place, type Review, type Verdict } from "./model.js";
2
2
  export declare function roundInProgress(review: Review): number;
3
+ export declare function inOrderJoined(review: Review): string[];
3
4
  export declare function allNotes(review: Review): Map<string, {
4
5
  note: Note;
5
6
  round: number;
@@ -27,6 +28,52 @@ export declare function problemsAddingToBefore(review: Review, flows: Flow[], ca
27
28
  export declare function withInBefore(before: Round, flows: Flow[], cantStart: string[], gone?: string[]): Round;
28
29
  export declare function problemsWithComparison(review: Review, comparison: Comparison): string[];
29
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
+ }[];
30
77
  export declare function problemsFinishing(review: Review, number: number): string[];
31
78
  export declare function problemsWithFile(review: Review, round: number, name: string): string[];
32
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>;