mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(qa): fail slack no-reply on any reply
This commit is contained in:
@@ -36,6 +36,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Google Meet: refresh realtime browser state during status and retry delayed speech after Meet finishes joining, so a just-opened in-call tab no longer leaves speech stuck behind stale `not-in-call` health.
|
||||
- Plugins/install: recover the install ledger from the managed npm root when `plugins/installs.json` is empty or partial, so reinstalling Discord and Codex no longer makes the other installed plugin disappear.
|
||||
- Google Meet: grant Meet media permissions through the Playwright browser context when CDP grants do not affect the attached Chrome page, and report in-call microphone/speaker permission problems instead of marking realtime speech ready.
|
||||
- QA/Slack: fail the live mention-gating scenario on any unexpected SUT reply, even when the reply does not echo the expected marker. Thanks @vincentkoc.
|
||||
- Channel docs: keep JSON5 channel config examples parseable and schema-valid, fixing BlueBubbles, QQ Bot, and Slack snippets that could not be copied into config or app manifests as shown. Thanks @vincentkoc.
|
||||
- Tlon: expose `groupInviteAllowlist` in the channel config schema and clarify that group invite auto-accept fails closed without an invite allowlist. Thanks @vincentkoc.
|
||||
- Google Chat: update the setup example to use the accepted `groups.<space>.enabled` key instead of the legacy `allow` alias, with a schema regression for the documented group shape. Thanks @vincentkoc.
|
||||
|
||||
@@ -54,4 +54,41 @@ describe("Slack live QA runtime helpers", () => {
|
||||
"slack-canary",
|
||||
]);
|
||||
});
|
||||
|
||||
it("fails mention-gating when the SUT replies without the marker", async () => {
|
||||
const observedMessages: Array<unknown> = [];
|
||||
await expect(
|
||||
__testing.waitForSlackNoReply({
|
||||
channelId: "C123456789",
|
||||
client: {
|
||||
conversations: {
|
||||
history: async () => ({
|
||||
messages: [
|
||||
{
|
||||
text: "I should not have replied",
|
||||
ts: "2.000000",
|
||||
user: "U999999999",
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
} as never,
|
||||
matchText: "SLACK_QA_NOMENTION_MARKER",
|
||||
observedMessages: observedMessages as never,
|
||||
observationScenarioId: "slack-mention-gating",
|
||||
observationScenarioTitle: "Slack unmentioned bot message does not trigger",
|
||||
sentTs: "1.000000",
|
||||
sutIdentity: { userId: "U999999999" },
|
||||
timeoutMs: 1_000,
|
||||
}),
|
||||
).rejects.toThrow("unexpected Slack SUT reply observed");
|
||||
expect(observedMessages).toMatchObject([
|
||||
{
|
||||
matchedScenario: false,
|
||||
text: "I should not have replied",
|
||||
ts: "2.000000",
|
||||
userId: "U999999999",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -428,16 +428,38 @@ async function waitForSlackNoReply(params: {
|
||||
sutIdentity: SlackAuthIdentity;
|
||||
timeoutMs: number;
|
||||
}) {
|
||||
try {
|
||||
await waitForSlackScenarioReply(params);
|
||||
} catch (error) {
|
||||
const message = formatErrorMessage(error);
|
||||
if (message === `timed out after ${params.timeoutMs}ms waiting for Slack message`) {
|
||||
return;
|
||||
const startedAt = Date.now();
|
||||
while (Date.now() - startedAt < params.timeoutMs) {
|
||||
const messages = await listSlackMessages({
|
||||
channelId: params.channelId,
|
||||
client: params.client,
|
||||
oldestTs: params.sentTs,
|
||||
});
|
||||
for (const message of messages) {
|
||||
const text = message.text ?? "";
|
||||
if (
|
||||
!message.ts ||
|
||||
message.ts === params.sentTs ||
|
||||
!isSutSlackMessage(message, params.sutIdentity)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const matchedScenario = text.includes(params.matchText);
|
||||
params.observedMessages.push({
|
||||
botId: message.bot_id,
|
||||
channelId: params.channelId,
|
||||
matchedScenario,
|
||||
scenarioId: params.observationScenarioId,
|
||||
scenarioTitle: params.observationScenarioTitle,
|
||||
text,
|
||||
threadTs: message.thread_ts,
|
||||
ts: message.ts,
|
||||
userId: message.user,
|
||||
});
|
||||
throw new Error("unexpected Slack SUT reply observed");
|
||||
}
|
||||
throw error;
|
||||
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
||||
}
|
||||
throw new Error("unexpected Slack SUT reply observed");
|
||||
}
|
||||
|
||||
async function waitForSlackChannelRunning(
|
||||
@@ -816,4 +838,5 @@ export const __testing = {
|
||||
parseSlackQaCredentialPayload,
|
||||
resolveSlackQaRuntimeEnv,
|
||||
SLACK_QA_STANDARD_SCENARIO_IDS,
|
||||
waitForSlackNoReply,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user