executeStep function test exported

Last updated: 2026-03-05T20:45:07.036Z

Metrics

LOC: 99 Complexity: 27 Params: 2

Signature

executeStep( payload: ExecuteStepPayload, ): : Promise<StepResult>

Summary

Execute a single flow step in the current page. Returns a StepResult describing the outcome. Never throws.

Architecture violations

View all

  • [warning] max-cyclomatic-complexity: 'executeStep' has cyclomatic complexity 27 (max 10)
  • [warning] max-lines: 'executeStep' has 99 lines (max 80)

Source Code

export async function executeStep(
  payload: ExecuteStepPayload,
): Promise<StepResult> {
  const { step, resolvedValue, replayConfig } = payload;

  try {
    let result: StepResult;

    const selector =
      step.smartSelectors?.[0]?.value ?? step.selector ?? undefined;

    // Partition effects by timing (respecting per-kind defaults)
    const allEffects: StepEffect[] = step.effects ?? [];
    const byTiming = (t: "before" | "during" | "after") =>
      allEffects.filter(
        (e) => (e.timing ?? DEFAULT_EFFECT_TIMING[e.kind]) === t,
      );

    const beforeEffects = byTiming("before");
    const duringEffects = byTiming("during");
    const afterEffects = byTiming("after");

    // 1. "before" effects complete fully before the action starts
    if (beforeEffects.length) await applyStepEffects(beforeEffects, selector);

    // 2. "during" effects start concurrently with the action
    const duringPromise = duringEffects.length
      ? applyStepEffects(duringEffects, selector)
      : Promise.resolve();

    switch (step.action) {
      case "navigate":
        result = handleNavigate(step);
        break;
      case "fill":
        result = await handleFill(step, resolvedValue, replayConfig);
        break;
      case "click":
        result = handleClick(step);
        break;
      case "select":
        result = handleSelect(step);
        break;
      case "check":
        result = handleCheck(step, true);
        break;
      case "uncheck":
        result = handleCheck(step, false);
        break;
      case "clear":
        result = handleClear(step);
        break;
      case "wait":
        result = await handleWait(step);
        break;
      case "scroll":
        result = handleScroll(step);
        break;
      case "press-key":
        result = handlePressKey(step);
        break;
      case "assert":
        result = handleAssert(step);
        break;
      case "caption":
        result = await handleCaption(step);
        break;
      default:
        return { status: "skipped", reason: `Unknown action: ${step.action}` };
    }

    // Wait for "during" effects (they run in parallel with the action)
    await duringPromise;

    // Check if any "during" zoom effect was indefinite (duration 0 or Infinity)
    // If so, cancel it now that the action is complete
    const hasIndefiniteZoom = duringEffects.some(
      (e) => e.kind === "zoom" && (e.duration === 0 || e.duration === Infinity),
    );
    if (hasIndefiniteZoom) {
      cancelActiveZoom();
    }

    // 3. "after" effects run once the action has finished successfully
    if (result.status === "success" && afterEffects.length) {
      await applyStepEffects(afterEffects, selector);
    }

    return result;
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    log.warn(`Step ${step.id} failed:`, message);

    if (step.optional) {
      return { status: "skipped", reason: message };
    }
    return { status: "failed", error: message };
  }
}

Dependencies (Outgoing)

graph LR executeStep["executeStep"] createLogger["createLogger"] FlowStep["FlowStep"] StepResult["StepResult"] ReplayConfig["ReplayConfig"] ExecuteStepPayload["ExecuteStepPayload"] applyStepEffects["applyStepEffects"] showCaption["showCaption"] cancelActiveZoom["cancelActiveZoom"] StepEffect["StepEffect"] handleNavigate["handleNavigate"] handleFill["handleFill"] handleClick["handleClick"] handleSelect["handleSelect"] handleCheck["handleCheck"] handleClear["handleClear"] handleWait["handleWait"] handleScroll["handleScroll"] handlePressKey["handlePressKey"] handleAssert["handleAssert"] handleCaption["handleCaption"] executeStep -->|uses| createLogger executeStep -->|uses| FlowStep executeStep -->|uses| StepResult executeStep -->|uses| ReplayConfig executeStep -->|uses| ExecuteStepPayload executeStep -->|uses| applyStepEffects executeStep -->|uses| showCaption executeStep -->|uses| cancelActiveZoom executeStep -->|uses| StepEffect executeStep -->|calls| handleNavigate executeStep -->|calls| handleFill executeStep -->|calls| handleClick executeStep -->|calls| handleSelect executeStep -->|calls| handleCheck executeStep -->|calls| handleClear executeStep -->|calls| handleWait executeStep -->|calls| handleScroll executeStep -->|calls| handlePressKey executeStep -->|calls| handleAssert executeStep -->|calls| handleCaption style executeStep fill:#dbeafe,stroke:#2563eb,stroke-width:2px click executeStep "a26ccfb820921de2.html" click createLogger "70597a0a6b5e9ebb.html" click FlowStep "9e707f428d9f0224.html" click StepResult "66548531c0f58b92.html" click ReplayConfig "4c8c81817aa14563.html" click ExecuteStepPayload "e310417b60dbdca7.html" click applyStepEffects "aed47434603419d0.html" click showCaption "bc25f610ecfb5828.html" click cancelActiveZoom "a0eaa380329081e4.html" click StepEffect "ad30ff415e80747b.html" click handleNavigate "fa502f0b873556f6.html" click handleFill "8f674e688d002684.html" click handleClick "4b4f336a7104e106.html" click handleSelect "3c2550d444ab28e5.html" click handleCheck "925d9bcf5b79be5d.html" click handleClear "9ce51648e6aea0e1.html" click handleWait "1e0c6f2b3548f948.html" click handleScroll "683f3c239bc85481.html" click handlePressKey "195a61c527b09c31.html" click handleAssert "fb80a5184e1878d1.html" click handleCaption "96ad0deafa86fab8.html"

Impact (Incoming)

graph LR executeStep["executeStep"] FillableElement["FillableElement"] assertFailed["assertFailed"] FillableElement -->|uses| executeStep assertFailed -->|uses| executeStep style executeStep fill:#dbeafe,stroke:#2563eb,stroke-width:2px click executeStep "a26ccfb820921de2.html" click FillableElement "2ecf5aaac3f668a8.html" click assertFailed "32e8f6272df2aded.html"
SourceType
FillableElement uses
assertFailed uses