test(ai): 补端到端形状契约用例

把 buildCreativeAssistantResult 在失败态下的**真实产出**打成一行 JSON,
供 .scratch/ai-assistant/verify-frontend-e2e.js 当输入喂给前端真实渲染函数,
验证的是「后端真实产出 → 前端真实渲染」整条链路,而非两侧各自自测。

实测产出为 {"status":"failed","answer":"生成失败,请稍后重试"},
不含 raw / workflow_id / req_id / 上游错误栈。

Refs: .scratch/ai-assistant/issues/01-creative-assistant-raw-json-bubble.md
This commit is contained in:
2026-09-24 03:51:49 +08:00
parent 23a7f001cc
commit c598d88506
@@ -0,0 +1,41 @@
package com.gxwebsoft.ai.controller;
import com.gxwebsoft.common.core.utils.JSONUtil;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 端到端形状契约:把后端失败态的**真实产出**打成一行 JSON,
* 供前端验证脚本当作输入,确认前端拿到它时渲染的是可读文案而非原始报文。
*
* <p>输出被 `.scratch/ai-assistant/verify-frontend-e2e.js` 读取;
* 断言放在那个脚本里(前端侧),这里只负责产出真实形状。
*/
class AiCreativeFailureShapeContractTest {
@Test
void 打印失败态真实返回形状() throws Exception {
String failureEvent = "{"
+ "\"event\":\"workflow_finished\","
+ "\"workflow_run_id\":\"b2e18332-68bd-49e6-90e2-bd9d16d428ff\","
+ "\"task_id\":\"0b1fdd88-cc6f-45b8-989d-be4f85bcff74\","
+ "\"data\":{\"status\":\"failed\",\"outputs\":{},"
+ "\"error\":\"req_id: dc688258de PluginInvokeError: Model disabled.\"}"
+ "}";
Map<String, Object> responseData = JSONUtil.parseObject(failureEvent, Map.class);
AiController controller = new AiController();
Method method = AiController.class.getDeclaredMethod(
"buildCreativeAssistantResult", Map.class, String.class);
method.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, Object> result = (Map<String, Object>) method.invoke(
controller, responseData, failureEvent);
// ApiResult 只包一层 {code,message,data},apiRequest 在前端会拆出 data,
// 所以这里打印的正是前端 formatCreativeResult 的入参。
System.out.println("__E2E_SHAPE__" + JSONUtil.toJSONString(result));
}
}