Skip to content

withMocks ​

Replaces step bodies at specific indices with mock functions, while letting all other steps run normally. Ideal for unit testing individual steps in isolation.

Setup ​

typescript
import { FlowBuilder } from "flowneer";
import { withMocks } from "flowneer/plugins/dev";

const AppFlow = FlowBuilder.extend([withMocks]);

Usage ​

typescript
const flow = new AppFlow<State>()
  .startWith(fetchData) // step 0
  .then(processData) // step 1
  .then(saveToDb) // step 2 — will be mocked
  .then(sendNotification); // step 3

// In your test:
const savedItems: any[] = [];

flow.withMocks({
  2: async (s) => {
    // Mock step 2: capture what would have been saved
    savedItems.push(structuredClone(s.processed));
  },
});

await flow.run(testState);

expect(savedItems).toHaveLength(1);
expect(savedItems[0]).toMatchObject({ id: "test-123" });

API ​

.withMocks(map: Record<number, NodeFn<S, P>>) ​

ParameterTypeDescription
mapRecord<number, NodeFn>Map of step index → mock function

Steps not in map execute their real bodies normally.

How It Works ​

Registers a wrapStep hook. When a step's index is in map, the mock function is called instead of next(). When not in map, next() is called normally.

Test Pattern ​

typescript
import { describe, it, expect, vi } from "vitest";

describe("myFlow", () => {
  it("calls the notification service with correct data", async () => {
    const notifySpy = vi.fn();

    const flow = buildMyFlow();
    const AppFlow = FlowBuilder.extend([withMocks]);
    const trackedFlow = new AppFlow();
    trackedFlow.withMocks({
      3: notifySpy, // step 3 = sendNotification
    });

    await flow.run({ ...testInitialState });

    expect(notifySpy).toHaveBeenCalledOnce();
    expect(notifySpy.mock.calls[0][0].result).toBe("expected value");
  });
});

Notes ​

  • Multiple calls to withMocks stack — later registrations override earlier ones for the same index.
  • Mock functions receive the same (shared, params) arguments as real steps.
  • Combine with withDryRun on all other steps for fully isolated unit tests.