

























@@ -98,6 +98,69 @@ async function writeLiveRuntimeToolEvidence(env: QaSuiteRuntimeEnv, toolName = "
9898]);
9999}
100100101+async function runMockRuntimeToolFixtureWithOutputs(params: {
102+toolName: string;
103+happyArgs: Record<string, unknown>;
104+failureArgs: Record<string, unknown>;
105+happyOutput: string;
106+failureOutput: string;
107+}) {
108+const env = await makeEnv({
109+mock: { baseUrl: "http://127.0.0.1:9999" },
110+});
111+const promptSnippet = `target=${params.toolName}`;
112+const failurePromptSnippet = `failure target=${params.toolName}`;
113+const happyCallId = `call-${params.toolName}-happy`;
114+const failureCallId = `call-${params.toolName}-failure`;
115+const fetchJson = vi
116+.fn()
117+.mockResolvedValueOnce([])
118+.mockResolvedValueOnce([
119+{
120+allInputText: promptSnippet,
121+plannedToolCallId: happyCallId,
122+plannedToolName: params.toolName,
123+plannedToolArgs: params.happyArgs,
124+},
125+{
126+allInputText: promptSnippet,
127+toolOutputCallId: happyCallId,
128+toolOutput: params.happyOutput,
129+},
130+{
131+allInputText: failurePromptSnippet,
132+plannedToolCallId: failureCallId,
133+plannedToolName: params.toolName,
134+plannedToolArgs: params.failureArgs,
135+},
136+{
137+allInputText: failurePromptSnippet,
138+toolOutputCallId: failureCallId,
139+toolOutput: params.failureOutput,
140+},
141+]);
142+143+return runRuntimeToolFixture(
144+env,
145+{
146+toolName: params.toolName,
147+toolCoverage: {
148+bucket: "openclaw-dynamic-integration",
149+expectedLayer: "openclaw-dynamic",
150+},
151+ promptSnippet,
152+ failurePromptSnippet,
153+},
154+{
155+createSession: vi.fn(async (_env, _label, key) => key!),
156+readEffectiveTools: vi.fn(async () => new Set([params.toolName])),
157+runAgentPrompt: vi.fn(async () => ({})),
158+ fetchJson,
159+ensureImageGenerationConfigured: vi.fn(),
160+},
161+);
162+}
163+101164afterEach(async () => {
102165await Promise.all(
103166tempRoots.splice(0).map((tempRoot) => fs.rm(tempRoot, { recursive: true, force: true })),
@@ -595,6 +658,59 @@ describe("runtime tool fixture", () => {
595658).rejects.toThrow("expected mock failure-path tool failure output for read");
596659});
597660661+it.each([
662+{
663+name: "required-field",
664+toolName: "sessions_spawn",
665+happyArgs: { task: "reply ok" },
666+happyOutput: "accepted",
667+failureOutput: "task required",
668+},
669+{
670+name: "unavailable-provider",
671+toolName: "web_search",
672+happyArgs: { query: "OpenClaw runtime parity fixed query" },
673+happyOutput: "result",
674+failureOutput: "web_search is disabled or no provider is available.",
675+},
676+])("accepts $name messages as mock failure fixture output", async (fixture) => {
677+const details = await runMockRuntimeToolFixtureWithOutputs({
678+ ...fixture,
679+failureArgs: { __qaFailureMode: "denied-input" },
680+});
681+682+expect(details).toContain(`${fixture.toolName} mock provider failure planned args`);
683+});
684+685+it.each([
686+{
687+name: "neutral required-text",
688+toolName: "sessions_spawn",
689+happyArgs: { task: "reply ok" },
690+happyOutput: "accepted",
691+failureOutput: "no action required",
692+expectedError: "expected mock failure-path tool failure output for sessions_spawn",
693+},
694+{
695+name: "unavailable-provider happy output",
696+toolName: "web_search",
697+happyArgs: { query: "OpenClaw runtime parity fixed query" },
698+happyOutput: "web_search is disabled or no provider is available.",
699+failureOutput: "web_search is disabled or no provider is available.",
700+expectedError: "expected mock happy-path successful tool output for web_search",
701+},
702+])("rejects $name as mock fixture output", async (fixture) => {
703+await expect(
704+runMockRuntimeToolFixtureWithOutputs({
705+toolName: fixture.toolName,
706+happyArgs: fixture.happyArgs,
707+failureArgs: { __qaFailureMode: "denied-input" },
708+happyOutput: fixture.happyOutput,
709+failureOutput: fixture.failureOutput,
710+}),
711+).rejects.toThrow(fixture.expectedError);
712+});
713+598714it("allows successful happy-path tool output to mention errors", async () => {
599715const env = await makeEnv({
600716mock: { baseUrl: "http://127.0.0.1:9999" },
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。