@vosjs/render-core 0.10.0 → 0.12.0

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.
@@ -438,6 +438,15 @@ declare function deadLine(r: DeadReport): string;
438
438
  * context (a session's cookies apply), and also when the take stops early
439
439
  * or throws once its first step has run. A teardown that fails never fails
440
440
  * the take: the footage is fine, and what is left behind is reported.
441
+ *
442
+ * `if`: a guard, `{ "do": "if", "selector": "…" }`. When its selector is on
443
+ * the page the steps after it run as usual; when it is not, they are skipped
444
+ * and the list ends there, which is not a failure. A teardown that undoes
445
+ * what the take may already have removed on camera starts its undoing with
446
+ * one (`if` the new key's row is still listed), so a good take reports
447
+ * nothing to undo instead of a failure; a setup that signs in guards its
448
+ * sign-in the same way (`if` the email field shows), so a session that is
449
+ * already signed in passes. A failure AFTER a guard is still a failure.
441
450
  */
442
451
 
443
452
  type SetupText = string | {
@@ -462,9 +471,15 @@ type SetupStep = ({
462
471
  } | {
463
472
  do: 'goto';
464
473
  url: string;
474
+ } | {
475
+ do: 'if';
476
+ selector: string;
477
+ ms?: number;
465
478
  }) & {
466
479
  id?: string;
467
480
  };
481
+ /** How long an `if` looks for its selector, when it names no `ms`. */
482
+ declare const IF_LOOK_MS = 3000;
468
483
  /** Which list a step belongs to, as its messages and log lines name it. */
469
484
  type StepPhase = 'setup' | 'teardown';
470
485
  /**
@@ -515,6 +530,15 @@ interface SetupResult {
515
530
  selector?: string;
516
531
  error?: string;
517
532
  };
533
+ /**
534
+ * An `if` whose selector was not on the page: the list ended there, and
535
+ * `rest` steps after it were skipped. Not a failure.
536
+ */
537
+ skipped?: {
538
+ step: number;
539
+ selector: string;
540
+ rest: number;
541
+ };
518
542
  }
519
543
  /** How long a whole teardown may take before it is stopped and reported. */
520
544
  declare const TEARDOWN_BOUND_MS = 60000;
@@ -531,6 +555,12 @@ interface TeardownReport {
531
555
  selector?: string;
532
556
  error: string;
533
557
  };
558
+ /** An `if` whose selector was gone: nothing left to undo, never a failure. */
559
+ skipped?: {
560
+ step: number;
561
+ selector: string;
562
+ rest: number;
563
+ };
534
564
  }
535
565
  /** The teardown in one line, for the end of a take or a rehearsal. */
536
566
  declare function teardownLine(report: TeardownReport): string;
@@ -1847,6 +1877,16 @@ interface RecordOpts {
1847
1877
  * captured.
1848
1878
  */
1849
1879
  peerStorageState?: (name: string) => Promise<string> | string;
1880
+ /**
1881
+ * In a rehearsal only: stop after the step with this `id` and hand the
1882
+ * page, as that step left it, to `at` (`vos look --until`). The steps
1883
+ * after it never run; the teardown still does, since the walk clicked
1884
+ * for real. Ignored by a take.
1885
+ */
1886
+ until?: {
1887
+ id: string;
1888
+ at: (page: RecorderPage) => Promise<void>;
1889
+ };
1850
1890
  }
1851
1891
  /**
1852
1892
  * The expression a scroll tick evaluates: move the first scrollable
@@ -2339,4 +2379,4 @@ declare function inlinePoints(path: {
2339
2379
  */
2340
2380
  declare function inlineScript<T extends Pick<ActionsFile, 'steps'>>(actions: T, files: LoadedFiles): T;
2341
2381
 
2342
- export { APP_QUIET_MS, APP_SETTLE_CAP_MS, AWAIT_HEARTBEAT_MS, AWAIT_POLL_S, AWAIT_TIMEOUT_S, type ActionStep, type ActionsFile, type Arrival, type AwaitUntil, CHANGE_AGE_PROBE, CLICK_BUTTONS, type ClickButton, type ConditionState, DEAD_SHARE_WARN_PCT, DEAD_STRETCH_WARN_MS, DEFAULT_READY, DOM_CHANGE_PROBE, DOM_QUIET_MS, DOM_SETTLE_CAP_MS, DOWNLOAD_TIMEOUT_S, DRAG_HOLD_MS, DRAG_MODIFIERS, type DeadReport, type DeadStep, type DisabledClick, type DragModifier, EXPECT_TIMEOUT_S, EXPOSURE_ADVICE, EXPOSURE_MATCHERS_SRC, EXPOSURE_PROBE, type EncodePageOptions, type Exposure, type ExposureKind, ExposureLog, type FrameRec, type FrameSink, type FreezeSpan, type FreshPlanOptions, type GuardedStep, type HeardSound, IDLE_CALL_MS, JS_SAID_MAX, JS_VALUE_MAX, KEY_ROUNDTRIP_MS, KEY_SEQUENCE_GAP_MS, type LoadedFiles, MAX_KEYS, MAX_PATH_POINTS, MAX_PEERS, MAX_PEER_STEPS, MEDIA_DRAIN_PROBE, MEDIA_WATCH_SCRIPT, MIN_SKIP_MS, MODIFIERS, MOTION_TICK_MS, MULTI_CLICK_GAP_MS, type MaskReport, type MaskRule, type MediaDrain, type MediaNote, type Modifier, NAV_TIMEOUT_MS, NETWORKIDLE_HYDRATION_MS, NOTICE_SRC, type Notice, NoticeLog, OUTPUT_MAX_BYTES, OVERRUN_MIN_MS, OVERRUN_MIN_PLANNED_MS, OVERRUN_SHARE, type OutputSink, PAGE_ERROR_LINE_CHARS, PASTE_MAX_BYTES, PASTE_READ_WINDOW_MS, PASTE_TYPES, PASTE_UNREAD_MS, PATH_DEFAULT_MS, PEER_VALUE_MAX, PEER_VERBS, POINTER_MAX_MS, POINTER_MIN_MS, POINTER_MS_PER_PX, PRESS_HOLD_MS, PRESS_KEYS, PRESS_LEAD_MS, type PaceReport, type PageError, PageErrorLog, PageSoundLog, type PasteItem, type PathPoint, type PathSample, type Peer, type PeerRun, type PeerStep, type PollResult, type PressKey, QUIET_MS, READY_MODES, READY_SETTLE_CAP_MS, READ_BEAT_MS, RESPONSE_MS, type ReadyMode, type ReadyOpts, type ReadyReport, type RecordOpts, RecordRefusedError, type RecordResult, type RecorderApiResponse, type RecorderBrowser, type RecorderButtonOpts, type RecorderCdp, type RecorderClock, type RecorderConsoleMessage, type RecorderContext, type RecorderDownload, type RecorderLocator, type RecorderLocatorRoot, type RecorderMediaElement, type RecorderPage, type RecorderRect, type RecorderResponse, type RecorderRoute, SCROLL_MAX_MS, SCROLL_MIN_MS, SCROLL_MS_PER_PX, SCROLL_SETTLE_MS, SETTLE_CAP_MS, SETTLE_MS, SETTLE_VERBS, STEP_GUARDS, STEP_MARGIN_MS, type ScannedNotice, type ScriptFiles, SetupEnvError, SetupError, type SetupResult, type SetupStep, type SetupText, type SkippedStep, type SoundSink, StepBound, type StepGuard, type StepOverrun, type StepPace, type StepPhase, StepSignals, type StoppedTake, type SurfaceFit, type SurfaceSize, TEARDOWN_BOUND_MS, TRAILING_HOLD_MS, TakeClock, type TeardownReport, WAIT_MARGIN_MS, WALL_PROBE, type WaitCondition, WallError, type WallKind, type WallVerdict, ZOOM_MARK_VERBS, appSettled, askedMs, base64Bytes, bounded, buildEncodePage, buttonNumber, capReached, cappedLine, chordProblem, clampWait, clockMotion, clockTyping, conditionMiss, deadLine, deadTime, deadWarns, domSettled, easeInOutCubic, exposureLine, extForType, fetchInPageScript, fileNameProblem, fitSurfaceToViewport, formatDurationCap, guardVerdict, guardedSteps, hangReason, headersFor, holdLeftMs, hostedRefusals, inlinePoints, inlineScript, isIdpHost, isKeyName, isSignInPath, jpegDims, jsConditionScript, keptValue, keySequencePlanMs, loadScriptFiles, maskInitScript, modifierBits, nameFromUrl, noticeAdvice, noticeLine, outputName, overrunLine, overrunOf, paceLine, paceReport, pageErrorLine, parseHeaders, pasteTypeOf, pathDurationMs, peerValue, peersHostedRefusal, plainName, planFreshTake, pointerTravelMs, pollCondition, pressSequence, publicUrl, readAllBytes, readCondition, readMediaSource, readPath, readyLine, readyProblem, realSleep, recordTake, redirectedAway, reloadUntilReady, resolveChord, resolveModifier, resolveSetupText, runPeer, runSetup, sameJson, sayCondition, sayDuration, sayJs, sayValue, schedulePath, scriptEnvNames, scriptFiles, scrollByScript, scrollTravelMs, settleMs, settleOn, settleVerdict, setupEnvNames, soundSrcForMeta, splitChord, splitSegmentsAtSkips, stageClipboardScript, stepBoundMs, syntheticPasteScript, teardownEnvProblem, teardownLine, typeOfName, untilReady, urlSchemeProblem, validateActions, validatePeers, validateSetup, visibleTextScript, wallVerdict, withFittingExport, withPageSound };
2382
+ export { APP_QUIET_MS, APP_SETTLE_CAP_MS, AWAIT_HEARTBEAT_MS, AWAIT_POLL_S, AWAIT_TIMEOUT_S, type ActionStep, type ActionsFile, type Arrival, type AwaitUntil, CHANGE_AGE_PROBE, CLICK_BUTTONS, type ClickButton, type ConditionState, DEAD_SHARE_WARN_PCT, DEAD_STRETCH_WARN_MS, DEFAULT_READY, DOM_CHANGE_PROBE, DOM_QUIET_MS, DOM_SETTLE_CAP_MS, DOWNLOAD_TIMEOUT_S, DRAG_HOLD_MS, DRAG_MODIFIERS, type DeadReport, type DeadStep, type DisabledClick, type DragModifier, EXPECT_TIMEOUT_S, EXPOSURE_ADVICE, EXPOSURE_MATCHERS_SRC, EXPOSURE_PROBE, type EncodePageOptions, type Exposure, type ExposureKind, ExposureLog, type FrameRec, type FrameSink, type FreezeSpan, type FreshPlanOptions, type GuardedStep, type HeardSound, IDLE_CALL_MS, IF_LOOK_MS, JS_SAID_MAX, JS_VALUE_MAX, KEY_ROUNDTRIP_MS, KEY_SEQUENCE_GAP_MS, type LoadedFiles, MAX_KEYS, MAX_PATH_POINTS, MAX_PEERS, MAX_PEER_STEPS, MEDIA_DRAIN_PROBE, MEDIA_WATCH_SCRIPT, MIN_SKIP_MS, MODIFIERS, MOTION_TICK_MS, MULTI_CLICK_GAP_MS, type MaskReport, type MaskRule, type MediaDrain, type MediaNote, type Modifier, NAV_TIMEOUT_MS, NETWORKIDLE_HYDRATION_MS, NOTICE_SRC, type Notice, NoticeLog, OUTPUT_MAX_BYTES, OVERRUN_MIN_MS, OVERRUN_MIN_PLANNED_MS, OVERRUN_SHARE, type OutputSink, PAGE_ERROR_LINE_CHARS, PASTE_MAX_BYTES, PASTE_READ_WINDOW_MS, PASTE_TYPES, PASTE_UNREAD_MS, PATH_DEFAULT_MS, PEER_VALUE_MAX, PEER_VERBS, POINTER_MAX_MS, POINTER_MIN_MS, POINTER_MS_PER_PX, PRESS_HOLD_MS, PRESS_KEYS, PRESS_LEAD_MS, type PaceReport, type PageError, PageErrorLog, PageSoundLog, type PasteItem, type PathPoint, type PathSample, type Peer, type PeerRun, type PeerStep, type PollResult, type PressKey, QUIET_MS, READY_MODES, READY_SETTLE_CAP_MS, READ_BEAT_MS, RESPONSE_MS, type ReadyMode, type ReadyOpts, type ReadyReport, type RecordOpts, RecordRefusedError, type RecordResult, type RecorderApiResponse, type RecorderBrowser, type RecorderButtonOpts, type RecorderCdp, type RecorderClock, type RecorderConsoleMessage, type RecorderContext, type RecorderDownload, type RecorderLocator, type RecorderLocatorRoot, type RecorderMediaElement, type RecorderPage, type RecorderRect, type RecorderResponse, type RecorderRoute, SCROLL_MAX_MS, SCROLL_MIN_MS, SCROLL_MS_PER_PX, SCROLL_SETTLE_MS, SETTLE_CAP_MS, SETTLE_MS, SETTLE_VERBS, STEP_GUARDS, STEP_MARGIN_MS, type ScannedNotice, type ScriptFiles, SetupEnvError, SetupError, type SetupResult, type SetupStep, type SetupText, type SkippedStep, type SoundSink, StepBound, type StepGuard, type StepOverrun, type StepPace, type StepPhase, StepSignals, type StoppedTake, type SurfaceFit, type SurfaceSize, TEARDOWN_BOUND_MS, TRAILING_HOLD_MS, TakeClock, type TeardownReport, WAIT_MARGIN_MS, WALL_PROBE, type WaitCondition, WallError, type WallKind, type WallVerdict, ZOOM_MARK_VERBS, appSettled, askedMs, base64Bytes, bounded, buildEncodePage, buttonNumber, capReached, cappedLine, chordProblem, clampWait, clockMotion, clockTyping, conditionMiss, deadLine, deadTime, deadWarns, domSettled, easeInOutCubic, exposureLine, extForType, fetchInPageScript, fileNameProblem, fitSurfaceToViewport, formatDurationCap, guardVerdict, guardedSteps, hangReason, headersFor, holdLeftMs, hostedRefusals, inlinePoints, inlineScript, isIdpHost, isKeyName, isSignInPath, jpegDims, jsConditionScript, keptValue, keySequencePlanMs, loadScriptFiles, maskInitScript, modifierBits, nameFromUrl, noticeAdvice, noticeLine, outputName, overrunLine, overrunOf, paceLine, paceReport, pageErrorLine, parseHeaders, pasteTypeOf, pathDurationMs, peerValue, peersHostedRefusal, plainName, planFreshTake, pointerTravelMs, pollCondition, pressSequence, publicUrl, readAllBytes, readCondition, readMediaSource, readPath, readyLine, readyProblem, realSleep, recordTake, redirectedAway, reloadUntilReady, resolveChord, resolveModifier, resolveSetupText, runPeer, runSetup, sameJson, sayCondition, sayDuration, sayJs, sayValue, schedulePath, scriptEnvNames, scriptFiles, scrollByScript, scrollTravelMs, settleMs, settleOn, settleVerdict, setupEnvNames, soundSrcForMeta, splitChord, splitSegmentsAtSkips, stageClipboardScript, stepBoundMs, syntheticPasteScript, teardownEnvProblem, teardownLine, typeOfName, untilReady, urlSchemeProblem, validateActions, validatePeers, validateSetup, visibleTextScript, wallVerdict, withFittingExport, withPageSound };
@@ -689,7 +689,8 @@ function noticeAdvice(notices) {
689
689
  }
690
690
 
691
691
  // src/record/setup.ts
692
- var VERBS = /* @__PURE__ */ new Set(["wait", "click", "type", "press", "goto"]);
692
+ var VERBS = /* @__PURE__ */ new Set(["wait", "click", "type", "press", "goto", "if"]);
693
+ var IF_LOOK_MS = 3e3;
693
694
  function urlSchemeProblem(url) {
694
695
  let u;
695
696
  try {
@@ -715,7 +716,7 @@ function validateSetup(value, phase = "setup") {
715
716
  errors.push(`${at}: "do" must be one of ${[...VERBS].join(", ")}`);
716
717
  return;
717
718
  }
718
- if ((s.do === "click" || s.do === "type") && typeof s.selector !== "string")
719
+ if ((s.do === "click" || s.do === "type" || s.do === "if") && typeof s.selector !== "string")
719
720
  errors.push(`${at}: ${s.do} needs a selector`);
720
721
  if (s.do === "wait" && typeof s.ms !== "number")
721
722
  errors.push(`${at}: wait needs ms`);
@@ -779,6 +780,9 @@ function teardownEnvProblem(steps, env) {
779
780
  var TEARDOWN_BOUND_MS = 6e4;
780
781
  function teardownLine(report) {
781
782
  const f = report.failed;
783
+ const k = report.skipped;
784
+ if (!f && k)
785
+ return `teardown: nothing to undo, ${k.selector} is not on the page (teardown[${k.step}] if); ${report.ran} step(s) ran, ${k.rest} skipped`;
782
786
  if (!f) return `teardown: ${report.ran} step(s) ran`;
783
787
  const reason = f.error.replace(/[.\s]+$/, "");
784
788
  return `TEARDOWN FAILED at teardown[${f.step}] (${f.do}${f.selector ? ` ${f.selector}` : ""}): ${reason}. What the take created may still be in the product; remove it by hand.`;
@@ -790,6 +794,7 @@ async function runSetup(page, steps, opts) {
790
794
  const deadline = opts.boundMs === void 0 ? void 0 : now() + opts.boundMs;
791
795
  const lines = [];
792
796
  let typed = "";
797
+ let gone = null;
793
798
  const runStep = async (step, i) => {
794
799
  const settle = "ms" in step && typeof step.ms === "number" ? step.ms : 150;
795
800
  switch (step.do) {
@@ -806,6 +811,12 @@ async function runSetup(page, steps, opts) {
806
811
  await page.keyboard.press(step.key);
807
812
  await opts.sleep(settle);
808
813
  return `${phase} #${i} press ${step.key}`;
814
+ case "if": {
815
+ const present = await page.locator(step.selector).first().waitFor({ state: "visible", timeout: step.ms ?? IF_LOOK_MS }).then(() => true).catch(() => false);
816
+ if (present) return `${phase} #${i} if ${step.selector}: on the page`;
817
+ gone = { step: i, selector: step.selector };
818
+ return `${phase} #${i} if ${step.selector}: not on the page, the ${steps.length - i - 1} step(s) after it skipped`;
819
+ }
809
820
  case "click": {
810
821
  const loc = page.locator(step.selector).first();
811
822
  await loc.waitFor({ state: "visible", timeout: 8e3 });
@@ -848,6 +859,13 @@ async function runSetup(page, steps, opts) {
848
859
  }
849
860
  };
850
861
  }
862
+ const ended = gone;
863
+ if (ended)
864
+ return {
865
+ ran: i + 1,
866
+ lines,
867
+ skipped: { ...ended, rest: steps.length - i - 1 }
868
+ };
851
869
  }
852
870
  return { ran: steps.length, lines };
853
871
  }
@@ -3270,7 +3288,8 @@ async function recordTakeSteps(browser, url, actions, sink, log, opts, late) {
3270
3288
  ...result.failed.selector !== void 0 ? { selector: result.failed.selector } : {},
3271
3289
  error: result.failed.error ?? "the step failed"
3272
3290
  }
3273
- } : {}
3291
+ } : {},
3292
+ ...result.skipped ? { skipped: result.skipped } : {}
3274
3293
  };
3275
3294
  } catch (e) {
3276
3295
  teardown = {
@@ -3577,6 +3596,7 @@ async function recordTakeSteps(browser, url, actions, sink, log, opts, late) {
3577
3596
  const outputNames = /* @__PURE__ */ new Set();
3578
3597
  const overruns = [];
3579
3598
  let stopped = null;
3599
+ let untilReached = false;
3580
3600
  let unpressedGuard = null;
3581
3601
  let capped = false;
3582
3602
  const signals = new StepSignals(
@@ -4278,6 +4298,11 @@ async function recordTakeSteps(browser, url, actions, sink, log, opts, late) {
4278
4298
  ...hang.hung ? { hung: true } : {}
4279
4299
  });
4280
4300
  if (stopped) break;
4301
+ if (dry && opts.until && step.id === opts.until.id) {
4302
+ await opts.until.at(rawPage);
4303
+ untilReached = true;
4304
+ break;
4305
+ }
4281
4306
  }
4282
4307
  signals.close();
4283
4308
  const peerRuns = await Promise.all(lanes);
@@ -4292,7 +4317,7 @@ async function recordTakeSteps(browser, url, actions, sink, log, opts, late) {
4292
4317
  ...ps.reason ? { reason: ps.reason } : {},
4293
4318
  peer: pr.id
4294
4319
  });
4295
- if (!capped && !stopped) await sleep(TRAILING_HOLD_MS);
4320
+ if (!capped && !stopped && !untilReached) await sleep(TRAILING_HOLD_MS);
4296
4321
  if (capped || capReached(now(), maxSeconds)) {
4297
4322
  capped = true;
4298
4323
  log(` ${cappedLine(maxSeconds)}`);
@@ -4673,6 +4698,7 @@ export {
4673
4698
  EXPOSURE_PROBE,
4674
4699
  ExposureLog,
4675
4700
  IDLE_CALL_MS,
4701
+ IF_LOOK_MS,
4676
4702
  JS_SAID_MAX,
4677
4703
  JS_VALUE_MAX,
4678
4704
  KEY_ROUNDTRIP_MS,