waygraph 0.16.2 → 0.16.4
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 +12 -0
- package/dist/analysis/practices-check.d.ts +1 -1
- package/dist/analysis/practices-check.js +36 -0
- package/dist/beta.d.ts +6 -0
- package/dist/beta.js +5 -0
- package/dist/cli/commands/codemod-flows.js +2 -2
- package/dist/cli/commands/codemod-stubs.js +43 -1
- package/dist/cli/commands/pilot.js +3 -16
- package/dist/cli/commands/session-ops.js +26 -1
- package/dist/cli/flags.d.ts +1 -1
- package/dist/cli/flags.js +1 -1
- package/dist/cli/usage.js +6 -0
- package/dist/demo/narration/stub-ctx.js +126 -124
- package/dist/demo/overlay/cursor.js +1 -1
- package/dist/demo/overlay/inpage/banner.js +5 -0
- package/dist/demo/overlay/inpage/core.js +1 -0
- package/dist/demo/overlay/inpage/network.js +1 -1
- package/dist/demo/overlay/inpage/todos.js +0 -15
- package/dist/demo/overlay/network-capture.js +2 -2
- package/dist/demo/overlay/overlay-css.js +18 -21
- package/dist/demo/overlay/overlay-stage.js +1 -1
- package/dist/demo/overlay/phase-fixtures.js +5 -5
- package/dist/demo/overlay/pilot/shell.js +7 -5
- package/dist/demo/overlay/ui/components/ring.js +2 -2
- package/dist/demo/overlay/ui/overlay.css +98 -35
- package/dist/demo/overlay/ui/shadow.js +69 -2
- package/dist/demo/stepper/demo-log.js +8 -8
- package/dist/demo/stepper/slides.d.ts +1 -1
- package/dist/demo/stepper/slides.js +1 -1
- package/dist/demo/stepper/stepper.js +1 -1
- package/dist/engine/block/kind.d.ts +3 -0
- package/dist/engine/block/kind.js +11 -0
- package/dist/engine/errors.d.ts +12 -0
- package/dist/engine/errors.js +12 -0
- package/dist/engine/read/read-block.d.ts +61 -0
- package/dist/engine/read/read-block.js +94 -0
- package/dist/engine/read/read-key.d.ts +32 -0
- package/dist/engine/read/read-key.js +34 -0
- package/dist/engine/read/read-page.d.ts +19 -0
- package/dist/engine/read/read-page.js +50 -0
- package/dist/engine/read/readers.d.ts +82 -0
- package/dist/engine/read/readers.js +43 -0
- package/dist/engine/read/run-read.d.ts +17 -0
- package/dist/engine/read/run-read.js +156 -0
- package/dist/engine/run/connect.js +3 -2
- package/dist/engine/run/events.d.ts +28 -10
- package/dist/engine/run/events.js +52 -38
- package/dist/engine/run/run.js +25 -13
- package/dist/engine/stub/stub.d.ts +26 -21
- package/dist/index.d.ts +7 -4
- package/dist/index.js +9 -4
- package/dist/live/auto/auto.js +2 -3
- package/dist/live/auto/menu.js +3 -2
- package/dist/live/auto-session/auto-session.d.ts +9 -2
- package/dist/live/auto-session/auto-session.js +23 -20
- package/dist/live/auto-session/feed.d.ts +16 -0
- package/dist/live/auto-session/feed.js +71 -0
- package/dist/live/auto-session/helpers.d.ts +7 -0
- package/dist/live/auto-session/helpers.js +9 -0
- package/dist/live/auto-session/ipc.d.ts +15 -47
- package/dist/live/auto-session/ipc.js +34 -4
- package/dist/live/auto-session/protocol.d.ts +127 -0
- package/dist/live/auto-session/protocol.js +6 -0
- package/dist/live/auto-session/read.d.ts +25 -0
- package/dist/live/auto-session/read.js +50 -0
- package/dist/live/traverse/worker.d.ts +1 -0
- package/dist/live/traverse/worker.js +6 -1
- package/dist/manifest/manifest.d.ts +22 -2
- package/dist/manifest/manifest.js +27 -1
- package/dist/manifest/project.d.ts +10 -1
- package/dist/manifest/project.js +9 -12
- package/dist/manifest/read-blocks.d.ts +2 -0
- package/dist/manifest/read-blocks.js +23 -0
- package/dist/manifest/scan.d.ts +3 -2
- package/dist/manifest/scan.js +8 -4
- package/dist/runner/runner.d.ts +0 -1
- package/dist/runner/runner.js +6 -6
- package/dist/runtime/full-launch.d.ts +2 -1
- package/dist/runtime/full-launch.js +29 -27
- package/dist/runtime/run-log.d.ts +2 -0
- package/dist/runtime/run-log.js +13 -6
- package/examples/saucedemo/README.md +2 -2
- package/examples/saucedemo/src/blocks/SITE-MAP.md +3 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/cart.read.block.ts +26 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/header.read.block.ts +25 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.read.block.ts +28 -0
- package/examples/saucedemo/src/flows/api-demo.flow.ts +1 -1
- package/examples/saucedemo/src/flows/cart-bulk.flow.ts +1 -1
- package/examples/saucedemo/src/flows/cart-continue.flow.ts +1 -1
- package/examples/saucedemo/src/flows/catalog-logout.flow.ts +1 -1
- package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +1 -1
- package/examples/saucedemo/src/flows/checkout.flow.ts +11 -11
- package/examples/saucedemo/src/flows/login.flow.ts +1 -1
- package/examples/saucedemo/src/flows/shop.flow.ts +1 -1
- package/examples/saucedemo/src/flows/stub-on-error.flow.ts +1 -1
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +1 -1
- package/examples/saucedemo/src/states/checkout.reads.ts +9 -0
- package/examples/saucedemo/src/stubs/device-showcase.ts +37 -37
- package/examples/saucedemo/src/stubs/finish-order.ts +2 -2
- package/examples/saucedemo/src/stubs/login.ts +5 -5
- package/package.json +5 -1
- package/templates/quickstart/src/flows/api-demo.flow.ts +1 -1
- package/templates/quickstart/src/flows/cart-bulk.flow.ts +1 -1
- package/templates/quickstart/src/flows/cart-continue.flow.ts +1 -1
- package/templates/quickstart/src/flows/catalog-logout.flow.ts +1 -1
- package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +1 -1
- package/templates/quickstart/src/flows/checkout.flow.ts +11 -11
- package/templates/quickstart/src/flows/login.flow.ts +1 -1
- package/templates/quickstart/src/flows/shop.flow.ts +1 -1
- package/templates/quickstart/src/flows/stub-on-error.flow.ts +1 -1
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +1 -1
- package/templates/quickstart/src/stubs/device-showcase.ts +37 -37
- package/templates/quickstart/src/stubs/finish-order.ts +2 -2
- package/templates/quickstart/src/stubs/login.ts +5 -5
- package/templates/scaffold/src/flows/(external)/hoppscotch/auth.flow.ts +1 -1
- package/templates/scaffold/src/flows/(external)/hoppscotch/get.flow.ts +1 -1
- package/templates/scaffold/src/flows/(external)/hoppscotch/post.flow.ts +1 -1
- package/templates/scaffold/src/flows/(user-stories)/email-verification.flow.ts +4 -4
- package/templates/scaffold/src/flows/README.md +1 -1
- package/templates/scaffold/src/flows/home/cart.flow.ts +7 -7
- package/templates/scaffold/src/flows/home/hello.flow.ts +8 -8
- package/templates/skills/waygraph-convention.skill.md +10 -2
- package/templates/skills/waygraph-pilot.skill.md +7 -0
|
@@ -3,12 +3,12 @@ import { CheckoutOverviewSel } from "../blocks/saucedemo-web/checkout-step-two/m
|
|
|
3
3
|
|
|
4
4
|
/** Rings Finish while the order is placed. */
|
|
5
5
|
export function placingOrder(ctx: StubCtx): void {
|
|
6
|
-
ctx.ring("finish", { selector: CheckoutOverviewSel.finishBtn, label: "Placing the order" });
|
|
6
|
+
ctx.ui.ring("finish", { selector: CheckoutOverviewSel.finishBtn, label: "Placing the order" });
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/** Yap slides after the order is placed. They play on the completion page, so they ring its header, not #finish. */
|
|
10
10
|
export function orderPlacedYap(ctx: StubCtx): void {
|
|
11
|
-
ctx.slides([
|
|
11
|
+
ctx.ui.slides([
|
|
12
12
|
{
|
|
13
13
|
caption: "Checkout is a short pipeline",
|
|
14
14
|
detail: "Cart -> info -> overview -> done. You just placed the order.",
|
|
@@ -3,8 +3,8 @@ import { LoginSel } from "../blocks/saucedemo-web/methods/login.sel.js";
|
|
|
3
3
|
|
|
4
4
|
/** What a refused login looks like on screen: the title, a finished checklist and the error banner. */
|
|
5
5
|
export function loginRefused(ctx: StubCtx): void {
|
|
6
|
-
ctx.title("Login blocked");
|
|
7
|
-
ctx.todos(
|
|
6
|
+
ctx.ui.title("Login blocked");
|
|
7
|
+
ctx.ui.todos(
|
|
8
8
|
"saucedemo",
|
|
9
9
|
[
|
|
10
10
|
{ id: "login-user", text: "Enter username", done: true },
|
|
@@ -13,7 +13,7 @@ export function loginRefused(ctx: StubCtx): void {
|
|
|
13
13
|
],
|
|
14
14
|
{ title: "Sign in", style: "checklist" },
|
|
15
15
|
);
|
|
16
|
-
ctx.ring("error", {
|
|
16
|
+
ctx.ui.ring("error", {
|
|
17
17
|
selector: LoginSel.errorBanner,
|
|
18
18
|
label: "Login error banner",
|
|
19
19
|
detail: "tone: danger (red)",
|
|
@@ -25,8 +25,8 @@ export function loginRefused(ctx: StubCtx): void {
|
|
|
25
25
|
|
|
26
26
|
/** Rings the error banner when the login step itself throws. */
|
|
27
27
|
export function loginFailed(ctx: StubCtx): void {
|
|
28
|
-
ctx.title("Login failed");
|
|
29
|
-
ctx.ring("error", {
|
|
28
|
+
ctx.ui.title("Login failed");
|
|
29
|
+
ctx.ui.ring("error", {
|
|
30
30
|
selector: LoginSel.errorBanner,
|
|
31
31
|
label: "Login error banner",
|
|
32
32
|
detail: "tone: danger (red)",
|
|
@@ -19,7 +19,7 @@ export const hoppscotchAuthFlow = engine
|
|
|
19
19
|
.start()
|
|
20
20
|
.gotoExternal(
|
|
21
21
|
NavHoppscotchSettingsBlock.stubBefore((ctx) => {
|
|
22
|
-
ctx.title("Scaffold: Hoppscotch GET with query params and bearer token");
|
|
22
|
+
ctx.ui.title("Scaffold: Hoppscotch GET with query params and bearer token");
|
|
23
23
|
}),
|
|
24
24
|
)
|
|
25
25
|
.method(PickExtensionInterceptorBlock)
|
|
@@ -13,7 +13,7 @@ export const hoppscotchGetFlow = engine
|
|
|
13
13
|
.start()
|
|
14
14
|
.gotoExternal(
|
|
15
15
|
NavHoppscotchSettingsBlock.stubBefore((ctx) => {
|
|
16
|
-
ctx.title("Scaffold: Hoppscotch GET");
|
|
16
|
+
ctx.ui.title("Scaffold: Hoppscotch GET");
|
|
17
17
|
}),
|
|
18
18
|
)
|
|
19
19
|
.method(PickExtensionInterceptorBlock)
|
|
@@ -18,7 +18,7 @@ export const hoppscotchPostFlow = engine
|
|
|
18
18
|
.start()
|
|
19
19
|
.gotoExternal(
|
|
20
20
|
NavHoppscotchSettingsBlock.stubBefore((ctx) => {
|
|
21
|
-
ctx.title("Scaffold: Hoppscotch POST with header and JSON body");
|
|
21
|
+
ctx.ui.title("Scaffold: Hoppscotch POST with header and JSON body");
|
|
22
22
|
}),
|
|
23
23
|
)
|
|
24
24
|
.method(PickExtensionInterceptorBlock)
|
|
@@ -14,12 +14,12 @@ export const emailVerificationFlow = engine
|
|
|
14
14
|
.start()
|
|
15
15
|
.gotoExternal(
|
|
16
16
|
NavMailpitInboxBlock.stubBefore((ctx) => {
|
|
17
|
-
ctx.title("Scaffold: Cross-origin mail verification (QA-rich)");
|
|
17
|
+
ctx.ui.title("Scaffold: Cross-origin mail verification (QA-rich)");
|
|
18
18
|
}),
|
|
19
19
|
)
|
|
20
20
|
.assert(
|
|
21
21
|
AssertEmailReceivedBlock.stubAfter((ctx) => {
|
|
22
|
-
ctx.ring("note", {
|
|
22
|
+
ctx.ui.ring("note", {
|
|
23
23
|
selector: MailpitSel.messageRow,
|
|
24
24
|
label: "AC · email arrived",
|
|
25
25
|
detail: "Confirmed before opening anything.",
|
|
@@ -30,12 +30,12 @@ export const emailVerificationFlow = engine
|
|
|
30
30
|
.method(OpenMessageBlock)
|
|
31
31
|
.assert(
|
|
32
32
|
AssertEmailContentBlock.stubAfter((ctx) => {
|
|
33
|
-
ctx.ring("note", { selector: MailpitSel.previewIframe, label: "AC · email body matches expected copy", tag: "AC" });
|
|
33
|
+
ctx.ui.ring("note", { selector: MailpitSel.previewIframe, label: "AC · email body matches expected copy", tag: "AC" });
|
|
34
34
|
}),
|
|
35
35
|
)
|
|
36
36
|
.method(
|
|
37
37
|
ExtractEmailLinkBlock.stubAfter((ctx) => {
|
|
38
|
-
ctx.ring("note", {
|
|
38
|
+
ctx.ui.ring("note", {
|
|
39
39
|
selector: MailpitSel.previewIframe,
|
|
40
40
|
label: "AC · link found",
|
|
41
41
|
detail: "Read from the message preview iframe.",
|
|
@@ -34,6 +34,6 @@ src/flows/
|
|
|
34
34
|
|
|
35
35
|
- Build it with `engine.map({ memStub })…end()`; nest another with `.flow(sub, { reset: true })`;
|
|
36
36
|
`.end()` takes nothing.
|
|
37
|
-
- The flow's name and narration are ctx stubs chained on the Block where they apply: `ctx.title("…")`, `ctx.ring(…)`.
|
|
37
|
+
- The flow's name and narration are ctx stubs chained on the Block where they apply: `ctx.ui.title("…")`, `ctx.ui.ring(…)`.
|
|
38
38
|
- A flow expected to fail (a locked-out user) says so in `map({ expectedFailure: "…" })`.
|
|
39
39
|
- A step's speed in the demo is `{ pace }`: `.method(FillBlock, { pace: "blitz" })`.
|
|
@@ -10,10 +10,10 @@ import "../../map/(app_base)/home/_page.block.js";
|
|
|
10
10
|
|
|
11
11
|
// `map({ memStub: true })` fills SelectedItem (alpha) from src/states/demo.mem-stubs.ts; --data overrides it.
|
|
12
12
|
const AddShown = AddItemBlock.stubBefore((ctx) => {
|
|
13
|
-
ctx.ring("add", { selector: DemoSel.catalog, label: "Catalog" });
|
|
13
|
+
ctx.ui.ring("add", { selector: DemoSel.catalog, label: "Catalog" });
|
|
14
14
|
})
|
|
15
15
|
.stubAfter((ctx) => {
|
|
16
|
-
ctx.ring("cart", {
|
|
16
|
+
ctx.ui.ring("cart", {
|
|
17
17
|
selector: DemoSel.cartCount,
|
|
18
18
|
label: "AC · item in cart",
|
|
19
19
|
detail: "Cart count bumped after Add.",
|
|
@@ -22,17 +22,17 @@ const AddShown = AddItemBlock.stubBefore((ctx) => {
|
|
|
22
22
|
});
|
|
23
23
|
})
|
|
24
24
|
.stubOnError((ctx) => {
|
|
25
|
-
ctx.ring("cart", { selector: DemoSel.cartCount, label: "Cart at failure", tag: "FAIL" });
|
|
25
|
+
ctx.ui.ring("cart", { selector: DemoSel.cartCount, label: "Cart at failure", tag: "FAIL" });
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
const RemoveShown = RemoveItemBlock.stubAfter((ctx) => {
|
|
29
|
-
ctx.ring("cart", { selector: DemoSel.cartCount, label: "Cart count", duration: true });
|
|
29
|
+
ctx.ui.ring("cart", { selector: DemoSel.cartCount, label: "Cart count", duration: true });
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
const ClearShown = ClearCartBlock.stubBefore((ctx) => {
|
|
33
|
-
ctx.ring("clear", { selector: DemoSel.clear, label: "Clear cart" });
|
|
33
|
+
ctx.ui.ring("clear", { selector: DemoSel.clear, label: "Clear cart" });
|
|
34
34
|
}).stubAfter((ctx) => {
|
|
35
|
-
ctx.ring("cart", { selector: DemoSel.cartCount, label: "Empty cart", duration: true });
|
|
35
|
+
ctx.ui.ring("cart", { selector: DemoSel.cartCount, label: "Empty cart", duration: true });
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
export const homeCartFlow = engine
|
|
@@ -40,7 +40,7 @@ export const homeCartFlow = engine
|
|
|
40
40
|
.start()
|
|
41
41
|
.gotoPage(
|
|
42
42
|
NavHomeBlock.stubBefore((ctx) => {
|
|
43
|
-
ctx.title("Scaffold: Shop (Effect + clear)");
|
|
43
|
+
ctx.ui.title("Scaffold: Shop (Effect + clear)");
|
|
44
44
|
}),
|
|
45
45
|
)
|
|
46
46
|
.method(AddShown)
|
|
@@ -13,32 +13,32 @@ export const homeHelloFlow = engine
|
|
|
13
13
|
.start()
|
|
14
14
|
.gotoPage(
|
|
15
15
|
NavHomeBlock.stubBefore((ctx) => {
|
|
16
|
-
ctx.title("Scaffold: Hello Waygraph");
|
|
16
|
+
ctx.ui.title("Scaffold: Hello Waygraph");
|
|
17
17
|
}).stubAfter((ctx) => {
|
|
18
|
-
ctx.ring("title", { selector: DemoSel.title, label: "Home heading", duration: true });
|
|
18
|
+
ctx.ui.ring("title", { selector: DemoSel.title, label: "Home heading", duration: true });
|
|
19
19
|
}).stubOnError((ctx) => {
|
|
20
|
-
ctx.ring("title", { selector: DemoSel.title, label: "Home heading at failure" });
|
|
20
|
+
ctx.ui.ring("title", { selector: DemoSel.title, label: "Home heading at failure" });
|
|
21
21
|
}),
|
|
22
22
|
)
|
|
23
23
|
.assert(
|
|
24
24
|
AssertHelloBlock.stubBefore((ctx) => {
|
|
25
|
-
ctx.ring("title", { selector: DemoSel.title, label: "Heading about to check" });
|
|
25
|
+
ctx.ui.ring("title", { selector: DemoSel.title, label: "Heading about to check" });
|
|
26
26
|
})
|
|
27
27
|
.stubAfter((ctx) => {
|
|
28
|
-
ctx.ring("title", {
|
|
28
|
+
ctx.ui.ring("title", {
|
|
29
29
|
selector: DemoSel.title,
|
|
30
30
|
label: "AC · Hello visible",
|
|
31
31
|
detail: "Replace this copy with your ticket lines.",
|
|
32
32
|
tag: "AC",
|
|
33
33
|
duration: true,
|
|
34
34
|
});
|
|
35
|
-
ctx.ring("sub", { selector: DemoSel.sub, label: "Subcopy", duration: 1500 });
|
|
36
|
-
ctx.slides([
|
|
35
|
+
ctx.ui.ring("sub", { selector: DemoSel.sub, label: "Subcopy", duration: 1500 });
|
|
36
|
+
ctx.ui.slides([
|
|
37
37
|
{ caption: "Scaffold covers auto + narration", detail: "Page hub, Effect instanceOptions, stubs, YAP.", tag: "YAP", duration: true },
|
|
38
38
|
]);
|
|
39
39
|
})
|
|
40
40
|
.stubOnError((ctx) => {
|
|
41
|
-
ctx.ring("title", { selector: DemoSel.title, label: "Heading at failure", tag: "FAIL" });
|
|
41
|
+
ctx.ui.ring("title", { selector: DemoSel.title, label: "Heading at failure", tag: "FAIL" });
|
|
42
42
|
}),
|
|
43
43
|
)
|
|
44
44
|
.gotoPage(NavDocsBlock)
|
|
@@ -68,18 +68,26 @@ against a live site, use `--skill-pilot-blind`.
|
|
|
68
68
|
when a *different* Block right after it in the `.flow.ts` is what actually confirms the
|
|
69
69
|
transition (e.g. an `AssertXBlock`) - `// waygraph-ignore: empty-verify`.
|
|
70
70
|
|
|
71
|
+
9. **Never hand-write UI.** All demo UI goes through `ctx.ui` (`ring`, `caption`, `title`, `todos`, `slides`,
|
|
72
|
+
`device`, `zoom`, `showNetworkTab`), chained where the flow uses the Block. Never build your own caption, highlight
|
|
73
|
+
or banner in the page (`page.evaluate` + `document.createElement` / `innerHTML` / `.style`, `page.addStyleTag`),
|
|
74
|
+
and never restyle or call waygraph's overlay (`#wg-*`, `.wg-*`, `window.__wg*`). It changes the page under test (an
|
|
75
|
+
injected banner can cover a button, an injected style can hide a bug) and breaks silently when the overlay changes.
|
|
76
|
+
If `ctx.ui` lacks something, say so and ask for it in waygraph - don't override. `waygraph check` flags it
|
|
77
|
+
(`hand-written-ui`).
|
|
78
|
+
|
|
71
79
|
## Flows, stubs and config (the scaffold's shape)
|
|
72
80
|
|
|
73
81
|
- **Build flows with `map()`** (`engine.map({ memStub }).start().gotoPage(Nav).method(B, { pace }).assert(A).end()`;
|
|
74
82
|
`.gotoExternal` for another origin); it is the only way to build one. Flow settings (`memStub`, `expectedFailure`, `demoPace`, `sessionReset`) go in `map({ … })` before the chain
|
|
75
|
-
and `.end()` takes nothing. The flow's title is `ctx.title(...)` in a stub. **Nest flows with `.flow(sub, { reset: true })`**.
|
|
83
|
+
and `.end()` takes nothing. The flow's title is `ctx.ui.title(...)` in a stub. **Nest flows with `.flow(sub, { reset: true })`**.
|
|
76
84
|
`defineFlow`, `chainFlow` and the `with*` flow wrappers were removed in 0.16.0; `waygraph upgrade --codemod flows` converts them.
|
|
77
85
|
- **`src/flows/` holds use cases and mirrors the front end's endpoints**: a folder per page (`flows/auth/login/`) with one
|
|
78
86
|
file per scenario named for its outcome (`success.flow.ts`, `wrong-password.flow.ts`, `empty-fields.flow.ts`), and
|
|
79
87
|
`(user-stories)/` (any `(group)`) for flows that cross pages. Export names are `<page><Outcome>Flow`. Not one file per
|
|
80
88
|
Block chain, not a flat folder of unrelated flows.
|
|
81
89
|
- **Blocks carry no stubs; the flow does.** Demo highlights are ctx stubs chained on the Block where the flow uses it:
|
|
82
|
-
`AddItemBlock.stubAfter((ctx) => { ctx.ring("cart", { selector: DemoSel.cartCount, label: "AC · item in cart" }); })`.
|
|
90
|
+
`AddItemBlock.stubAfter((ctx) => { ctx.ui.ring("cart", { selector: DemoSel.cartCount, label: "AC · item in cart" }); })`.
|
|
83
91
|
That chained function is the only form: a Block's definition (its options or `instruction`) takes no stub, and a stub
|
|
84
92
|
is never a slot map. A Block used twice gets one `const AddShown = AddItemBlock.stubAfter(...)`. A stub that throws
|
|
85
93
|
fails its step in the demo, named.
|
|
@@ -157,6 +157,13 @@ the entire reason this package exists. If a needed action truly has no Block, wr
|
|
|
157
157
|
properly (mirroring a sibling Block's shape) and `auto reload` it in rather than raw-clicking
|
|
158
158
|
past the gap.
|
|
159
159
|
|
|
160
|
+
To know what the page shows, read the `read` field every `status`/`send`/`reach` reply
|
|
161
|
+
carries (or `pilot read <id> [path]` for one part, uncut): it comes from the project's Read
|
|
162
|
+
Blocks (`*.read.block.ts`, beta) as typed JSON. Reach for `auto dom` only when `read` is empty
|
|
163
|
+
(no Read Block covers the page) or misses what you need - and then consider writing the Read
|
|
164
|
+
Block. `pilot watch <id>` streams every step, read and snapshot as JSON lines if you need to
|
|
165
|
+
follow changes you did not cause (another user, a server push).
|
|
166
|
+
|
|
160
167
|
The one legitimate exception: `auto dom` to resolve a real ambiguity the menu's own labels
|
|
161
168
|
can't (e.g. two products tied at the same displayed price) - and say so explicitly when you
|
|
162
169
|
do it.
|