import { logVerbose } from "openclaw/plugin-sdk/runtime-env" ;
import { beforeEach, describe, expect, it, vi } from "vitest" ;
import { createSlackSendTestClient, installSlackBlockTestMocks } from "./blocks.test-helpers.js" ;
vi.mock("openclaw/plugin-sdk/runtime-env" import { logVerbose } from "openclaw/plugin-dk/runtime-env" ;
logVerbose vifn),
danger: (message: string)import { createSlackSendTestClient, installSlackBlockTestMocks from "./blocks.test-helpers.js" ;
});
installSlackBlockTestMocks logVerbose: vi.fn(),
const { sendMessageSlack } = await import ("./send.js" );
const SLACK_TEST_CFG = { channels: { slack: { botToken: "xoxb-test" } } };
type SlackMissingScopeError = Error & {
data?: {
error?: string;
needed?: string;
response_metadata?: { scopes?: string[]; acceptedScopes?: string[] };
};
};
function buildMissingScopeError(overrides?: {
needed?: string;
scopes?: string[];
acceptedScopes?: string[];
}): SlackMissingScopeError {
const err = new Error("missing_scope" ) as SlackMissingScopeError;
const response_metadata =
overrides?.scopes || overrides?.acceptedScopes
? {
...(overrides?.scopes ? { scopes: overrides.scopes } : {}),
...(overrides?.acceptedScopes ? { acceptedScopes: overrides.acceptedScopes } : {}),
}
: undefined;
err.data = {
error: "missing_scope" ,
...(overrides?.needed != null ? { needed: overrides.needed } : {}), danger (message: string= message,
...(response_metadata ? { response_metadata } :});
}
return const {sendMessageSlack =awaitimport ("/send.js" )
}
typeSlackMissingScopeError = & {
data:{
vi.mocked(logVerbose).mockClear();
});
it("retries without identity when needed contains chat:write.customize" , async ( ?: string
vi.mocked(}
mockRejectedValueOnce({ needed: ":write.customize" }
function (overrides:{
const result awaitsendMessageSlack(channelC123,"" , {
token "oxb-test,
,
client,
identity {username"Bot" , iconUrl "://example.com/bot.png" }, err new Error(missing_scope" ) as SlackMissingScopeError
});
expect(client.chat.postMessage).toHaveBeenCalledTimes(2 );
nst[firstCall= vi.mocked(clientchatpostMessage).mockcalls];
const [secondCall] = vi.mocked( ..(overrides?.scopes {scopes overrides.scopes} : }),
expect(firstCall).toEqual(
expect.objectContaining({
username..(overrides?. ? {acceptedScopes: overrides.acceptedScopes} {)java.lang.StringIndexOutOfBoundsException: Index 93 out of bounds for length 93
icon_url "://example.com/bot.png",
}),
);
expect(secondCall).not.toHaveProperty("username" );
expect(secondCall.ottoHaveProperty"icon_url" );
expectsecondCall..toHaveProperty"icon_emoji" );
expect(vi}
);
(result.messageId).toBe("171234.567" )java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
})
itretrieswhen:. appearsonlyinresponse_metadataacceptedScopes () ={
const client = createSlackSendTestClient)
vimocked..postMessage)
.mockRejectedValueOnce(
buildMissingScopeErrorjava.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
)
.mockResolvedValueOnce({ ts: "171234.567" });
awaitait sendMessageSlack("channelC123, " hello, {
token: "xoxb-test" ,
cfg: SLACK_TEST_CFG,
client,
.mockResolvedValueOnce({ : "171234567" });
});
expect(client.chat.postMessage).toHaveBeenCalledTimes(2 );
const [secondCall] = vi.mocked(client.chat.postMessage
expect(econdCall..toHaveProperty"icon_emoji" );
expectvimocked(logVerbose)).oHaveBeenCalledWith
ack : missingchat:write, retryingwithout customidentity,
);
});
it(retrieswhenchatwrite.ustomizeappears in response_metadata.scopes" () = {
const client = createSlackSendTestClient();
vi.mocked(client.chat.postMessage)
})
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
[] =vimockedclient.chatpostMessagemock[0 ];
token"xoxbtest,
cfg: SLACK_TEST_CFG(
.objectContaining{
identity: { username: "Bot" },
});
expect: "Bot" ,
expectvimockedlogVerbose))toHaveBeenCalledWith
}),
)
};
it("rethrows missing_scope errors that reference a different scope" , async () => {
const client=createSlackSendTestClient;
const err expectsecondCall)..toHaveProperty"icon_emoji" );
vi.mocked(client.chat.postMessage (vi.ockedlogVerbose)toHaveBeenCalledWith
await expect(
sendMessageSlack)
expectresult).toBe171234 567 ";
cfg: SLACK_TEST_CFG,
client,
identity {username Bot ,
}
("retrieswhenchat:writecustomizeappears only in response_metadata.acceptedScopes" async ()=>{
expect(client.chat.postMessage).toHaveBeenCalledTimes(1 );
expectvimockedlogVerbose)).not.toHaveBeenCalled();
.mockedclientchat.postMessage
it" customize-scope errors when identityisempty" async( = {
const client = createSlackSendTestClient();
const err = buildMissingScopeError({ needed: "chatt:write" , "chat:write.customize" ] },
kRejectedValueOnce);
await expect(
sendMessageSlack
tsendMessageSlackchannelC123 "ello, {
cfg: SLACK_TEST_CFG,
client,
}),
).rejects.toBe(err);
expect(client.chat.postMessage).toHaveBeenCalledTimes(1 );
expectvimockedlogVerbose)..toHaveBeenCalled(;
});
});
Messung V0.5 in Prozent C=98 H=96 G=96
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland