playthrough 0.1.0 → 0.3.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/reporter.js CHANGED
@@ -1 +1 @@
1
- export { t as ACTIONS, n as ASSETS, i as GLIMPSES, a as HANDS, o as HOLD, s as PERSON, c as PICTURE, l as READINGS, u as RECORDING, r as default, d as firstLine, f as glimpsesOf, p as readingsOf, m as readingsOn, h as seconds } from "./reporter-Biym3TnN.js";
1
+ export { t as ACTIONS, n as ASSETS, i as GLIMPSES, a as HANDS, o as HOLD, s as PERSON, c as PICTURE, l as READINGS, u as RECORDING, d as UNMET, f as WROTE, r as default, p as firstLine, m as glimpsesOf, h as hashOf, g as readingsOf, _ as readingsOn, v as seconds } from "./reporter-4C_7joIm.js";
package/src/test.js CHANGED
@@ -1,9 +1,10 @@
1
- import { _ as make, a as REACHES_OUTSIDE, b as repo, i as ALONGSIDE, m as firstOf, n as readPage, o as WALKED, r as unhovered, v as personIn, y as setupIn } from "./read-BBNVC-oH.js";
2
- import { a as HANDS, c as PICTURE, d as firstLine, g as keepAssets, h as seconds, i as GLIMPSES, l as READINGS, n as ASSETS, o as HOLD, s as PERSON, t as ACTIONS, u as RECORDING } from "./reporter-Biym3TnN.js";
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";
3
+ import { n as readPage, r as unhovered } from "./read-Bg9XVTtn.js";
3
4
  import { readFileSync, writeFileSync } from "node:fs";
4
5
  import { join } from "node:path";
5
- import { pathToFileURL } from "node:url";
6
6
  import { expect as expect$1, test as test$1 } from "@playwright/test";
7
+ import { pathToFileURL } from "node:url";
7
8
  import { AsyncLocalStorage } from "node:async_hooks";
8
9
  // src/rest.ts
9
10
  const STILL = 300;
@@ -82,7 +83,7 @@ function onlyWaits(expect) {
82
83
  if (typeof check !== "function") return check;
83
84
  return (...args) => {
84
85
  try {
85
- return Promise.resolve(check.apply(target, args)).catch(() => {});
86
+ return Promise.resolve(check.apply(target, args)).catch(() => underway && (underway.unmet = (underway.unmet ?? 0) + 1));
86
87
  } catch {}
87
88
  };
88
89
  } });
@@ -124,6 +125,10 @@ const seeded = `(() => {
124
125
  const recorded = test$1.extend({
125
126
  locale: "en-US",
126
127
  timezoneId: "UTC",
128
+ contextOptions: async ({ contextOptions }, use) => use({
129
+ ...(await setupOf()).use,
130
+ ...contextOptions
131
+ }),
127
132
  person: [async ({}, use) => use(firstOf(await setupOf())), { option: true }],
128
133
  rest: async ({ page }, use) => use(run ? await watchRest(page) : async () => {}),
129
134
  setup: async ({ page, request, baseURL, person, rest: _ }, use, testInfo) => {
@@ -151,7 +156,7 @@ const recorded = test$1.extend({
151
156
  await use(async (person, screen = {}) => {
152
157
  const app = await setupOf();
153
158
  personIn(app, person);
154
- const { page, context } = await pageFor(browser, baseURL, screen);
159
+ const { page, context } = await pageFor(browser, baseURL, screen, app.use);
155
160
  opened.push(context);
156
161
  const flow = underway;
157
162
  const rest = run && flow && await watchRest(page);
@@ -185,6 +190,7 @@ const recorded = test$1.extend({
185
190
  await page.exposeFunction("__playthrough", (event) => void (flow.page === page && flow.events.push(event)));
186
191
  flow.assets.push(keepAssets(page, run.folder));
187
192
  pace(page);
193
+ dialogsOn(page, flow);
188
194
  pointer = {
189
195
  page,
190
196
  x: 640,
@@ -192,6 +198,7 @@ const recorded = test$1.extend({
192
198
  };
193
199
  underway = flow;
194
200
  const { events, readings, glimpses, pictures, actions } = flow;
201
+ if (page.url() !== "about:blank") await page.evaluate(() => window.rrwebRecord?.record.takeFullSnapshot());
195
202
  await page.mouse.move(pointer.x, pointer.y);
196
203
  try {
197
204
  await use();
@@ -249,6 +256,14 @@ const recorded = test$1.extend({
249
256
  body: JSON.stringify(flow.hands),
250
257
  contentType: "application/json"
251
258
  });
259
+ if (flow.wrote) await testInfo.attach(WROTE, {
260
+ body: flow.wrote,
261
+ contentType: "text/plain"
262
+ });
263
+ if (flow.unmet) await testInfo.attach(UNMET, {
264
+ body: String(flow.unmet),
265
+ contentType: "text/plain"
266
+ });
252
267
  for (const picture of pictures) await testInfo.attach(PICTURE, {
253
268
  body: picture,
254
269
  contentType: "image/png"
@@ -256,12 +271,18 @@ const recorded = test$1.extend({
256
271
  }, { auto: true }]
257
272
  });
258
273
  async function readied(page, run) {
274
+ const host = new URL(run.app.url).hostname;
275
+ page.on("request", (sent) => {
276
+ const flow = underway;
277
+ if (flow && !flow.wrote && changes(sent.method()) && new URL(sent.url()).hostname === host) flow.wrote = `${sent.method()} ${new URL(sent.url()).pathname}`;
278
+ });
259
279
  await page.addInitScript({ content: recorder(run.recorder) });
260
280
  await page.clock.setSystemTime(onReviewDay(run.started));
261
281
  await page.addInitScript({ content: seeded });
262
282
  }
263
- async function pageFor(browser, baseURL, screen) {
283
+ async function pageFor(browser, baseURL, screen, use) {
264
284
  const context = await browser.newContext({
285
+ ...use,
265
286
  baseURL,
266
287
  locale: "en-US",
267
288
  timezoneId: "UTC",
@@ -277,6 +298,7 @@ async function carryOn(flow, page, rest, person, run) {
277
298
  await flow.page.waitForTimeout(HANDING);
278
299
  await page.exposeFunction("__playthrough", (event) => void (flow.page === page && flow.events.push(event)));
279
300
  flow.assets.push(keepAssets(page, run.folder));
301
+ dialogsOn(page, flow);
280
302
  flow.hands.push({
281
303
  at: Date.now(),
282
304
  person
@@ -294,6 +316,70 @@ async function carryOn(flow, page, rest, person, run) {
294
316
  };
295
317
  if (page.url() !== "about:blank") await page.evaluate(() => window.rrwebRecord?.record.takeFullSnapshot());
296
318
  }
319
+ const holding = /* @__PURE__ */ new WeakMap();
320
+ const answered = /* @__PURE__ */ new WeakSet();
321
+ function dialogsOn(page, flow) {
322
+ const listening = (to) => to.listenerCount("dialog");
323
+ page.on("dialog", (dialog) => {
324
+ const theirs = listening(page) > 1 || listening(page.context()) > 0;
325
+ if (dialog.type() === "beforeunload") return void (theirs || dialog.accept().catch(() => {}));
326
+ answers(dialog);
327
+ const said = {
328
+ type: dialog.type(),
329
+ message: dialog.message(),
330
+ ...dialog.type() === "prompt" && { value: dialog.defaultValue() }
331
+ };
332
+ if (flow.page === page) flow.events.push({
333
+ type: 5,
334
+ data: {
335
+ tag: "dialog",
336
+ payload: said
337
+ },
338
+ timestamp: Date.now()
339
+ });
340
+ let answered = () => {};
341
+ flow.dialog = new Promise((done) => answered = done);
342
+ holding.set(dialog, {
343
+ flow,
344
+ page,
345
+ read: new Promise((read) => setTimeout(read, Math.min(4e3, 1200 + 40 * dialog.message().length))),
346
+ answered
347
+ });
348
+ if (!theirs) dialog.dismiss().catch(() => {});
349
+ });
350
+ }
351
+ function answers(dialog) {
352
+ const prototype = Object.getPrototypeOf(dialog);
353
+ if (answered.has(prototype)) return;
354
+ answered.add(prototype);
355
+ for (const [name, yes] of [["accept", true], ["dismiss", false]]) {
356
+ const original = prototype[name];
357
+ prototype[name] = async function(value) {
358
+ const held = holding.get(this);
359
+ holding.delete(this);
360
+ if (held) {
361
+ await held.read;
362
+ const answer = {
363
+ yes,
364
+ ...yes && this.type() === "prompt" && { value: value ?? "" }
365
+ };
366
+ if (held.flow.page === held.page) held.flow.events.push({
367
+ type: 5,
368
+ data: {
369
+ tag: "dialog answered",
370
+ payload: answer
371
+ },
372
+ timestamp: Date.now()
373
+ });
374
+ }
375
+ try {
376
+ return await original.call(this, value);
377
+ } finally {
378
+ held?.answered();
379
+ }
380
+ };
381
+ }
382
+ }
297
383
  let collecting;
298
384
  let around = [];
299
385
  let loading = Promise.resolve();
@@ -346,7 +432,7 @@ async function runAlongside(page, { request, baseURL, started, setup: appSetup,
346
432
  let made;
347
433
  const handTo = async (person, screen = {}) => {
348
434
  personIn(appSetup, person);
349
- const next = await pageFor(page.context().browser(), baseURL, screen);
435
+ const next = await pageFor(page.context().browser(), baseURL, screen, appSetup.use);
350
436
  opened.push(next.context);
351
437
  const rest = await readied(next.page);
352
438
  await appSetup.signIn?.({
@@ -506,6 +592,7 @@ const step = Object.assign(async (title, body, options) => {
506
592
  const flow = underway;
507
593
  if (!flow || flow.depth) return playwrightStep(title, body, options);
508
594
  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.");
509
596
  Object.assign(flow, {
510
597
  step: title,
511
598
  inStep: 0
@@ -520,12 +607,13 @@ const step = Object.assign(async (title, body, options) => {
520
607
  await flow.rest();
521
608
  const at = seconds(Date.now() - (flow.events[0]?.timestamp ?? Date.now()));
522
609
  await unhovered(flow.page, async () => {
523
- const { screen, things } = await readPage(flow.page);
610
+ const { screen, things, items } = await readPage(flow.page);
524
611
  flow.readings.push({
525
612
  step: title,
526
613
  at,
527
614
  screen,
528
- things
615
+ things,
616
+ items
529
617
  });
530
618
  flow.pictures.push(await flow.page.screenshot({
531
619
  animations: "disabled",
@@ -598,7 +686,8 @@ function pace(page) {
598
686
  await pointer.page.mouse.move(pointer.x, pointer.y);
599
687
  await pointer.page.waitForTimeout(HANDING);
600
688
  }
601
- if (pointer) await approach(this, pointer);
689
+ const timeout = args.findLast((arg) => !!arg && typeof arg === "object" && typeof arg.timeout === "number")?.timeout;
690
+ if (pointer) await approach(this, pointer, timeout).catch((error) => Promise.reject(asAction(error, action)));
602
691
  const [text, options] = args;
603
692
  const typed = pointer && action === "fill" && typeof text === "string" && text && await typedInto(this) ? text : void 0;
604
693
  const result = await acted(action, () => pathTo(this), typed ? async () => {
@@ -642,7 +731,12 @@ async function acted(does, target, act, given) {
642
731
  keeping.wrote = false;
643
732
  [on, address] = [await target(keeping.page), keeping.page.url()];
644
733
  }
645
- const result = await act();
734
+ if (underway) underway.dialog = void 0;
735
+ const result = await act().catch(async (error) => {
736
+ const dialog = underway?.dialog;
737
+ if (!dialog) throw error;
738
+ await dialog;
739
+ });
646
740
  underway?.actions.push(Date.now());
647
741
  const walk = run?.walk;
648
742
  if (walk && underway?.depth && !underway.walked && walk.step === underway.step && walk.actions === ++underway.inStep) {
@@ -698,12 +792,13 @@ async function walkOn(flow, walk) {
698
792
  await flow.rest();
699
793
  walked.done.push(since());
700
794
  await unhovered(flow.page, async () => {
701
- const { screen, things } = await readPage(flow.page);
795
+ const { screen, things, items } = await readPage(flow.page);
702
796
  flow.readings.push({
703
797
  step: "In the app",
704
798
  at: since(),
705
799
  screen,
706
- things
800
+ things,
801
+ items
707
802
  });
708
803
  });
709
804
  await look();
@@ -744,7 +839,18 @@ const typedInto = (target) => target.evaluate((on) => on.isContentEditable || on
744
839
  "tel",
745
840
  "password"
746
841
  ].includes(on.type)).catch(() => false);
747
- async function approach(target, at) {
842
+ function asAction(error, action) {
843
+ if (error instanceof Error) {
844
+ error.message = error.message.replace("locator.waitFor", `locator.${action}`);
845
+ error.stack &&= error.stack.replace("locator.waitFor", `locator.${action}`);
846
+ }
847
+ return error;
848
+ }
849
+ async function approach(target, at, timeout) {
850
+ await target.waitFor({
851
+ state: "attached",
852
+ timeout
853
+ });
748
854
  const scroll = await target.evaluate((element) => {
749
855
  const box = element.getBoundingClientRect();
750
856
  if (box.top >= 0 && box.bottom <= innerHeight) return void 0;
@@ -753,8 +859,7 @@ async function approach(target, at) {
753
859
  from: scrollY,
754
860
  to: Math.max(0, Math.min(most, scrollY + box.top + box.height / 2 - innerHeight / 2))
755
861
  };
756
- }, void 0, { timeout: 5e3 }).catch(() => "missing");
757
- if (scroll === "missing") return;
862
+ }, void 0, { timeout: 5e3 }).catch(() => void 0);
758
863
  if (scroll && Math.abs(scroll.to - scroll.from) >= 1) {
759
864
  const moves = Math.max(10, Math.min(36, Math.round(Math.abs(scroll.to - scroll.from) / 25)));
760
865
  for (let i = 1; i <= moves; i++) {
@@ -0,0 +1,4 @@
1
+ import { type App } from "./repo.js";
2
+ export declare function keepRunning(app: App, root: string): Promise<number | undefined>;
3
+ export declare function stopApp(url: string): Promise<void>;
4
+ export declare const serves: (url: string) => Promise<boolean>;
@@ -6,6 +6,7 @@ export type Found = {
6
6
  element?: Element;
7
7
  alike?: Element[];
8
8
  box?: Box;
9
+ pieces: string[];
9
10
  };
10
11
  export declare function changesAt(then: Reading, now: Reading, unsteady?: Set<string>, shown?: Shown): Found[];
11
12
  type Shown = {
@@ -9,5 +9,10 @@ export type Recorded = {
9
9
  picture: (name: string) => Promise<Buffer>;
10
10
  };
11
11
  export declare function compareWithEarlier(reviews: Reviews, id: string, number: number, flows: Flow[]): Promise<Comparison[]>;
12
- export declare function changesByThemselves(first: Recorded, second: Recorded): Promise<Change[]>;
13
- export declare function compare(page: Page, earlier: Recorded, round: Recorded, unsteady?: Set<string>): Promise<Comparison>;
12
+ export declare function changesByThemselves(first: Recorded, second: Recorded): Promise<(Change & {
13
+ pieces: string[];
14
+ })[]>;
15
+ export declare function compare(page: Page, earlier: Recorded, round: Recorded, unsteady?: Unsteady): Promise<Comparison>;
16
+ type Unsteady = (flow: string) => Set<string>;
17
+ export declare function unsteadyIn(flows: Flow[]): Unsteady;
18
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { type Did, type Flow } from "../../review/src/index.js";
2
- import { type Failed } from "./reporter.js";
2
+ import { type Failed, type Written } from "./reporter.js";
3
3
  import { type App, type Repo } from "./repo.js";
4
4
  export type Run = {
5
5
  flows: string;
@@ -14,6 +14,7 @@ export type Run = {
14
14
  taken: string[];
15
15
  started: string;
16
16
  walk?: Walk;
17
+ stops?: Record<string, string>;
17
18
  };
18
19
  export type Walk = {
19
20
  flow: string;
@@ -73,7 +74,9 @@ export type Cookie = {
73
74
  export declare const ALONGSIDE: unique symbol;
74
75
  export declare const REACHES_OUTSIDE = "reaches outside";
75
76
  export declare const BEAT = 650;
77
+ export declare const waitsFor: ({ before }: Pick<Run, "before">) => 3000 | 10000;
76
78
  export declare function makeFlowsFolder(repo: Repo, id: string): Promise<void>;
79
+ export declare const called: (names: string[]) => string;
77
80
  export declare const isFlow: (name: string) => boolean;
78
81
  export declare function howToWriteFlows(repo: Repo, id: string): string;
79
82
  export declare function runFlows(repo: Repo, id: string, round: number, { later, first }: {
@@ -86,15 +89,17 @@ export declare function runFlows(repo: Repo, id: string, round: number, { later,
86
89
  export declare function keepFailed(repo: Repo, id: string, round: number, failed: Failed[]): Promise<void>;
87
90
  export declare const failedLastTime: (repo: Repo, id: string) => Promise<string[]>;
88
91
  export declare const whereItStopped: (repo: Repo, id: string, failed: Failed[]) => string;
89
- type Ran = {
92
+ export type Ran = {
90
93
  recorded: {
91
94
  flow: Flow;
92
95
  files: {
93
96
  name: string;
94
97
  bytes: Buffer;
95
98
  }[];
99
+ wrote?: string;
96
100
  }[];
97
101
  failed: Failed[];
102
+ written: Record<string, Written>;
98
103
  };
99
104
  export type WalkedRun = Walked & {
100
105
  events: {
@@ -109,5 +114,4 @@ export type WalkedRun = Walked & {
109
114
  pictures: (Buffer | undefined)[];
110
115
  };
111
116
  export declare function walkFork(repo: Repo, id: string, walk: Walk): Promise<WalkedRun | undefined>;
112
- export declare const failedAt: ({ flow, at }: Failed) => string;
113
- export {};
117
+ export declare const failedAt: ({ flow, at, why }: Failed) => string;
@@ -1,6 +1,7 @@
1
1
  import type { Page } from "@playwright/test";
2
2
  import { type Reading } from "../../page/src/index.js";
3
3
  import { type Found } from "./changes.js";
4
+ export declare const HERE = "here:";
4
5
  export declare function picturesAt(page: Page, then: Reading, now: Reading, pictures: {
5
6
  then: Buffer;
6
7
  now: Buffer;
@@ -1,8 +1,9 @@
1
1
  import type { Page } from "@playwright/test";
2
- import type { Reading, Thing } from "../../page/src/index.js";
2
+ import type { Item, Reading, Thing } from "../../page/src/index.js";
3
3
  export declare function readPage(page: Page): Promise<{
4
4
  screen: Reading["screen"];
5
5
  things: Thing[];
6
+ items: Item[];
6
7
  }>;
7
8
  export declare function unhovered<T>(page: Page, look: () => Promise<T>): Promise<T>;
8
9
  export declare function read(): {
@@ -11,4 +12,5 @@ export declare function read(): {
11
12
  height: number;
12
13
  };
13
14
  things: any[];
15
+ items: Item[];
14
16
  };
@@ -2,6 +2,7 @@ import { Reviews } from "../../review/src/index.js";
2
2
  export type App = {
3
3
  start: string;
4
4
  url: string;
5
+ oneAtATime?: boolean;
5
6
  };
6
7
  export type Repo = ReturnType<typeof repo>;
7
8
  export declare function repo(root?: string): {
@@ -10,9 +11,12 @@ export declare function repo(root?: string): {
10
11
  flows: (review: string) => string;
11
12
  failed: (review: string) => string;
12
13
  round: (review: string, round: number) => string;
14
+ ranOnBefore: (review: string) => string;
13
15
  setAside: string;
16
+ appFile: string;
14
17
  setup: string;
15
18
  borrowed: string;
19
+ tried: string;
16
20
  show: (path: string) => string;
17
21
  keepOutOfGit(): Promise<void>;
18
22
  app(): Promise<App>;
@@ -1,6 +1,6 @@
1
- import type { Reporter, TestCase, TestResult } from "@playwright/test/reporter";
1
+ import type { Reporter, TestCase, TestError, TestResult } from "@playwright/test/reporter";
2
2
  import type { Reading } from "../../page/src/index.js";
3
- import type { Flow, Reviews } from "../../review/src/index.js";
3
+ import { type Flow, type Reviews } from "../../review/src/index.js";
4
4
  export declare const RECORDING = "playthrough recording";
5
5
  export declare const READINGS = "playthrough readings";
6
6
  export declare const GLIMPSES = "playthrough glimpses";
@@ -9,11 +9,13 @@ export declare const ASSETS = "playthrough assets";
9
9
  export declare const PERSON = "playthrough person";
10
10
  export declare const HANDS = "playthrough hands";
11
11
  export declare const ACTIONS = "playthrough actions";
12
+ export declare const WROTE = "playthrough wrote";
13
+ export declare const UNMET = "playthrough unmet";
12
14
  export declare const HOLD = 1500;
13
15
  export declare const readingsOf: (flow: Flow) => string;
14
16
  export declare function readingsOn(reviews: Reviews, review: string, round: number, flow: Flow): Promise<Reading[]>;
15
17
  export declare const glimpsesOf: (flow: Flow) => string;
16
- export declare const firstLine: (said: string) => string;
18
+ export declare function firstLine(said: string): string;
17
19
  export type Failed = {
18
20
  flow: string;
19
21
  at?: string;
@@ -23,19 +25,27 @@ export type Failed = {
23
25
  export type Recorded = {
24
26
  flow: Flow;
25
27
  files: string[];
28
+ wrote?: string;
26
29
  };
27
30
  export type Hand = {
28
31
  at: number;
29
32
  person: string;
30
33
  };
34
+ export type Written = {
35
+ file: string;
36
+ hash: string;
37
+ };
38
+ export declare const hashOf: (file: string) => string | undefined;
31
39
  export default class Flows implements Reporter {
32
40
  #private;
33
- constructor({ folder, before, taken }: {
41
+ constructor({ folder, flows, before, taken }: {
34
42
  folder: string;
43
+ flows: string;
35
44
  before: boolean;
36
45
  taken: string[];
37
46
  });
38
- onTestEnd(test: TestCase, result: TestResult): undefined;
47
+ onTestEnd(test: TestCase, result: TestResult): void;
48
+ onError(error: TestError): void;
39
49
  onEnd(): void;
40
50
  printsToStdio(): boolean;
41
51
  }
@@ -1,4 +1,4 @@
1
- import { type APIRequestContext, type Page } from "@playwright/test";
1
+ import { type APIRequestContext, type BrowserContextOptions, type Page } from "@playwright/test";
2
2
  type Make = (given: {
3
3
  page: Page;
4
4
  request: APIRequestContext;
@@ -21,13 +21,16 @@ export type Setup = {
21
21
  after?: After;
22
22
  signIn?: SignIn;
23
23
  people?: People;
24
+ use?: BrowserContextOptions;
24
25
  };
25
26
  export declare function setupIn(file: string, written?: number): Promise<Setup>;
27
+ export declare const changes: (method: string) => boolean;
28
+ export declare function watching(request: APIRequestContext, changed: () => void): APIRequestContext;
26
29
  export declare const firstOf: ({ people }: Setup) => string;
27
30
  export declare function personIn({ people }: Setup, person: string): void;
28
31
  export type Made = {
29
32
  setup: Record<string, any>;
30
- giveBack: () => Promise<void>;
33
+ giveBack: () => Promise<boolean>;
31
34
  };
32
35
  export declare function make({ make, after }: Setup, borrowed: string, given: Parameters<Make>[0] & {
33
36
  baseURL: string;
@@ -8,7 +8,7 @@ export declare const tablet: Screen;
8
8
  export declare const expect: import("@playwright/test").Expect<{}>;
9
9
  export declare const onReviewDay: (started: string, now?: number) => Date;
10
10
  export type HandTo = (person: string, screen?: Screen) => Promise<Page>;
11
- export declare function pageFor(browser: Browser, baseURL: string, screen: Screen): Promise<{
11
+ export declare function pageFor(browser: Browser, baseURL: string, screen: Screen, use?: BrowserContextOptions): Promise<{
12
12
  context: BrowserContext;
13
13
  page: Page;
14
14
  }>;
@@ -0,0 +1,2 @@
1
+ import type { Repo } from "./repo.js";
2
+ export declare function trySetup(repo: Repo, again: string): Promise<void>;
@@ -26,6 +26,16 @@ export type Thing = {
26
26
  labelled?: true;
27
27
  live?: true;
28
28
  node?: number;
29
+ item?: number;
30
+ };
31
+ export type Item = {
32
+ role: "row" | "listitem";
33
+ words: string;
34
+ box: Thing["box"];
35
+ page: Thing["page"];
36
+ list: number;
37
+ holder?: number;
38
+ node?: number;
29
39
  };
30
40
  export type Reading = {
31
41
  step: string;
@@ -36,5 +46,6 @@ export type Reading = {
36
46
  };
37
47
  picture: string;
38
48
  things: Thing[];
49
+ items?: Item[];
39
50
  };
40
51
  export type Glimpse = Omit<Reading, "picture">;
@@ -24,8 +24,9 @@ export declare function problemsWithId(id: string): string[];
24
24
  export declare function problemsStarting(id: string, title: string, asked?: string): string[];
25
25
  export declare function problemsWithRound(review: Review, round: Round): string[];
26
26
  export declare function problemsAddingToBefore(review: Review, flows: Flow[], cantStart: string[]): string[];
27
- export declare function withInBefore(before: Round, flows: Flow[], cantStart: string[]): Round;
27
+ export declare function withInBefore(before: Round, flows: Flow[], cantStart: string[], gone?: string[]): Round;
28
28
  export declare function problemsWithComparison(review: Review, comparison: Comparison): string[];
29
+ export declare const LONGEST_LINE = 140;
29
30
  export declare function problemsFinishing(review: Review, number: number): string[];
30
31
  export declare function problemsWithFile(review: Review, round: number, name: string): string[];
31
32
  export declare function problemsWithFileName(name: string): string[];
@@ -29,10 +29,13 @@ export declare class Reviews {
29
29
  name: string;
30
30
  bytes: Uint8Array;
31
31
  }[];
32
+ commit?: string;
33
+ gone?: string[];
32
34
  }): Promise<void>;
33
35
  saveComparison(id: string, comparison: Comparison): Promise<void>;
34
36
  send(id: string, send: Send): Promise<void>;
35
37
  accept(id: string, by: string): Promise<void>;
36
38
  file(id: string, round: number, name: string): Promise<Uint8Array | undefined>;
39
+ files(id: string, round: number): Promise<string[]>;
37
40
  wait(id: string, until: (review: Review) => boolean, signal?: AbortSignal): Promise<Review>;
38
41
  }