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/INSTRUCTIONS.md +60 -64
- package/package.json +1 -1
- package/src/{read-BBNVC-oH.js → flows-Dt7fcPLt.js} +647 -1098
- package/src/playthrough.js +246 -122
- package/src/playwright.config.js +6 -10
- package/src/read-Bg9XVTtn.js +278 -0
- package/src/reporter-4C_7joIm.js +919 -0
- package/src/reporter.js +1 -1
- package/src/test.js +121 -16
- package/types/cli/src/app.d.ts +4 -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 +4 -0
- package/types/cli/src/reporter.d.ts +15 -5
- package/types/cli/src/setup.d.ts +5 -2
- package/types/cli/src/test.d.ts +1 -1
- package/types/cli/src/try-setup.d.ts +2 -0
- package/types/page/src/reading.d.ts +11 -0
- package/types/review/src/rules.d.ts +2 -1
- package/types/review/src/store.d.ts +3 -0
- package/viewer/assets/index-Bbi9sjtm.js +193 -0
- package/viewer/assets/index-gTfnUrcK.css +2 -0
- package/viewer/index.html +2 -2
- package/src/reporter-Biym3TnN.js +0 -197
- 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 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 {
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(() =>
|
|
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++) {
|
|
@@ -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,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
|
|
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
|
|
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):
|
|
47
|
+
onTestEnd(test: TestCase, result: TestResult): void;
|
|
48
|
+
onError(error: TestError): void;
|
|
39
49
|
onEnd(): void;
|
|
40
50
|
printsToStdio(): boolean;
|
|
41
51
|
}
|
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,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<
|
|
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;
|
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
|
}>;
|
|
@@ -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
|
}
|