playthrough 0.2.0 → 0.3.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/INSTRUCTIONS.md +63 -73
- package/package.json +1 -1
- package/src/{read-C9bKWxxP.js → flows-BcISV1M-.js} +683 -1184
- package/src/playthrough.js +249 -87
- package/src/playwright.config.js +6 -10
- package/src/read-Bg9XVTtn.js +278 -0
- package/src/reporter-BEodHYRI.js +930 -0
- package/src/reporter.js +1 -1
- package/src/test.js +125 -16
- package/types/cli/src/app.d.ts +2 -0
- package/types/cli/src/changes.d.ts +1 -0
- package/types/cli/src/compare.d.ts +7 -2
- package/types/cli/src/flows.d.ts +8 -4
- package/types/cli/src/pictures.d.ts +1 -0
- package/types/cli/src/read.d.ts +3 -1
- package/types/cli/src/repo.d.ts +2 -0
- package/types/cli/src/reporter.d.ts +18 -4
- package/types/cli/src/setup.d.ts +4 -1
- package/types/cli/src/test.d.ts +1 -1
- package/types/page/src/found.d.ts +4 -2
- package/types/page/src/reading.d.ts +11 -0
- package/types/review/src/rules.d.ts +3 -1
- package/types/review/src/store.d.ts +3 -0
- package/viewer/assets/index-D64VrgNj.js +193 -0
- package/viewer/assets/index-gTfnUrcK.css +2 -0
- package/viewer/index.html +2 -2
- package/src/reporter-CECNk7aW.js +0 -200
- package/viewer/assets/index-BriVL50M.js +0 -193
- package/viewer/assets/index-DaS2F2-s.css +0 -2
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,
|
|
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 STOPPED_ON, f as UNMET, p as WROTE, r as default, m as firstLine, h as glimpsesOf, g as hashOf, _ as onPage, v as pathOf, y as readingsOf, b as readingsOn, x as seconds } from "./reporter-BEodHYRI.js";
|
package/src/test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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";
|
|
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,18 @@ 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
|
+
});
|
|
267
|
+
if (!ended && last.url() !== "about:blank") await testInfo.attach(STOPPED_ON, {
|
|
268
|
+
body: pathOf(last.url()),
|
|
269
|
+
contentType: "text/plain"
|
|
270
|
+
});
|
|
252
271
|
for (const picture of pictures) await testInfo.attach(PICTURE, {
|
|
253
272
|
body: picture,
|
|
254
273
|
contentType: "image/png"
|
|
@@ -256,12 +275,18 @@ const recorded = test$1.extend({
|
|
|
256
275
|
}, { auto: true }]
|
|
257
276
|
});
|
|
258
277
|
async function readied(page, run) {
|
|
278
|
+
const host = new URL(run.app.url).hostname;
|
|
279
|
+
page.on("request", (sent) => {
|
|
280
|
+
const flow = underway;
|
|
281
|
+
if (flow && !flow.wrote && changes(sent.method()) && new URL(sent.url()).hostname === host) flow.wrote = `${sent.method()} ${new URL(sent.url()).pathname}`;
|
|
282
|
+
});
|
|
259
283
|
await page.addInitScript({ content: recorder(run.recorder) });
|
|
260
284
|
await page.clock.setSystemTime(onReviewDay(run.started));
|
|
261
285
|
await page.addInitScript({ content: seeded });
|
|
262
286
|
}
|
|
263
|
-
async function pageFor(browser, baseURL, screen) {
|
|
287
|
+
async function pageFor(browser, baseURL, screen, use) {
|
|
264
288
|
const context = await browser.newContext({
|
|
289
|
+
...use,
|
|
265
290
|
baseURL,
|
|
266
291
|
locale: "en-US",
|
|
267
292
|
timezoneId: "UTC",
|
|
@@ -277,6 +302,7 @@ async function carryOn(flow, page, rest, person, run) {
|
|
|
277
302
|
await flow.page.waitForTimeout(HANDING);
|
|
278
303
|
await page.exposeFunction("__playthrough", (event) => void (flow.page === page && flow.events.push(event)));
|
|
279
304
|
flow.assets.push(keepAssets(page, run.folder));
|
|
305
|
+
dialogsOn(page, flow);
|
|
280
306
|
flow.hands.push({
|
|
281
307
|
at: Date.now(),
|
|
282
308
|
person
|
|
@@ -294,6 +320,70 @@ async function carryOn(flow, page, rest, person, run) {
|
|
|
294
320
|
};
|
|
295
321
|
if (page.url() !== "about:blank") await page.evaluate(() => window.rrwebRecord?.record.takeFullSnapshot());
|
|
296
322
|
}
|
|
323
|
+
const holding = /* @__PURE__ */ new WeakMap();
|
|
324
|
+
const answered = /* @__PURE__ */ new WeakSet();
|
|
325
|
+
function dialogsOn(page, flow) {
|
|
326
|
+
const listening = (to) => to.listenerCount("dialog");
|
|
327
|
+
page.on("dialog", (dialog) => {
|
|
328
|
+
const theirs = listening(page) > 1 || listening(page.context()) > 0;
|
|
329
|
+
if (dialog.type() === "beforeunload") return void (theirs || dialog.accept().catch(() => {}));
|
|
330
|
+
answers(dialog);
|
|
331
|
+
const said = {
|
|
332
|
+
type: dialog.type(),
|
|
333
|
+
message: dialog.message(),
|
|
334
|
+
...dialog.type() === "prompt" && { value: dialog.defaultValue() }
|
|
335
|
+
};
|
|
336
|
+
if (flow.page === page) flow.events.push({
|
|
337
|
+
type: 5,
|
|
338
|
+
data: {
|
|
339
|
+
tag: "dialog",
|
|
340
|
+
payload: said
|
|
341
|
+
},
|
|
342
|
+
timestamp: Date.now()
|
|
343
|
+
});
|
|
344
|
+
let answered = () => {};
|
|
345
|
+
flow.dialog = new Promise((done) => answered = done);
|
|
346
|
+
holding.set(dialog, {
|
|
347
|
+
flow,
|
|
348
|
+
page,
|
|
349
|
+
read: new Promise((read) => setTimeout(read, Math.min(4e3, 1200 + 40 * dialog.message().length))),
|
|
350
|
+
answered
|
|
351
|
+
});
|
|
352
|
+
if (!theirs) dialog.dismiss().catch(() => {});
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
function answers(dialog) {
|
|
356
|
+
const prototype = Object.getPrototypeOf(dialog);
|
|
357
|
+
if (answered.has(prototype)) return;
|
|
358
|
+
answered.add(prototype);
|
|
359
|
+
for (const [name, yes] of [["accept", true], ["dismiss", false]]) {
|
|
360
|
+
const original = prototype[name];
|
|
361
|
+
prototype[name] = async function(value) {
|
|
362
|
+
const held = holding.get(this);
|
|
363
|
+
holding.delete(this);
|
|
364
|
+
if (held) {
|
|
365
|
+
await held.read;
|
|
366
|
+
const answer = {
|
|
367
|
+
yes,
|
|
368
|
+
...yes && this.type() === "prompt" && { value: value ?? "" }
|
|
369
|
+
};
|
|
370
|
+
if (held.flow.page === held.page) held.flow.events.push({
|
|
371
|
+
type: 5,
|
|
372
|
+
data: {
|
|
373
|
+
tag: "dialog answered",
|
|
374
|
+
payload: answer
|
|
375
|
+
},
|
|
376
|
+
timestamp: Date.now()
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
return await original.call(this, value);
|
|
381
|
+
} finally {
|
|
382
|
+
held?.answered();
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
297
387
|
let collecting;
|
|
298
388
|
let around = [];
|
|
299
389
|
let loading = Promise.resolve();
|
|
@@ -346,7 +436,7 @@ async function runAlongside(page, { request, baseURL, started, setup: appSetup,
|
|
|
346
436
|
let made;
|
|
347
437
|
const handTo = async (person, screen = {}) => {
|
|
348
438
|
personIn(appSetup, person);
|
|
349
|
-
const next = await pageFor(page.context().browser(), baseURL, screen);
|
|
439
|
+
const next = await pageFor(page.context().browser(), baseURL, screen, appSetup.use);
|
|
350
440
|
opened.push(next.context);
|
|
351
441
|
const rest = await readied(next.page);
|
|
352
442
|
await appSetup.signIn?.({
|
|
@@ -506,6 +596,7 @@ const step = Object.assign(async (title, body, options) => {
|
|
|
506
596
|
const flow = underway;
|
|
507
597
|
if (!flow || flow.depth) return playwrightStep(title, body, options);
|
|
508
598
|
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.");
|
|
509
600
|
Object.assign(flow, {
|
|
510
601
|
step: title,
|
|
511
602
|
inStep: 0
|
|
@@ -520,12 +611,13 @@ const step = Object.assign(async (title, body, options) => {
|
|
|
520
611
|
await flow.rest();
|
|
521
612
|
const at = seconds(Date.now() - (flow.events[0]?.timestamp ?? Date.now()));
|
|
522
613
|
await unhovered(flow.page, async () => {
|
|
523
|
-
const { screen, things } = await readPage(flow.page);
|
|
614
|
+
const { screen, things, items } = await readPage(flow.page);
|
|
524
615
|
flow.readings.push({
|
|
525
616
|
step: title,
|
|
526
617
|
at,
|
|
527
618
|
screen,
|
|
528
|
-
things
|
|
619
|
+
things,
|
|
620
|
+
items
|
|
529
621
|
});
|
|
530
622
|
flow.pictures.push(await flow.page.screenshot({
|
|
531
623
|
animations: "disabled",
|
|
@@ -598,7 +690,8 @@ function pace(page) {
|
|
|
598
690
|
await pointer.page.mouse.move(pointer.x, pointer.y);
|
|
599
691
|
await pointer.page.waitForTimeout(HANDING);
|
|
600
692
|
}
|
|
601
|
-
|
|
693
|
+
const timeout = args.findLast((arg) => !!arg && typeof arg === "object" && typeof arg.timeout === "number")?.timeout;
|
|
694
|
+
if (pointer) await approach(this, pointer, timeout).catch((error) => Promise.reject(asAction(error, action)));
|
|
602
695
|
const [text, options] = args;
|
|
603
696
|
const typed = pointer && action === "fill" && typeof text === "string" && text && await typedInto(this) ? text : void 0;
|
|
604
697
|
const result = await acted(action, () => pathTo(this), typed ? async () => {
|
|
@@ -642,7 +735,12 @@ async function acted(does, target, act, given) {
|
|
|
642
735
|
keeping.wrote = false;
|
|
643
736
|
[on, address] = [await target(keeping.page), keeping.page.url()];
|
|
644
737
|
}
|
|
645
|
-
|
|
738
|
+
if (underway) underway.dialog = void 0;
|
|
739
|
+
const result = await act().catch(async (error) => {
|
|
740
|
+
const dialog = underway?.dialog;
|
|
741
|
+
if (!dialog) throw error;
|
|
742
|
+
await dialog;
|
|
743
|
+
});
|
|
646
744
|
underway?.actions.push(Date.now());
|
|
647
745
|
const walk = run?.walk;
|
|
648
746
|
if (walk && underway?.depth && !underway.walked && walk.step === underway.step && walk.actions === ++underway.inStep) {
|
|
@@ -698,12 +796,13 @@ async function walkOn(flow, walk) {
|
|
|
698
796
|
await flow.rest();
|
|
699
797
|
walked.done.push(since());
|
|
700
798
|
await unhovered(flow.page, async () => {
|
|
701
|
-
const { screen, things } = await readPage(flow.page);
|
|
799
|
+
const { screen, things, items } = await readPage(flow.page);
|
|
702
800
|
flow.readings.push({
|
|
703
801
|
step: "In the app",
|
|
704
802
|
at: since(),
|
|
705
803
|
screen,
|
|
706
|
-
things
|
|
804
|
+
things,
|
|
805
|
+
items
|
|
707
806
|
});
|
|
708
807
|
});
|
|
709
808
|
await look();
|
|
@@ -744,7 +843,18 @@ const typedInto = (target) => target.evaluate((on) => on.isContentEditable || on
|
|
|
744
843
|
"tel",
|
|
745
844
|
"password"
|
|
746
845
|
].includes(on.type)).catch(() => false);
|
|
747
|
-
|
|
846
|
+
function asAction(error, action) {
|
|
847
|
+
if (error instanceof Error) {
|
|
848
|
+
error.message = error.message.replace("locator.waitFor", `locator.${action}`);
|
|
849
|
+
error.stack &&= error.stack.replace("locator.waitFor", `locator.${action}`);
|
|
850
|
+
}
|
|
851
|
+
return error;
|
|
852
|
+
}
|
|
853
|
+
async function approach(target, at, timeout) {
|
|
854
|
+
await target.waitFor({
|
|
855
|
+
state: "attached",
|
|
856
|
+
timeout
|
|
857
|
+
});
|
|
748
858
|
const scroll = await target.evaluate((element) => {
|
|
749
859
|
const box = element.getBoundingClientRect();
|
|
750
860
|
if (box.top >= 0 && box.bottom <= innerHeight) return void 0;
|
|
@@ -753,8 +863,7 @@ async function approach(target, at) {
|
|
|
753
863
|
from: scrollY,
|
|
754
864
|
to: Math.max(0, Math.min(most, scrollY + box.top + box.height / 2 - innerHeight / 2))
|
|
755
865
|
};
|
|
756
|
-
}, void 0, { timeout: 5e3 }).catch(() =>
|
|
757
|
-
if (scroll === "missing") return;
|
|
866
|
+
}, void 0, { timeout: 5e3 }).catch(() => void 0);
|
|
758
867
|
if (scroll && Math.abs(scroll.to - scroll.from) >= 1) {
|
|
759
868
|
const moves = Math.max(10, Math.min(36, Math.round(Math.abs(scroll.to - scroll.from) / 25)));
|
|
760
869
|
for (let i = 1; i <= moves; i++) {
|
package/types/cli/src/app.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 {};
|
package/types/cli/src/flows.d.ts
CHANGED
|
@@ -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;
|
package/types/cli/src/read.d.ts
CHANGED
|
@@ -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
|
};
|
package/types/cli/src/repo.d.ts
CHANGED
|
@@ -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,6 +11,7 @@ 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;
|
|
14
16
|
appFile: string;
|
|
15
17
|
setup: string;
|
|
@@ -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
|
|
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,6 +9,9 @@ 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";
|
|
14
|
+
export declare const STOPPED_ON = "playthrough stopped on";
|
|
12
15
|
export declare const HOLD = 1500;
|
|
13
16
|
export declare const readingsOf: (flow: Flow) => string;
|
|
14
17
|
export declare function readingsOn(reviews: Reviews, review: string, round: number, flow: Flow): Promise<Reading[]>;
|
|
@@ -19,23 +22,34 @@ export type Failed = {
|
|
|
19
22
|
at?: string;
|
|
20
23
|
why?: string;
|
|
21
24
|
broken?: true;
|
|
25
|
+
on?: string;
|
|
22
26
|
};
|
|
27
|
+
export declare const pathOf: (address: string) => string;
|
|
28
|
+
export declare const onPage: (on?: string) => string;
|
|
23
29
|
export type Recorded = {
|
|
24
30
|
flow: Flow;
|
|
25
31
|
files: string[];
|
|
32
|
+
wrote?: string;
|
|
26
33
|
};
|
|
27
34
|
export type Hand = {
|
|
28
35
|
at: number;
|
|
29
36
|
person: string;
|
|
30
37
|
};
|
|
38
|
+
export type Written = {
|
|
39
|
+
file: string;
|
|
40
|
+
hash: string;
|
|
41
|
+
};
|
|
42
|
+
export declare const hashOf: (file: string) => string | undefined;
|
|
31
43
|
export default class Flows implements Reporter {
|
|
32
44
|
#private;
|
|
33
|
-
constructor({ folder, before, taken }: {
|
|
45
|
+
constructor({ folder, flows, before, taken }: {
|
|
34
46
|
folder: string;
|
|
47
|
+
flows: string;
|
|
35
48
|
before: boolean;
|
|
36
49
|
taken: string[];
|
|
37
50
|
});
|
|
38
|
-
onTestEnd(test: TestCase, result: TestResult):
|
|
51
|
+
onTestEnd(test: TestCase, result: TestResult): void;
|
|
52
|
+
onError(error: TestError): void;
|
|
39
53
|
onEnd(): void;
|
|
40
54
|
printsToStdio(): boolean;
|
|
41
55
|
}
|
package/types/cli/src/setup.d.ts
CHANGED
|
@@ -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,8 +21,11 @@ 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 = {
|
package/types/cli/src/test.d.ts
CHANGED
|
@@ -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
|
}>;
|
|
@@ -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;
|
|
@@ -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">;
|
|
@@ -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;
|
|
@@ -24,8 +25,9 @@ export declare function problemsWithId(id: string): string[];
|
|
|
24
25
|
export declare function problemsStarting(id: string, title: string, asked?: string): string[];
|
|
25
26
|
export declare function problemsWithRound(review: Review, round: Round): string[];
|
|
26
27
|
export declare function problemsAddingToBefore(review: Review, flows: Flow[], cantStart: string[]): string[];
|
|
27
|
-
export declare function withInBefore(before: Round, flows: Flow[], cantStart: string[]): Round;
|
|
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[];
|
|
30
|
+
export declare const LONGEST_LINE = 140;
|
|
29
31
|
export declare function problemsFinishing(review: Review, number: number): string[];
|
|
30
32
|
export declare function problemsWithFile(review: Review, round: number, name: string): string[];
|
|
31
33
|
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
|
}
|