waygraph 0.15.51 → 0.15.52
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/analysis/graph.d.ts +1 -1
- package/dist/analysis/graph.js +10 -15
- package/dist/analysis/practices-check.d.ts +0 -1
- package/dist/analysis/practices-check.js +0 -13
- package/dist/auto-session/session.d.ts +1 -1
- package/dist/auto-session/session.js +13 -8
- package/dist/blocks-select.d.ts +7 -4
- package/dist/blocks-select.js +0 -14
- package/dist/browser.d.ts +27 -0
- package/dist/browser.js +62 -0
- package/dist/cli/run-chain.js +4 -0
- package/dist/cli/usage.js +14 -1
- package/dist/cli.js +10 -1
- package/dist/commands/agent-dive-scaffold.d.ts +5 -0
- package/dist/commands/agent-dive-scaffold.js +7 -0
- package/dist/commands/extensions.d.ts +1 -0
- package/dist/commands/extensions.js +22 -0
- package/dist/commands/init.js +42 -4
- package/dist/commands/test.js +16 -2
- package/dist/commands/try.js +2 -1
- package/dist/commands/upgrade.d.ts +6 -0
- package/dist/commands/upgrade.js +107 -0
- package/dist/config.d.ts +47 -3
- package/dist/config.js +45 -12
- package/dist/core/block.d.ts +12 -0
- package/dist/core/block.js +36 -0
- package/dist/core/blocks/nav.d.ts +11 -0
- package/dist/core/blocks/nav.js +8 -0
- package/dist/core/config.d.ts +5 -0
- package/dist/core/engine.d.ts +17 -16
- package/dist/core/engine.js +3 -3
- package/dist/core/flow.d.ts +17 -0
- package/dist/core/flow.js +44 -21
- package/dist/core/map-builder.d.ts +3 -3
- package/dist/core/map-builder.js +3 -3
- package/dist/env-file.d.ts +7 -7
- package/dist/env-file.js +29 -16
- package/dist/extensions.d.ts +21 -0
- package/dist/extensions.js +178 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +3 -2
- package/dist/pilot-overlay/overlay-fixtures.d.ts +0 -7
- package/dist/pilot-overlay/overlay-fixtures.js +0 -45
- package/dist/playwright-config.d.ts +4 -0
- package/dist/playwright-config.js +15 -0
- package/dist/playwright.config.d.ts +2 -0
- package/dist/playwright.config.js +6 -0
- package/dist/runner/demo-log.js +1 -7
- package/dist/runner/inpage/core.d.ts +1 -1
- package/dist/runner/inpage/core.js +8 -7
- package/dist/runner/main.js +18 -10
- package/dist/runner/rings.js +0 -49
- package/dist/session/auto-explore-run.js +9 -5
- package/dist/session/auto-explore.js +6 -4
- package/dist/session/step-overlay.js +3 -1
- package/dist/traverse/run.js +3 -1
- package/dist/ui/components/ring.js +1 -0
- package/dist/ui/overlay.css +1 -0
- package/dist/ui/shadow.d.ts +1 -3
- package/dist/ui/shadow.js +0 -4
- package/dist/ui/tokens.d.ts +0 -11
- package/dist/ui/tokens.js +0 -5
- package/dist/video-dir.d.ts +8 -0
- package/dist/video-dir.js +60 -0
- package/dist/webserver.js +5 -1
- package/package.json +1 -1
- package/templates/scaffold/README.md +4 -2
- package/templates/scaffold/STRUCTURE.md +5 -2
- package/templates/scaffold/config/waygraph.config.ts +26 -0
- package/templates/scaffold/package.json +1 -1
- package/templates/scaffold/src/flows/README.md +5 -5
- package/templates/scaffold/src/flows/example.flow.ts +31 -17
- package/templates/scaffold/src/flows/hoppscotch-auth.flow.ts +35 -0
- package/templates/scaffold/src/flows/hoppscotch-get.flow.ts +23 -0
- package/templates/scaffold/src/flows/hoppscotch-post.flow.ts +33 -0
- package/templates/scaffold/src/flows/mail-verify.flow.ts +36 -75
- package/templates/scaffold/src/flows/shop.flow.ts +41 -65
- package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +0 -9
- package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +0 -5
- package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +1 -1
- package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +3 -19
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +2 -25
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +2 -19
- package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +1 -17
- package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +1 -10
- package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +1 -12
- package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +0 -9
- package/templates/scaffold/src/map/(app_base)/home/_sel.ts +3 -1
- package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +1 -23
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +19 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +20 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +18 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +15 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +20 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +23 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +36 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +17 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +22 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +18 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +11 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +36 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_sel.ts +27 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +10 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +2 -27
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +2 -21
- package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +1 -19
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +1 -11
- package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +1 -9
- package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +0 -11
- package/templates/scaffold/src/states/demo.mem-keys.ts +20 -19
- package/templates/scaffold/src/states/demo.mem-stubs.ts +4 -0
- package/templates/scaffold/src/states/demo.states.ts +5 -1
- package/templates/scaffold/tests/example.spec.ts +2 -3
- package/templates/scaffold/tests/hoppscotch.spec.ts +97 -0
- package/templates/scaffold/tests/mail-verify.spec.ts +2 -11
- package/templates/scaffold/tsconfig.json +1 -1
- package/templates/skills/waygraph-convention.skill.md +32 -3
- package/templates/skills/waygraph-pilot.skill.md +4 -5
- package/dist/browser-path.d.ts +0 -5
- package/dist/browser-path.js +0 -18
- package/dist/runner/overlay-present.d.ts +0 -8
- package/dist/runner/overlay-present.js +0 -57
- package/dist/ui/components/banner.d.ts +0 -2
- package/dist/ui/components/banner.js +0 -10
- package/dist/ui/components/cursor.d.ts +0 -2
- package/dist/ui/components/cursor.js +0 -19
- package/templates/scaffold/playwright.config.ts +0 -12
|
@@ -72,7 +72,14 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
72
72
|
ring.style.width = width + "px";
|
|
73
73
|
ring.style.height = height + "px";
|
|
74
74
|
ring.style.opacity = "1";
|
|
75
|
-
|
|
75
|
+
if (labelId === "wg-ring-label") {
|
|
76
|
+
// The demo ring's caption is drawn from data-label (CSS ::after), not DOM text, so the page's own
|
|
77
|
+
// text selectors (getByText, text=...) never match waygraph's overlay twice.
|
|
78
|
+
ringLabel.dataset.label = label || "";
|
|
79
|
+
ringLabel.textContent = "";
|
|
80
|
+
} else {
|
|
81
|
+
ringLabel.textContent = label || "";
|
|
82
|
+
}
|
|
76
83
|
ringLabel.style.opacity = "1";
|
|
77
84
|
const lw = ringLabel.offsetWidth;
|
|
78
85
|
const lh = ringLabel.offsetHeight;
|
|
@@ -104,12 +111,6 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
104
111
|
ringLabel.style.top = labelTop + "px";
|
|
105
112
|
return [ring, ringLabel];
|
|
106
113
|
};
|
|
107
|
-
window.__wgHideRingAt = (ringId, labelId) => {
|
|
108
|
-
const ring = __wgById(ringId);
|
|
109
|
-
const label = __wgById(labelId);
|
|
110
|
-
if (ring) ring.style.opacity = "0";
|
|
111
|
-
if (label) label.style.opacity = "0";
|
|
112
|
-
};
|
|
113
114
|
window.__wgEnsureRingEl("wg-ring", "wg-ring-label");
|
|
114
115
|
if (!__wgById("wg-cursor")) {
|
|
115
116
|
const cursor = document.createElement("div");
|
package/dist/runner/main.js
CHANGED
|
@@ -10,7 +10,8 @@ import { connect } from "../types.js";
|
|
|
10
10
|
import { MemPage } from "../mem-page.js";
|
|
11
11
|
import { Engine, start, end, chainFlow, isFastForwardBlock, branchRoutes, runBranchRegression } from "../core.js";
|
|
12
12
|
import { withWebServer } from "../webserver.js";
|
|
13
|
-
import {
|
|
13
|
+
import { resolveVideoDir } from "../video-dir.js";
|
|
14
|
+
import { chromiumExecutablePath, extensionPathsFromEnv, launchContext } from "../browser.js";
|
|
14
15
|
|
|
15
16
|
async function runMain() {
|
|
16
17
|
const projectDir = process.argv[2];
|
|
@@ -252,7 +253,7 @@ async function runMain() {
|
|
|
252
253
|
const videoEnv = process.env.WAYGRAPH_VIDEO;
|
|
253
254
|
let videoDir = null;
|
|
254
255
|
if (videoEnv) {
|
|
255
|
-
videoDir = videoEnv === "1" ?
|
|
256
|
+
videoDir = videoEnv === "1" ? await resolveVideoDir(projectDir) : videoEnv;
|
|
256
257
|
mkdirSync(videoDir, { recursive: true });
|
|
257
258
|
}
|
|
258
259
|
/** Fixed 16:9 capture for --video (demo QA and headless run). Step+video no longer maximizes. */
|
|
@@ -290,12 +291,6 @@ async function runMain() {
|
|
|
290
291
|
const executablePath = chromiumExecutablePath();
|
|
291
292
|
// Maximized for interactive step, and for fixed video viewport so the
|
|
292
293
|
// locked record size can actually fit (otherwise .webm gets grey pad).
|
|
293
|
-
const browser = await chromium.launch({
|
|
294
|
-
headless: !headed,
|
|
295
|
-
slowMo,
|
|
296
|
-
args: step || fixedVideoViewport ? ["--start-maximized"] : [],
|
|
297
|
-
...(executablePath ? { executablePath } : {}),
|
|
298
|
-
});
|
|
299
294
|
const contextOpts = fixedVideoViewport
|
|
300
295
|
? {
|
|
301
296
|
baseURL,
|
|
@@ -313,7 +308,17 @@ async function runMain() {
|
|
|
313
308
|
? { dir: videoDir, size: fixedVideoViewport }
|
|
314
309
|
: { dir: videoDir };
|
|
315
310
|
}
|
|
316
|
-
const context = await
|
|
311
|
+
const { context, close: closeBrowser } = await launchContext({
|
|
312
|
+
launcher: chromium,
|
|
313
|
+
launch: {
|
|
314
|
+
headless: !headed,
|
|
315
|
+
slowMo,
|
|
316
|
+
args: step || fixedVideoViewport ? ["--start-maximized"] : [],
|
|
317
|
+
...(executablePath ? { executablePath } : {}),
|
|
318
|
+
},
|
|
319
|
+
context: contextOpts,
|
|
320
|
+
extensions: extensionPathsFromEnv(),
|
|
321
|
+
});
|
|
317
322
|
let pageForVideo = null;
|
|
318
323
|
try {
|
|
319
324
|
if (step) {
|
|
@@ -369,7 +374,7 @@ async function runMain() {
|
|
|
369
374
|
if (savedVideo) {
|
|
370
375
|
console.log("waygraph: video saved to " + savedVideo);
|
|
371
376
|
}
|
|
372
|
-
await
|
|
377
|
+
await closeBrowser();
|
|
373
378
|
}
|
|
374
379
|
} else {
|
|
375
380
|
if (chainFlows && chainFlows.length > 0) {
|
|
@@ -421,6 +426,9 @@ async function runAllBranchesMode(chainFlows, mem, baseURL, headed, engine) {
|
|
|
421
426
|
process.exitCode = 1;
|
|
422
427
|
return;
|
|
423
428
|
}
|
|
429
|
+
if (extensionPathsFromEnv().length > 0) {
|
|
430
|
+
console.warn("waygraph run --all-branches: extensions are not loaded (branches run in cloned contexts)");
|
|
431
|
+
}
|
|
424
432
|
const { chromium } = await import("@playwright/test");
|
|
425
433
|
const browser = await chromium.launch({ headless: !headed });
|
|
426
434
|
const cloneSession = process.env.WAYGRAPH_SHARED_SESSION !== "1";
|
package/dist/runner/rings.js
CHANGED
|
@@ -381,55 +381,6 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
|
|
384
|
-
/**
|
|
385
|
-
* Paint a NAMED ring instance (ui/css/ring.css's shared `.wg-ring-el`/`.wg-ring-el-label`) at a
|
|
386
|
-
* known viewport box - the primitive both the demo/auto singleton (`showRing`, always "wg-ring")
|
|
387
|
-
* and Pilot's several simultaneous fixture rings (their own ids) paint through, so there is one
|
|
388
|
-
* ring-rendering implementation, not two. No collision/follow/focus - those are `#wg-ring`'s own
|
|
389
|
-
* extras (see `showRing`/`inpage/core.js`'s `__wgPositionRing`), meaningless for an independent
|
|
390
|
-
* fixture ring that isn't "the current action."
|
|
391
|
-
*/
|
|
392
|
-
export async function showRingAt(page, ringId, labelId, box, label, tone, style) {
|
|
393
|
-
const size = normalizeHighlightSize(style && style.size);
|
|
394
|
-
const weight = normalizeHighlightWeight(style && style.weight);
|
|
395
|
-
const color = style && style.color ? String(style.color) : "";
|
|
396
|
-
await page
|
|
397
|
-
.evaluate(
|
|
398
|
-
({ ringId, labelId, box, label, tone, size, weight, color }) => {
|
|
399
|
-
if (window.__wgPaintRingAt) {
|
|
400
|
-
window.__wgPaintRingAt(ringId, labelId, box, label, tone, { size, weight, color });
|
|
401
|
-
}
|
|
402
|
-
},
|
|
403
|
-
{ ringId, labelId, box, label, tone: tone || "planned", size, weight, color },
|
|
404
|
-
)
|
|
405
|
-
.catch(() => {});
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/** Hide (not remove) a named ring instance painted via {@link showRingAt}. */
|
|
409
|
-
export async function hideRingAt(page, ringId, labelId) {
|
|
410
|
-
await page
|
|
411
|
-
.evaluate(
|
|
412
|
-
({ ringId, labelId }) => {
|
|
413
|
-
if (window.__wgHideRingAt) window.__wgHideRingAt(ringId, labelId);
|
|
414
|
-
},
|
|
415
|
-
{ ringId, labelId },
|
|
416
|
-
)
|
|
417
|
-
.catch(() => {});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/** Remove a named ring instance entirely (Pilot's fixture rings are short-lived, not reused). */
|
|
421
|
-
export async function removeRingAt(page, ringId, labelId) {
|
|
422
|
-
await page
|
|
423
|
-
.evaluate(
|
|
424
|
-
({ ringId, labelId }) => {
|
|
425
|
-
__wgById(ringId)?.remove();
|
|
426
|
-
__wgById(labelId)?.remove();
|
|
427
|
-
},
|
|
428
|
-
{ ringId, labelId },
|
|
429
|
-
)
|
|
430
|
-
.catch(() => {});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
384
|
export async function showRing(page, box, label, tone, style) {
|
|
434
385
|
const size = normalizeHighlightSize(style && style.size);
|
|
435
386
|
const weight = normalizeHighlightWeight(style && style.weight);
|
|
@@ -5,9 +5,9 @@ import { Engine, start, end, locate } from "../core.js";
|
|
|
5
5
|
import { MemPage } from "../mem-page.js";
|
|
6
6
|
import { buildExploreContext, buildExploreMenu, } from "./auto-explore.js";
|
|
7
7
|
import { installDemoChrome, instrumentInteractionHighlighting } from "./step-overlay.js";
|
|
8
|
-
import { resolveBaseUrl } from "../config.js";
|
|
8
|
+
import { configuredExtensions, resolveBaseUrl } from "../config.js";
|
|
9
9
|
import { withWebServer } from "../webserver.js";
|
|
10
|
-
import { chromiumExecutablePath } from "../browser
|
|
10
|
+
import { chromiumExecutablePath, launchContext } from "../browser.js";
|
|
11
11
|
/** See `../config.js`'s own `resolveBaseUrl` - re-exported so existing importers of this module
|
|
12
12
|
* don't need to change their import path. */
|
|
13
13
|
export { resolveBaseUrl };
|
|
@@ -587,13 +587,17 @@ async function runAutoExploreCore(projectDir, options = {}) {
|
|
|
587
587
|
launchOpts.slowMo = 250;
|
|
588
588
|
if (executablePath)
|
|
589
589
|
launchOpts.executablePath = executablePath;
|
|
590
|
-
const browser = await chromium.launch(launchOpts);
|
|
591
590
|
const contextOpts = cli
|
|
592
591
|
? { viewport: { width: 1280, height: 720 } }
|
|
593
592
|
: { viewport: null };
|
|
594
593
|
if (baseURL)
|
|
595
594
|
contextOpts.baseURL = baseURL;
|
|
596
|
-
const context = await
|
|
595
|
+
const { close: closeBrowser, context } = await launchContext({
|
|
596
|
+
launcher: chromium,
|
|
597
|
+
launch: launchOpts,
|
|
598
|
+
context: contextOpts,
|
|
599
|
+
extensions: await configuredExtensions(projectDir),
|
|
600
|
+
});
|
|
597
601
|
let page = await context.newPage();
|
|
598
602
|
if (startUrl) {
|
|
599
603
|
await page.goto(startUrl, { waitUntil: "domcontentloaded" }).catch(() => { });
|
|
@@ -692,6 +696,6 @@ async function runAutoExploreCore(projectDir, options = {}) {
|
|
|
692
696
|
finally {
|
|
693
697
|
cliRl?.close();
|
|
694
698
|
await context.close();
|
|
695
|
-
await
|
|
699
|
+
await closeBrowser();
|
|
696
700
|
}
|
|
697
701
|
}
|
|
@@ -169,7 +169,7 @@ export function exploreChoices(graph, here) {
|
|
|
169
169
|
const out = [];
|
|
170
170
|
for (const edge of graph.edges) {
|
|
171
171
|
if (here === null) {
|
|
172
|
-
if (edge.kind !== "nav")
|
|
172
|
+
if (edge.kind !== "nav" || edge.from !== "*")
|
|
173
173
|
continue;
|
|
174
174
|
}
|
|
175
175
|
else if (edge.from !== here && edge.from !== "*") {
|
|
@@ -283,8 +283,9 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
283
283
|
continue;
|
|
284
284
|
if (here === null) {
|
|
285
285
|
// Bootstrap only: URL deep-links as "Start here". Click-nav needs a live
|
|
286
|
-
// control so it cannot seed an unknown page
|
|
287
|
-
|
|
286
|
+
// control so it cannot seed an unknown page, and a Nav with `from` needs
|
|
287
|
+
// that state first (e.g. signed in) so it cannot start one either.
|
|
288
|
+
if (!isUrlNav(entry) || edge.from !== "*")
|
|
288
289
|
continue;
|
|
289
290
|
push(navigate, edge);
|
|
290
291
|
continue;
|
|
@@ -295,7 +296,8 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
295
296
|
// Graph still marks NavBlocks from:"*" for pathfinding/traverse; auto menu
|
|
296
297
|
// only offers click-nav whose control is visible on this page (navRunnable).
|
|
297
298
|
// Otherwise LoginForm lists every app route + mailpit as if legal moves.
|
|
298
|
-
|
|
299
|
+
// A url Nav that declares `from` is only an edge from those pages, so it IS a real move here.
|
|
300
|
+
if (isUrlNav(entry) && edge.from === "*")
|
|
299
301
|
continue;
|
|
300
302
|
if (isBackEdge(edge) && (edge.from === here || edge.from === "*")) {
|
|
301
303
|
push(back, edge);
|
|
@@ -86,7 +86,9 @@ export async function installDemoChrome(page, title = "waygraph auto", options =
|
|
|
86
86
|
ring.style.width = box.width + pad * 2 + "px";
|
|
87
87
|
ring.style.height = box.height + pad * 2 + "px";
|
|
88
88
|
ring.style.opacity = "1";
|
|
89
|
-
|
|
89
|
+
// Drawn from data-label (CSS ::after), not DOM text, so the page's own text selectors never match it.
|
|
90
|
+
ringLabel.dataset.label = label;
|
|
91
|
+
ringLabel.textContent = "";
|
|
90
92
|
ringLabel.style.left = box.x + "px";
|
|
91
93
|
ringLabel.style.top = box.y + box.height + 8 + "px";
|
|
92
94
|
ringLabel.style.opacity = "1";
|
package/dist/traverse/run.js
CHANGED
|
@@ -5,7 +5,7 @@ import { defaultMemValueForKey } from "../session/auto-explore-run.js";
|
|
|
5
5
|
import { resolveBaseUrl } from "../config.js";
|
|
6
6
|
import { EdgeLeaseCoordinator } from "./lease.js";
|
|
7
7
|
import { buildCoverageReport, collectGraphEdgeKeys, defaultCoverageOutPath, formatCoverageLine, writeCoverageReport, } from "./coverage.js";
|
|
8
|
-
import { chromiumExecutablePath } from "../browser
|
|
8
|
+
import { chromiumExecutablePath } from "../browser.js";
|
|
9
9
|
function seedMem(library, mem, dataJson) {
|
|
10
10
|
const raw = dataJson ?? process.env.WAYGRAPH_DATA ?? process.env.WAYGRAPH_AUTO_MEM;
|
|
11
11
|
let envParsed = {};
|
|
@@ -253,6 +253,8 @@ export async function runTraverse(projectDir, options = {}) {
|
|
|
253
253
|
const allEdgeKeys = collectGraphEdgeKeys(graph.edges);
|
|
254
254
|
const leases = new EdgeLeaseCoordinator({ projectDir, persist: parallel > 1 });
|
|
255
255
|
const engine = new Engine({ headless: !headed, slowMo: headed ? 100 : 0 });
|
|
256
|
+
if (process.env.WAYGRAPH_EXTENSIONS)
|
|
257
|
+
console.error("waygraph traverse: extensions are not loaded (workers use plain contexts)");
|
|
256
258
|
const { chromium } = await import("@playwright/test");
|
|
257
259
|
const executablePath = chromiumExecutablePath();
|
|
258
260
|
const launchOpts = {
|
|
@@ -20,6 +20,7 @@ export function ringCss() {
|
|
|
20
20
|
"#wg-ring-label{position:fixed;z-index:2147483646;pointer-events:none;opacity:0;" +
|
|
21
21
|
`max-width:min(360px,70vw);white-space:normal;padding:6px 10px;border-radius:7px;background:${p.labelBg};color:${p.labelFg};` +
|
|
22
22
|
"font:600 12px/1.35 system-ui,sans-serif;transition:opacity .3s ease;}" +
|
|
23
|
+
"#wg-ring-label::after{content:attr(data-label);}" +
|
|
23
24
|
toneRules("#wg-ring-label", (t) => `background:${t.labelBg};color:${t.labelFg};`) +
|
|
24
25
|
// Gray = a real Playwright-driven instruction: mark it with a robot.
|
|
25
26
|
`#wg-ring-label[data-tone=auto]::before{${ROBOT}}` +
|
package/dist/ui/overlay.css
CHANGED
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
font: 600 12px/1.35 var(--wg-font); transition: opacity .3s ease;
|
|
87
87
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,.25);
|
|
88
88
|
}
|
|
89
|
+
#wg-ring-label::after { content: attr(data-label); }
|
|
89
90
|
.wg-ring-el-label[data-tone=planned] { --wg-tone-bg: var(--wg-tone-planned-bg); --wg-tone-fg: var(--wg-tone-planned-fg); }
|
|
90
91
|
.wg-ring-el-label[data-tone=auto] { --wg-tone-bg: var(--wg-tone-auto-bg); --wg-tone-fg: var(--wg-tone-auto-fg); }
|
|
91
92
|
.wg-ring-el-label[data-tone=info] { --wg-tone-bg: var(--wg-tone-info-bg); --wg-tone-fg: var(--wg-tone-info-fg); }
|
package/dist/ui/shadow.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* lookups check the shadow root first and fall back to the light DOM (the device stage shell and
|
|
8
8
|
* host-page markers such as `[data-wg-zoomed]` intentionally stay in the light DOM).
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
10
|
+
import type { Page } from "@playwright/test";
|
|
11
11
|
/**
|
|
12
12
|
* `overlaySheet` is the ONE real-CSS bundle (`ui/stylesheet.ts` -> `dist/ui/overlay.css`, built on
|
|
13
13
|
* Open Props - see `src/ui/css/README.md`) every surface shares; passed in from Node since in-page
|
|
@@ -16,5 +16,3 @@ import type { BrowserContext, Page } from "@playwright/test";
|
|
|
16
16
|
export declare function installShadowRoot(overlaySheet?: string): void;
|
|
17
17
|
/** Idempotent; call before any overlay install on a page. Installs the shared stylesheet bundle. */
|
|
18
18
|
export declare function ensureShadowRoot(page: Page): Promise<void>;
|
|
19
|
-
/** Also define the helpers on every future document (pilot overlay persists across navigations). */
|
|
20
|
-
export declare function installShadowRootEverywhere(context: BrowserContext): Promise<void>;
|
package/dist/ui/shadow.js
CHANGED
|
@@ -44,7 +44,3 @@ export function installShadowRoot(overlaySheet) {
|
|
|
44
44
|
export async function ensureShadowRoot(page) {
|
|
45
45
|
await page.evaluate(installShadowRoot, getOverlaySheet()).catch(() => { });
|
|
46
46
|
}
|
|
47
|
-
/** Also define the helpers on every future document (pilot overlay persists across navigations). */
|
|
48
|
-
export async function installShadowRootEverywhere(context) {
|
|
49
|
-
await context.addInitScript(installShadowRoot, getOverlaySheet());
|
|
50
|
-
}
|
package/dist/ui/tokens.d.ts
CHANGED
|
@@ -18,14 +18,3 @@ export interface Tone {
|
|
|
18
18
|
export declare const TONES: Record<ToneName, Tone>;
|
|
19
19
|
/** Dark surface shared by panels, banner, docks, HUD chips. */
|
|
20
20
|
export declare const SURFACE = "rgba(20,10,40,.94)";
|
|
21
|
-
export declare const ACCENT = "#7C3AED";
|
|
22
|
-
/** Secondary accent used on the dark surface (section titles, kinds). */
|
|
23
|
-
export declare const ACCENT_SOFT = "#c9a6ff";
|
|
24
|
-
/** Stacking order: one scale instead of magic numbers. */
|
|
25
|
-
export declare const Z: {
|
|
26
|
-
readonly top: 2147483647;
|
|
27
|
-
readonly ring: 2147483646;
|
|
28
|
-
readonly fx: 2147483645;
|
|
29
|
-
readonly focus: 2147483644;
|
|
30
|
-
readonly dock: 2147483000;
|
|
31
|
-
};
|
package/dist/ui/tokens.js
CHANGED
|
@@ -14,8 +14,3 @@ export const TONES = {
|
|
|
14
14
|
};
|
|
15
15
|
/** Dark surface shared by panels, banner, docks, HUD chips. */
|
|
16
16
|
export const SURFACE = "rgba(20,10,40,.94)";
|
|
17
|
-
export const ACCENT = "#7C3AED";
|
|
18
|
-
/** Secondary accent used on the dark surface (section titles, kinds). */
|
|
19
|
-
export const ACCENT_SOFT = "#c9a6ff";
|
|
20
|
-
/** Stacking order: one scale instead of magic numbers. */
|
|
21
|
-
export const Z = { top: 2147483647, ring: 2147483646, fx: 2147483645, focus: 2147483644, dock: 2147483000 };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The user's Downloads folder, or undefined when there is none (a server, a container). */
|
|
2
|
+
export declare function downloadsDir(): string | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* Where `--video` recordings go: `WAYGRAPH_VIDEO_DIR`, else `video.dir` from the config (absolute, `~/…`, or relative to
|
|
5
|
+
* the project), else `<Downloads>/waygraph-videos/<project>`. With no usable Downloads folder, or on CI, it is
|
|
6
|
+
* `<project>/.waygraph-videos`. An explicit `--video <dir>` never reaches this.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveVideoDir(projectDir: string): Promise<string>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { loadWaygraphConfig } from "./config.js";
|
|
5
|
+
/** The user's Downloads folder, or undefined when there is none (a server, a container). */
|
|
6
|
+
export function downloadsDir() {
|
|
7
|
+
const home = homedir();
|
|
8
|
+
let dir = process.env.XDG_DOWNLOAD_DIR;
|
|
9
|
+
if (!dir && process.platform === "linux") {
|
|
10
|
+
try {
|
|
11
|
+
const line = readFileSync(join(process.env.XDG_CONFIG_HOME ?? join(home, ".config"), "user-dirs.dirs"), "utf-8")
|
|
12
|
+
.split("\n")
|
|
13
|
+
.find((l) => l.startsWith("XDG_DOWNLOAD_DIR="));
|
|
14
|
+
dir = line?.slice("XDG_DOWNLOAD_DIR=".length).replace(/^"|"$/g, "").replace("$HOME", home);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* no user-dirs file: use the conventional name */
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
dir ??= join(home, "Downloads");
|
|
21
|
+
return existsSync(dir) ? dir : undefined;
|
|
22
|
+
}
|
|
23
|
+
const expandHome = (p) => (p === "~" || p.startsWith("~/") ? join(homedir(), p.slice(1)) : p);
|
|
24
|
+
/** True if a file can be created in `dir` (macOS asks permission for Downloads the first time; a denial surfaces here). */
|
|
25
|
+
function writable(dir) {
|
|
26
|
+
try {
|
|
27
|
+
mkdirSync(dir, { recursive: true });
|
|
28
|
+
const probe = join(dir, `.waygraph-probe-${process.pid}`);
|
|
29
|
+
writeFileSync(probe, "");
|
|
30
|
+
rmSync(probe);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Where `--video` recordings go: `WAYGRAPH_VIDEO_DIR`, else `video.dir` from the config (absolute, `~/…`, or relative to
|
|
39
|
+
* the project), else `<Downloads>/waygraph-videos/<project>`. With no usable Downloads folder, or on CI, it is
|
|
40
|
+
* `<project>/.waygraph-videos`. An explicit `--video <dir>` never reaches this.
|
|
41
|
+
*/
|
|
42
|
+
export async function resolveVideoDir(projectDir) {
|
|
43
|
+
const fallback = join(projectDir, ".waygraph-videos");
|
|
44
|
+
const configured = process.env.WAYGRAPH_VIDEO_DIR || (await loadWaygraphConfig(projectDir))?.video?.dir;
|
|
45
|
+
if (configured) {
|
|
46
|
+
const dir = isAbsolute(expandHome(configured)) ? expandHome(configured) : resolve(projectDir, configured);
|
|
47
|
+
if (writable(dir))
|
|
48
|
+
return dir;
|
|
49
|
+
console.error(`waygraph: cannot write videos to ${dir} - using ${fallback}`);
|
|
50
|
+
return fallback;
|
|
51
|
+
}
|
|
52
|
+
const downloads = process.env.CI ? undefined : downloadsDir();
|
|
53
|
+
if (!downloads)
|
|
54
|
+
return fallback;
|
|
55
|
+
const dir = join(downloads, "waygraph-videos", basename(resolve(projectDir)));
|
|
56
|
+
if (writable(dir))
|
|
57
|
+
return dir;
|
|
58
|
+
console.error(`waygraph: cannot write to ${downloads} (denied?) - saving videos in ${fallback}`);
|
|
59
|
+
return fallback;
|
|
60
|
+
}
|
package/dist/webserver.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Starts/stops a project's
|
|
1
|
+
// Starts/stops a project's `webServer` (waygraph.config, or a legacy playwright.config) around `waygraph run`/`demo`/`auto`,
|
|
2
2
|
// the same block `waygraph test` already honors.
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
|
+
import { loadWaygraphConfig } from "./config.js";
|
|
7
8
|
const CONFIG_FILES = [
|
|
8
9
|
"playwright.config.ts",
|
|
9
10
|
"playwright.config.mts",
|
|
@@ -12,6 +13,9 @@ const CONFIG_FILES = [
|
|
|
12
13
|
"playwright.config.cjs",
|
|
13
14
|
];
|
|
14
15
|
async function loadWebServerConfigs(projectDir) {
|
|
16
|
+
const fromWaygraph = (await loadWaygraphConfig(projectDir))?.webServer;
|
|
17
|
+
if (fromWaygraph)
|
|
18
|
+
return Array.isArray(fromWaygraph) ? fromWaygraph : [fromWaygraph];
|
|
15
19
|
for (const name of CONFIG_FILES) {
|
|
16
20
|
const p = join(projectDir, name);
|
|
17
21
|
if (!existsSync(p))
|
package/package.json
CHANGED
|
@@ -25,8 +25,10 @@ one Block per action, flows in `src/flows/`.
|
|
|
25
25
|
## Point it at your real app
|
|
26
26
|
|
|
27
27
|
Change each `_nav.block.ts`'s `url` from the local `file://` path to a real one, and set a real
|
|
28
|
-
`baseUrl` if your Nav Blocks use relative paths (`waygraph.config.ts`, a `.env`, or
|
|
29
|
-
`package.json`'s `"waygraph"` field - see the main docs' "Project config" section).
|
|
28
|
+
`baseUrl` if your Nav Blocks use relative paths (`config/waygraph.config.ts`, a `.env`, or
|
|
29
|
+
`package.json`'s `"waygraph"` field - see the main docs' "Project config" section). That file also
|
|
30
|
+
holds the test settings (`testDir`, `webServer`, `playwright: { workers, timeout, ... }`), so the
|
|
31
|
+
project needs no `playwright.config.ts`. Keep each
|
|
30
32
|
`src/map/` folder matching the URL it represents (`waygraph map` enforces this).
|
|
31
33
|
|
|
32
34
|
Docs: https://deviate-dv8.github.io/waygraph/
|
|
@@ -7,6 +7,8 @@ Next.js route groups) and never appear in a URL or Checkpoint name.
|
|
|
7
7
|
```text
|
|
8
8
|
.
|
|
9
9
|
├── package.json
|
|
10
|
+
├── .agents/skills/ # waygraph skills for coding agents
|
|
11
|
+
├── config/waygraph.config.ts # baseUrl, tests, extensions, webServer - no playwright.config
|
|
10
12
|
├── src/
|
|
11
13
|
│ ├── map/
|
|
12
14
|
│ │ ├── (app_base)/ # your app (opened via file:// here)
|
|
@@ -22,7 +24,8 @@ Next.js route groups) and never appear in a URL or Checkpoint name.
|
|
|
22
24
|
│ │ │ │ ├── assert-hello.method.block.ts # + stubs + YAP slide
|
|
23
25
|
│ │ │ │ └── assert-item-added.method.block.ts
|
|
24
26
|
│ │ │ └── docs/ # a second page, same shape
|
|
25
|
-
│ │
|
|
27
|
+
│ │ ├── (external)/mailpit/ # a different origin (mail catcher)
|
|
28
|
+
│ │ └── (external)/hoppscotch/ # API client, REST client, needs the hoppscotch extension
|
|
26
29
|
│ ├── states/ # Checkpoint types + mem keys
|
|
27
30
|
│ └── flows/ # example / shop / mail-verify
|
|
28
31
|
└── tests/example.spec.ts
|
|
@@ -39,7 +42,7 @@ page folder uses, so any agent or teammate knows where to look without asking.
|
|
|
39
42
|
| Add an action on a page | one file in that page's `_methods/` |
|
|
40
43
|
| Verify a state (button disabled, error shown) | `defineAssertBlock` + `Trait.disabled` / `Trait.enabled` |
|
|
41
44
|
| Wire steps together | `src/flows/*.flow.ts` |
|
|
42
|
-
| Give a flow fake data | `registerMemStub(key, fake)` + `
|
|
45
|
+
| Give a flow fake data | `registerMemStub(key, fake)` + `memStub: true` in the flow's options (docs: docs/REFERENCE.md, "memStub") |
|
|
43
46
|
| Explore by hand | `npm run auto` (headed) or `npm run auto:cli` |
|
|
44
47
|
| Check your work | `npm run check`, `npm run graph`, `waygraph map` |
|
|
45
48
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig } from "waygraph";
|
|
2
|
+
|
|
3
|
+
export default defineConfig(({ env }) => ({
|
|
4
|
+
// Where the app under test lives. BASE_URL comes from .env / .env.<mode>: waygraph test --env staging
|
|
5
|
+
baseUrl: env.BASE_URL ?? "__APP_BASE_URL__",
|
|
6
|
+
|
|
7
|
+
// ── waygraph: uncomment what you need ─────────────────────────────────────────────────────────
|
|
8
|
+
// extensions: ["hoppscotch"], // browser extensions to load (a waygraph feature, not Playwright's)
|
|
9
|
+
// video: { // recordings made with `waygraph run|demo --video`
|
|
10
|
+
// dir: "~/Downloads/waygraph-videos", // where they are saved (default: Downloads/waygraph-videos/<project>)
|
|
11
|
+
// viewport: "1920x1080", // recording size: demo defaults to 1920x1080, run to 1280x720
|
|
12
|
+
// },
|
|
13
|
+
// slowMo: 250, // ms to pause before each browser action, so a run is watchable
|
|
14
|
+
// headed: true, // show the browser window (demo and auto already do)
|
|
15
|
+
// demo: { autoNext: true, fast: false }, // advance demo steps without clicking Next; blitz fast-forward steps
|
|
16
|
+
// webServer: { command: "npm start", port: 3000 }, // started around test / run / demo / auto
|
|
17
|
+
|
|
18
|
+
// ── test runner (Playwright) ──────────────────────────────────────────────────────────────────
|
|
19
|
+
// testDir: "tests",
|
|
20
|
+
// playwright: { // any Playwright test option, merged over waygraph's defaults
|
|
21
|
+
// workers: 1,
|
|
22
|
+
// retries: 1,
|
|
23
|
+
// timeout: 60_000,
|
|
24
|
+
// use: { video: "on", trace: "on", screenshot: "only-on-failure", viewport: { width: 1280, height: 720 } },
|
|
25
|
+
// },
|
|
26
|
+
}));
|
|
@@ -7,12 +7,12 @@ all point at an export here by name (`waygraph run --blocks shopFlow`).
|
|
|
7
7
|
`.branch()`) over hand-composing raw Blocks - it checks each step's Block kind at runtime and
|
|
8
8
|
the Checkpoint chain at compile time, so a wrong step is a build/test failure, not a
|
|
9
9
|
mid-run surprise.
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
- Flow settings go in `.end({ title, memStub, sessionReset })`. No nested `withTitle(withMemStub(...))`.
|
|
11
|
+
- Demo highlights are ctx stubs chained on the Block where the flow uses it:
|
|
12
|
+
`AddItemBlock.stubAfter((ctx) => { ctx.ring("cart", { selector, label }); })`.
|
|
13
13
|
- One flow, one scenario. A flow that needs a genuinely different starting session
|
|
14
|
-
(re-entering the login page mid-chain)
|
|
15
|
-
|
|
14
|
+
(re-entering the login page mid-chain) sets `sessionReset: true`, rather than hand-clearing
|
|
15
|
+
cookies inside a Block.
|
|
16
16
|
|
|
17
17
|
New flow → new file here, named for the scenario (`checkout.flow.ts`), not for the Blocks it
|
|
18
18
|
happens to use.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Engine
|
|
1
|
+
import { Engine } from "waygraph";
|
|
2
|
+
import config from "../../config/waygraph.config.js";
|
|
3
|
+
import { DemoSel } from "../map/(app_base)/home/_sel.js";
|
|
2
4
|
import { NavHomeBlock } from "../map/(app_base)/home/_nav.block.js";
|
|
3
5
|
import { AssertHelloBlock } from "../map/(app_base)/home/_methods/assert-hello.method.block.js";
|
|
4
6
|
import { NavDocsBlock } from "../map/(app_base)/docs/_nav.block.js";
|
|
@@ -6,24 +8,36 @@ import { NavDocsBlock } from "../map/(app_base)/docs/_nav.block.js";
|
|
|
6
8
|
import "../map/(app_base)/home/_page.block.js";
|
|
7
9
|
import "../map/(app_base)/docs/_page.block.js";
|
|
8
10
|
|
|
9
|
-
const engine = new Engine();
|
|
11
|
+
const engine = new Engine(config);
|
|
10
12
|
|
|
11
13
|
/** Smoke: nav + assert (no mem), then nav to the sibling docs/ page. Green offline. */
|
|
12
|
-
export const exampleFlow =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
export const exampleFlow = engine
|
|
15
|
+
.map()
|
|
16
|
+
.start()
|
|
17
|
+
.gotoPage(
|
|
18
|
+
NavHomeBlock.stubAfter((ctx) => {
|
|
19
|
+
ctx.ring("title", { selector: DemoSel.title, label: "Home heading", duration: true });
|
|
20
|
+
}).stubOnError((ctx) => {
|
|
21
|
+
ctx.ring("title", { selector: DemoSel.title, label: "Home heading at failure" });
|
|
22
|
+
}),
|
|
23
|
+
)
|
|
24
|
+
.assert(
|
|
25
|
+
AssertHelloBlock.stubBefore((ctx) => {
|
|
26
|
+
ctx.ring("title", { selector: DemoSel.title, label: "Heading about to check" });
|
|
27
|
+
})
|
|
28
|
+
.stubAfter((ctx) => {
|
|
29
|
+
ctx.ring("title", {
|
|
30
|
+
selector: DemoSel.title,
|
|
21
31
|
label: "AC · Hello visible",
|
|
22
|
-
detail: "Replace this
|
|
32
|
+
detail: "Replace this copy with your ticket lines.",
|
|
23
33
|
tag: "AC",
|
|
24
34
|
duration: true,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
35
|
+
});
|
|
36
|
+
ctx.ring("sub", { selector: DemoSel.sub, label: "Subcopy", duration: 1500 });
|
|
37
|
+
})
|
|
38
|
+
.stubOnError((ctx) => {
|
|
39
|
+
ctx.ring("title", { selector: DemoSel.title, label: "Heading at failure", tag: "FAIL" });
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.gotoPage(NavDocsBlock)
|
|
43
|
+
.end({ title: "Scaffold: Hello Waygraph" });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Engine } from "waygraph";
|
|
2
|
+
import config from "../../config/waygraph.config.js";
|
|
3
|
+
import { NavHoppscotchSettingsBlock } from "../map/(external)/hoppscotch/settings/_nav.block.js";
|
|
4
|
+
import { PickExtensionInterceptorBlock } from "../map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.js";
|
|
5
|
+
import { NavHoppscotchRestBlock } from "../map/(external)/hoppscotch/_nav.block.js";
|
|
6
|
+
import { SetQueryParamsBlock } from "../map/(external)/hoppscotch/_methods/set-query-params.method.block.js";
|
|
7
|
+
import { SetUrlBlock } from "../map/(external)/hoppscotch/_methods/set-url.method.block.js";
|
|
8
|
+
import { SetBearerTokenBlock } from "../map/(external)/hoppscotch/_methods/set-bearer-token.method.block.js";
|
|
9
|
+
import { SendRequestBlock } from "../map/(external)/hoppscotch/_methods/send-request.method.block.js";
|
|
10
|
+
import { AssertStatusBlock } from "../map/(external)/hoppscotch/_methods/assert-status.method.block.js";
|
|
11
|
+
import { ReadResponseHeadersBlock } from "../map/(external)/hoppscotch/_methods/read-response-headers.method.block.js";
|
|
12
|
+
import { AssertResponseHeaderBlock } from "../map/(external)/hoppscotch/_methods/assert-response-header.method.block.js";
|
|
13
|
+
import { ReadResponseBodyBlock } from "../map/(external)/hoppscotch/_methods/read-response-body.method.block.js";
|
|
14
|
+
import { AssertResponseBodyBlock } from "../map/(external)/hoppscotch/_methods/assert-response-body.method.block.js";
|
|
15
|
+
import "../map/(external)/hoppscotch/_page.block.js";
|
|
16
|
+
|
|
17
|
+
const engine = new Engine(config);
|
|
18
|
+
|
|
19
|
+
/** GET with query params and a bearer token, check the status, that the API received them, and a response header. Needs `extensions: ["hoppscotch"]`. */
|
|
20
|
+
export const hoppscotchAuthFlow = engine
|
|
21
|
+
.map()
|
|
22
|
+
.start()
|
|
23
|
+
.gotoExternal(NavHoppscotchSettingsBlock)
|
|
24
|
+
.method(PickExtensionInterceptorBlock)
|
|
25
|
+
.gotoExternal(NavHoppscotchRestBlock)
|
|
26
|
+
.method(SetUrlBlock)
|
|
27
|
+
.method(SetQueryParamsBlock)
|
|
28
|
+
.method(SetBearerTokenBlock)
|
|
29
|
+
.method(SendRequestBlock)
|
|
30
|
+
.assert(AssertStatusBlock)
|
|
31
|
+
.method(ReadResponseBodyBlock)
|
|
32
|
+
.assert(AssertResponseBodyBlock)
|
|
33
|
+
.method(ReadResponseHeadersBlock)
|
|
34
|
+
.assert(AssertResponseHeaderBlock)
|
|
35
|
+
.end({ title: "Scaffold: Hoppscotch GET with query params and bearer token" });
|