waygraph 0.15.2 → 0.15.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/dist/auto-session-ipc.d.ts +14 -0
- package/dist/auto-session-ipc.js +4 -0
- package/dist/auto-session.d.ts +15 -0
- package/dist/auto-session.js +34 -1
- package/dist/cli.js +43 -2
- package/dist/engine.d.ts +124 -12
- package/dist/engine.js +170 -13
- package/dist/highlights.d.ts +8 -0
- package/dist/highlights.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/pilot-overlay.d.ts +42 -0
- package/dist/pilot-overlay.js +148 -0
- package/dist/types.d.ts +17 -0
- package/examples/saucedemo/.waygraph-auto/1d266123.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c7e8edd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/49edc885.log +4 -0
- package/examples/saucedemo/.waygraph-auto/79600ead.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d2c6ed66.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ddcb4212.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ebc2ebdb.log +0 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +8 -7
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -10
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -10
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
- package/examples/saucedemo/src/flows/checkout.flow.ts +61 -97
- package/examples/saucedemo/src/flows/login.flow.ts +11 -2
- package/examples/saucedemo/src/flows/shop.flow.ts +13 -13
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +9 -2
- package/package.json +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +8 -7
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -10
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -10
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
- package/templates/quickstart/src/flows/checkout.flow.ts +61 -97
- package/templates/quickstart/src/flows/login.flow.ts +11 -2
- package/templates/quickstart/src/flows/shop.flow.ts +13 -13
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +9 -2
- package/templates/skills/waygraph-blind-pilot.skill.md +2 -1
- package/templates/skills/waygraph-pilot.skill.md +17 -0
- package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +0 -8
package/dist/engine.js
CHANGED
|
@@ -811,52 +811,108 @@ export class MapBuilder {
|
|
|
811
811
|
engine;
|
|
812
812
|
steps;
|
|
813
813
|
homeOrigin;
|
|
814
|
-
|
|
814
|
+
ff;
|
|
815
|
+
constructor(engine, steps, homeOrigin, ff = null) {
|
|
815
816
|
this.engine = engine;
|
|
816
817
|
this.steps = steps;
|
|
817
818
|
this.homeOrigin = homeOrigin;
|
|
819
|
+
this.ff = ff;
|
|
818
820
|
}
|
|
819
821
|
/** @internal - use `engine.map()` or the standalone `map()` export. */
|
|
820
822
|
static begin(engine, homeOrigin) {
|
|
821
|
-
return new MapBuilder(engine, [], homeOrigin);
|
|
823
|
+
return new MapBuilder(engine, [], homeOrigin, null);
|
|
822
824
|
}
|
|
823
825
|
/** Readable chain-opener - mirrors `defineFlow`'s leading `start` sentinel. Returns `this` unchanged; entirely optional. */
|
|
824
826
|
start() {
|
|
825
827
|
return this;
|
|
826
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* Open a fast-forward window - steps until {@link ffEnd} collapse into one
|
|
831
|
+
* opaque `fastForwardComposeBlock` (blitz theater). Kind/salt checks still
|
|
832
|
+
* run on each inner step as it is added.
|
|
833
|
+
*/
|
|
834
|
+
ffStart(name) {
|
|
835
|
+
if (this.ff) {
|
|
836
|
+
throw new Error(`Waygraph map: .ffStart() while already inside "${this.ff.name}" - call .ffEnd() first`);
|
|
837
|
+
}
|
|
838
|
+
const ffName = typeof name === "string" && name.trim()
|
|
839
|
+
? name.trim()
|
|
840
|
+
: `ff-${this.steps.length + 1}`;
|
|
841
|
+
return new MapBuilder(this.engine, this.steps, this.homeOrigin, {
|
|
842
|
+
name: ffName,
|
|
843
|
+
buffer: [],
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Close the current fast-forward window and append one FFCompose step.
|
|
848
|
+
* Throws if empty or if {@link ffStart} was never opened.
|
|
849
|
+
*/
|
|
850
|
+
ffEnd() {
|
|
851
|
+
if (!this.ff) {
|
|
852
|
+
throw new Error("Waygraph map: .ffEnd() with no open .ffStart()");
|
|
853
|
+
}
|
|
854
|
+
if (this.ff.buffer.length === 0) {
|
|
855
|
+
throw new Error(`Waygraph map: .ffEnd() for "${this.ff.name}" has no steps - add .gotoPage/.method/… inside the window`);
|
|
856
|
+
}
|
|
857
|
+
const composed = fastForwardComposeBlock(this.ff.name,
|
|
858
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
859
|
+
this.ff.buffer);
|
|
860
|
+
return new MapBuilder(this.engine, [...this.steps, composed], this.homeOrigin, null);
|
|
861
|
+
}
|
|
862
|
+
appendStep(block) {
|
|
863
|
+
if (this.ff) {
|
|
864
|
+
return new MapBuilder(this.engine, this.steps, this.homeOrigin, {
|
|
865
|
+
name: this.ff.name,
|
|
866
|
+
buffer: [...this.ff.buffer, block],
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
return new MapBuilder(this.engine, [...this.steps, block], this.homeOrigin, null);
|
|
870
|
+
}
|
|
827
871
|
/**
|
|
828
872
|
* Appends an internal navigation/page-arrival step - requires a Block from
|
|
829
873
|
* `defineNavBlock`/`defineMemNavBlock`/`definePageBlock`. Throws if given
|
|
830
874
|
* anything else, including a `homeOrigin`-mismatched static `url`.
|
|
875
|
+
* Compile-time: {@link NavBlock} or {@link PageBlock} only (not Assert/Method).
|
|
831
876
|
*/
|
|
832
877
|
gotoPage(block) {
|
|
833
878
|
assertMapKind(block, ["nav", "page"], "gotoPage");
|
|
834
879
|
assertMapOrigin(block, this.homeOrigin, "internal", "gotoPage");
|
|
835
|
-
return
|
|
880
|
+
return this.appendStep(block);
|
|
836
881
|
}
|
|
837
882
|
/**
|
|
838
883
|
* Appends a genuinely cross-origin navigation step (e.g. `(external)/`
|
|
839
884
|
* Blocks in the Waygraph Map convention: mailpit, maildrop.cc) - same
|
|
840
885
|
* kind requirement as {@link gotoPage}, plus the inverse `homeOrigin` check.
|
|
886
|
+
* Compile-time: {@link NavBlock} or {@link PageBlock} only.
|
|
841
887
|
*/
|
|
842
888
|
gotoExternal(block) {
|
|
843
889
|
assertMapKind(block, ["nav", "page"], "gotoExternal");
|
|
844
890
|
assertMapOrigin(block, this.homeOrigin, "external", "gotoExternal");
|
|
845
|
-
return
|
|
891
|
+
return this.appendStep(block);
|
|
846
892
|
}
|
|
847
|
-
/**
|
|
893
|
+
/**
|
|
894
|
+
* Appends a self-loop verification step - requires a Block from
|
|
895
|
+
* `defineAssertBlock`. Compile-time: {@link AssertBlock} only (not `.method()`).
|
|
896
|
+
*/
|
|
848
897
|
assert(block) {
|
|
849
898
|
assertMapKind(block, ["assert"], "assert");
|
|
850
|
-
return
|
|
899
|
+
return this.appendStep(block);
|
|
851
900
|
}
|
|
852
901
|
/**
|
|
853
902
|
* Appends a non-navigating page action (submit, upload, add/remove an
|
|
854
903
|
* instance) - requires a Block from `defineMethodBlock`/`defineActionBlock`/
|
|
855
904
|
* `defineEffectBlock`/`defineMemEffectBlock`.
|
|
905
|
+
* Compile-time: {@link MethodBlock} or {@link EffectBlock} only - Assert
|
|
906
|
+
* Blocks must use `.assert()`. Runtime also rejects `__waygraphKind =
|
|
907
|
+
* "assert"` (those still carry method salt from the factory internals).
|
|
856
908
|
*/
|
|
857
909
|
method(block) {
|
|
910
|
+
if (mapKindOf(block) === "assert") {
|
|
911
|
+
throw new Error(`Waygraph map: .method("${block.name}") got a defineAssertBlock - use .assert() for ` +
|
|
912
|
+
"self-loop verify steps (Assert Blocks share method salt internally but are not methods).");
|
|
913
|
+
}
|
|
858
914
|
assertMapSalt(block, ["method", "effect"], "method");
|
|
859
|
-
return
|
|
915
|
+
return this.appendStep(block);
|
|
860
916
|
}
|
|
861
917
|
/**
|
|
862
918
|
* Finalizes this chain into a real, runnable {@link Flow} - same object
|
|
@@ -867,6 +923,9 @@ export class MapBuilder {
|
|
|
867
923
|
* isn't a flow.
|
|
868
924
|
*/
|
|
869
925
|
end() {
|
|
926
|
+
if (this.ff) {
|
|
927
|
+
throw new Error(`Waygraph map: .end() while .ffStart("${this.ff.name}") is still open - call .ffEnd() first`);
|
|
928
|
+
}
|
|
870
929
|
if (this.steps.length === 0) {
|
|
871
930
|
throw new Error("Waygraph map: .end() called with zero steps - add at least one .gotoPage()/.gotoExternal()/" +
|
|
872
931
|
".assert()/.method() before .end()");
|
|
@@ -937,8 +996,38 @@ function stripMethods(block) {
|
|
|
937
996
|
...(block.next ? { next: block.next } : {}),
|
|
938
997
|
...(block.requires ? { requires: block.requires } : {}),
|
|
939
998
|
...(block.routes ? { routes: block.routes } : {}),
|
|
999
|
+
...(block.instanceOptions ? { instanceOptions: block.instanceOptions } : {}),
|
|
940
1000
|
};
|
|
941
1001
|
}
|
|
1002
|
+
/** Copy non-enumerable waygraph markers so decorate/withVerify keep map() kind checks. */
|
|
1003
|
+
function copyWaygraphRuntime(from, to) {
|
|
1004
|
+
for (const key of [
|
|
1005
|
+
"__waygraphKind",
|
|
1006
|
+
"__waygraphSalt",
|
|
1007
|
+
"__waygraphNavUrl",
|
|
1008
|
+
"__waygraphNavClick",
|
|
1009
|
+
]) {
|
|
1010
|
+
const desc = Object.getOwnPropertyDescriptor(from, key);
|
|
1011
|
+
if (!desc)
|
|
1012
|
+
continue;
|
|
1013
|
+
// Re-define as configurable so later decorate chains can copy again
|
|
1014
|
+
// (factory markers are non-configurable on the original).
|
|
1015
|
+
Object.defineProperty(to, key, {
|
|
1016
|
+
value: desc.value,
|
|
1017
|
+
enumerable: false,
|
|
1018
|
+
writable: false,
|
|
1019
|
+
configurable: true,
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
const ff = from.fastForward;
|
|
1023
|
+
if (ff === true) {
|
|
1024
|
+
to.fastForward = true;
|
|
1025
|
+
}
|
|
1026
|
+
const pace = from.demoPace;
|
|
1027
|
+
if (pace !== undefined) {
|
|
1028
|
+
to.demoPace = pace;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
942
1031
|
/**
|
|
943
1032
|
* Builds a Block with `withVerify`/`modVerify`/`modVerifyAll` attached as
|
|
944
1033
|
* methods - `LoginBlock.withVerify([...])`, discoverable by typing
|
|
@@ -958,12 +1047,19 @@ export function defineBlock(base) {
|
|
|
958
1047
|
...(base.routes ? { routes: base.routes } : {}),
|
|
959
1048
|
...(base.instanceOptions ? { instanceOptions: base.instanceOptions } : {}),
|
|
960
1049
|
};
|
|
961
|
-
|
|
1050
|
+
// Methods must close over `defined` (this object), not `plain` - factories
|
|
1051
|
+
// attach __waygraphKind/__waygraphSalt on the returned object after
|
|
1052
|
+
// defineBlock returns; decorate/withVerify need those markers.
|
|
1053
|
+
const defined = {
|
|
962
1054
|
...plain,
|
|
963
|
-
withVerify: (verify) => withVerify(
|
|
964
|
-
modVerify: (nameOrIndex, newCheck) => modVerify(
|
|
965
|
-
modVerifyAll: (patches) => modVerifyAll(
|
|
1055
|
+
withVerify: (verify) => withVerify(defined, verify),
|
|
1056
|
+
modVerify: (nameOrIndex, newCheck) => modVerify(defined, nameOrIndex, newCheck),
|
|
1057
|
+
modVerifyAll: (patches) => modVerifyAll(defined, patches),
|
|
1058
|
+
stubBefore: (stub) => withStubBefore(defined, stub),
|
|
1059
|
+
stubAfter: (stub) => withStubAfter(defined, stub),
|
|
1060
|
+
stubOnError: (stub) => withStubOnError(defined, stub),
|
|
966
1061
|
};
|
|
1062
|
+
return defined;
|
|
967
1063
|
}
|
|
968
1064
|
/**
|
|
969
1065
|
* Builds a {@link NavBlock}. The generated `act()` is always exactly
|
|
@@ -1120,6 +1216,8 @@ export function defineAssertBlock(options) {
|
|
|
1120
1216
|
enumerable: false,
|
|
1121
1217
|
configurable: false,
|
|
1122
1218
|
});
|
|
1219
|
+
// Brand for map().assert() - distinct from MethodBlock so .method(assert)
|
|
1220
|
+
// is a compile error even though runtime still carries method salt.
|
|
1123
1221
|
return built;
|
|
1124
1222
|
}
|
|
1125
1223
|
function resolvePageMethods(methods) {
|
|
@@ -1326,7 +1424,64 @@ export async function locate(page, library, options) {
|
|
|
1326
1424
|
*/
|
|
1327
1425
|
export function withVerify(block, verify) {
|
|
1328
1426
|
const base = stripMethods(block);
|
|
1329
|
-
|
|
1427
|
+
const next = defineBlock({ ...base, instruction: { ...base.instruction, verify } });
|
|
1428
|
+
copyWaygraphRuntime(block, next);
|
|
1429
|
+
return next;
|
|
1430
|
+
}
|
|
1431
|
+
function isHighlightStubPhase(v) {
|
|
1432
|
+
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
1433
|
+
}
|
|
1434
|
+
/** Run a prior stub (fn or slot map) into an open ctx so decorate can chain. */
|
|
1435
|
+
async function applyStubIntoCtx(raw, ctx) {
|
|
1436
|
+
if (raw === undefined)
|
|
1437
|
+
return;
|
|
1438
|
+
if (typeof raw === "function") {
|
|
1439
|
+
const ret = await raw(ctx);
|
|
1440
|
+
if (isHighlightStubPhase(ret)) {
|
|
1441
|
+
for (const [id, stub] of Object.entries(ret)) {
|
|
1442
|
+
if (stub)
|
|
1443
|
+
ctx.ring(id, stub);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (isHighlightStubPhase(raw)) {
|
|
1449
|
+
for (const [id, stub] of Object.entries(raw)) {
|
|
1450
|
+
if (stub)
|
|
1451
|
+
ctx.ring(id, stub);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
function withStubPhase(block, phase, stub) {
|
|
1456
|
+
const base = stripMethods(block);
|
|
1457
|
+
const instr = base.instruction;
|
|
1458
|
+
const prev = instr[phase];
|
|
1459
|
+
const chained = async (ctx) => {
|
|
1460
|
+
await applyStubIntoCtx(prev, ctx);
|
|
1461
|
+
await applyStubIntoCtx(stub, ctx);
|
|
1462
|
+
};
|
|
1463
|
+
const next = defineBlock({
|
|
1464
|
+
...base,
|
|
1465
|
+
instruction: { ...base.instruction, [phase]: chained },
|
|
1466
|
+
});
|
|
1467
|
+
copyWaygraphRuntime(block, next);
|
|
1468
|
+
return next;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Attach / chain a stubBefore lifecycle on a Block. Prefer
|
|
1472
|
+
* `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
|
|
1473
|
+
* @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
|
|
1474
|
+
*/
|
|
1475
|
+
export function withStubBefore(block, stub) {
|
|
1476
|
+
return withStubPhase(block, "stubBefore", stub);
|
|
1477
|
+
}
|
|
1478
|
+
/** @see {@link withStubBefore} */
|
|
1479
|
+
export function withStubAfter(block, stub) {
|
|
1480
|
+
return withStubPhase(block, "stubAfter", stub);
|
|
1481
|
+
}
|
|
1482
|
+
/** @see {@link withStubBefore} */
|
|
1483
|
+
export function withStubOnError(block, stub) {
|
|
1484
|
+
return withStubPhase(block, "stubOnError", stub);
|
|
1330
1485
|
}
|
|
1331
1486
|
/**
|
|
1332
1487
|
* Replaces one Trait inside `block`'s verify list, leaving every other check
|
|
@@ -1371,5 +1526,7 @@ export function modVerify(block, nameOrIndex, newCheck) {
|
|
|
1371
1526
|
* same fail-loud-on-unknown-name behavior holds for every entry.
|
|
1372
1527
|
*/
|
|
1373
1528
|
export function modVerifyAll(block, patches) {
|
|
1374
|
-
|
|
1529
|
+
const seed = defineBlock(stripMethods(block));
|
|
1530
|
+
copyWaygraphRuntime(block, seed);
|
|
1531
|
+
return Object.entries(patches).reduce((current, [name, newCheck]) => modVerify(current, name, newCheck), seed);
|
|
1375
1532
|
}
|
package/dist/highlights.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* before advancing is authored the same way on stubs, flow fixtures, and slides.
|
|
14
14
|
*/
|
|
15
15
|
import type { Block, Checkpoint } from "./types.js";
|
|
16
|
+
import type { MemPage } from "./mem-page.js";
|
|
16
17
|
/** Shared dwell fields on stubs, fixtures, and yap slides. */
|
|
17
18
|
export type FixtureDurationFields = {
|
|
18
19
|
/**
|
|
@@ -313,6 +314,12 @@ export type HighlightStubPhase = Record<string, WaygraphHighlightStub>;
|
|
|
313
314
|
* }
|
|
314
315
|
*/
|
|
315
316
|
export type StubCtx<Out extends Checkpoint<string> = Checkpoint<string>> = {
|
|
317
|
+
/**
|
|
318
|
+
* Live Mem for this run - same store `act`/`observe` read. Prefer this over
|
|
319
|
+
* closing over outer scope or inventing parallel fixture bags.
|
|
320
|
+
* Undefined only if the caller ran a stub phase without passing mem (tests).
|
|
321
|
+
*/
|
|
322
|
+
readonly mem: MemPage | undefined;
|
|
316
323
|
/** Present after resolve (stubAfter). Undefined for stubBefore. */
|
|
317
324
|
readonly out: Out | undefined;
|
|
318
325
|
/** Present on stubOnError when the step threw. */
|
|
@@ -636,6 +643,7 @@ export declare function completeSequentialTodoDock(dock: TodoDockState | undefin
|
|
|
636
643
|
export declare function runStubPhase(block: Block<any, any>, phase: HighlightStubPhaseName, opts?: {
|
|
637
644
|
out?: Checkpoint<string>;
|
|
638
645
|
error?: unknown;
|
|
646
|
+
mem?: MemPage;
|
|
639
647
|
fixtures?: HighlightFixtureMap;
|
|
640
648
|
}): Promise<StubPhaseResult>;
|
|
641
649
|
/**
|
package/dist/highlights.js
CHANGED
|
@@ -795,6 +795,7 @@ export function completeSequentialTodoDock(dock) {
|
|
|
795
795
|
}
|
|
796
796
|
function createStubCtx(bag, opts) {
|
|
797
797
|
return {
|
|
798
|
+
mem: opts.mem,
|
|
798
799
|
out: opts.out,
|
|
799
800
|
error: opts.error,
|
|
800
801
|
highlights(slots) {
|
|
@@ -1143,6 +1144,7 @@ export async function runStubPhase(block, phase, opts) {
|
|
|
1143
1144
|
const ctx = createStubCtx(bag, {
|
|
1144
1145
|
...(opts?.out !== undefined ? { out: opts.out } : {}),
|
|
1145
1146
|
...(opts?.error !== undefined ? { error: opts.error } : {}),
|
|
1147
|
+
...(opts?.mem !== undefined ? { mem: opts.mem } : {}),
|
|
1146
1148
|
});
|
|
1147
1149
|
const raw = readStubRaw(block, phase);
|
|
1148
1150
|
if (typeof raw === "function") {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ export type { Checkpoint, Instruction, Block, DefinedBlock, Start, WaygraphInsta
|
|
|
2
2
|
export { connect, checkpoint } from "./types.js";
|
|
3
3
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
4
4
|
export { Trait, urlMatches, textEquals, visible, frameVisible, frameTextEquals, frameContainsText } from "./trait.js";
|
|
5
|
-
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
5
|
+
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
6
6
|
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, normalizeTodoPos, normalizeTodoStyle, buildTodoDock, applyTodoPhase, advanceTodoDock, completeSequentialTodoDock, applyDevicePhase, resolveDeviceState, normalizeDevicePreset, normalizeDeviceOrientation, applyOrientation, orientationFromViewport, DEVICE_PRESETS, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, WAYGRAPH_RING_CSS, } from "./highlights.js";
|
|
7
7
|
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockState, TodoListStyle, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, DevicePreset, DeviceViewport, DeviceState, DeviceOrientation, } from "./highlights.js";
|
|
8
|
-
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./engine.js";
|
|
8
|
+
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./engine.js";
|
|
9
9
|
export type { ActionPage } from "./types.js";
|
|
10
10
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
11
11
|
export type { WaygraphGraph, WaygraphNode, WaygraphEdge, SkippedBlock, OrphanBlock } from "./graph.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { connect, checkpoint } from "./types.js";
|
|
2
2
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
3
3
|
export { Trait, urlMatches, textEquals, visible, frameVisible, frameTextEquals, frameContainsText } from "./trait.js";
|
|
4
|
-
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
4
|
+
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
5
5
|
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, normalizeTodoPos, normalizeTodoStyle, buildTodoDock, applyTodoPhase, advanceTodoDock, completeSequentialTodoDock, applyDevicePhase, resolveDeviceState, normalizeDevicePreset, normalizeDeviceOrientation, applyOrientation, orientationFromViewport, DEVICE_PRESETS, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, WAYGRAPH_RING_CSS, } from "./highlights.js";
|
|
6
6
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
7
7
|
export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./blocks-select.js";
|
package/dist/pilot-overlay.d.ts
CHANGED
|
@@ -52,8 +52,50 @@ export declare function showPilotActivity(page: Page, text: string): Promise<voi
|
|
|
52
52
|
* raw click/type/upload IS a real Playwright-driven action (`auto` was
|
|
53
53
|
* always documented as meaning exactly that), while a pure `auto dom` read
|
|
54
54
|
* touches nothing, so it gets its own "orange" tone instead.
|
|
55
|
+
*
|
|
56
|
+
* For agent-authored multi-ring / todo narration, use {@link showPilotFixtures}
|
|
57
|
+
* (`auto highlight`) instead - this vision ring is one-shot inspect feedback.
|
|
55
58
|
*/
|
|
56
59
|
export declare function showPilotVision(page: Page, selector: string, label: string, tone?: HighlightTone): Promise<void>;
|
|
60
|
+
/** One ring the Pilot agent wants painted (same fields as demo stub rings). */
|
|
61
|
+
export type PilotFixtureRing = {
|
|
62
|
+
selector: string;
|
|
63
|
+
label: string;
|
|
64
|
+
tone?: HighlightTone;
|
|
65
|
+
size?: "sm" | "md" | "lg";
|
|
66
|
+
weight?: "normal" | "bold";
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Agent-sent highlight fixtures for a live Pilot / auto session.
|
|
70
|
+
* Painted by {@link showPilotFixtures}; driven via IPC `op: "highlight"`.
|
|
71
|
+
*/
|
|
72
|
+
export type PilotHighlightFixtures = {
|
|
73
|
+
/** Replace current fixture rings with these (empty + no todos = clear). */
|
|
74
|
+
rings?: readonly PilotFixtureRing[];
|
|
75
|
+
/** Optional floating todo list (demo-dock language, simplified). */
|
|
76
|
+
todos?: readonly string[];
|
|
77
|
+
/** 0-based index of the "current" todo row (others before it = done). */
|
|
78
|
+
todoIndex?: number;
|
|
79
|
+
/** Optional title above the todo list. */
|
|
80
|
+
todoTitle?: string;
|
|
81
|
+
/**
|
|
82
|
+
* How long fixtures stay visible (ms). `0` = until the next highlight /
|
|
83
|
+
* clear. Default `12000`. Vision rings (`showPilotVision`) stay separate.
|
|
84
|
+
*/
|
|
85
|
+
holdMs?: number;
|
|
86
|
+
/** Drop every agent fixture ring/todo immediately. */
|
|
87
|
+
clear?: boolean;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
91
|
+
* Multi-ring + optional todo strip - what Block `stubBefore` does in
|
|
92
|
+
* `waygraph demo`, available to the Pilot agent without going through demo.
|
|
93
|
+
* Does not import `cli.ts` (see file header).
|
|
94
|
+
*/
|
|
95
|
+
export declare function showPilotFixtures(page: Page, fixtures: PilotHighlightFixtures): Promise<{
|
|
96
|
+
painted: number;
|
|
97
|
+
missing: string[];
|
|
98
|
+
}>;
|
|
57
99
|
/** Minimal shape needed to render the graph tree - matches WaygraphGraph. */
|
|
58
100
|
export interface PilotOverlayGraph {
|
|
59
101
|
nodes: readonly {
|
package/dist/pilot-overlay.js
CHANGED
|
@@ -60,6 +60,44 @@ const OVERLAY_CSS = `
|
|
|
60
60
|
opacity: 0; transform: translateY(4px); transition: opacity 0.15s, transform 0.15s;
|
|
61
61
|
}
|
|
62
62
|
#wg-pilot-activity.wg-pilot-toast-show { opacity: 1; transform: translateY(0); }
|
|
63
|
+
/* Agent-sent fixture rings share tone/size CSS with #wg-ring (demo language). */
|
|
64
|
+
.wg-pilot-fx-ring{position:fixed;z-index:2147483645;pointer-events:none;opacity:0;
|
|
65
|
+
border:3px solid #7C3AED;border-radius:10px;box-sizing:border-box;
|
|
66
|
+
transition:opacity .12s ease,left .12s,top .12s,width .12s,height .12s;}
|
|
67
|
+
.wg-pilot-fx-ring[data-tone=planned]{border-color:#7C3AED;box-shadow:0 0 0 4px rgba(124,58,237,.16);}
|
|
68
|
+
.wg-pilot-fx-ring[data-tone=auto]{border-color:#9CA3AF;box-shadow:0 0 0 4px rgba(156,163,175,.28);}
|
|
69
|
+
.wg-pilot-fx-ring[data-tone=info]{border-color:#3B82F6;box-shadow:0 0 0 4px rgba(59,130,246,.22);}
|
|
70
|
+
.wg-pilot-fx-ring[data-tone=warning]{border-color:#EAB308;box-shadow:0 0 0 4px rgba(234,179,8,.22);}
|
|
71
|
+
.wg-pilot-fx-ring[data-tone=danger]{border-color:#EF4444;box-shadow:0 0 0 4px rgba(239,68,68,.22);}
|
|
72
|
+
.wg-pilot-fx-ring[data-tone=success]{border-color:#22C55E;box-shadow:0 0 0 4px rgba(34,197,94,.22);}
|
|
73
|
+
.wg-pilot-fx-ring[data-tone=orange]{border-color:#F97316;box-shadow:0 0 0 4px rgba(249,115,22,.22);}
|
|
74
|
+
.wg-pilot-fx-label{position:fixed;z-index:2147483645;pointer-events:none;opacity:0;
|
|
75
|
+
font:600 12px/1.3 ui-sans-serif,system-ui,sans-serif;padding:5px 9px;border-radius:6px;
|
|
76
|
+
max-width:min(360px,80vw);box-shadow:0 2px 8px rgba(0,0,0,.25);white-space:nowrap;
|
|
77
|
+
overflow:hidden;text-overflow:ellipsis;transition:opacity .12s ease;}
|
|
78
|
+
.wg-pilot-fx-label[data-tone=planned]{background:#7C3AED;color:#fff;}
|
|
79
|
+
.wg-pilot-fx-label[data-tone=auto]{background:#6B7280;color:#fff;}
|
|
80
|
+
.wg-pilot-fx-label[data-tone=info]{background:#2563EB;color:#fff;}
|
|
81
|
+
.wg-pilot-fx-label[data-tone=warning]{background:#EAB308;color:#1c1917;}
|
|
82
|
+
.wg-pilot-fx-label[data-tone=danger]{background:#DC2626;color:#fff;}
|
|
83
|
+
.wg-pilot-fx-label[data-tone=success]{background:#16A34A;color:#fff;}
|
|
84
|
+
.wg-pilot-fx-label[data-tone=orange]{background:#EA580C;color:#fff;}
|
|
85
|
+
.wg-pilot-fx-ring[data-size=sm]{border-width:1.5px;border-radius:8px;}
|
|
86
|
+
.wg-pilot-fx-ring[data-size=lg]{border-width:4px;border-radius:12px;}
|
|
87
|
+
.wg-pilot-fx-label[data-size=sm]{font-size:10px;padding:4px 7px;}
|
|
88
|
+
.wg-pilot-fx-label[data-size=lg]{font-size:16px;padding:8px 14px;}
|
|
89
|
+
.wg-pilot-fx-label[data-weight=bold]{font-weight:800;}
|
|
90
|
+
#wg-pilot-fx-todos{
|
|
91
|
+
position:fixed;z-index:2147483645;top:72px;left:14px;max-width:280px;
|
|
92
|
+
font:12px/1.4 ui-sans-serif,system-ui,sans-serif;color:#fff;
|
|
93
|
+
background:rgba(20,10,40,.94);border-radius:10px;padding:10px 12px;
|
|
94
|
+
box-shadow:0 2px 10px rgba(0,0,0,.3);pointer-events:none;
|
|
95
|
+
}
|
|
96
|
+
#wg-pilot-fx-todos .wg-pilot-fx-todo-title{font-weight:700;color:#c9a6ff;margin-bottom:6px;}
|
|
97
|
+
#wg-pilot-fx-todos ol{margin:0;padding-left:18px;}
|
|
98
|
+
#wg-pilot-fx-todos li{margin:3px 0;color:#ddd;}
|
|
99
|
+
#wg-pilot-fx-todos li.wg-pilot-fx-todo-done{color:#888;text-decoration:line-through;}
|
|
100
|
+
#wg-pilot-fx-todos li.wg-pilot-fx-todo-now{color:#fff;font-weight:700;}
|
|
63
101
|
` + WAYGRAPH_RING_CSS;
|
|
64
102
|
/** Idempotent - safe to call before every update, matching narrate mode's own precedent. */
|
|
65
103
|
async function ensureInstalled(page) {
|
|
@@ -159,6 +197,9 @@ export async function showPilotActivity(page, text) {
|
|
|
159
197
|
* raw click/type/upload IS a real Playwright-driven action (`auto` was
|
|
160
198
|
* always documented as meaning exactly that), while a pure `auto dom` read
|
|
161
199
|
* touches nothing, so it gets its own "orange" tone instead.
|
|
200
|
+
*
|
|
201
|
+
* For agent-authored multi-ring / todo narration, use {@link showPilotFixtures}
|
|
202
|
+
* (`auto highlight`) instead - this vision ring is one-shot inspect feedback.
|
|
162
203
|
*/
|
|
163
204
|
export async function showPilotVision(page, selector, label, tone = "auto") {
|
|
164
205
|
await ensureInstalled(page);
|
|
@@ -211,6 +252,113 @@ export async function showPilotVision(page, selector, label, tone = "auto") {
|
|
|
211
252
|
}, { selector, label, tone })
|
|
212
253
|
.catch(() => { });
|
|
213
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
257
|
+
* Multi-ring + optional todo strip - what Block `stubBefore` does in
|
|
258
|
+
* `waygraph demo`, available to the Pilot agent without going through demo.
|
|
259
|
+
* Does not import `cli.ts` (see file header).
|
|
260
|
+
*/
|
|
261
|
+
export async function showPilotFixtures(page, fixtures) {
|
|
262
|
+
await ensureInstalled(page);
|
|
263
|
+
const holdMs = fixtures.clear === true
|
|
264
|
+
? 0
|
|
265
|
+
: fixtures.holdMs === undefined
|
|
266
|
+
? 12_000
|
|
267
|
+
: Math.max(0, fixtures.holdMs);
|
|
268
|
+
const rings = fixtures.clear ? [] : (fixtures.rings ?? []);
|
|
269
|
+
const todos = fixtures.clear ? [] : (fixtures.todos ?? []);
|
|
270
|
+
const todoIndex = fixtures.todoIndex ?? 0;
|
|
271
|
+
const todoTitle = fixtures.todoTitle ?? "Plan";
|
|
272
|
+
return page
|
|
273
|
+
.evaluate(({ rings, todos, todoIndex, todoTitle, holdMs }) => {
|
|
274
|
+
const w = window;
|
|
275
|
+
if (w.__wgPilotFxHideTimer)
|
|
276
|
+
clearTimeout(w.__wgPilotFxHideTimer);
|
|
277
|
+
const clearFx = () => {
|
|
278
|
+
document.querySelectorAll(".wg-pilot-fx-ring, .wg-pilot-fx-label").forEach((el) => el.remove());
|
|
279
|
+
document.getElementById("wg-pilot-fx-todos")?.remove();
|
|
280
|
+
};
|
|
281
|
+
w.__wgPilotFxClear = clearFx;
|
|
282
|
+
clearFx();
|
|
283
|
+
const missing = [];
|
|
284
|
+
let painted = 0;
|
|
285
|
+
for (const ring of rings) {
|
|
286
|
+
const el = document.querySelector(ring.selector);
|
|
287
|
+
if (!el) {
|
|
288
|
+
missing.push(ring.selector);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const rect = el.getBoundingClientRect();
|
|
292
|
+
if (rect.width === 0 && rect.height === 0) {
|
|
293
|
+
missing.push(ring.selector);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const tone = ring.tone || "planned";
|
|
297
|
+
const size = ring.size === "sm" || ring.size === "lg" ? ring.size : "md";
|
|
298
|
+
const weight = ring.weight === "bold" ? "bold" : "normal";
|
|
299
|
+
const pad = size === "sm" ? 3 : size === "lg" ? 10 : 6;
|
|
300
|
+
const ringEl = document.createElement("div");
|
|
301
|
+
ringEl.className = "wg-pilot-fx-ring";
|
|
302
|
+
ringEl.dataset.tone = tone;
|
|
303
|
+
ringEl.dataset.size = size;
|
|
304
|
+
ringEl.style.left = `${rect.left - pad}px`;
|
|
305
|
+
ringEl.style.top = `${rect.top - pad}px`;
|
|
306
|
+
ringEl.style.width = `${Math.max(4, rect.width + pad * 2)}px`;
|
|
307
|
+
ringEl.style.height = `${Math.max(4, rect.height + pad * 2)}px`;
|
|
308
|
+
ringEl.style.opacity = "1";
|
|
309
|
+
const labelEl = document.createElement("div");
|
|
310
|
+
labelEl.className = "wg-pilot-fx-label";
|
|
311
|
+
labelEl.dataset.tone = tone;
|
|
312
|
+
labelEl.dataset.size = size;
|
|
313
|
+
labelEl.dataset.weight = weight;
|
|
314
|
+
labelEl.textContent = ring.label;
|
|
315
|
+
labelEl.style.opacity = "1";
|
|
316
|
+
document.documentElement.appendChild(ringEl);
|
|
317
|
+
document.documentElement.appendChild(labelEl);
|
|
318
|
+
const lw = labelEl.offsetWidth;
|
|
319
|
+
const lh = labelEl.offsetHeight;
|
|
320
|
+
let labelLeft = rect.left - pad;
|
|
321
|
+
let labelTop = rect.top - pad + rect.height + pad * 2 + 8;
|
|
322
|
+
if (labelTop + lh > window.innerHeight - 6)
|
|
323
|
+
labelTop = rect.top - pad - lh - 8;
|
|
324
|
+
if (labelTop < 6)
|
|
325
|
+
labelTop = 6;
|
|
326
|
+
if (labelLeft + lw > window.innerWidth - 6) {
|
|
327
|
+
labelLeft = Math.max(6, window.innerWidth - 6 - lw);
|
|
328
|
+
}
|
|
329
|
+
if (labelLeft < 6)
|
|
330
|
+
labelLeft = 6;
|
|
331
|
+
labelEl.style.left = `${labelLeft}px`;
|
|
332
|
+
labelEl.style.top = `${labelTop}px`;
|
|
333
|
+
painted += 1;
|
|
334
|
+
}
|
|
335
|
+
if (todos.length > 0) {
|
|
336
|
+
const dock = document.createElement("div");
|
|
337
|
+
dock.id = "wg-pilot-fx-todos";
|
|
338
|
+
const title = document.createElement("div");
|
|
339
|
+
title.className = "wg-pilot-fx-todo-title";
|
|
340
|
+
title.textContent = todoTitle;
|
|
341
|
+
dock.appendChild(title);
|
|
342
|
+
const ol = document.createElement("ol");
|
|
343
|
+
todos.forEach((text, i) => {
|
|
344
|
+
const li = document.createElement("li");
|
|
345
|
+
li.textContent = text;
|
|
346
|
+
if (i < todoIndex)
|
|
347
|
+
li.className = "wg-pilot-fx-todo-done";
|
|
348
|
+
else if (i === todoIndex)
|
|
349
|
+
li.className = "wg-pilot-fx-todo-now";
|
|
350
|
+
ol.appendChild(li);
|
|
351
|
+
});
|
|
352
|
+
dock.appendChild(ol);
|
|
353
|
+
document.documentElement.appendChild(dock);
|
|
354
|
+
}
|
|
355
|
+
if (holdMs > 0 && (painted > 0 || todos.length > 0)) {
|
|
356
|
+
w.__wgPilotFxHideTimer = setTimeout(() => clearFx(), holdMs);
|
|
357
|
+
}
|
|
358
|
+
return { painted, missing };
|
|
359
|
+
}, { rings, todos, todoIndex, todoTitle, holdMs })
|
|
360
|
+
.catch(() => ({ painted: 0, missing: rings.map((r) => r.selector) }));
|
|
361
|
+
}
|
|
214
362
|
/**
|
|
215
363
|
* Refreshes the badge text and the (possibly-collapsed) panel's two tabs
|
|
216
364
|
* ("Here" - current live menu; "All nodes" - whole project graph as a
|
package/dist/types.d.ts
CHANGED
|
@@ -276,6 +276,23 @@ export type DefinedBlock<In extends Checkpoint<string>, Out extends Checkpoint<s
|
|
|
276
276
|
withVerify(verify: Trait[] | ((out: Out) => Trait[])): DefinedBlock<In, Out>;
|
|
277
277
|
modVerify(nameOrIndex: string | number, newCheck: Trait["check"] | Trait): DefinedBlock<In, Out>;
|
|
278
278
|
modVerifyAll(patches: Record<string, Trait["check"] | Trait>): DefinedBlock<In, Out>;
|
|
279
|
+
/**
|
|
280
|
+
* Demo narration before act - prefer `(ctx) => { ctx.ring(...); ctx.mem?.get(...) }`.
|
|
281
|
+
* Chains after any existing stubBefore on this Block (library then call-site).
|
|
282
|
+
* Overloads keep `ctx` typed when the author passes a lifecycle function
|
|
283
|
+
* (a single union parameter would make the callback param `any`).
|
|
284
|
+
*/
|
|
285
|
+
stubBefore(stub: import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
286
|
+
stubBefore(stub: import("./highlights.js").StubLifecycleFn<Out>): DefinedBlock<In, Out>;
|
|
287
|
+
stubBefore(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
288
|
+
/** Demo narration after resolve. Prefer ctx callbacks over slot-map objects. */
|
|
289
|
+
stubAfter(stub: import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
290
|
+
stubAfter(stub: import("./highlights.js").StubLifecycleFn<Out>): DefinedBlock<In, Out>;
|
|
291
|
+
stubAfter(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
292
|
+
/** Demo narration when the step fails / expected-failure path. */
|
|
293
|
+
stubOnError(stub: import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
294
|
+
stubOnError(stub: import("./highlights.js").StubLifecycleFn<Out>): DefinedBlock<In, Out>;
|
|
295
|
+
stubOnError(stub: (out: Out) => import("./highlights.js").HighlightStubPhase): DefinedBlock<In, Out>;
|
|
279
296
|
};
|
|
280
297
|
/**
|
|
281
298
|
* Structural (not imported) twin of `engine.ts`'s `Layout` - `types.ts` sits
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:218615) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:218615) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineMethodBlock, checkpoint, Trait, narrate } from "waygraph";
|
|
1
|
+
import { defineMethodBlock, checkpoint, Trait, narrate, type StubCtx } from "waygraph";
|
|
2
2
|
import type { CheckoutOverviewPage, OrderComplete } from "../../../../states/checkout.states.js";
|
|
3
3
|
import { CheckoutOverviewSel } from "./checkout-overview.sel.js";
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ import { CheckoutOverviewSel } from "./checkout-overview.sel.js";
|
|
|
8
8
|
* Route: saucedemo-web/checkout-step-two/methods/ (= /checkout-step-two.html)
|
|
9
9
|
*
|
|
10
10
|
* Places the order on the overview page - form/finish click, not a NavBlock.
|
|
11
|
+
* Stubs use open ctx lifecycles (preferred) - not static slot maps.
|
|
11
12
|
*/
|
|
12
13
|
export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderComplete>({
|
|
13
14
|
name: "finish-order",
|
|
@@ -19,23 +20,23 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
|
|
|
19
20
|
},
|
|
20
21
|
resolve: () => checkpoint("OrderComplete"),
|
|
21
22
|
verify: [Trait.text(CheckoutOverviewSel.completeHeader, "Thank you for your order!")],
|
|
22
|
-
stubBefore: {
|
|
23
|
-
finish
|
|
23
|
+
stubBefore: (ctx: StubCtx) => {
|
|
24
|
+
ctx.ring("finish", {
|
|
24
25
|
selector: CheckoutOverviewSel.finishBtn,
|
|
25
26
|
label: "Finish",
|
|
26
27
|
detail: "tone: warning (yellow) - place order",
|
|
27
28
|
tone: "warning",
|
|
28
29
|
weight: "bold",
|
|
29
|
-
}
|
|
30
|
+
});
|
|
30
31
|
},
|
|
31
|
-
stubAfter: {
|
|
32
|
-
thanks
|
|
32
|
+
stubAfter: (ctx: StubCtx) => {
|
|
33
|
+
ctx.ring("thanks", {
|
|
33
34
|
selector: CheckoutOverviewSel.completeHeader,
|
|
34
35
|
label: "Order confirmed",
|
|
35
36
|
detail: "tone: success (green) - thank you!",
|
|
36
37
|
tone: "success",
|
|
37
38
|
duration: true,
|
|
38
|
-
}
|
|
39
|
+
});
|
|
39
40
|
},
|
|
40
41
|
// Shown AFTER act (order already placed) - selectors must match the
|
|
41
42
|
// completion page, not #finish on the overview.
|