Skip to content

Commit 2c74c70

Browse files
committed
docs: async fixture response documentation and changelog
Dynamic/async responses section on examples page. Info-box callouts on fixtures and multi-turn pages. Changelog entry credits @5ebastianMeier (issue #154).
1 parent 55fe40e commit 2c74c70

4 files changed

Lines changed: 67 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Added
66

7+
- **Async fixture responses** — Fixture responses can now be sync or async functions that receive the request and return the response dynamically. Enables awaiting side effects (database writes, API calls) before constructing the response — eliminating race conditions in complex multi-turn E2E tests. Works with all providers, streaming, and convenience methods (`on()`, `onMessage()`, `onTurn()`). (Feature request by @5ebastianMeier, issue #154)
78
- **Snapshot-style recording** — When `X-Test-Id` is present, recorded fixtures are saved to `<fixturePath>/<slugified-testId>/<provider>.json` instead of timestamp-based filenames. Multiple fixtures for the same test+provider merge into one file. Stable paths enable meaningful PR diffs and easy test-to-fixture mapping. (Feature request by @jantimon, issue #155)
89

910
## [1.18.0] - 2026-05-04

docs/examples/index.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,52 @@ <h3>Tool-call cycle with hasToolResult</h3>
607607
]
608608
}</code></pre>
609609
</div>
610+
611+
<!-- ─── Dynamic / Async Responses ──────────────────────────── -->
612+
613+
<h2>Dynamic / Async Responses</h2>
614+
615+
<p>
616+
Fixture responses can be functions &mdash; sync or async &mdash; that receive the request
617+
and return the response dynamically. Use this when you need to await side effects, compute
618+
responses based on request content, or inject runtime data into fixtures.
619+
</p>
620+
621+
<h3>Async response with side-effect</h3>
622+
<p>
623+
Wait for an external operation to complete before constructing the fixture response.
624+
Eliminates race conditions in multi-turn E2E tests where entity creation happens
625+
out-of-band.
626+
</p>
627+
<div class="code-block">
628+
<div class="code-block-header">async-side-effect.ts <span class="lang-tag">ts</span></div>
629+
<pre><code><span class="op">mock</span>.<span class="fn">on</span>(
630+
{ <span class="prop">toolCallId</span>: <span class="str">"call_create_entity"</span> },
631+
<span class="kw">async</span> (<span class="op">req</span>) <span class="kw">=&gt;</span> {
632+
<span class="kw">const</span> <span class="op">entity</span> = <span class="kw">await</span> <span class="op">createEntityPromise</span>;
633+
<span class="kw">return</span> {
634+
<span class="prop">content</span>: <span class="str">`Entity "${entity.name}" created!`</span>,
635+
<span class="prop">toolCalls</span>: [{
636+
<span class="prop">name</span>: <span class="str">"next_step"</span>,
637+
<span class="prop">arguments</span>: <span class="op">JSON</span>.<span class="fn">stringify</span>({ <span class="prop">entityId</span>: <span class="op">entity</span>.<span class="prop">id</span> }),
638+
}],
639+
};
640+
},
641+
);</code></pre>
642+
</div>
643+
644+
<h3>Request-aware response</h3>
645+
<p>
646+
Compute the response from the incoming request content. Useful for echo-style fixtures,
647+
transformations, or conditional logic that goes beyond what match fields can express.
648+
</p>
649+
<div class="code-block">
650+
<div class="code-block-header">request-aware.ts <span class="lang-tag">ts</span></div>
651+
<pre><code><span class="op">mock</span>.<span class="fn">onMessage</span>(<span class="str">"translate"</span>, (<span class="op">req</span>) <span class="kw">=&gt;</span> {
652+
<span class="kw">const</span> <span class="op">text</span> = <span class="op">req</span>.<span class="prop">messages</span>.<span class="fn">at</span>(-<span class="num">1</span>)?.<span class="prop">content</span> <span class="kw">??</span> <span class="str">""</span>;
653+
<span class="kw">return</span> { <span class="prop">content</span>: <span class="str">`Translated: ${text.toUpperCase()}`</span> };
654+
});</code></pre>
655+
</div>
610656
</main>
611657
<aside class="page-toc" id="page-toc"></aside>
612658
</div>

docs/fixtures/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,14 @@ <h2>Response Types</h2>
355355
</p>
356356
</div>
357357

358+
<div class="info-box">
359+
<p>
360+
<strong>Dynamic responses:</strong> Responses can also be sync or async functions that
361+
receive the request and return the response dynamically. See
362+
<a href="/examples#dynamic-async-responses">Dynamic Responses</a> on the Examples page.
363+
</p>
364+
</div>
365+
358366
<h2>Response Override Fields</h2>
359367
<p>
360368
Fixture responses can include optional fields to override auto-generated envelope values.

docs/multi-turn/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,18 @@ <h3>hasToolResult &mdash; match by tool execution state</h3>
182182
}</code></pre>
183183
</div>
184184

185+
<div class="info-box">
186+
<p>
187+
<strong>Async fixture responses for race-free multi-turn tests.</strong> When a
188+
multi-turn test depends on side effects between turns (database writes, entity creation,
189+
external API calls), async fixture responses let you <code>await</code> those operations
190+
before constructing the response &mdash; eliminating race conditions without
191+
<code>setTimeout</code> hacks. See
192+
<a href="/examples#dynamic-async-responses">Dynamic / Async Responses</a> on the
193+
Examples page.
194+
</p>
195+
</div>
196+
185197
<h3>Programmatic API</h3>
186198
<p>
187199
The <code>onTurn()</code> convenience method combines <code>turnIndex</code> with a

0 commit comments

Comments
 (0)