mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-27 04:37:13 +00:00
feat(bots): add platform event debugger
This commit is contained in:
@@ -188,11 +188,7 @@ try {
|
||||
.getByText(/Event Routing|事件路由|イベントルーティング/)
|
||||
.first()
|
||||
.waitFor({ timeout: 15_000 });
|
||||
await page
|
||||
.getByText(
|
||||
/Events this adapter can receive|此适配器可接收的事件|このアダプターが受信できるイベント/,
|
||||
)
|
||||
.waitFor();
|
||||
await page.getByText(/Supported events|支持的事件|対応イベント/).waitFor();
|
||||
await page
|
||||
.getByText(/Message received|收到消息|メッセージを受信/)
|
||||
.first()
|
||||
@@ -237,6 +233,57 @@ try {
|
||||
.click();
|
||||
await page.getByRole("dialog").waitFor({ state: "hidden" });
|
||||
|
||||
await page
|
||||
.getByRole("button", {
|
||||
name: /Listen for platform events|监听平台事件|プラットフォームイベントを監視/,
|
||||
})
|
||||
.click();
|
||||
const adapterDialog = page.getByRole("dialog");
|
||||
await adapterDialog.waitFor();
|
||||
await adapterDialog
|
||||
.getByText(/Listening|正在监听|監視中/, { exact: true })
|
||||
.waitFor({ timeout: 15_000 });
|
||||
|
||||
const inboundText = `adapter event ${paths.runId}`;
|
||||
const inbound = await apiJson(
|
||||
backendUrl,
|
||||
`/bots/${encodeURIComponent(botId)}`,
|
||||
{
|
||||
method: "POST",
|
||||
token,
|
||||
body: {
|
||||
session_id: `adapter-debug-${paths.runId}`,
|
||||
session_type: "person",
|
||||
sender: { id: "adapter-debug-user", name: "Adapter QA" },
|
||||
message: [{ type: "Plain", text: inboundText }],
|
||||
},
|
||||
},
|
||||
);
|
||||
result.api.adapter_event_webhook = {
|
||||
http_status: inbound.status,
|
||||
code: inbound.json.code ?? null,
|
||||
};
|
||||
if (inbound.status >= 400 || inbound.json.code !== 0) {
|
||||
throw new Error(
|
||||
inbound.json.msg || "The HTTP Bot adapter rejected the inbound event.",
|
||||
);
|
||||
}
|
||||
|
||||
await adapterDialog
|
||||
.getByText(/Message received|收到消息|メッセージ受信/, { exact: true })
|
||||
.waitFor({ timeout: 15_000 });
|
||||
await adapterDialog.getByText("message.received", { exact: true }).waitFor();
|
||||
await adapterDialog.getByText(inboundText, { exact: true }).waitFor();
|
||||
result.visible_signals.push(
|
||||
"adapter-event-listening",
|
||||
"adapter-event-received",
|
||||
"adapter-event-raw-code",
|
||||
);
|
||||
await adapterDialog
|
||||
.getByRole("button", { name: /Close|关闭|閉じる/ })
|
||||
.click();
|
||||
await adapterDialog.waitFor({ state: "hidden" });
|
||||
|
||||
const text = await bodyText(page);
|
||||
if (/\bEBA event\b/.test(text)) {
|
||||
throw new Error(
|
||||
@@ -291,7 +338,7 @@ try {
|
||||
}
|
||||
result.status = "pass";
|
||||
result.reason =
|
||||
"Bot event routing, dry-run, synthetic dispatch, and visible route status passed in the WebUI.";
|
||||
"Bot event routing, dry-run, real adapter input, and visible route status passed in the WebUI.";
|
||||
} catch (error) {
|
||||
if (!["blocked", "env_issue"].includes(result.status)) result.status = "fail";
|
||||
result.reason = result.reason || error.message;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
id: bot-event-routing-product-flow
|
||||
title: "Bot event routing can be configured and tested from the WebUI"
|
||||
title: "Bot event routing and adapter input can be inspected from the WebUI"
|
||||
mode: agent-browser
|
||||
area: bot
|
||||
type: feature
|
||||
@@ -33,16 +33,18 @@ steps:
|
||||
- "Confirm the adapter capability summary, friendly event name, target, and route status are visible."
|
||||
- "Confirm overlapping routes and unmatched-event fallback behavior are explained before save."
|
||||
- "Open Test event route and run a dry-run against the current form."
|
||||
- "Run the saved runtime route with a synthetic event."
|
||||
- "Close the dialog and confirm the route card shows the latest discarded status."
|
||||
- "Open Platform event debugging and send a real inbound event through the HTTP Bot adapter."
|
||||
- "Confirm the normalized event, raw event code, payload, and latest discarded route status are visible."
|
||||
checks:
|
||||
- "UI: A user can choose a channel and add a scenario-labeled behavior during initial Bot creation."
|
||||
- "UI: Event routing uses user-facing labels and does not require the raw event name in the primary route card."
|
||||
- "UI: Definite route shadowing and unmatched-event fallback behavior are visible without opening raw logs."
|
||||
- "UI: Dry-run visibly reports that the route matched the discard processor."
|
||||
- "UI: Saved-route execution visibly succeeds, explains its side-effect boundary, and updates route status to discarded."
|
||||
- "UI: Adapter event debugging is clearly separate from route preview and starts listening only after the dialog opens."
|
||||
- "UI: A real adapter event shows its friendly name, raw code, and normalized event data."
|
||||
- "UI: The route card updates to discarded after the real inbound event is handled."
|
||||
- "Console: No unexpected frontend errors appear during the flow."
|
||||
- "Network: Bot, dry-run, route-status, and test-event requests return without 5xx responses."
|
||||
- "Network: Bot, dry-run, route-status, log, and HTTP Bot webhook requests return without 5xx responses."
|
||||
- "Cleanup: The temporary Bot is deleted after evidence is collected."
|
||||
evidence_required:
|
||||
- ui
|
||||
@@ -51,7 +53,8 @@ evidence_required:
|
||||
- api_diagnostic
|
||||
diagnostics:
|
||||
- "The fixture deliberately uses the discard processor so the product-flow test cannot invoke a model, tool, or external callback."
|
||||
- "A passing API call without the visible matched and discarded UI states is not a pass."
|
||||
- "The adapter dialog observes normalized platform events; it does not simulate route matching."
|
||||
- "A passing webhook call without the visible adapter event and discarded UI states is not a pass."
|
||||
troubleshooting:
|
||||
- backend-not-listening
|
||||
- proxy-env-mismatch
|
||||
|
||||
Reference in New Issue
Block a user