🔑 Why MockChain Is a Chain

🔑 Why MockChain Is a Chain

When testing asynchronous methods, you often want to control behavior without rewriting the method logic. MockChain allows you to inject and observe behavior at any point in a promise chain, not just at the start.


🧩 Two Ends of the Chain

Consider a typical async method:

function fetchData(url, opts, autoStart = true) {
  return MockChain.fromResponse(url, opts, autoStart)
    .then(res => res.json())
    .then(obj => obj.ok);
}

There are three promises involved:

  1. Root node (root) — the initial wrapped promise (e.g., fetch()) resolving to a Response object.
  2. Mid node — the in-between promise resolving to the JSON object.
  3. Leaf node (end) — the last node resolving to a Boolean flag.

In tests, you usually mock the root to trigger the end manually:

const chain = fetchData(undefined, undefined, false); // don’t await — get the mockable chain
chain.root.mock(new Response(JSON.stringify({ ok: true }))); // inject mock Response
const flag = await chain; // await leaf node resolution
console.log(flag); // -> true

🃏 Walking the Chain

Each MockChain node tracks both its parent node. This lets you navigate the chain and mock any intermediate step:

let end = fetchData(undefined, undefined, false);
const mid = end.parent;        // walk one step up
const root = mid.parent;       // go to the root node

mid.mock({ ok: false }); // mock mid-level transformation
const flag = await end;        // observe downstream effect
console.log(flag);  // -> false

By exposing .parent and .root, MockChain allows testing at different depths of your async flow — verifying transformations, simulating partial failures, or injecting data exactly where needed.


🧠 Why This Matters

Traditional Promise chains are opaque — each .then() hides its intermediate state. MockChain keeps the structure visible and testable:

  • Mock upstream to control inputs.
  • Inspect or mock midstream to verify transformations.
  • Observe downstream to confirm outcomes.

This lets you navigate the logical flow of async code — injecting or inspecting results at any depth with full determinism.


Comments

Popular posts from this blog

🏁 The autostart Flag

⚠️ Async Functions Are Not Mockable