waygraph 0.15.1 → 0.15.3
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/cli.js +6 -1
- 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/types.d.ts +17 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +4 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +19 -8
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +6 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -9
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -9
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +6 -5
- 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/cart/nav-cart.block.ts +4 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +19 -8
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +6 -5
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +8 -9
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +11 -9
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +6 -5
- 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
|
@@ -38,9 +38,9 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
38
38
|
cart: {
|
|
39
39
|
selector: CartSel.cartLink,
|
|
40
40
|
label: "Cart",
|
|
41
|
-
detail: "
|
|
41
|
+
detail: "tone: planned (purple) - open cart",
|
|
42
|
+
tone: "planned",
|
|
42
43
|
focus: true,
|
|
43
|
-
color: "#c9a6ff",
|
|
44
44
|
zoomOut: false,
|
|
45
45
|
followMouse: false,
|
|
46
46
|
weight: "bold",
|
|
@@ -56,9 +56,9 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
56
56
|
ctx.ring("items", {
|
|
57
57
|
selector: InventorySel.cartItem,
|
|
58
58
|
label: "Cart items",
|
|
59
|
-
detail: "
|
|
59
|
+
detail: "tone: success (green) - product in cart",
|
|
60
|
+
tone: "success",
|
|
60
61
|
focus: true,
|
|
61
|
-
color: "#86efac",
|
|
62
62
|
zoomOut: true,
|
|
63
63
|
followMouse: false,
|
|
64
64
|
duration: true,
|
|
@@ -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,16 +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
|
-
|
|
23
|
+
stubBefore: (ctx: StubCtx) => {
|
|
24
|
+
ctx.ring("finish", {
|
|
25
|
+
selector: CheckoutOverviewSel.finishBtn,
|
|
26
|
+
label: "Finish",
|
|
27
|
+
detail: "tone: warning (yellow) - place order",
|
|
28
|
+
tone: "warning",
|
|
29
|
+
weight: "bold",
|
|
30
|
+
});
|
|
24
31
|
},
|
|
25
|
-
stubAfter: {
|
|
26
|
-
thanks
|
|
32
|
+
stubAfter: (ctx: StubCtx) => {
|
|
33
|
+
ctx.ring("thanks", {
|
|
27
34
|
selector: CheckoutOverviewSel.completeHeader,
|
|
28
35
|
label: "Order confirmed",
|
|
29
|
-
detail: "
|
|
36
|
+
detail: "tone: success (green) - thank you!",
|
|
37
|
+
tone: "success",
|
|
30
38
|
duration: true,
|
|
31
|
-
}
|
|
39
|
+
});
|
|
32
40
|
},
|
|
33
41
|
// Shown AFTER act (order already placed) - selectors must match the
|
|
34
42
|
// completion page, not #finish on the overview.
|
|
@@ -37,12 +45,14 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
|
|
|
37
45
|
caption: "Checkout is a short pipeline",
|
|
38
46
|
detail: "Cart -> info -> overview -> done. You just placed the order.",
|
|
39
47
|
tag: "YAP",
|
|
48
|
+
tone: "info",
|
|
40
49
|
duration: true,
|
|
41
50
|
},
|
|
42
51
|
{
|
|
43
52
|
caption: "Completion page is the durable proof",
|
|
44
|
-
detail: "
|
|
53
|
+
detail: "tone: success - the thank-you header is what verify asserts on.",
|
|
45
54
|
tag: "YAP",
|
|
55
|
+
tone: "success",
|
|
46
56
|
selector: CheckoutOverviewSel.completeHeader,
|
|
47
57
|
duration: 2500,
|
|
48
58
|
fastMode: 700,
|
|
@@ -51,6 +61,7 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
|
|
|
51
61
|
caption: "Episode continues after this yap",
|
|
52
62
|
detail: "Next step rings the same banner, then you move on.",
|
|
53
63
|
tag: "YAP",
|
|
64
|
+
tone: "planned",
|
|
54
65
|
selector: CheckoutOverviewSel.completeHeader,
|
|
55
66
|
duration: true,
|
|
56
67
|
fastMode: 500,
|
package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -57,17 +57,18 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
57
57
|
product: {
|
|
58
58
|
selector: InventorySel.title(DEMO_PRODUCT_ID),
|
|
59
59
|
label: "Sauce Labs Backpack",
|
|
60
|
-
detail: "
|
|
60
|
+
detail: "tone: info (blue)",
|
|
61
|
+
tone: "info",
|
|
61
62
|
focus: true,
|
|
62
|
-
color: "#c9a6ff",
|
|
63
63
|
zoom: 1.45,
|
|
64
64
|
zoomOut: false,
|
|
65
65
|
},
|
|
66
66
|
add: {
|
|
67
67
|
selector: InventorySel.addBtn(DEMO_PRODUCT_ID),
|
|
68
68
|
label: "Add to cart",
|
|
69
|
+
detail: "tone: success (green)",
|
|
70
|
+
tone: "success",
|
|
69
71
|
focus: true,
|
|
70
|
-
color: "#86efac",
|
|
71
72
|
zoom: 1.5,
|
|
72
73
|
zoomOut: false,
|
|
73
74
|
weight: "bold",
|
|
@@ -92,9 +93,9 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
92
93
|
ctx.ring("badge", {
|
|
93
94
|
selector: InventorySel.cartBadge,
|
|
94
95
|
label: "Cart badge",
|
|
95
|
-
detail: "
|
|
96
|
+
detail: "tone: success (green) - count updated",
|
|
97
|
+
tone: "success",
|
|
96
98
|
focus: true,
|
|
97
|
-
color: "#86efac",
|
|
98
99
|
zoomOut: false,
|
|
99
100
|
duration: true,
|
|
100
101
|
});
|
|
@@ -22,15 +22,14 @@ export const FillPasswordBlock = defineMethodBlock<LoginPage, LoginPage>({
|
|
|
22
22
|
},
|
|
23
23
|
resolve: () => checkpoint("LoginPage"),
|
|
24
24
|
stubBefore: (ctx: StubCtx) => {
|
|
25
|
-
ctx.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
25
|
+
ctx.ring("password", {
|
|
26
|
+
selector: LoginSel.password,
|
|
27
|
+
label: "Password",
|
|
28
|
+
detail: "tone: planned (purple)",
|
|
29
|
+
todo: "login-pass",
|
|
30
|
+
tone: "planned",
|
|
31
|
+
focus: true,
|
|
32
|
+
zoom: 1.4,
|
|
34
33
|
});
|
|
35
34
|
},
|
|
36
35
|
stubAfter: (ctx: StubCtx) => {
|
|
@@ -40,15 +40,17 @@ export const FillUsernameBlock = defineMethodBlock<LoginPage, LoginPage>({
|
|
|
40
40
|
{ title: "Device showcase", index: 0 },
|
|
41
41
|
);
|
|
42
42
|
ctx.zoom(1.35);
|
|
43
|
-
ctx.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
const fromMem = ctx.mem?.get(LoginCreds.key)?.username;
|
|
44
|
+
ctx.ring("username", {
|
|
45
|
+
selector: LoginSel.username,
|
|
46
|
+
label: "Username",
|
|
47
|
+
detail: fromMem
|
|
48
|
+
? `tone: info (blue) - mem ${fromMem}`
|
|
49
|
+
: "tone: info (blue)",
|
|
50
|
+
tone: "info",
|
|
51
|
+
todo: "login-user",
|
|
52
|
+
focus: true,
|
|
53
|
+
zoom: 1.4,
|
|
52
54
|
});
|
|
53
55
|
},
|
|
54
56
|
stubAfter: (ctx: StubCtx) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MethodBlock } from "waygraph";
|
|
2
2
|
import type { LoginPage, LoggedIn } from "../../../states/checkout.states.js";
|
|
3
3
|
import { SubmitLoginBlock } from "./submit-login.method.block.js";
|
|
4
4
|
|
|
@@ -7,7 +7,8 @@ import { SubmitLoginBlock } from "./submit-login.method.block.js";
|
|
|
7
7
|
* Helper: typed alias over SubmitLoginBlock
|
|
8
8
|
* Route: saucedemo-web/methods/ (page URL /)
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* runtime still branches on bad credentials via
|
|
10
|
+
* MethodBlock cast so map().method() keeps the factory brand while Flows can
|
|
11
|
+
* treat Out as LoggedIn; runtime still branches on bad credentials via
|
|
12
|
+
* SubmitLoginBlock.
|
|
12
13
|
*/
|
|
13
|
-
export const SubmitLoginForFlow = SubmitLoginBlock as unknown as
|
|
14
|
+
export const SubmitLoginForFlow = SubmitLoginBlock as unknown as MethodBlock<LoginPage, LoggedIn>;
|
|
@@ -48,9 +48,10 @@ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>
|
|
|
48
48
|
submit: {
|
|
49
49
|
selector: LoginSel.loginButton,
|
|
50
50
|
label: "Login",
|
|
51
|
+
detail: "tone: warning (yellow)",
|
|
51
52
|
todo: "login-submit",
|
|
53
|
+
tone: "warning",
|
|
52
54
|
focus: true,
|
|
53
|
-
color: "#86efac",
|
|
54
55
|
zoom: 1.55,
|
|
55
56
|
weight: "bold",
|
|
56
57
|
gesture: "tap",
|
|
@@ -72,9 +73,9 @@ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>
|
|
|
72
73
|
ctx.ring("error", {
|
|
73
74
|
selector: LoginSel.errorBanner,
|
|
74
75
|
label: "Login error banner",
|
|
76
|
+
detail: "tone: danger (red)",
|
|
75
77
|
tone: "danger",
|
|
76
78
|
focus: true,
|
|
77
|
-
color: "#f87171",
|
|
78
79
|
duration: true,
|
|
79
80
|
});
|
|
80
81
|
return;
|
|
@@ -96,9 +97,9 @@ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>
|
|
|
96
97
|
ctx.ring("shelf", {
|
|
97
98
|
selector: ".inventory_list",
|
|
98
99
|
label: "Product shelf",
|
|
99
|
-
detail: "
|
|
100
|
+
detail: "tone: success (green) - ready to shop",
|
|
101
|
+
tone: "success",
|
|
100
102
|
focus: true,
|
|
101
|
-
color: "#c9a6ff",
|
|
102
103
|
zoom: 1.25,
|
|
103
104
|
duration: true,
|
|
104
105
|
});
|
|
@@ -108,9 +109,9 @@ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>
|
|
|
108
109
|
ctx.ring("error", {
|
|
109
110
|
selector: LoginSel.errorBanner,
|
|
110
111
|
label: "Login error banner",
|
|
112
|
+
detail: "tone: danger (red)",
|
|
111
113
|
tone: "danger",
|
|
112
114
|
focus: true,
|
|
113
|
-
color: "#f87171",
|
|
114
115
|
duration: true,
|
|
115
116
|
});
|
|
116
117
|
},
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import { Engine,
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
CheckoutInfoPage,
|
|
7
|
-
CheckoutOverviewPage,
|
|
8
|
-
OrderComplete,
|
|
9
|
-
} from "../states/checkout.states.js";
|
|
10
|
-
import { FfOwnerAuthBlock } from "../blocks/saucedemo-web/ff-owner-auth.block.js";
|
|
1
|
+
import { Engine, withTitle } from "waygraph";
|
|
2
|
+
import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
|
|
3
|
+
import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
|
|
4
|
+
import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
|
|
5
|
+
import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
|
|
11
6
|
import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
|
|
12
7
|
import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
|
|
13
8
|
import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
|
|
@@ -16,98 +11,67 @@ import { FillLastNameBlock } from "../blocks/saucedemo-web/checkout-step-one/met
|
|
|
16
11
|
import { FillPostalCodeBlock } from "../blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.js";
|
|
17
12
|
import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.js";
|
|
18
13
|
import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.js";
|
|
14
|
+
import { LoginSel } from "../blocks/saucedemo-web/methods/login.sel.js";
|
|
19
15
|
|
|
20
16
|
const engine = new Engine({ headless: false, slowMo: 250 });
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
CheckoutInfoPage,
|
|
39
|
-
CheckoutInfoPage,
|
|
40
|
-
CheckoutInfoPage,
|
|
41
|
-
CheckoutOverviewPage,
|
|
42
|
-
OrderComplete
|
|
43
|
-
>([
|
|
44
|
-
start,
|
|
45
|
-
FfOwnerAuthBlock,
|
|
46
|
-
AddToCartBlock,
|
|
47
|
-
NavCartBlock,
|
|
48
|
-
NavCheckoutInfoBlock,
|
|
49
|
-
FillFirstNameBlock,
|
|
50
|
-
FillLastNameBlock,
|
|
51
|
-
FillPostalCodeBlock,
|
|
52
|
-
SubmitCheckoutInfoBlock,
|
|
53
|
-
FinishOrderBlock,
|
|
54
|
-
end,
|
|
55
|
-
]),
|
|
56
|
-
"Owner: Full Checkout",
|
|
57
|
-
),
|
|
58
|
-
{
|
|
59
|
-
"ff-owner-auth": {
|
|
60
|
-
stubAfter: {
|
|
61
|
-
inventory: {
|
|
62
|
-
label: "Signed in (fast-forward)",
|
|
63
|
-
detail: "Auth collapsed via FFCompose - interesting work starts here.",
|
|
64
|
-
tag: "AC",
|
|
65
|
-
duration: true,
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
// Kept for --ff-expand (inners become separate steps again: nav-login,
|
|
70
|
-
// fill-username, fill-password, submit-login).
|
|
71
|
-
"fill-username": {
|
|
72
|
-
stubBefore: {
|
|
73
|
-
username: {
|
|
18
|
+
/**
|
|
19
|
+
* Owner checkout via map() + .ffStart/.ffEnd (no separate FfOwnerAuthBlock,
|
|
20
|
+
* no HighlightFixtureMap). Auth collapses to one blitz step; post-login
|
|
21
|
+
* blocks keep their own ctx stubBefore/stubAfter. Call-site decorate example
|
|
22
|
+
* on fill-username when --ff-expand shows inners again.
|
|
23
|
+
*/
|
|
24
|
+
export const checkoutFlow = withTitle(
|
|
25
|
+
engine
|
|
26
|
+
.map()
|
|
27
|
+
.start()
|
|
28
|
+
.ffStart("ff-owner-auth")
|
|
29
|
+
.gotoPage(NavLoginBlock)
|
|
30
|
+
.method(
|
|
31
|
+
FillUsernameBlock.stubBefore((ctx) => {
|
|
32
|
+
ctx.ring("username", {
|
|
33
|
+
selector: LoginSel.username,
|
|
74
34
|
label: "Demo user",
|
|
75
|
-
detail: "standard_user from Mem - library block stays neutral
|
|
35
|
+
detail: "standard_user from Mem - library block stays neutral underneath",
|
|
76
36
|
tag: "AC",
|
|
77
37
|
duration: true,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
"finish-order": {
|
|
102
|
-
stubAfter: {
|
|
103
|
-
thanks: {
|
|
104
|
-
label: "Order placed",
|
|
105
|
-
detail: "Completion header is the durable proof.",
|
|
38
|
+
focus: true,
|
|
39
|
+
});
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.method(
|
|
43
|
+
FillPasswordBlock.stubBefore((ctx) => {
|
|
44
|
+
ctx.ring("password", {
|
|
45
|
+
selector: LoginSel.password,
|
|
46
|
+
label: "Password",
|
|
47
|
+
detail: "Filled from Mem credentials.",
|
|
48
|
+
duration: 1500,
|
|
49
|
+
focus: true,
|
|
50
|
+
});
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
.method(
|
|
54
|
+
SubmitLoginForFlow.stubBefore((ctx) => {
|
|
55
|
+
ctx.ring("submit", {
|
|
56
|
+
selector: LoginSel.loginButton,
|
|
57
|
+
label: "Sign in",
|
|
106
58
|
tag: "GATE",
|
|
107
|
-
duration:
|
|
108
|
-
fastMode:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
59
|
+
duration: true,
|
|
60
|
+
fastMode: 500,
|
|
61
|
+
focus: true,
|
|
62
|
+
weight: "bold",
|
|
63
|
+
});
|
|
64
|
+
}),
|
|
65
|
+
)
|
|
66
|
+
.ffEnd()
|
|
67
|
+
.method(AddToCartBlock)
|
|
68
|
+
.gotoPage(NavCartBlock)
|
|
69
|
+
.gotoPage(NavCheckoutInfoBlock)
|
|
70
|
+
.method(FillFirstNameBlock)
|
|
71
|
+
.method(FillLastNameBlock)
|
|
72
|
+
.method(FillPostalCodeBlock)
|
|
73
|
+
.method(SubmitCheckoutInfoBlock)
|
|
74
|
+
.method(FinishOrderBlock)
|
|
75
|
+
.end(),
|
|
76
|
+
"Owner: Full Checkout",
|
|
113
77
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Engine,
|
|
1
|
+
import { Engine, withTitle } from "waygraph";
|
|
2
2
|
import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
|
|
3
3
|
import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
|
|
4
4
|
import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
|
|
@@ -8,7 +8,16 @@ const engine = new Engine();
|
|
|
8
8
|
|
|
9
9
|
// The step-mode overlay prepends "Episode N: " itself - the title here is
|
|
10
10
|
// just the label, not the full heading.
|
|
11
|
+
// map() + ctx stubs on the Method blocks (see fill-username / fill-password /
|
|
12
|
+
// submit-login) - no HighlightFixtureMap.
|
|
11
13
|
export const loginFlow = withTitle(
|
|
12
|
-
engine
|
|
14
|
+
engine
|
|
15
|
+
.map()
|
|
16
|
+
.start()
|
|
17
|
+
.gotoPage(NavLoginBlock)
|
|
18
|
+
.method(FillUsernameBlock)
|
|
19
|
+
.method(FillPasswordBlock)
|
|
20
|
+
.method(SubmitLoginForFlow)
|
|
21
|
+
.end(),
|
|
13
22
|
"Sign In",
|
|
14
23
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Engine,
|
|
1
|
+
import { Engine, withTitle } from "waygraph";
|
|
2
2
|
import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
|
|
3
3
|
import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
|
|
4
4
|
import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
|
|
@@ -13,17 +13,17 @@ const engine = new Engine();
|
|
|
13
13
|
// Episode-2 half of chainFlow(loginFlow, shopFlow) - assumes already LoggedIn
|
|
14
14
|
// (AddToCartBlock's In is the Checkpoint<string> wildcard).
|
|
15
15
|
export const shopFlow = withTitle(
|
|
16
|
-
engine
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
engine
|
|
17
|
+
.map()
|
|
18
|
+
.start()
|
|
19
|
+
.method(AddToCartBlock)
|
|
20
|
+
.gotoPage(NavCartBlock)
|
|
21
|
+
.gotoPage(NavCheckoutInfoBlock)
|
|
22
|
+
.method(FillFirstNameBlock)
|
|
23
|
+
.method(FillLastNameBlock)
|
|
24
|
+
.method(FillPostalCodeBlock)
|
|
25
|
+
.method(SubmitCheckoutInfoBlock)
|
|
26
|
+
.method(FinishOrderBlock)
|
|
27
|
+
.end(),
|
|
28
28
|
"Shop & Checkout",
|
|
29
29
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Engine,
|
|
1
|
+
import { Engine, withTitle, withSessionReset, withExpectedFailure } from "waygraph";
|
|
2
2
|
import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
|
|
3
3
|
import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
|
|
4
4
|
import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
|
|
@@ -25,7 +25,14 @@ const engine = new Engine();
|
|
|
25
25
|
export const viewerBlockedFlow = withExpectedFailure(
|
|
26
26
|
withTitle(
|
|
27
27
|
withSessionReset(
|
|
28
|
-
engine
|
|
28
|
+
engine
|
|
29
|
+
.map()
|
|
30
|
+
.start()
|
|
31
|
+
.gotoPage(NavLoginBlock)
|
|
32
|
+
.method(FillUsernameBlock)
|
|
33
|
+
.method(FillPasswordBlock)
|
|
34
|
+
.method(SubmitLoginBlock)
|
|
35
|
+
.end(),
|
|
29
36
|
),
|
|
30
37
|
"Viewer: Blocked Login Attempt",
|
|
31
38
|
),
|
package/package.json
CHANGED
|
@@ -38,9 +38,9 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
38
38
|
cart: {
|
|
39
39
|
selector: CartSel.cartLink,
|
|
40
40
|
label: "Cart",
|
|
41
|
-
detail: "
|
|
41
|
+
detail: "tone: planned (purple) - open cart",
|
|
42
|
+
tone: "planned",
|
|
42
43
|
focus: true,
|
|
43
|
-
color: "#c9a6ff",
|
|
44
44
|
zoomOut: false,
|
|
45
45
|
followMouse: false,
|
|
46
46
|
weight: "bold",
|
|
@@ -56,9 +56,9 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
56
56
|
ctx.ring("items", {
|
|
57
57
|
selector: InventorySel.cartItem,
|
|
58
58
|
label: "Cart items",
|
|
59
|
-
detail: "
|
|
59
|
+
detail: "tone: success (green) - product in cart",
|
|
60
|
+
tone: "success",
|
|
60
61
|
focus: true,
|
|
61
|
-
color: "#86efac",
|
|
62
62
|
zoomOut: true,
|
|
63
63
|
followMouse: false,
|
|
64
64
|
duration: true,
|
|
@@ -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,16 +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
|
-
|
|
23
|
+
stubBefore: (ctx: StubCtx) => {
|
|
24
|
+
ctx.ring("finish", {
|
|
25
|
+
selector: CheckoutOverviewSel.finishBtn,
|
|
26
|
+
label: "Finish",
|
|
27
|
+
detail: "tone: warning (yellow) - place order",
|
|
28
|
+
tone: "warning",
|
|
29
|
+
weight: "bold",
|
|
30
|
+
});
|
|
24
31
|
},
|
|
25
|
-
stubAfter: {
|
|
26
|
-
thanks
|
|
32
|
+
stubAfter: (ctx: StubCtx) => {
|
|
33
|
+
ctx.ring("thanks", {
|
|
27
34
|
selector: CheckoutOverviewSel.completeHeader,
|
|
28
35
|
label: "Order confirmed",
|
|
29
|
-
detail: "
|
|
36
|
+
detail: "tone: success (green) - thank you!",
|
|
37
|
+
tone: "success",
|
|
30
38
|
duration: true,
|
|
31
|
-
}
|
|
39
|
+
});
|
|
32
40
|
},
|
|
33
41
|
// Shown AFTER act (order already placed) - selectors must match the
|
|
34
42
|
// completion page, not #finish on the overview.
|
|
@@ -37,12 +45,14 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
|
|
|
37
45
|
caption: "Checkout is a short pipeline",
|
|
38
46
|
detail: "Cart -> info -> overview -> done. You just placed the order.",
|
|
39
47
|
tag: "YAP",
|
|
48
|
+
tone: "info",
|
|
40
49
|
duration: true,
|
|
41
50
|
},
|
|
42
51
|
{
|
|
43
52
|
caption: "Completion page is the durable proof",
|
|
44
|
-
detail: "
|
|
53
|
+
detail: "tone: success - the thank-you header is what verify asserts on.",
|
|
45
54
|
tag: "YAP",
|
|
55
|
+
tone: "success",
|
|
46
56
|
selector: CheckoutOverviewSel.completeHeader,
|
|
47
57
|
duration: 2500,
|
|
48
58
|
fastMode: 700,
|
|
@@ -51,6 +61,7 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
|
|
|
51
61
|
caption: "Episode continues after this yap",
|
|
52
62
|
detail: "Next step rings the same banner, then you move on.",
|
|
53
63
|
tag: "YAP",
|
|
64
|
+
tone: "planned",
|
|
54
65
|
selector: CheckoutOverviewSel.completeHeader,
|
|
55
66
|
duration: true,
|
|
56
67
|
fastMode: 500,
|
package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -57,17 +57,18 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
57
57
|
product: {
|
|
58
58
|
selector: InventorySel.title(DEMO_PRODUCT_ID),
|
|
59
59
|
label: "Sauce Labs Backpack",
|
|
60
|
-
detail: "
|
|
60
|
+
detail: "tone: info (blue)",
|
|
61
|
+
tone: "info",
|
|
61
62
|
focus: true,
|
|
62
|
-
color: "#c9a6ff",
|
|
63
63
|
zoom: 1.45,
|
|
64
64
|
zoomOut: false,
|
|
65
65
|
},
|
|
66
66
|
add: {
|
|
67
67
|
selector: InventorySel.addBtn(DEMO_PRODUCT_ID),
|
|
68
68
|
label: "Add to cart",
|
|
69
|
+
detail: "tone: success (green)",
|
|
70
|
+
tone: "success",
|
|
69
71
|
focus: true,
|
|
70
|
-
color: "#86efac",
|
|
71
72
|
zoom: 1.5,
|
|
72
73
|
zoomOut: false,
|
|
73
74
|
weight: "bold",
|
|
@@ -92,9 +93,9 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
92
93
|
ctx.ring("badge", {
|
|
93
94
|
selector: InventorySel.cartBadge,
|
|
94
95
|
label: "Cart badge",
|
|
95
|
-
detail: "
|
|
96
|
+
detail: "tone: success (green) - count updated",
|
|
97
|
+
tone: "success",
|
|
96
98
|
focus: true,
|
|
97
|
-
color: "#86efac",
|
|
98
99
|
zoomOut: false,
|
|
99
100
|
duration: true,
|
|
100
101
|
});
|