mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 16:30:23 +00:00
refactor: unify reply content checks
This commit is contained in:
66
src/interactive/payload.test.ts
Normal file
66
src/interactive/payload.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
hasReplyChannelData,
|
||||
hasReplyContent,
|
||||
normalizeInteractiveReply,
|
||||
resolveInteractiveTextFallback,
|
||||
} from "./payload.js";
|
||||
|
||||
describe("hasReplyChannelData", () => {
|
||||
it("accepts non-empty objects only", () => {
|
||||
expect(hasReplyChannelData(undefined)).toBe(false);
|
||||
expect(hasReplyChannelData({})).toBe(false);
|
||||
expect(hasReplyChannelData([])).toBe(false);
|
||||
expect(hasReplyChannelData({ slack: { blocks: [] } })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasReplyContent", () => {
|
||||
it("treats whitespace-only text and empty structured payloads as empty", () => {
|
||||
expect(
|
||||
hasReplyContent({
|
||||
text: " ",
|
||||
mediaUrls: ["", " "],
|
||||
interactive: { blocks: [] },
|
||||
hasChannelData: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts shared interactive blocks and explicit extra content", () => {
|
||||
expect(
|
||||
hasReplyContent({
|
||||
interactive: {
|
||||
blocks: [{ type: "buttons", buttons: [{ label: "Retry", value: "retry" }] }],
|
||||
},
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasReplyContent({
|
||||
text: " ",
|
||||
extraContent: true,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("interactive payload helpers", () => {
|
||||
it("normalizes interactive replies and resolves text fallbacks", () => {
|
||||
const interactive = normalizeInteractiveReply({
|
||||
blocks: [
|
||||
{ type: "text", text: "First" },
|
||||
{ type: "buttons", buttons: [{ label: "Retry", value: "retry" }] },
|
||||
{ type: "text", text: "Second" },
|
||||
],
|
||||
});
|
||||
|
||||
expect(interactive).toEqual({
|
||||
blocks: [
|
||||
{ type: "text", text: "First" },
|
||||
{ type: "buttons", buttons: [{ label: "Retry", value: "retry" }] },
|
||||
{ type: "text", text: "Second" },
|
||||
],
|
||||
});
|
||||
expect(resolveInteractiveTextFallback({ interactive })).toBe("First\n\nSecond");
|
||||
});
|
||||
});
|
||||
@@ -136,6 +136,30 @@ export function hasInteractiveReplyBlocks(value: unknown): value is InteractiveR
|
||||
return Boolean(normalizeInteractiveReply(value));
|
||||
}
|
||||
|
||||
export function hasReplyChannelData(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(
|
||||
value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
export function hasReplyContent(params: {
|
||||
text?: string | null;
|
||||
mediaUrl?: string | null;
|
||||
mediaUrls?: ReadonlyArray<string | null | undefined>;
|
||||
interactive?: unknown;
|
||||
hasChannelData?: boolean;
|
||||
extraContent?: boolean;
|
||||
}): boolean {
|
||||
return Boolean(
|
||||
params.text?.trim() ||
|
||||
params.mediaUrl?.trim() ||
|
||||
params.mediaUrls?.some((entry) => Boolean(entry?.trim())) ||
|
||||
hasInteractiveReplyBlocks(params.interactive) ||
|
||||
params.hasChannelData ||
|
||||
params.extraContent,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveInteractiveTextFallback(params: {
|
||||
text?: string;
|
||||
interactive?: InteractiveReply;
|
||||
|
||||
Reference in New Issue
Block a user