refactor(test): stabilize case tables and readonly helper inputs

This commit is contained in:
Peter Steinberger
2026-02-22 00:00:53 +01:00
parent 03586e3d00
commit 8752203f59
11 changed files with 106 additions and 52 deletions

View File

@@ -9,7 +9,7 @@ export type OutboundResultEnvelope = {
};
type BuildEnvelopeParams = {
payloads?: ReplyPayload[] | OutboundPayloadJson[];
payloads?: readonly ReplyPayload[] | readonly OutboundPayloadJson[];
meta?: unknown;
delivery?: OutboundDeliveryJson;
flattenDelivery?: boolean;
@@ -29,8 +29,8 @@ export function buildOutboundResultEnvelope(
: params.payloads.length === 0
? []
: isOutboundPayloadJson(params.payloads[0])
? (params.payloads as OutboundPayloadJson[])
: normalizeOutboundPayloadsForJson(params.payloads as ReplyPayload[]);
? [...(params.payloads as readonly OutboundPayloadJson[])]
: normalizeOutboundPayloadsForJson(params.payloads as readonly ReplyPayload[]);
if (params.flattenDelivery !== false && params.delivery && !params.meta && !hasPayloads) {
return params.delivery;

View File

@@ -8,6 +8,7 @@ import type { ReplyPayload } from "../../auto-reply/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
import { typedCases } from "../../test-utils/typed-cases.js";
import {
ackDelivery,
computeBackoffMs,
@@ -447,7 +448,11 @@ describe("buildOutboundResultEnvelope", () => {
mediaUrl: null,
channelId: "C1",
};
const cases = [
const cases = typedCases<{
name: string;
input: Parameters<typeof buildOutboundResultEnvelope>[0];
expected: unknown;
}>([
{
name: "flatten delivery by default",
input: { delivery: whatsappDelivery },
@@ -478,7 +483,7 @@ describe("buildOutboundResultEnvelope", () => {
input: { delivery: discordDelivery, flattenDelivery: false },
expected: { delivery: discordDelivery },
},
];
]);
for (const testCase of cases) {
const input: Parameters<typeof buildOutboundResultEnvelope>[0] =
"payloads" in testCase.input
@@ -814,7 +819,10 @@ describe("resolveOutboundSessionRoute", () => {
describe("normalizeOutboundPayloadsForJson", () => {
it("normalizes payloads for JSON output", () => {
const cases = [
const cases = typedCases<{
input: Parameters<typeof normalizeOutboundPayloadsForJson>[0];
expected: ReturnType<typeof normalizeOutboundPayloadsForJson>;
}>([
{
input: [
{ text: "hi" },
@@ -852,7 +860,7 @@ describe("normalizeOutboundPayloadsForJson", () => {
},
],
},
];
]);
for (const testCase of cases) {
const input: ReplyPayload[] = testCase.input.map((payload) =>
@@ -878,7 +886,11 @@ describe("normalizeOutboundPayloads", () => {
describe("formatOutboundPayloadLog", () => {
it("formats text+media and media-only logs", () => {
const cases = [
const cases = typedCases<{
name: string;
input: Parameters<typeof formatOutboundPayloadLog>[0];
expected: string;
}>([
{
name: "text with media lines",
input: {
@@ -895,7 +907,7 @@ describe("formatOutboundPayloadLog", () => {
},
expected: "MEDIA:https://x.test/a.png",
},
];
]);
for (const testCase of cases) {
expect(

View File

@@ -15,7 +15,7 @@ export type OutboundPayloadJson = {
channelData?: Record<string, unknown>;
};
function mergeMediaUrls(...lists: Array<Array<string | undefined> | undefined>): string[] {
function mergeMediaUrls(...lists: Array<ReadonlyArray<string | undefined> | undefined>): string[] {
const seen = new Set<string>();
const merged: string[] = [];
for (const list of lists) {
@@ -37,7 +37,9 @@ function mergeMediaUrls(...lists: Array<Array<string | undefined> | undefined>):
return merged;
}
export function normalizeReplyPayloadsForDelivery(payloads: ReplyPayload[]): ReplyPayload[] {
export function normalizeReplyPayloadsForDelivery(
payloads: readonly ReplyPayload[],
): ReplyPayload[] {
return payloads.flatMap((payload) => {
const parsed = parseReplyDirectives(payload.text ?? "");
const explicitMediaUrls = payload.mediaUrls ?? parsed.mediaUrls;
@@ -68,7 +70,9 @@ export function normalizeReplyPayloadsForDelivery(payloads: ReplyPayload[]): Rep
});
}
export function normalizeOutboundPayloads(payloads: ReplyPayload[]): NormalizedOutboundPayload[] {
export function normalizeOutboundPayloads(
payloads: readonly ReplyPayload[],
): NormalizedOutboundPayload[] {
return normalizeReplyPayloadsForDelivery(payloads)
.map((payload) => {
const channelData = payload.channelData;
@@ -89,7 +93,9 @@ export function normalizeOutboundPayloads(payloads: ReplyPayload[]): NormalizedO
);
}
export function normalizeOutboundPayloadsForJson(payloads: ReplyPayload[]): OutboundPayloadJson[] {
export function normalizeOutboundPayloadsForJson(
payloads: readonly ReplyPayload[],
): OutboundPayloadJson[] {
return normalizeReplyPayloadsForDelivery(payloads).map((payload) => ({
text: payload.text ?? "",
mediaUrl: payload.mediaUrl ?? null,
@@ -98,7 +104,11 @@ export function normalizeOutboundPayloadsForJson(payloads: ReplyPayload[]): Outb
}));
}
export function formatOutboundPayloadLog(payload: NormalizedOutboundPayload): string {
export function formatOutboundPayloadLog(
payload: Pick<NormalizedOutboundPayload, "text" | "channelData"> & {
mediaUrls: readonly string[];
},
): string {
const lines: string[] = [];
if (payload.text) {
lines.push(payload.text.trimEnd());