@rehearsal-labs/retest 0.1.0 → 0.2.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/README.md +6 -0
- package/dist/agent/session.d.ts +21 -2
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +73 -11
- package/dist/api/app-page.d.ts +39 -3
- package/dist/api/app-page.d.ts.map +1 -1
- package/dist/api/app-page.js +108 -0
- package/dist/api/dialog.d.ts +38 -0
- package/dist/api/dialog.d.ts.map +1 -0
- package/dist/api/dialog.js +78 -0
- package/dist/api/drag.d.ts +32 -0
- package/dist/api/drag.d.ts.map +1 -0
- package/dist/api/drag.js +26 -0
- package/dist/api/files.d.ts +49 -0
- package/dist/api/files.d.ts.map +1 -0
- package/dist/api/files.js +168 -0
- package/dist/api/inbox.d.ts +97 -0
- package/dist/api/inbox.d.ts.map +1 -0
- package/dist/api/inbox.js +191 -0
- package/dist/api/locator-recipes.d.ts +1 -1
- package/dist/api/locator-recipes.d.ts.map +1 -1
- package/dist/api/locator-recipes.js +4 -3
- package/dist/api/page.d.ts +214 -4
- package/dist/api/page.d.ts.map +1 -1
- package/dist/api/route.d.ts +21 -0
- package/dist/api/route.d.ts.map +1 -0
- package/dist/api/route.js +99 -0
- package/dist/api/test-run.d.ts +127 -1
- package/dist/api/test-run.d.ts.map +1 -1
- package/dist/api/test-run.js +293 -0
- package/dist/assertions/expect.d.ts +91 -2
- package/dist/assertions/expect.d.ts.map +1 -1
- package/dist/assertions/expect.js +98 -0
- package/dist/assertions/look-until.d.ts +5 -0
- package/dist/assertions/look-until.d.ts.map +1 -1
- package/dist/assertions/look-until.js +1 -1
- package/dist/assertions/poll-layout.d.ts +24 -0
- package/dist/assertions/poll-layout.d.ts.map +1 -0
- package/dist/assertions/poll-layout.js +63 -0
- package/dist/assertions/screenshot.d.ts +36 -0
- package/dist/assertions/screenshot.d.ts.map +1 -0
- package/dist/assertions/screenshot.js +125 -0
- package/dist/browser/accessibility.d.ts.map +1 -1
- package/dist/browser/accessibility.js +22 -1
- package/dist/browser/actionability.d.ts +9 -6
- package/dist/browser/actionability.d.ts.map +1 -1
- package/dist/browser/actionability.js +17 -8
- package/dist/browser/browser.d.ts.map +1 -1
- package/dist/browser/browser.js +15 -4
- package/dist/browser/cdp/connection.d.ts +6 -0
- package/dist/browser/cdp/connection.d.ts.map +1 -1
- package/dist/browser/cdp/connection.js +8 -0
- package/dist/browser/checked-state.d.ts +2 -2
- package/dist/browser/checked-state.d.ts.map +1 -1
- package/dist/browser/chromium-process.d.ts +9 -2
- package/dist/browser/chromium-process.d.ts.map +1 -1
- package/dist/browser/chromium-process.js +17 -4
- package/dist/browser/contract.d.ts +119 -5
- package/dist/browser/contract.d.ts.map +1 -1
- package/dist/browser/dialogs.d.ts +157 -0
- package/dist/browser/dialogs.d.ts.map +1 -0
- package/dist/browser/dialogs.js +271 -0
- package/dist/browser/downloads.d.ts +71 -0
- package/dist/browser/downloads.d.ts.map +1 -0
- package/dist/browser/downloads.js +253 -0
- package/dist/browser/drag.d.ts +50 -0
- package/dist/browser/drag.d.ts.map +1 -0
- package/dist/browser/drag.js +584 -0
- package/dist/browser/electron-window-watch.d.ts +32 -0
- package/dist/browser/electron-window-watch.d.ts.map +1 -0
- package/dist/browser/electron-window-watch.js +93 -0
- package/dist/browser/electron.d.ts +13 -2
- package/dist/browser/electron.d.ts.map +1 -1
- package/dist/browser/electron.js +53 -8
- package/dist/browser/element-queries.d.ts +51 -15
- package/dist/browser/element-queries.d.ts.map +1 -1
- package/dist/browser/element-queries.js +92 -13
- package/dist/browser/emulation.d.ts.map +1 -1
- package/dist/browser/emulation.js +7 -5
- package/dist/browser/file-chooser.d.ts +75 -0
- package/dist/browser/file-chooser.d.ts.map +1 -0
- package/dist/browser/file-chooser.js +449 -0
- package/dist/browser/firefox/input.d.ts +5 -0
- package/dist/browser/firefox/input.d.ts.map +1 -1
- package/dist/browser/firefox/input.js +6 -3
- package/dist/browser/firefox/page.d.ts +11 -1
- package/dist/browser/firefox/page.d.ts.map +1 -1
- package/dist/browser/firefox/page.js +66 -7
- package/dist/browser/frames.d.ts +205 -0
- package/dist/browser/frames.d.ts.map +1 -0
- package/dist/browser/frames.js +657 -0
- package/dist/browser/input-guard.d.ts +18 -5
- package/dist/browser/input-guard.d.ts.map +1 -1
- package/dist/browser/input-guard.js +65 -6
- package/dist/browser/isolated-world.d.ts +8 -1
- package/dist/browser/isolated-world.d.ts.map +1 -1
- package/dist/browser/layout.d.ts +120 -0
- package/dist/browser/layout.d.ts.map +1 -0
- package/dist/browser/layout.js +213 -0
- package/dist/browser/locate.d.ts +10 -0
- package/dist/browser/locate.d.ts.map +1 -1
- package/dist/browser/locate.js +24 -6
- package/dist/browser/origin-document.d.ts +4 -0
- package/dist/browser/origin-document.d.ts.map +1 -1
- package/dist/browser/origin-document.js +9 -1
- package/dist/browser/page-scripts.d.ts +48 -0
- package/dist/browser/page-scripts.d.ts.map +1 -1
- package/dist/browser/page-scripts.js +515 -39
- package/dist/browser/page.d.ts +60 -1
- package/dist/browser/page.d.ts.map +1 -1
- package/dist/browser/page.js +275 -32
- package/dist/browser/popups.d.ts +166 -0
- package/dist/browser/popups.d.ts.map +1 -0
- package/dist/browser/popups.js +317 -0
- package/dist/browser/routes.d.ts +97 -0
- package/dist/browser/routes.d.ts.map +1 -0
- package/dist/browser/routes.js +226 -0
- package/dist/browser/screenshot.d.ts +44 -0
- package/dist/browser/screenshot.d.ts.map +1 -0
- package/dist/browser/screenshot.js +51 -0
- package/dist/browser/shadow-candidates.d.ts +20 -0
- package/dist/browser/shadow-candidates.d.ts.map +1 -0
- package/dist/browser/shadow-candidates.js +77 -0
- package/dist/browser/webkit/page.d.ts +11 -1
- package/dist/browser/webkit/page.d.ts.map +1 -1
- package/dist/browser/webkit/page.js +53 -2
- package/dist/browser/webkit/relay.d.ts.map +1 -1
- package/dist/browser/webkit/relay.js +5 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +2 -0
- package/dist/cli/inspect/test-timeline.d.ts.map +1 -1
- package/dist/cli/inspect/test-timeline.js +38 -4
- package/dist/config/loaded.d.ts +12 -2
- package/dist/config/loaded.d.ts.map +1 -1
- package/dist/config/read-inboxes.d.ts +10 -0
- package/dist/config/read-inboxes.d.ts.map +1 -0
- package/dist/config/read-inboxes.js +78 -0
- package/dist/config/register.d.ts +5 -1
- package/dist/config/register.d.ts.map +1 -1
- package/dist/config/types.d.ts +36 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/validate.d.ts.map +1 -1
- package/dist/config/validate.js +4 -1
- package/dist/diagnostics/artifact.d.ts.map +1 -1
- package/dist/diagnostics/artifact.js +10 -2
- package/dist/diagnostics/attempt.d.ts +5 -0
- package/dist/diagnostics/attempt.d.ts.map +1 -1
- package/dist/diagnostics/attempt.js +10 -0
- package/dist/diagnostics/chromium-collector.d.ts +9 -1
- package/dist/diagnostics/chromium-collector.d.ts.map +1 -1
- package/dist/diagnostics/chromium-collector.js +19 -4
- package/dist/diagnostics/observations.d.ts +8 -0
- package/dist/diagnostics/observations.d.ts.map +1 -1
- package/dist/diagnostics/session-capture.d.ts.map +1 -1
- package/dist/diagnostics/session-capture.js +8 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/media/policy.d.ts +2 -2
- package/dist/media/policy.d.ts.map +1 -1
- package/dist/media/policy.js +1 -1
- package/dist/playwright/not-yet.d.ts.map +1 -1
- package/dist/playwright/not-yet.js +5 -2
- package/dist/protocol/commands.d.ts +122 -13
- package/dist/protocol/commands.d.ts.map +1 -1
- package/dist/protocol/commands.js +85 -6
- package/dist/protocol/diagnostics.d.ts +10 -0
- package/dist/protocol/diagnostics.d.ts.map +1 -1
- package/dist/protocol/diagnostics.js +5 -0
- package/dist/protocol/dialogs.d.ts +104 -0
- package/dist/protocol/dialogs.d.ts.map +1 -0
- package/dist/protocol/dialogs.js +101 -0
- package/dist/protocol/drag.d.ts +45 -0
- package/dist/protocol/drag.d.ts.map +1 -0
- package/dist/protocol/drag.js +31 -0
- package/dist/protocol/events.d.ts +153 -1
- package/dist/protocol/events.d.ts.map +1 -1
- package/dist/protocol/events.js +97 -0
- package/dist/protocol/files.d.ts +83 -0
- package/dist/protocol/files.d.ts.map +1 -0
- package/dist/protocol/files.js +68 -0
- package/dist/protocol/inbox.d.ts +87 -0
- package/dist/protocol/inbox.d.ts.map +1 -0
- package/dist/protocol/inbox.js +51 -0
- package/dist/protocol/index.d.ts +4 -1
- package/dist/protocol/index.d.ts.map +1 -1
- package/dist/protocol/layout-checks.d.ts +83 -0
- package/dist/protocol/layout-checks.d.ts.map +1 -0
- package/dist/protocol/layout-checks.js +214 -0
- package/dist/protocol/layout.d.ts +135 -0
- package/dist/protocol/layout.d.ts.map +1 -0
- package/dist/protocol/layout.js +124 -0
- package/dist/protocol/locator-checks.d.ts +19 -2
- package/dist/protocol/locator-checks.d.ts.map +1 -1
- package/dist/protocol/locator-checks.js +23 -1
- package/dist/protocol/locator.d.ts +55 -7
- package/dist/protocol/locator.d.ts.map +1 -1
- package/dist/protocol/locator.js +99 -18
- package/dist/protocol/messages.d.ts +95 -0
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/messages.js +63 -0
- package/dist/protocol/popups.d.ts +43 -0
- package/dist/protocol/popups.d.ts.map +1 -0
- package/dist/protocol/popups.js +27 -0
- package/dist/protocol/result.d.ts +5 -0
- package/dist/protocol/result.d.ts.map +1 -1
- package/dist/protocol/result.js +1 -0
- package/dist/protocol/routes.d.ts +136 -0
- package/dist/protocol/routes.d.ts.map +1 -0
- package/dist/protocol/routes.js +191 -0
- package/dist/protocol/screenshot.d.ts +219 -0
- package/dist/protocol/screenshot.d.ts.map +1 -0
- package/dist/protocol/screenshot.js +335 -0
- package/dist/reporters/actions.d.ts +6 -4
- package/dist/reporters/actions.d.ts.map +1 -1
- package/dist/reporters/actions.js +24 -6
- package/dist/reporters/agent.d.ts.map +1 -1
- package/dist/reporters/agent.js +4 -2
- package/dist/reporters/dialogs-popups.d.ts +22 -0
- package/dist/reporters/dialogs-popups.d.ts.map +1 -0
- package/dist/reporters/dialogs-popups.js +30 -0
- package/dist/reporters/failure-card.d.ts +10 -1
- package/dist/reporters/failure-card.d.ts.map +1 -1
- package/dist/reporters/failure-card.js +5 -1
- package/dist/reporters/format.d.ts +33 -0
- package/dist/reporters/format.d.ts.map +1 -1
- package/dist/reporters/format.js +42 -0
- package/dist/reporters/html/comparison-view.d.ts +12 -0
- package/dist/reporters/html/comparison-view.d.ts.map +1 -0
- package/dist/reporters/html/comparison-view.js +21 -0
- package/dist/reporters/html/diagnostics-view.js +8 -0
- package/dist/reporters/html/downloads-view.d.ts +10 -0
- package/dist/reporters/html/downloads-view.d.ts.map +1 -0
- package/dist/reporters/html/downloads-view.js +29 -0
- package/dist/reporters/html/style.d.ts.map +1 -1
- package/dist/reporters/html/style.js +3 -0
- package/dist/reporters/html/summary-view.d.ts.map +1 -1
- package/dist/reporters/html/summary-view.js +3 -2
- package/dist/reporters/html/test-view.d.ts.map +1 -1
- package/dist/reporters/html/test-view.js +6 -3
- package/dist/reporters/html/timeline-view.d.ts.map +1 -1
- package/dist/reporters/html/timeline-view.js +26 -2
- package/dist/reporters/human-card.js +10 -0
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +3 -1
- package/dist/reporters/routes.d.ts +9 -0
- package/dist/reporters/routes.d.ts.map +1 -0
- package/dist/reporters/routes.js +17 -0
- package/dist/runner/child-program.js +10 -0
- package/dist/runner/contract.d.ts +5 -0
- package/dist/runner/contract.d.ts.map +1 -1
- package/dist/runner/dialogs.d.ts +71 -0
- package/dist/runner/dialogs.d.ts.map +1 -0
- package/dist/runner/dialogs.js +189 -0
- package/dist/runner/files.d.ts +79 -0
- package/dist/runner/files.d.ts.map +1 -0
- package/dist/runner/files.js +312 -0
- package/dist/runner/inbox-links.d.ts +19 -0
- package/dist/runner/inbox-links.d.ts.map +1 -0
- package/dist/runner/inbox-links.js +63 -0
- package/dist/runner/inbox.d.ts +87 -0
- package/dist/runner/inbox.d.ts.map +1 -0
- package/dist/runner/inbox.js +340 -0
- package/dist/runner/index.d.ts +2 -1
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/native-pool.d.ts.map +1 -1
- package/dist/runner/native-pool.js +2 -0
- package/dist/runner/observations.d.ts +15 -2
- package/dist/runner/observations.d.ts.map +1 -1
- package/dist/runner/observations.js +109 -6
- package/dist/runner/popups.d.ts +82 -0
- package/dist/runner/popups.d.ts.map +1 -0
- package/dist/runner/popups.js +236 -0
- package/dist/runner/redactor.d.ts.map +1 -1
- package/dist/runner/redactor.js +10 -6
- package/dist/runner/routes.d.ts +23 -0
- package/dist/runner/routes.d.ts.map +1 -0
- package/dist/runner/routes.js +128 -0
- package/dist/runner/run-media.d.ts +6 -0
- package/dist/runner/run-media.d.ts.map +1 -1
- package/dist/runner/run-media.js +21 -0
- package/dist/runner/run-session.d.ts.map +1 -1
- package/dist/runner/run-session.js +93 -8
- package/dist/runner/running-test.d.ts +35 -0
- package/dist/runner/running-test.d.ts.map +1 -1
- package/dist/runner/running-test.js +333 -22
- package/dist/runner/screenshot-baselines.d.ts +159 -0
- package/dist/runner/screenshot-baselines.d.ts.map +1 -0
- package/dist/runner/screenshot-baselines.js +357 -0
- package/dist/runner/secrets.d.ts +13 -0
- package/dist/runner/secrets.d.ts.map +1 -1
- package/dist/runner/secrets.js +6 -4
- package/dist/runner/test-pages.d.ts +3 -1
- package/dist/runner/test-pages.d.ts.map +1 -1
- package/dist/runner/test-pages.js +4 -3
- package/dist/schemas/event-v1.schema.json +118873 -6311
- package/dist/schemas/result-v1.schema.json +4 -0
- package/dist/shared/image-diff.d.ts +36 -0
- package/dist/shared/image-diff.d.ts.map +1 -0
- package/dist/shared/image-diff.js +242 -0
- package/dist/shared/metadata-process.d.ts +4 -1
- package/dist/shared/metadata-process.d.ts.map +1 -1
- package/dist/shared/metadata-process.js +51 -9
- package/dist/shared/png.d.ts +35 -0
- package/dist/shared/png.d.ts.map +1 -0
- package/dist/shared/png.js +251 -0
- package/dist/shared/process-ownership.d.ts +15 -4
- package/dist/shared/process-ownership.d.ts.map +1 -1
- package/dist/shared/process-ownership.js +123 -34
- package/dist/store/artifacts.d.ts +23 -2
- package/dist/store/artifacts.d.ts.map +1 -1
- package/dist/store/artifacts.js +40 -1
- package/dist/store/rebuild-result.d.ts.map +1 -1
- package/dist/store/rebuild-result.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { originAndPath } from "../browser/page-url.js";
|
|
2
|
+
import { smallestBudget } from "../protocol/deadline.js";
|
|
3
|
+
import { formatSessionId } from "../protocol/evidence.js";
|
|
4
|
+
import { errorMessage, failure, withLocation } from "../protocol/failures.js";
|
|
5
|
+
import { describeRoutePattern, routeRequestProblem, summarizeRouteAnswer } from "../protocol/routes.js";
|
|
6
|
+
import { shorten } from "../protocol/text.js";
|
|
7
|
+
import { NativePageAdapter } from "./native-pool.js";
|
|
8
|
+
/**
|
|
9
|
+
* The parent's side of a test's routes. A change goes to the app's page, which answers once Chrome holds what the
|
|
10
|
+
* change asks for, so the test's next command meets it; the answer goes back to the test process, and every change,
|
|
11
|
+
* made or refused, is written down as a `route` event. The routes end with the page: a test's own pages close as it
|
|
12
|
+
* ends, and Retest removes nothing before then. A refused change is the parent's own failure, as a refused wait for a
|
|
13
|
+
* file is, which fails the test whatever its process claims; so is a request whose route's answer Chrome refused, which
|
|
14
|
+
* the page failed in its place. A pattern is redacted whole before it is cut, so no part of a secret is left at the cut.
|
|
15
|
+
*/
|
|
16
|
+
export class TestRoutes {
|
|
17
|
+
#host;
|
|
18
|
+
#running = new Set();
|
|
19
|
+
constructor(host) {
|
|
20
|
+
this.#host = host;
|
|
21
|
+
}
|
|
22
|
+
/** Hears each request of an app's page whose route's answer Chrome refused. Returns a function that stops listening. */
|
|
23
|
+
watch(app, page) {
|
|
24
|
+
return page.onRouteRefused?.((refusal) => this.#refused(app, refusal)) ?? (() => undefined);
|
|
25
|
+
}
|
|
26
|
+
receive(message) {
|
|
27
|
+
if (message.testId !== this.#host.testId || message.attemptId !== this.#host.attemptId)
|
|
28
|
+
return this.#host.violation('sent a route for an inactive test attempt');
|
|
29
|
+
if (this.#running.has(message.id))
|
|
30
|
+
return this.#host.violation(`sent route ${message.id} again while the first was still running`);
|
|
31
|
+
const page = this.#host.page(message.app);
|
|
32
|
+
if (page === undefined)
|
|
33
|
+
return this.#host.violation(`sent a route for the app ${JSON.stringify(message.app)}, which this test does not use`);
|
|
34
|
+
this.#running.add(message.id);
|
|
35
|
+
void this.#change(message, page)
|
|
36
|
+
.catch((error) => ({ ok: false, failure: failure('setup_failed', `Retest could not change the routes: ${errorMessage(error)}`) }))
|
|
37
|
+
.then((reply) => {
|
|
38
|
+
this.#running.delete(message.id);
|
|
39
|
+
this.#settle(message, reply);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async #change({ app, request, timeoutMs, location }, page) {
|
|
43
|
+
const refusal = this.#host.refusal();
|
|
44
|
+
if (refusal !== undefined)
|
|
45
|
+
return { ok: false, failure: withLocation(refusal, location) };
|
|
46
|
+
const problem = routeRequestProblem(request);
|
|
47
|
+
if (problem !== undefined)
|
|
48
|
+
return { ok: false, failure: problem };
|
|
49
|
+
const remaining = this.#host.remainingMs();
|
|
50
|
+
const budget = Math.max(1, remaining === undefined ? timeoutMs : smallestBudget(timeoutMs, remaining));
|
|
51
|
+
if (request.kind === 'add') {
|
|
52
|
+
if (page.addRoute === undefined)
|
|
53
|
+
return { ok: false, failure: noRoutes(app, page) };
|
|
54
|
+
const added = await page.addRoute(request.pattern, request.answer, budget);
|
|
55
|
+
return added.ok ? { ok: true, kind: 'added' } : added;
|
|
56
|
+
}
|
|
57
|
+
if (page.removeRoute === undefined)
|
|
58
|
+
return { ok: false, failure: noRoutes(app, page) };
|
|
59
|
+
const removed = await page.removeRoute(request.pattern, budget);
|
|
60
|
+
if (!removed.ok)
|
|
61
|
+
return removed;
|
|
62
|
+
if (removed.removed === 0)
|
|
63
|
+
return { ok: false, failure: { ...failure('usage', `page.unroute(${describeRoutePattern(request.pattern)}) matches no route of this page. Pass the pattern the route was added with, as it was written.`), details: { removed: 0 } } };
|
|
64
|
+
return { ok: true, kind: 'removed', removed: removed.removed };
|
|
65
|
+
}
|
|
66
|
+
// A change is written down whether it was made or refused, then answered, its failure redacted, if anyone still waits.
|
|
67
|
+
#settle(message, reply) {
|
|
68
|
+
const placed = reply.ok ? reply : { ok: false, failure: withLocation(reply.failure, message.location) };
|
|
69
|
+
this.#emit(message, placed);
|
|
70
|
+
if (!this.#host.answerable())
|
|
71
|
+
return;
|
|
72
|
+
if (!placed.ok)
|
|
73
|
+
this.#host.observe(placed.failure);
|
|
74
|
+
this.#host.send({ type: 'route-result', id: message.id, answer: placed.ok ? placed : { ok: false, failure: redacted(placed.failure, this.#host.redact) } });
|
|
75
|
+
}
|
|
76
|
+
#emit({ app, request, stepId, location }, reply) {
|
|
77
|
+
const { testId, attemptId } = this.#host;
|
|
78
|
+
this.#host.emit({
|
|
79
|
+
type: 'route',
|
|
80
|
+
testId,
|
|
81
|
+
attemptId,
|
|
82
|
+
...(stepId === undefined ? {} : { stepId }),
|
|
83
|
+
session: app,
|
|
84
|
+
sessionId: formatSessionId(attemptId, app),
|
|
85
|
+
operation: request.kind,
|
|
86
|
+
pattern: this.#written(describeRoutePattern(request.pattern)),
|
|
87
|
+
...answerOf(request),
|
|
88
|
+
...(reply.ok && reply.kind === 'removed' ? { removed: reply.removed } : {}),
|
|
89
|
+
...(location === undefined ? {} : { location }),
|
|
90
|
+
...(reply.ok ? {} : { failure: redacted(reply.failure, this.#host.redact) }),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// A request the route matched, whose answer Chrome would not take: the page failed it instead, so the test's own answer
|
|
94
|
+
// never reached the page, and the test fails for it.
|
|
95
|
+
#refused(app, { pattern, url, reason }) {
|
|
96
|
+
const { testId, attemptId } = this.#host;
|
|
97
|
+
const parsed = URL.parse(url);
|
|
98
|
+
const address = this.#host.redact(parsed === null ? url : originAndPath(parsed));
|
|
99
|
+
const written = this.#written(pattern);
|
|
100
|
+
const problem = {
|
|
101
|
+
...failure('setup_failed', this.#host.redact(`Chrome refused the answer page.route(${pattern}) gave a request for ${address}: ${reason}. Retest failed the request in its place, so the page saw a network error.`)),
|
|
102
|
+
details: { url: address },
|
|
103
|
+
};
|
|
104
|
+
this.#host.emit({ type: 'route', testId, attemptId, ...stepOf(this.#host.stepId()), session: app, sessionId: formatSessionId(attemptId, app), operation: 'answer', pattern: written, url: address, failure: problem });
|
|
105
|
+
if (this.#host.answerable())
|
|
106
|
+
this.#host.observe(problem);
|
|
107
|
+
}
|
|
108
|
+
// A pattern as an event records it: redacted whole, then cut as messages cut text.
|
|
109
|
+
#written(pattern) {
|
|
110
|
+
return shorten(this.#host.redact(pattern));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function stepOf(stepId) {
|
|
114
|
+
return stepId === undefined ? {} : { stepId };
|
|
115
|
+
}
|
|
116
|
+
function answerOf(request) {
|
|
117
|
+
return request.kind === 'add' ? { answer: summarizeRouteAnswer(request.answer) } : {};
|
|
118
|
+
}
|
|
119
|
+
function redacted(problem, redact) {
|
|
120
|
+
return { ...problem, message: redact(problem.message) };
|
|
121
|
+
}
|
|
122
|
+
// A native app has no network a route can answer for; any other page without routes belongs to an engine that refuses
|
|
123
|
+
// them, and says so itself.
|
|
124
|
+
function noRoutes(app, page) {
|
|
125
|
+
if (page instanceof NativePageAdapter)
|
|
126
|
+
return failure('unsupported', `${app} is a native app, and page.route() answers the requests of a web page.`);
|
|
127
|
+
return failure('unsupported', `The page of ${app} cannot answer its requests with routes.`);
|
|
128
|
+
}
|
|
@@ -129,6 +129,12 @@ export declare class AttemptRecorder implements AttemptRecordings {
|
|
|
129
129
|
* to start, within the start budget, so no action comes before its recording began.
|
|
130
130
|
*/
|
|
131
131
|
start(pages: readonly AppPage[]): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Notes a session the run cannot record, such as a page a test's page opened: when the app it comes from, `root`, is
|
|
134
|
+
* one the run records, it gets a recording that never began, with `reason`, so the attempt's evidence never counts it
|
|
135
|
+
* as seen. Before `finish` only.
|
|
136
|
+
*/
|
|
137
|
+
notRecorded(page: AppPage, root: string, reason: string): void;
|
|
132
138
|
/** The session's recording for AI checks of its frames. */
|
|
133
139
|
recording(app: string): AttemptRecording | undefined;
|
|
134
140
|
step(name: string): StepSpan | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-media.d.ts","sourceRoot":"","sources":["../../src/runner/run-media.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"run-media.d.ts","sourceRoot":"","sources":["../../src/runner/run-media.ts"],"names":[],"mappings":"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"}
|
package/dist/runner/run-media.js
CHANGED
|
@@ -320,6 +320,8 @@ export class AttemptRecorder {
|
|
|
320
320
|
#steps = new Map();
|
|
321
321
|
#latest = new Map();
|
|
322
322
|
#finishing;
|
|
323
|
+
#pageCount = 0;
|
|
324
|
+
#unrecorded = 0;
|
|
323
325
|
constructor(options) {
|
|
324
326
|
this.#options = options;
|
|
325
327
|
}
|
|
@@ -328,8 +330,27 @@ export class AttemptRecorder {
|
|
|
328
330
|
* to start, within the start budget, so no action comes before its recording began.
|
|
329
331
|
*/
|
|
330
332
|
async start(pages) {
|
|
333
|
+
this.#pageCount = pages.length;
|
|
331
334
|
await Promise.all(pages.map((page, index) => this.#startOne(page, index)));
|
|
332
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Notes a session the run cannot record, such as a page a test's page opened: when the app it comes from, `root`, is
|
|
338
|
+
* one the run records, it gets a recording that never began, with `reason`, so the attempt's evidence never counts it
|
|
339
|
+
* as seen. Before `finish` only.
|
|
340
|
+
*/
|
|
341
|
+
notRecorded(page, root, reason) {
|
|
342
|
+
const { app, session } = page;
|
|
343
|
+
const { testId, attemptId, records, sequences } = this.#options;
|
|
344
|
+
if (this.#finishing !== undefined || !records(root) || this.#order.includes(app))
|
|
345
|
+
return;
|
|
346
|
+
const identity = { testId, attemptId, app, sessionId: session.sessionId };
|
|
347
|
+
const sequence = sequences.next(identity, 'recording');
|
|
348
|
+
// Numbered after every page the attempt began with, as each of those is by its place.
|
|
349
|
+
this.#unrecorded += 1;
|
|
350
|
+
const recordingId = `${attemptId}-${this.#pageCount + this.#unrecorded}-${sequence}`;
|
|
351
|
+
this.#order.push(app);
|
|
352
|
+
this.#unstarted.set(app, unstartedRecording({ identity, sequence, recordingId }, 'no_frame_source', reason));
|
|
353
|
+
}
|
|
333
354
|
/** The session's recording for AI checks of its frames. */
|
|
334
355
|
recording(app) {
|
|
335
356
|
const withheld = this.#options.withheldFrom(app);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-session.d.ts","sourceRoot":"","sources":["../../src/runner/run-session.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAkC,SAAS,EAAc,MAAM,uBAAuB,CAAA;AAGlG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAiC,MAAM,mBAAmB,CAAA;AACrH,OAAO,KAAK,EAAe,UAAU,EAAyB,MAAM,eAAe,CAAA;AAWnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"run-session.d.ts","sourceRoot":"","sources":["../../src/runner/run-session.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAkC,SAAS,EAAc,MAAM,uBAAuB,CAAA;AAGlG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAiC,MAAM,mBAAmB,CAAA;AACrH,OAAO,KAAK,EAAe,UAAU,EAAyB,MAAM,eAAe,CAAA;AAWnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAgChD,OAAO,KAAK,EAAE,cAAc,EAAqB,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAqCtF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,UAAU,CAAA;IACnB,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC9B,MAAM,EAAE,aAAa,CAAA;IACrB,cAAc,EAAE,cAAc,CAAA;IAC9B,KAAK,EAAE,QAAQ,CAAA;IACf,oFAAoF;IACpF,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,wIAAwI;IACxI,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,CAAA;IACnF,sHAAsH;IACtH,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,OAAO,gBAAgB,EAAE,aAAa,CAAA;CACvD,CAAA;AAgGD;;;;;;GAMG;AACH,qBAAa,UAAU;;gBAmGT,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,iBAAiB;IAkHjI,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;CA88ChC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { resolve } from 'node:path';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
4
|
import { isDeepStrictEqual } from 'node:util';
|
|
5
5
|
import { AttemptDiagnostics } from "../diagnostics/attempt.js";
|
|
6
6
|
import { defaultRecordingSettings, recordsApp, resolveRecording } from "../config/read-recording.js";
|
|
@@ -19,7 +19,7 @@ import { appLogFile, browserLogFile, childLogFile, stateFile, targetBrowserLogFi
|
|
|
19
19
|
import { originOf, withoutCredentials } from "../protocol/url.js";
|
|
20
20
|
import { variantKey } from "../protocol/variant.js";
|
|
21
21
|
import { relativePosixPath } from "../shared/posix-path.js";
|
|
22
|
-
import { applyRetention, recordingArtifactReferences, ArtifactSequences, inventoryArtifacts, planRetention } from "../store/artifacts.js";
|
|
22
|
+
import { applyRetention, recordingArtifactReferences, ArtifactSequences, downloadsFolder, inventoryArtifacts, planRetention } from "../store/artifacts.js";
|
|
23
23
|
import { retestVersion } from "../version.js";
|
|
24
24
|
import { AppServers } from "./app-servers.js";
|
|
25
25
|
import { newAttemptId } from "./attempt-id.js";
|
|
@@ -40,12 +40,15 @@ import { interruptionOf, runOutcome, stopReasonOf, testStatus } from "./outcome.
|
|
|
40
40
|
import { collectedTest, planTests } from "./plan.js";
|
|
41
41
|
import { declaredBackend, preparationsScopeProblem, preparationsShapeProblem, prepareAttempt, readPreparations, testPreparations } from "./preparation.js";
|
|
42
42
|
import { endedBeforeTest, fileProcessFailure, laterTestsReason, reportedErrors } from "./process-failures.js";
|
|
43
|
+
import { AttemptFiles } from "./files.js";
|
|
44
|
+
import { AttemptInbox } from "./inbox.js";
|
|
43
45
|
import { Redactor } from "./redactor.js";
|
|
44
46
|
import { runConfig } from "./run-config.js";
|
|
45
47
|
import { runHostChecks } from "./run-host-checks.js";
|
|
46
48
|
import { AttemptRecorder, discoverMediaLocation, RunMedia, startMediaProcess } from "./run-media.js";
|
|
47
49
|
import { abortGraceMs, RunningTest } from "./running-test.js";
|
|
48
50
|
import { attemptKey, phasesOf, scheduleRun } from "./schedule.js";
|
|
51
|
+
import { AttemptScreenshots, pictureApp, ScreenshotBaselines } from "./screenshot-baselines.js";
|
|
49
52
|
import { SecretFiller, secretValuesProblem, secretVariables } from "./secrets.js";
|
|
50
53
|
import { emptySelectionFailure, selectionProblem, testSelected, variantSelected } from "./selection.js";
|
|
51
54
|
import { acquireResources, hostResources, leasePart, partFree, resourceNeeds, sessionResource } from "./resources.js";
|
|
@@ -55,9 +58,12 @@ import { skippedCheckFailures } from "./skipped-checks.js";
|
|
|
55
58
|
import { attemptRefusal, targetDriver } from "./target-drivers.js";
|
|
56
59
|
import { TestFileProcess } from "./test-file-process.js";
|
|
57
60
|
import { timerMs } from "./timer.js";
|
|
61
|
+
import { AttemptPopups } from "./popups.js";
|
|
58
62
|
import { captureFailure, disposePages, openPage, saveState } from "./test-pages.js";
|
|
59
63
|
// How much longer than the media process's own deadline the run waits for a recording's end.
|
|
60
64
|
const finishMarginMs = 5000;
|
|
65
|
+
// Why a page a test's page opened has no diagnostics: Retest watches only the pages a test begins with.
|
|
66
|
+
const notCaptured = 'popups are not captured';
|
|
61
67
|
// A target's first browser keeps the log's name; each further one adds its number, as logs/browser-2.log.
|
|
62
68
|
function instanceLogFile(file, instance) {
|
|
63
69
|
return instance === 0 ? file : file.replace(/\.log$/, `-${instance + 1}.log`);
|
|
@@ -76,6 +82,8 @@ export class RunSession {
|
|
|
76
82
|
#redactor = new Redactor();
|
|
77
83
|
#reporterNames;
|
|
78
84
|
#rootDir;
|
|
85
|
+
/** Where each screenshot's baseline is, and, in a run that updates them, what the run wrote. */
|
|
86
|
+
#baselines;
|
|
79
87
|
#files;
|
|
80
88
|
#runId = randomUUID();
|
|
81
89
|
#startedAt = new Date();
|
|
@@ -149,9 +157,13 @@ export class RunSession {
|
|
|
149
157
|
/** Each running attempt's recordings, by attempt id, and each attempt by its id for the policy's records. */
|
|
150
158
|
#recorders = new Map();
|
|
151
159
|
#attempts = new Map();
|
|
160
|
+
/** When each running attempt started, in milliseconds since 1970: a message its inboxes received before then is not its. */
|
|
161
|
+
#attemptStarts = new Map();
|
|
152
162
|
#sequences = new ArtifactSequences();
|
|
153
163
|
/** Each attempt's lost or withheld failure screenshots, for its evidence. */
|
|
154
164
|
#screenshotGaps = new Map();
|
|
165
|
+
/** The app of the test's own that each popup came from, by the popup's app name, whose capture rules it follows. */
|
|
166
|
+
#popupRoots = new Map();
|
|
155
167
|
/** Every recording the run wrote down, and every partial file a record names, as retention reads them. */
|
|
156
168
|
#recordingReferences = [];
|
|
157
169
|
/** Recordings retention removed, by path, and why. */
|
|
@@ -168,6 +180,7 @@ export class RunSession {
|
|
|
168
180
|
this.#browserCount = options.browsers ?? defaultBrowsers(this.#workers);
|
|
169
181
|
this.#store = store;
|
|
170
182
|
this.#rootDir = resolve(options.rootDir);
|
|
183
|
+
this.#baselines = new ScreenshotBaselines({ rootDir: this.#rootDir, update: options.updateScreenshots === true });
|
|
171
184
|
this.#files = options.files.map((file) => relativePosixPath(this.#rootDir, resolve(this.#rootDir, file)));
|
|
172
185
|
this.#reporterNames = describeReporters(reporters);
|
|
173
186
|
this.#events = new EventLog({
|
|
@@ -267,7 +280,7 @@ export class RunSession {
|
|
|
267
280
|
this.#recording = recording.ok ? recording.settings : defaultRecordingSettings;
|
|
268
281
|
this.#recordsApps = appNames.some((app) => recordsApp(this.#recording, app, pixels));
|
|
269
282
|
this.#clockUs = microsecondsSince(this.#start);
|
|
270
|
-
this.#policy = this.#recordsApps || pixels.size > 0 || declared.size > 0 ? new PixelCapturePolicy({ rules: (app) => pixels.get(app) ?? defaultAppPixelRules, clock: this.#clockUs, record: (record) => this.#policyRecord(record) }) : undefined;
|
|
283
|
+
this.#policy = this.#recordsApps || pixels.size > 0 || declared.size > 0 ? new PixelCapturePolicy({ rules: (app) => pixels.get(this.#popupRoots.get(app) ?? app) ?? defaultAppPixelRules, clock: this.#clockUs, record: (record) => this.#policyRecord(record) }) : undefined;
|
|
271
284
|
this.#media = this.#recordsApps
|
|
272
285
|
? new RunMedia({
|
|
273
286
|
location: startMedia !== undefined && discoverMedia === undefined && options.media !== undefined ? options.media : signal => (discoverMedia ?? discoverMediaLocation)(options.media, process.env, timeouts.setup, signal),
|
|
@@ -816,6 +829,8 @@ export class RunSession {
|
|
|
816
829
|
const { test } = described;
|
|
817
830
|
const execution = this.#executionRecord(described, planned, prepared, hashModules(this.#rootDir, modules.collected, modules.hashes));
|
|
818
831
|
const shown = { name: test.registered.name, file: test.file, location: test.registered.location, ...describePath(test), ...setupMark(test) };
|
|
832
|
+
// A host's preparation can send mail the test then reads, so the attempt's inboxes count from here.
|
|
833
|
+
this.#attemptStarts.set(described.attemptId, Date.now());
|
|
819
834
|
this.#emitFor(described, { type: 'test.started', testId: described.testId, attemptId: described.attemptId, ...shown, execution });
|
|
820
835
|
const finished = { ...described, startedAt, failure: undefined, assertionCount: 0, evidence: [], cleanupFailures: [], execution };
|
|
821
836
|
const { variant } = described;
|
|
@@ -833,6 +848,7 @@ export class RunSession {
|
|
|
833
848
|
? await this.#runPrepared(child, described, planned, prepared, finished)
|
|
834
849
|
: { kind: 'finished', finished: { ...finished, failure: preparing.failure, seen: [preparing.failure] } };
|
|
835
850
|
// An app launched for the attempt is gone before the host cleans its state up, so it cannot touch that state again.
|
|
851
|
+
this.#attemptStarts.delete(described.attemptId);
|
|
836
852
|
const quitFailures = await this.#quitLaunches(planned.config, described, prepared, ran.leftOpen ?? []);
|
|
837
853
|
const cleaned = await preparing.cleanUp(ran.kind === 'not_run' || ran.finished.failure !== undefined);
|
|
838
854
|
const records = { execution, preparations: preparing.records, cleanups: cleaned.records };
|
|
@@ -931,7 +947,7 @@ export class RunSession {
|
|
|
931
947
|
async #runRecorded(child, described, planned, finished, opened) {
|
|
932
948
|
const { context, pages, diagnostics, recorder } = opened;
|
|
933
949
|
const evaluations = this.#evaluations.attempt({ context, pages, hostChecks: described.hostEvaluations, runSignal: this.#options.signal, diagnostics: Object.freeze({ snapshot: (app) => diagnostics.snapshot(app) }), ...(recorder === undefined ? {} : { recordings: recorder }) });
|
|
934
|
-
const { report, running } = await this.#runBody(child, pages, described, planned.config, evaluations);
|
|
950
|
+
const { report, running, popups } = await this.#runBody(child, pages, described, planned.config, evaluations);
|
|
935
951
|
let checked;
|
|
936
952
|
try {
|
|
937
953
|
if (report.endedBeforeStart !== undefined)
|
|
@@ -953,6 +969,11 @@ export class RunSession {
|
|
|
953
969
|
running.close();
|
|
954
970
|
}
|
|
955
971
|
const observed = [...(report.observed ?? []), ...(checked?.failure === undefined ? [] : [checked.failure])];
|
|
972
|
+
// A page a test's page opened is neither recorded nor watched for diagnostics, and its records say so.
|
|
973
|
+
for (const popup of popups.all()) {
|
|
974
|
+
diagnostics.notCaptured(popup.app, popup.session, notCaptured);
|
|
975
|
+
recorder?.notRecorded(popup, this.#popupRoots.get(popup.app) ?? popup.app, 'Popups are not captured, so Retest did not record this page.');
|
|
976
|
+
}
|
|
956
977
|
// Capture ends once the body, its dispatched commands and the parent's checks are over, before the screenshot and
|
|
957
978
|
// before any app is closed. A diagnostics policy's failure follows any failure the test already had, and never
|
|
958
979
|
// replaces it.
|
|
@@ -960,10 +981,13 @@ export class RunSession {
|
|
|
960
981
|
// Recordings end after the last check and before the screenshot, so their frames stop before anything is closed.
|
|
961
982
|
const recordings = recorder === undefined ? {} : { recordings: await recorder.finish() };
|
|
962
983
|
const verdict = withDiagnosticsFailure(withEvaluationFailures({ reported: report.failure ?? checked?.failure, recorded: await evaluations.failures(), observed }), diagnosed.failure);
|
|
963
|
-
|
|
984
|
+
// The popups still open are pictured and closed with the pages, each before the page that opened it.
|
|
985
|
+
const evidence = verdict === undefined ? [] : await captureFailure(context, [...pages, ...popups.open()]);
|
|
964
986
|
const unsaved = verdict === undefined ? await this.#saveSetupState(context, described, pages) : undefined;
|
|
965
987
|
const browserLost = pages.some((page) => !this.#connected(page.browser));
|
|
966
|
-
const { cleanupFailures, leftOpen } = await this.#closePages(context, pages);
|
|
988
|
+
const { cleanupFailures, leftOpen } = await this.#closePages(context, [...popups.open(), ...pages]);
|
|
989
|
+
for (const { session } of popups.all())
|
|
990
|
+
this.#policy?.pageLeft(recordIdentity(described, session.owner.app, session.sessionId), 'session_ended');
|
|
967
991
|
const problem = verdict ?? unsaved;
|
|
968
992
|
const hostChecks = checked === undefined ? {} : { checked: checked.results };
|
|
969
993
|
const crashed = report.crashed === true ? { crashed: true } : {};
|
|
@@ -1085,11 +1109,13 @@ export class RunSession {
|
|
|
1085
1109
|
return state;
|
|
1086
1110
|
}
|
|
1087
1111
|
const baseUrl = runtime.kind === 'web' ? config.apps.get(app)?.baseUrl : undefined;
|
|
1112
|
+
const downloads = this.#downloadsOf(described, app, runtime, config);
|
|
1088
1113
|
const options = {
|
|
1089
1114
|
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
1090
1115
|
...(emulation === undefined ? {} : { emulation }),
|
|
1091
1116
|
...(state === undefined ? {} : { storageState: state.value.storage }),
|
|
1092
1117
|
...(proxy === undefined ? {} : { proxy }),
|
|
1118
|
+
...(downloads === undefined ? {} : { downloads: downloads.folder }),
|
|
1093
1119
|
};
|
|
1094
1120
|
const { testId: id, attemptId } = described;
|
|
1095
1121
|
const session = { sessionId: formatSessionId(attemptId, app), owner: { runId: this.#runId, testId: id, attemptId, app }, runtime };
|
|
@@ -1172,6 +1198,26 @@ export class RunSession {
|
|
|
1172
1198
|
// An Electron app shows whatever origin it serves, so a fill on its window takes only the origins `secretOrigins` lists.
|
|
1173
1199
|
const electron = new Set(test.apps.filter((app) => isElectronTarget(targetOf(config, app, described.targets[app]))));
|
|
1174
1200
|
const fillSecret = (command, context) => this.#secrets.resolve(command, { ...context, appOrigins, ...(electron.has(context.app) ? { target: 'electron' } : {}) });
|
|
1201
|
+
const inbox = this.#inboxAccess(described, appOrigins, electron);
|
|
1202
|
+
const popups = new AttemptPopups({ pages, runId: this.#runId, rooted: (popup, app) => this.#popupRoots.set(popup, app) });
|
|
1203
|
+
const files = new AttemptFiles({
|
|
1204
|
+
pages: new Map(pages.map((page) => [page.app, this.#filesPage(described, config, page)])),
|
|
1205
|
+
runFolder: this.#store.directory,
|
|
1206
|
+
testId: id,
|
|
1207
|
+
attemptId,
|
|
1208
|
+
redactor: this.#redactor,
|
|
1209
|
+
emit: (body) => this.#emitFor(described, body),
|
|
1210
|
+
});
|
|
1211
|
+
const screenshots = new AttemptScreenshots({
|
|
1212
|
+
baselines: this.#baselines,
|
|
1213
|
+
context: this.#pagesContext(described),
|
|
1214
|
+
// A popup is one of the test's pages once it opens, so a page's matchers reach it; it follows the rules of its root.
|
|
1215
|
+
app: (name) => {
|
|
1216
|
+
const found = pages.find((page) => page.app === name) ?? popups.all().find((page) => page.app === name);
|
|
1217
|
+
return found === undefined ? undefined : pictureApp(found.page, found.session.runtime, electron.has(this.#popupRoots.get(name) ?? name));
|
|
1218
|
+
},
|
|
1219
|
+
testFile: test.file,
|
|
1220
|
+
});
|
|
1175
1221
|
const running = new RunningTest({
|
|
1176
1222
|
process: child,
|
|
1177
1223
|
pages: new Map(pages.map(({ app, page }) => [app, page])),
|
|
@@ -1184,7 +1230,12 @@ export class RunSession {
|
|
|
1184
1230
|
redactor: this.#redactor,
|
|
1185
1231
|
touch: new Set(pages.filter((page) => page.touch).map(({ app }) => app)),
|
|
1186
1232
|
evaluations,
|
|
1187
|
-
|
|
1233
|
+
popups,
|
|
1234
|
+
...(inbox === undefined ? {} : { inbox }),
|
|
1235
|
+
files,
|
|
1236
|
+
...(this.#options.playwright === true ? { playwright: true } : {}),
|
|
1237
|
+
...(this.#policy === undefined ? {} : { secretEntry: (app, secret) => this.#secretEntry(described, [...pages, ...popups.open()], app, secret) }),
|
|
1238
|
+
screenshots,
|
|
1188
1239
|
});
|
|
1189
1240
|
// The test is known as running only while its body runs, as before: a browser lost while it settles is the
|
|
1190
1241
|
// next test's problem, not this one's.
|
|
@@ -1198,7 +1249,40 @@ export class RunSession {
|
|
|
1198
1249
|
this.#running.delete(active);
|
|
1199
1250
|
}
|
|
1200
1251
|
await running.settle(this.#settleBudget());
|
|
1201
|
-
return { report, running };
|
|
1252
|
+
return { report, running, popups };
|
|
1253
|
+
}
|
|
1254
|
+
// The attempt's reads of the config's inboxes, which bind a code and a link to the origins of the test's apps' base URLs
|
|
1255
|
+
// and the inbox's own, as a secret is bound. None in a run whose config declares no inbox.
|
|
1256
|
+
#inboxAccess(described, appOrigins, electron) {
|
|
1257
|
+
const { apps } = this.#options;
|
|
1258
|
+
const inboxes = apps.kind === 'config' ? apps.config.inboxes : undefined;
|
|
1259
|
+
if (inboxes === undefined)
|
|
1260
|
+
return undefined;
|
|
1261
|
+
const attempt = new AttemptInbox({ inboxes, redactor: this.#redactor, startedAt: this.#attemptStarts.get(described.attemptId) ?? Date.now() });
|
|
1262
|
+
return {
|
|
1263
|
+
read: (request, options) => attempt.read(request, options),
|
|
1264
|
+
fillCode: (command, context) => attempt.resolveCode(command, { ...context, appOrigins, ...(electron.has(context.app) ? { target: 'electron' } : {}) }),
|
|
1265
|
+
openLink: (reference) => attempt.resolveLink(reference, { appOrigins }),
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
// A Chromium page saves its downloads in its session's folder of the run. An Electron app saves them its own way, and
|
|
1269
|
+
// another engine's page and a native app have none Retest keeps.
|
|
1270
|
+
#downloadsOf(described, app, runtime, config) {
|
|
1271
|
+
if (runtime.kind !== 'web' || runtime.engine !== 'chromium' || isElectronTarget(targetOf(config, app, described.targets[app])))
|
|
1272
|
+
return undefined;
|
|
1273
|
+
const reference = downloadsFolder({ testId: described.testId, attemptId: described.attemptId, app, sessionId: formatSessionId(described.attemptId, app) });
|
|
1274
|
+
return { folder: join(this.#store.directory, reference), reference };
|
|
1275
|
+
}
|
|
1276
|
+
// An app's page as the attempt's files see it, with where it runs, for a refusal that names it.
|
|
1277
|
+
#filesPage(described, config, { app, page, session }) {
|
|
1278
|
+
const { runtime } = session;
|
|
1279
|
+
const downloads = this.#downloadsOf(described, app, runtime, config);
|
|
1280
|
+
const where = runtime.kind !== 'web' ? 'in a native app'
|
|
1281
|
+
: isElectronTarget(targetOf(config, app, described.targets[app])) ? 'in an Electron app'
|
|
1282
|
+
: runtime.engine === 'firefox' ? 'on Firefox'
|
|
1283
|
+
: runtime.engine === 'webkit' ? 'on WebKit'
|
|
1284
|
+
: 'on this browser';
|
|
1285
|
+
return { files: page.files, where, sessionId: session.sessionId, ...(downloads === undefined ? {} : { downloads }) };
|
|
1202
1286
|
}
|
|
1203
1287
|
// An interrupted run waits for nothing more.
|
|
1204
1288
|
#settleBudget() {
|
|
@@ -1705,6 +1789,7 @@ export class RunSession {
|
|
|
1705
1789
|
...(this.#nativeStarts.length === 0 ? {} : { natives: this.#nativeStarts }),
|
|
1706
1790
|
...(this.#options.apps.kind === 'config' ? { browsers } : {}),
|
|
1707
1791
|
...(this.#narrowed === undefined ? {} : { narrowed: this.#narrowed }),
|
|
1792
|
+
...(this.#baselines.written === 0 ? {} : { baselinesWritten: this.#baselines.written }),
|
|
1708
1793
|
...evidence,
|
|
1709
1794
|
files,
|
|
1710
1795
|
};
|
|
@@ -2,11 +2,16 @@ import type { OwnedPage } from '../browser/contract.ts';
|
|
|
2
2
|
import type { EvaluationRequests } from '../evaluation/attempt.ts';
|
|
3
3
|
import type { EventBody, EventOrigin } from '../protocol/events.ts';
|
|
4
4
|
import type { Failure } from '../protocol/failures.ts';
|
|
5
|
+
import type { InboxLinkRef, InboxRequest } from '../protocol/inbox.ts';
|
|
5
6
|
import type { Timeouts } from '../protocol/timeouts.ts';
|
|
6
7
|
import type { Variant } from '../protocol/variant.ts';
|
|
7
8
|
import type { ProcessExit } from '../shared/process-exit.ts';
|
|
8
9
|
import type { Redactor } from './redactor.ts';
|
|
10
|
+
import type { ScreenshotAccess } from './screenshot-baselines.ts';
|
|
11
|
+
import type { InboxCodeFill, InboxRead, InboxReadBudget, LinkResolution } from './inbox.ts';
|
|
12
|
+
import type { PopupRegistry } from './popups.ts';
|
|
9
13
|
import type { FillResolution, SecretFill } from './secrets.ts';
|
|
14
|
+
import type { AttemptFiles } from './files.ts';
|
|
10
15
|
import type { TestFileProcess } from './test-file-process.ts';
|
|
11
16
|
/** How long a stopped test's process has to answer, and a page that lost its browser has to say so. */
|
|
12
17
|
export declare const abortGraceMs = 1000;
|
|
@@ -31,12 +36,40 @@ export type RunningTestOptions = {
|
|
|
31
36
|
touch?: ReadonlySet<string>;
|
|
32
37
|
/** Runs the test's AI checks in this process. Without it, every check is refused. */
|
|
33
38
|
evaluations?: EvaluationRequests;
|
|
39
|
+
/** Reads the run's inboxes for the test, and resolves the codes and links they gave it. Without it, every read is refused. */
|
|
40
|
+
inbox?: InboxAccess;
|
|
41
|
+
/**
|
|
42
|
+
* Makes the pages a test's pages open sessions of the attempt, which `page.popup()` hands the test. Without it, every
|
|
43
|
+
* wait for a popup is refused.
|
|
44
|
+
*/
|
|
45
|
+
popups?: PopupRegistry;
|
|
46
|
+
/**
|
|
47
|
+
* The attempt's files: what a test gives a file input, the pickers and downloads it waits for, and every download its
|
|
48
|
+
* pages make. Without it, every command and request about files is refused.
|
|
49
|
+
*/
|
|
50
|
+
files?: FilesAccess;
|
|
51
|
+
/** The test file is a Playwright test file, whose page has no `fileChooser()` and whose locators no `setInputFiles()`. */
|
|
52
|
+
playwright?: true;
|
|
34
53
|
/**
|
|
35
54
|
* Told just before a secret's keys go to an app's page, with the secret's name, and given how far the keys got once
|
|
36
55
|
* the fill has answered; the pixel capture policy withholds captures of that session in between. Absent in a run with
|
|
37
56
|
* no capture policy.
|
|
38
57
|
*/
|
|
39
58
|
secretEntry?: (app: string, secret: string) => SecretEntryEnd;
|
|
59
|
+
/**
|
|
60
|
+
* Takes the pictures of the test's screenshot checks and keeps them, and leaves what a judged comparison needs in
|
|
61
|
+
* the run folder or the baseline. Without it, every screenshot check is refused.
|
|
62
|
+
*/
|
|
63
|
+
screenshots?: ScreenshotAccess;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* What a running test needs of the run's inboxes: to read one, to turn a code it gave into the text a fill types, bound
|
|
67
|
+
* to the origins it may be typed on, and to turn a link it gave into the address a goto opens, when its origin allows.
|
|
68
|
+
*/
|
|
69
|
+
export type InboxAccess = {
|
|
70
|
+
read: (request: InboxRequest, budget: InboxReadBudget) => Promise<InboxRead>;
|
|
71
|
+
fillCode: (command: InboxCodeFill, context: SecretFillContext) => Promise<FillResolution>;
|
|
72
|
+
openLink: (reference: InboxLinkRef) => LinkResolution;
|
|
40
73
|
};
|
|
41
74
|
/** Ends a secret's entry once its fill has answered: whether its keys were sent, not sent, or may have been. */
|
|
42
75
|
export type SecretEntryEnd = (input: 'not_sent' | 'sent' | 'unknown') => void;
|
|
@@ -80,6 +113,8 @@ export type BodyReport = {
|
|
|
80
113
|
*/
|
|
81
114
|
observed?: readonly Failure[];
|
|
82
115
|
};
|
|
116
|
+
/** What a running test needs of its attempt's files. */
|
|
117
|
+
export type FilesAccess = Pick<AttemptFiles, 'stage' | 'chooser' | 'download' | 'saved' | 'close'>;
|
|
83
118
|
/**
|
|
84
119
|
* The parent's side of one test body. It forwards the child's page commands to the browser, reports
|
|
85
120
|
* each action, writes down each look it serves, judges each assertion against the look it names, and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"running-test.d.ts","sourceRoot":"","sources":["../../src/runner/running-test.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"running-test.d.ts","sourceRoot":"","sources":["../../src/runner/running-test.ts"],"names":[],"mappings":"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"}
|