waygraph 0.13.3 → 0.13.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/cli.js +87 -3
- package/examples/saucedemo/.tmp/device-demo/orientation-gestures.webm +0 -0
- package/examples/saucedemo/.tmp/device-demo/page@fe3808e393870b60560762cb58982a73.webm +0 -0
- package/examples/saucedemo/.tmp/device-showcase/device-showcase.webm +0 -0
- package/examples/saucedemo/.tmp/device-showcase/page@10a295d8efbf9eae139eb931ef00363c.webm +0 -0
- package/examples/saucedemo/README.md +2 -0
- package/examples/saucedemo/package.json +2 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +7 -2
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +4 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +6 -3
- package/examples/saucedemo/src/flows/device-showcase.flow.ts +28 -0
- package/package.json +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +10 -4
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +7 -5
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +6 -3
- package/templates/quickstart/src/flows/device-showcase.flow.ts +28 -0
package/dist/cli.js
CHANGED
|
@@ -2942,9 +2942,73 @@ async function clickPulseAt(page, x, y, tone) {
|
|
|
2942
2942
|
.catch(() => {});
|
|
2943
2943
|
}
|
|
2944
2944
|
|
|
2945
|
+
/**
|
|
2946
|
+
* Fit + center the OS browser window on the device viewport so mobile/tablet
|
|
2947
|
+
* is not stuck top-left inside a maximized frame (Dan 0.13.4).
|
|
2948
|
+
* Desktop clear restores maximized.
|
|
2949
|
+
*/
|
|
2950
|
+
async function fitWindowToDeviceViewport(page, viewport, opts) {
|
|
2951
|
+
const maximize = !!(opts && opts.maximize);
|
|
2952
|
+
let client;
|
|
2953
|
+
try {
|
|
2954
|
+
client = await page.context().newCDPSession(page);
|
|
2955
|
+
const { windowId } = await client.send("Browser.getWindowForTarget");
|
|
2956
|
+
if (maximize) {
|
|
2957
|
+
await client.send("Browser.setWindowBounds", {
|
|
2958
|
+
windowId,
|
|
2959
|
+
bounds: { windowState: "maximized" },
|
|
2960
|
+
});
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
if (!viewport || !viewport.width || !viewport.height) return;
|
|
2964
|
+
const metrics = await page
|
|
2965
|
+
.evaluate(() => {
|
|
2966
|
+
const chromeW = Math.max(0, (window.outerWidth || 0) - (window.innerWidth || 0));
|
|
2967
|
+
const chromeH = Math.max(0, (window.outerHeight || 0) - (window.innerHeight || 0));
|
|
2968
|
+
return {
|
|
2969
|
+
chromeW: Number.isFinite(chromeW) ? chromeW : 0,
|
|
2970
|
+
// First paint after maximize often reports 0 chrome - use a floor.
|
|
2971
|
+
chromeH: chromeH > 20 ? chromeH : 88,
|
|
2972
|
+
screenW: window.screen.availWidth || 1920,
|
|
2973
|
+
screenH: window.screen.availHeight || 1080,
|
|
2974
|
+
};
|
|
2975
|
+
})
|
|
2976
|
+
.catch(() => ({ chromeW: 0, chromeH: 88, screenW: 1920, screenH: 1080 }));
|
|
2977
|
+
// Leave maximized before setting pixel bounds (Chromium ignores size while max).
|
|
2978
|
+
await client.send("Browser.setWindowBounds", {
|
|
2979
|
+
windowId,
|
|
2980
|
+
bounds: { windowState: "normal" },
|
|
2981
|
+
});
|
|
2982
|
+
const winW = Math.min(
|
|
2983
|
+
metrics.screenW,
|
|
2984
|
+
Math.max(320, Math.floor(viewport.width + metrics.chromeW)),
|
|
2985
|
+
);
|
|
2986
|
+
const winH = Math.min(
|
|
2987
|
+
metrics.screenH,
|
|
2988
|
+
Math.max(320, Math.floor(viewport.height + metrics.chromeH)),
|
|
2989
|
+
);
|
|
2990
|
+
const left = Math.max(0, Math.floor((metrics.screenW - winW) / 2));
|
|
2991
|
+
const top = Math.max(0, Math.floor((metrics.screenH - winH) / 2));
|
|
2992
|
+
await client.send("Browser.setWindowBounds", {
|
|
2993
|
+
windowId,
|
|
2994
|
+
bounds: {
|
|
2995
|
+
windowState: "normal",
|
|
2996
|
+
left,
|
|
2997
|
+
top,
|
|
2998
|
+
width: winW,
|
|
2999
|
+
height: winH,
|
|
3000
|
+
},
|
|
3001
|
+
});
|
|
3002
|
+
} catch {
|
|
3003
|
+
/* headless / no window - ignore */
|
|
3004
|
+
} finally {
|
|
3005
|
+
if (client) await client.detach().catch(() => {});
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
|
|
2945
3009
|
/**
|
|
2946
3010
|
* Apply authored device fixture to the live page (0.13+).
|
|
2947
|
-
* Seamless viewport lerp + toast on set/clear
|
|
3011
|
+
* Seamless viewport lerp + centered window + toast on set/clear.
|
|
2948
3012
|
*/
|
|
2949
3013
|
async function applyDeviceToPage(page, device, sync) {
|
|
2950
3014
|
const mode = sync || (device ? "set" : "keep");
|
|
@@ -2973,6 +3037,8 @@ async function applyDeviceToPage(page, device, sync) {
|
|
|
2973
3037
|
from = null;
|
|
2974
3038
|
}
|
|
2975
3039
|
const announce = mode === "set" || mode === "clear";
|
|
3040
|
+
const toDesktop =
|
|
3041
|
+
mode === "clear" || (d.preset === "desktop" && !d.touchMode);
|
|
2976
3042
|
const shouldAnimate =
|
|
2977
3043
|
announce &&
|
|
2978
3044
|
from &&
|
|
@@ -2980,6 +3046,14 @@ async function applyDeviceToPage(page, device, sync) {
|
|
|
2980
3046
|
from.height > 0 &&
|
|
2981
3047
|
(from.width !== target.width || from.height !== target.height);
|
|
2982
3048
|
|
|
3049
|
+
// Unmaximize + center early so the lerp does not sit in the corner of a
|
|
3050
|
+
// maximized frame. Desktop clear maximizes at the end instead.
|
|
3051
|
+
if (!toDesktop) {
|
|
3052
|
+
await fitWindowToDeviceViewport(page, from && from.width ? from : target, {
|
|
3053
|
+
maximize: false,
|
|
3054
|
+
});
|
|
3055
|
+
}
|
|
3056
|
+
|
|
2983
3057
|
try {
|
|
2984
3058
|
if (shouldAnimate) {
|
|
2985
3059
|
const steps = 14;
|
|
@@ -2988,10 +3062,14 @@ async function applyDeviceToPage(page, device, sync) {
|
|
|
2988
3062
|
for (let i = 1; i <= steps; i++) {
|
|
2989
3063
|
const t = i / steps;
|
|
2990
3064
|
const e = t * t * (3 - 2 * t); // smoothstep
|
|
2991
|
-
|
|
3065
|
+
const mid = {
|
|
2992
3066
|
width: Math.round(from.width + (target.width - from.width) * e),
|
|
2993
3067
|
height: Math.round(from.height + (target.height - from.height) * e),
|
|
2994
|
-
}
|
|
3068
|
+
};
|
|
3069
|
+
await realSet(mid);
|
|
3070
|
+
if (!toDesktop && (i === 1 || i === steps || i % 3 === 0)) {
|
|
3071
|
+
await fitWindowToDeviceViewport(page, mid, { maximize: false });
|
|
3072
|
+
}
|
|
2995
3073
|
if (i < steps) await new Promise((r) => setTimeout(r, stepMs));
|
|
2996
3074
|
}
|
|
2997
3075
|
} else {
|
|
@@ -3001,6 +3079,12 @@ async function applyDeviceToPage(page, device, sync) {
|
|
|
3001
3079
|
/* maximized / null viewport hosts may reject - toast still updates */
|
|
3002
3080
|
}
|
|
3003
3081
|
|
|
3082
|
+
if (toDesktop) {
|
|
3083
|
+
await fitWindowToDeviceViewport(page, target, { maximize: true });
|
|
3084
|
+
} else {
|
|
3085
|
+
await fitWindowToDeviceViewport(page, target, { maximize: false });
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3004
3088
|
// Fire toast near the end of the lerp so it reads as one seamless beat.
|
|
3005
3089
|
await page
|
|
3006
3090
|
.evaluate(
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -39,6 +39,8 @@ npx playwright install chromium
|
|
|
39
39
|
| Coverage JSON + min gate (10%) | `npm run traverse:coverage` |
|
|
40
40
|
| Shop demo stepper | `npm run demo:step` |
|
|
41
41
|
| Shop demo autoplay | `npm run demo:autoplay` |
|
|
42
|
+
| **Device showcase** (mobile/tablet + portrait/landscape) | `npm run demo:device` |
|
|
43
|
+
| Device showcase + `.webm` | `npm run demo:device:video` |
|
|
42
44
|
| **Cart bulk** demo (add-all → remove-all) | `npm run demo:bulk` |
|
|
43
45
|
| Cart bulk stepper | `npm run demo:bulk:step` |
|
|
44
46
|
| List flows | `npm run flows` |
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"prove:add-to-cart-menu": "node scripts/prove-add-to-cart-menu.mjs",
|
|
26
26
|
"prove": "npm run prove:login-branch && npm run prove:graph && npm run prove:add-to-cart-menu && npm test",
|
|
27
27
|
"record": "waygraph run --blocks \"loginFlow then shopFlow({\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}})\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --video --no-step",
|
|
28
|
+
"demo:device": "waygraph demo --blocks deviceShowcaseFlow --auto-next --title \"Device showcase\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
|
|
29
|
+
"demo:device:video": "waygraph demo --blocks deviceShowcaseFlow --auto-next --video ./.tmp/device-showcase --title \"Device showcase\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
|
|
28
30
|
"demo:bulk": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
|
|
29
31
|
"demo:bulk:auto-next": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --auto-next --title \"Cart bulk demo\"",
|
|
30
32
|
"demo:bulk:video": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --auto-play-video --title \"Cart bulk demo\"",
|
|
@@ -17,7 +17,9 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
17
17
|
click: ".shopping_cart_link",
|
|
18
18
|
verify: [Trait.url({ pathname: "/cart.html" })],
|
|
19
19
|
stubBefore: (ctx: StubCtx) => {
|
|
20
|
-
ctx.title("Open cart");
|
|
20
|
+
ctx.title("Open cart · landscape");
|
|
21
|
+
// Device showcase: rotate tablet to landscape before the cart tap.
|
|
22
|
+
ctx.landscape();
|
|
21
23
|
ctx.todoId("saucedemo-cart");
|
|
22
24
|
ctx.todos([
|
|
23
25
|
{ id: "cart-find", text: "Find the product" },
|
|
@@ -38,11 +40,14 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
38
40
|
zoomOut: false,
|
|
39
41
|
followMouse: false,
|
|
40
42
|
weight: "bold",
|
|
43
|
+
gesture: "tap",
|
|
41
44
|
},
|
|
42
45
|
});
|
|
43
46
|
},
|
|
44
47
|
stubAfter: (ctx: StubCtx) => {
|
|
45
|
-
ctx.banner("Your cart");
|
|
48
|
+
ctx.banner("Your cart · desktop");
|
|
49
|
+
// Showcase finale: back to desktop.
|
|
50
|
+
ctx.clearDevice();
|
|
46
51
|
ctx.zoomOut(false);
|
|
47
52
|
ctx.ring("items", {
|
|
48
53
|
selector: InventorySel.cartItem,
|
package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -36,9 +36,10 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
36
36
|
],
|
|
37
37
|
// Demo: zoom product -> add (stay zoomed), then badge after act.
|
|
38
38
|
stubBefore: (ctx: StubCtx) => {
|
|
39
|
-
ctx.title("Pick a product");
|
|
40
|
-
//
|
|
41
|
-
ctx.
|
|
39
|
+
ctx.title("Pick a product · tablet");
|
|
40
|
+
// Device showcase: tablet portrait (toast + lerp from mobile landscape).
|
|
41
|
+
ctx.device("tablet");
|
|
42
|
+
ctx.portrait();
|
|
42
43
|
ctx.todoId("saucedemo-cart");
|
|
43
44
|
ctx.todos([
|
|
44
45
|
{ id: "cart-find", text: "Find the product" },
|
|
@@ -50,9 +50,10 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
|
|
|
50
50
|
// Open lifecycle: banner title, todos, Screen Studio camera zoom,
|
|
51
51
|
// sequential highlight queue (appear / dwell / fade), focus + color.
|
|
52
52
|
stubBefore: (ctx: StubCtx) => {
|
|
53
|
-
ctx.title("Signing in");
|
|
54
|
-
// 0.13
|
|
53
|
+
ctx.title("Signing in · mobile");
|
|
54
|
+
// 0.13.3: mobile portrait + touch; tap Login.
|
|
55
55
|
ctx.device("mobile");
|
|
56
|
+
ctx.portrait();
|
|
56
57
|
ctx.todoId("saucedemo-login");
|
|
57
58
|
ctx.todos([
|
|
58
59
|
{ id: "login-user", text: "Enter username" },
|
|
@@ -109,7 +110,9 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
|
|
|
109
110
|
});
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
|
-
ctx.banner("Inventory");
|
|
113
|
+
ctx.banner("Inventory · landscape");
|
|
114
|
+
// Rotate mobile to landscape on the product shelf (toast + lerp).
|
|
115
|
+
ctx.landscape();
|
|
113
116
|
ctx.todoId("saucedemo-login");
|
|
114
117
|
ctx.todos([
|
|
115
118
|
{ id: "login-user", text: "Enter username" },
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Engine, start, end, withTitle } from "waygraph";
|
|
2
|
+
import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
|
|
3
|
+
import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
|
|
4
|
+
import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
|
|
5
|
+
import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
|
|
6
|
+
|
|
7
|
+
const engine = new Engine();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Short device/orientation showcase (0.13.3+):
|
|
11
|
+
* login mobile portrait -> land on inventory landscape ->
|
|
12
|
+
* add-to-cart tablet portrait -> open cart tablet landscape -> desktop
|
|
13
|
+
*
|
|
14
|
+
* Run:
|
|
15
|
+
* npm run demo:device
|
|
16
|
+
* npm run demo:device:video
|
|
17
|
+
*/
|
|
18
|
+
export const deviceShowcaseFlow = withTitle(
|
|
19
|
+
engine.defineFlow([
|
|
20
|
+
start,
|
|
21
|
+
NavLoginBlock,
|
|
22
|
+
SubmitLoginForFlow,
|
|
23
|
+
AddToCartBlock,
|
|
24
|
+
NavCartBlock,
|
|
25
|
+
end,
|
|
26
|
+
]),
|
|
27
|
+
"Device showcase",
|
|
28
|
+
);
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineNavClickBlock, Trait } from "waygraph";
|
|
2
|
+
import type { StubCtx } from "waygraph";
|
|
2
3
|
import type { CartPage } from "../../../states/checkout.states.js";
|
|
3
4
|
import { InventorySel } from "../inventory/methods/inventory-items.js";
|
|
4
5
|
|
|
@@ -15,8 +16,10 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
15
16
|
checkpoint: "CartPage",
|
|
16
17
|
click: ".shopping_cart_link",
|
|
17
18
|
verify: [Trait.url({ pathname: "/cart.html" })],
|
|
18
|
-
stubBefore: (ctx) => {
|
|
19
|
-
ctx.title("Open cart");
|
|
19
|
+
stubBefore: (ctx: StubCtx) => {
|
|
20
|
+
ctx.title("Open cart · landscape");
|
|
21
|
+
// Device showcase: rotate tablet to landscape before the cart tap.
|
|
22
|
+
ctx.landscape();
|
|
20
23
|
ctx.todoId("saucedemo-cart");
|
|
21
24
|
ctx.todos([
|
|
22
25
|
{ id: "cart-find", text: "Find the product" },
|
|
@@ -37,11 +40,14 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
|
|
|
37
40
|
zoomOut: false,
|
|
38
41
|
followMouse: false,
|
|
39
42
|
weight: "bold",
|
|
43
|
+
gesture: "tap",
|
|
40
44
|
},
|
|
41
45
|
});
|
|
42
46
|
},
|
|
43
|
-
stubAfter: (ctx) => {
|
|
44
|
-
ctx.banner("Your cart");
|
|
47
|
+
stubAfter: (ctx: StubCtx) => {
|
|
48
|
+
ctx.banner("Your cart · desktop");
|
|
49
|
+
// Showcase finale: back to desktop.
|
|
50
|
+
ctx.clearDevice();
|
|
45
51
|
ctx.zoomOut(false);
|
|
46
52
|
ctx.ring("items", {
|
|
47
53
|
selector: InventorySel.cartItem,
|
package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineEffectBlock, checkpoint, type Checkpoint, type WaygraphInstanceOption } from "waygraph";
|
|
2
|
+
import type { StubCtx } from "waygraph";
|
|
2
3
|
import type { ItemInCart } from "../../../../states/checkout.states.js";
|
|
3
4
|
import { SelectedItem } from "../../../../states/checkout.mem-keys.js";
|
|
4
5
|
import { collectAddableItems, InventorySel } from "./inventory-items.js";
|
|
@@ -34,10 +35,11 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
34
35
|
},
|
|
35
36
|
],
|
|
36
37
|
// Demo: zoom product -> add (stay zoomed), then badge after act.
|
|
37
|
-
stubBefore: (ctx) => {
|
|
38
|
-
ctx.title("Pick a product");
|
|
39
|
-
//
|
|
40
|
-
ctx.
|
|
38
|
+
stubBefore: (ctx: StubCtx) => {
|
|
39
|
+
ctx.title("Pick a product · tablet");
|
|
40
|
+
// Device showcase: tablet portrait (toast + lerp from mobile landscape).
|
|
41
|
+
ctx.device("tablet");
|
|
42
|
+
ctx.portrait();
|
|
41
43
|
ctx.todoId("saucedemo-cart");
|
|
42
44
|
ctx.todos([
|
|
43
45
|
{ id: "cart-find", text: "Find the product" },
|
|
@@ -68,7 +70,7 @@ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
|
|
|
68
70
|
},
|
|
69
71
|
});
|
|
70
72
|
},
|
|
71
|
-
stubAfter: (ctx) => {
|
|
73
|
+
stubAfter: (ctx: StubCtx) => {
|
|
72
74
|
ctx.banner("In the cart");
|
|
73
75
|
ctx.todoId("saucedemo-cart");
|
|
74
76
|
ctx.todos([
|
|
@@ -50,9 +50,10 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
|
|
|
50
50
|
// Open lifecycle: banner title, todos, Screen Studio camera zoom,
|
|
51
51
|
// sequential highlight queue (appear / dwell / fade), focus + color.
|
|
52
52
|
stubBefore: (ctx: StubCtx) => {
|
|
53
|
-
ctx.title("Signing in");
|
|
54
|
-
// 0.13
|
|
53
|
+
ctx.title("Signing in · mobile");
|
|
54
|
+
// 0.13.3: mobile portrait + touch; tap Login.
|
|
55
55
|
ctx.device("mobile");
|
|
56
|
+
ctx.portrait();
|
|
56
57
|
ctx.todoId("saucedemo-login");
|
|
57
58
|
ctx.todos([
|
|
58
59
|
{ id: "login-user", text: "Enter username" },
|
|
@@ -109,7 +110,9 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
|
|
|
109
110
|
});
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
|
-
ctx.banner("Inventory");
|
|
113
|
+
ctx.banner("Inventory · landscape");
|
|
114
|
+
// Rotate mobile to landscape on the product shelf (toast + lerp).
|
|
115
|
+
ctx.landscape();
|
|
113
116
|
ctx.todoId("saucedemo-login");
|
|
114
117
|
ctx.todos([
|
|
115
118
|
{ id: "login-user", text: "Enter username" },
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Engine, start, end, withTitle } from "waygraph";
|
|
2
|
+
import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
|
|
3
|
+
import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
|
|
4
|
+
import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
|
|
5
|
+
import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
|
|
6
|
+
|
|
7
|
+
const engine = new Engine();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Short device/orientation showcase (0.13.3+):
|
|
11
|
+
* login mobile portrait -> land on inventory landscape ->
|
|
12
|
+
* add-to-cart tablet portrait -> open cart tablet landscape -> desktop
|
|
13
|
+
*
|
|
14
|
+
* Run:
|
|
15
|
+
* npm run demo:device
|
|
16
|
+
* npm run demo:device:video
|
|
17
|
+
*/
|
|
18
|
+
export const deviceShowcaseFlow = withTitle(
|
|
19
|
+
engine.defineFlow([
|
|
20
|
+
start,
|
|
21
|
+
NavLoginBlock,
|
|
22
|
+
SubmitLoginForFlow,
|
|
23
|
+
AddToCartBlock,
|
|
24
|
+
NavCartBlock,
|
|
25
|
+
end,
|
|
26
|
+
]),
|
|
27
|
+
"Device showcase",
|
|
28
|
+
);
|