mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 17:20:45 +00:00
test(e2e): align release harness coverage
This commit is contained in:
@@ -32,6 +32,7 @@ function createPage(opts: { targetId: string; snapshotFull?: string; hasSnapshot
|
||||
context: () => context,
|
||||
locator,
|
||||
on: vi.fn(),
|
||||
url: vi.fn(() => `https://example.test/${opts.targetId}`),
|
||||
...(opts.hasSnapshotForAI === false
|
||||
? {}
|
||||
: {
|
||||
@@ -86,8 +87,8 @@ describe("pw-ai", () => {
|
||||
});
|
||||
|
||||
expect(res.snapshot).toBe("TWO");
|
||||
expect(p1.session.detach).toHaveBeenCalledTimes(1);
|
||||
expect(p2.session.detach).toHaveBeenCalledTimes(1);
|
||||
expect(p1.session.detach).toHaveBeenCalled();
|
||||
expect(p2.session.detach).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers aria refs from ai snapshots for act commands", async () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { vi } from "vitest";
|
||||
import { formatEnvelopeTimestamp } from "../../../test/helpers/envelope-timestamp.js";
|
||||
import type { MockBaileysSocket } from "../../../test/mocks/baileys.js";
|
||||
import { createMockBaileys } from "../../../test/mocks/baileys.js";
|
||||
|
||||
@@ -84,7 +85,11 @@ function loadSessionStoreMock(storePath: string) {
|
||||
|
||||
type BufferedDispatchReplyParams = {
|
||||
ctx: Record<string, unknown>;
|
||||
replyResolver: (ctx: Record<string, unknown>) => Promise<Record<string, unknown> | undefined>;
|
||||
replyResolver: (
|
||||
ctx: Record<string, unknown>,
|
||||
opts?: BufferedReplyOptions,
|
||||
) => Promise<Record<string, unknown> | undefined>;
|
||||
replyOptions?: BufferedReplyOptions;
|
||||
dispatcherOptions: {
|
||||
deliver: (
|
||||
payload: Record<string, unknown>,
|
||||
@@ -94,32 +99,151 @@ type BufferedDispatchReplyParams = {
|
||||
};
|
||||
};
|
||||
|
||||
type MockTypingController = {
|
||||
markDispatchIdle?: () => void;
|
||||
markRunComplete?: () => void;
|
||||
};
|
||||
|
||||
type BufferedReplyOptions = Record<string, unknown> & {
|
||||
onTypingController?: (typing: MockTypingController) => void;
|
||||
};
|
||||
|
||||
type TestEnvelopeOptions = {
|
||||
timezone?: string;
|
||||
includeTimestamp?: boolean;
|
||||
includeElapsed?: boolean;
|
||||
userTimezone?: string;
|
||||
};
|
||||
|
||||
type TestInboundEnvelopeParams = {
|
||||
channel?: string;
|
||||
from?: string;
|
||||
body: string;
|
||||
timestamp?: number | Date;
|
||||
chatType?: string;
|
||||
senderLabel?: string;
|
||||
sender?: { name?: string; e164?: string; id?: string };
|
||||
previousTimestamp?: number | Date;
|
||||
envelope?: TestEnvelopeOptions;
|
||||
fromMe?: boolean;
|
||||
};
|
||||
|
||||
function sanitizeEnvelopeHeaderPart(value: string) {
|
||||
return value
|
||||
.replace(/\r\n|\r|\n/g, " ")
|
||||
.replaceAll("[", "(")
|
||||
.replaceAll("]", ")")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function resolveEnvelopeOptionsMock(cfg?: {
|
||||
agents?: {
|
||||
defaults?: {
|
||||
envelopeTimezone?: string;
|
||||
envelopeTimestamp?: "on" | "off";
|
||||
envelopeElapsed?: "on" | "off";
|
||||
userTimezone?: string;
|
||||
};
|
||||
};
|
||||
}): TestEnvelopeOptions {
|
||||
const defaults = cfg?.agents?.defaults;
|
||||
return {
|
||||
timezone: defaults?.envelopeTimezone,
|
||||
includeTimestamp: defaults?.envelopeTimestamp !== "off",
|
||||
includeElapsed: defaults?.envelopeElapsed !== "off",
|
||||
userTimezone: defaults?.userTimezone,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveEnvelopeTimestampMock(
|
||||
timestamp: number | Date | undefined,
|
||||
envelope?: TestEnvelopeOptions,
|
||||
) {
|
||||
if (!timestamp || envelope?.includeTimestamp === false) {
|
||||
return undefined;
|
||||
}
|
||||
const date = timestamp instanceof Date ? timestamp : new Date(timestamp);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return undefined;
|
||||
}
|
||||
const zone = envelope?.timezone?.trim();
|
||||
if (zone === "user") {
|
||||
return formatEnvelopeTimestamp(date, envelope?.userTimezone?.trim() || "local");
|
||||
}
|
||||
return formatEnvelopeTimestamp(date, zone || "local");
|
||||
}
|
||||
|
||||
function resolveSenderLabelMock(sender?: TestInboundEnvelopeParams["sender"]) {
|
||||
const display = sender?.name?.trim();
|
||||
const idPart = sender?.e164?.trim() || sender?.id?.trim();
|
||||
if (display && idPart && display !== idPart) {
|
||||
return `${display} (${idPart})`;
|
||||
}
|
||||
return display || idPart || undefined;
|
||||
}
|
||||
|
||||
function formatInboundEnvelopeMock(params: TestInboundEnvelopeParams) {
|
||||
const chatType = normalizeLowercaseStringOrEmpty(params.chatType);
|
||||
const isDirect = !chatType || chatType === "direct";
|
||||
const sender = params.senderLabel?.trim() || resolveSenderLabelMock(params.sender);
|
||||
const body =
|
||||
isDirect && params.fromMe
|
||||
? `(self): ${params.body}`
|
||||
: !isDirect && sender
|
||||
? `${sanitizeEnvelopeHeaderPart(sender)}: ${params.body}`
|
||||
: params.body;
|
||||
const parts = [sanitizeEnvelopeHeaderPart(params.channel?.trim() || "Channel")];
|
||||
const from = params.from?.trim();
|
||||
if (from) {
|
||||
parts.push(sanitizeEnvelopeHeaderPart(from));
|
||||
}
|
||||
const timestamp = resolveEnvelopeTimestampMock(params.timestamp, params.envelope);
|
||||
if (timestamp) {
|
||||
parts.push(timestamp);
|
||||
}
|
||||
return `[${parts.join(" ")}] ${body}`;
|
||||
}
|
||||
|
||||
function createBufferedDispatchReplyMock() {
|
||||
return vi.fn(async (params: BufferedDispatchReplyParams) => {
|
||||
await params.dispatcherOptions.onReplyStart?.();
|
||||
const payload = await params.replyResolver(params.ctx);
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return {
|
||||
queuedFinal: false,
|
||||
counts: { tool: 0, block: 0, final: 0 },
|
||||
};
|
||||
}
|
||||
const text = typeof payload.text === "string" ? payload.text.trim() : "";
|
||||
const hasMedia =
|
||||
typeof payload.mediaUrl === "string" ||
|
||||
typeof payload.mediaPath === "string" ||
|
||||
typeof payload.fileUrl === "string";
|
||||
if (!text && !hasMedia) {
|
||||
return {
|
||||
queuedFinal: false,
|
||||
counts: { tool: 0, block: 0, final: 0 },
|
||||
};
|
||||
}
|
||||
await params.dispatcherOptions.deliver(payload, { kind: "final" });
|
||||
return {
|
||||
queuedFinal: true,
|
||||
counts: { tool: 0, block: 0, final: 1 },
|
||||
let typingController: MockTypingController | undefined;
|
||||
const replyOptions: BufferedReplyOptions = {
|
||||
...params.replyOptions,
|
||||
onTypingController: (typing) => {
|
||||
typingController = typing;
|
||||
params.replyOptions?.onTypingController?.(typing);
|
||||
},
|
||||
};
|
||||
await params.dispatcherOptions.onReplyStart?.();
|
||||
try {
|
||||
const payload = await params.replyResolver(params.ctx, replyOptions);
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return {
|
||||
queuedFinal: false,
|
||||
counts: { tool: 0, block: 0, final: 0 },
|
||||
};
|
||||
}
|
||||
const text = typeof payload.text === "string" ? payload.text.trim() : "";
|
||||
const hasMedia =
|
||||
typeof payload.mediaUrl === "string" ||
|
||||
typeof payload.mediaPath === "string" ||
|
||||
typeof payload.fileUrl === "string";
|
||||
if (!text && !hasMedia) {
|
||||
return {
|
||||
queuedFinal: false,
|
||||
counts: { tool: 0, block: 0, final: 0 },
|
||||
};
|
||||
}
|
||||
await params.dispatcherOptions.deliver(payload, { kind: "final" });
|
||||
return {
|
||||
queuedFinal: true,
|
||||
counts: { tool: 0, block: 0, final: 1 },
|
||||
};
|
||||
} finally {
|
||||
typingController?.markRunComplete?.();
|
||||
typingController?.markDispatchIdle?.();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -310,8 +434,7 @@ vi.mock("./auto-reply/monitor/runtime-api.js", () => ({
|
||||
}),
|
||||
dispatchReplyWithBufferedBlockDispatcher: createBufferedDispatchReplyMock(),
|
||||
finalizeInboundContext: <T>(ctx: T) => ctx,
|
||||
formatInboundEnvelope: (params: { body: string; senderLabel?: string }) =>
|
||||
`${params.senderLabel ? `${params.senderLabel}: ` : ""}${params.body}`,
|
||||
formatInboundEnvelope: formatInboundEnvelopeMock,
|
||||
getAgentScopedMediaLocalRoots: () => [] as string[],
|
||||
jidToE164: (jid: string) => {
|
||||
const digits = jid.replace(/\D+/g, "");
|
||||
@@ -330,11 +453,11 @@ vi.mock("./auto-reply/monitor/runtime-api.js", () => ({
|
||||
cfg.messages?.responsePrefix,
|
||||
resolveInboundLastRouteSessionKey: (params: { sessionKey: string }) => params.sessionKey,
|
||||
resolveInboundSessionEnvelopeContext: (params: {
|
||||
cfg: { session?: { store?: string } };
|
||||
cfg: { session?: { store?: string } } & Parameters<typeof resolveEnvelopeOptionsMock>[0];
|
||||
agentId: string;
|
||||
}) => ({
|
||||
storePath: resolveStorePathFallback(params.cfg.session?.store, { agentId: params.agentId }),
|
||||
envelopeOptions: {},
|
||||
envelopeOptions: resolveEnvelopeOptionsMock(params.cfg),
|
||||
previousTimestamp: undefined,
|
||||
}),
|
||||
resolveMarkdownTableMode: () => undefined,
|
||||
@@ -437,13 +560,7 @@ vi.mock("./auto-reply/monitor/group-activation.runtime.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("./auto-reply/monitor/message-line.runtime.js", () => ({
|
||||
formatInboundEnvelope: (params: {
|
||||
body: string;
|
||||
sender?: { name?: string; e164?: string; id?: string };
|
||||
}) => {
|
||||
const sender = params.sender?.name ?? params.sender?.e164 ?? params.sender?.id ?? undefined;
|
||||
return sender ? `${sender}: ${params.body}` : params.body;
|
||||
},
|
||||
formatInboundEnvelope: formatInboundEnvelopeMock,
|
||||
resolveMessagePrefix: (
|
||||
cfg: {
|
||||
channels?: { whatsapp?: { messagePrefix?: string; allowFrom?: string[] } };
|
||||
@@ -451,7 +568,13 @@ vi.mock("./auto-reply/monitor/message-line.runtime.js", () => ({
|
||||
},
|
||||
_agentId: string,
|
||||
params?: { configured?: string; hasAllowFrom?: boolean },
|
||||
) => params?.configured ?? cfg.messages?.messagePrefix,
|
||||
) => {
|
||||
const configured = params?.configured ?? cfg.messages?.messagePrefix;
|
||||
if (configured !== undefined) {
|
||||
return configured;
|
||||
}
|
||||
return params?.hasAllowFrom === true ? "" : "[openclaw]";
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("./auth-store.runtime.js", () => ({
|
||||
|
||||
Reference in New Issue
Block a user