Files
openclaw/test/scripts/mock-openai-http.test.ts
Leon-SK668 1f5c8239d7 fix(scripts): preserve emoji in request log previews (#109481)
* fix(scripts): preserve emoji in request log previews

* fix(scripts): keep mock preview standalone

* refactor(scripts): reuse UTF-16 truncation helper

Co-authored-by: Leon-SK668 <0668001470@xydigit.com>

* test(scripts): cover raw Node mock loading

Co-authored-by: Leon-SK668 <0668001470@xydigit.com>

* docs(scripts): note raw Node type stripping contract

Co-authored-by: Leon-SK668 <0668001470@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 18:49:36 -07:00

92 lines
2.8 KiB
TypeScript

// Mock Openai Http tests cover mock openai http script behavior.
import { spawnSync } from "node:child_process";
import { PassThrough } from "node:stream";
import { describe, expect, it } from "vitest";
import {
boundedRequestLogBody,
isRequestBodyTooLargeError,
readBody,
readMockOpenAiHttpLimits,
} from "../../scripts/e2e/lib/mock-openai-http.mjs";
function bodyStream(text: string) {
const stream = new PassThrough();
stream.end(text);
return stream;
}
describe("mock OpenAI HTTP helpers", () => {
it("loads under raw Node without a TypeScript loader", () => {
const result = spawnSync(
process.execPath,
["--input-type=module", "--eval", "await import('./scripts/e2e/lib/mock-openai-http.mjs')"],
{ cwd: process.cwd(), encoding: "utf8" },
);
expect(result.status, result.stderr).toBe(0);
expect(result.signal).toBeNull();
});
it("reads request bodies within the configured ceiling", async () => {
await expect(readBody(bodyStream("small"), { requestMaxBytes: 8 })).resolves.toBe("small");
});
it("rejects request bodies that exceed the configured ceiling", async () => {
const error = await readBody(bodyStream("too large"), { requestMaxBytes: 4 }).catch(
(cause: unknown) => cause,
);
expect(isRequestBodyTooLargeError(error)).toBe(true);
expect(error).toMatchObject({
code: "ETOOBIG",
message: "mock OpenAI request body exceeded 4 bytes",
});
});
it("truncates oversized request-log bodies", () => {
expect(
boundedRequestLogBody({ full: "x".repeat(16) }, JSON.stringify({ full: "x".repeat(16) }), {
requestLogBodyMaxBytes: 8,
}),
).toEqual({
truncated: true,
byteLength: 27,
preview: '{"full":"xxxxxxxxxxxxxxxx"}',
});
});
it("does not split emoji in request-log previews", () => {
const bodyText = `${"a".repeat(4095)}😀tail`;
expect(
boundedRequestLogBody({ full: bodyText }, bodyText, {
requestLogBodyMaxBytes: 8,
}),
).toEqual({
truncated: true,
byteLength: Buffer.byteLength(bodyText, "utf8"),
preview: "a".repeat(4095),
});
});
it("keeps small request-log bodies intact", () => {
const body = { ok: true };
expect(boundedRequestLogBody(body, JSON.stringify(body), { requestLogBodyMaxBytes: 64 })).toBe(
body,
);
});
it("rejects loose numeric env limits instead of parsing prefixes", () => {
expect(() =>
readMockOpenAiHttpLimits({
OPENCLAW_MOCK_OPENAI_REQUEST_MAX_BYTES: "1000ms",
}),
).toThrow("invalid OPENCLAW_MOCK_OPENAI_REQUEST_MAX_BYTES: 1000ms");
expect(() =>
readMockOpenAiHttpLimits({
OPENCLAW_MOCK_OPENAI_REQUEST_LOG_BODY_MAX_BYTES: "1e3",
}),
).toThrow("invalid OPENCLAW_MOCK_OPENAI_REQUEST_LOG_BODY_MAX_BYTES: 1e3");
});
});