147 lines
4.5 KiB
TypeScript
147 lines
4.5 KiB
TypeScript
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import { SandboxVmBridgeError } from "../error-codes/error-codes.js";
|
|
import {
|
|
SerializedResponseSchema,
|
|
unmarshalResponse,
|
|
} from "./marshal-response.js";
|
|
|
|
function encode(bytes: ArrayLike<number>): string {
|
|
return Buffer.from(Uint8Array.from(bytes)).toString("base64url");
|
|
}
|
|
|
|
describe("unmarshalResponse", () => {
|
|
it("base64url body produces a Response with matching bytes", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const r = unmarshalResponse({
|
|
status: 200,
|
|
headers: [["content-type", "text/plain"]],
|
|
bodyBase64: encode(
|
|
new TextEncoder().encode(
|
|
"hello"
|
|
) as unknown as ArrayLike<number>
|
|
),
|
|
});
|
|
expect(r.status).toBe(200);
|
|
expect(r.headers.get("content-type")).toBe("text/plain");
|
|
expect(await r.text()).toBe("hello");
|
|
});
|
|
|
|
it("binary body crosses unchanged through base64url", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const bytes = [1, 2, 3, 200, 250, 255];
|
|
const r = unmarshalResponse({
|
|
status: 201,
|
|
headers: [],
|
|
bodyBase64: encode(bytes),
|
|
});
|
|
expect(r.status).toBe(201);
|
|
const buf = new Uint8Array(await r.arrayBuffer());
|
|
expect(Array.from(buf)).toEqual(bytes);
|
|
});
|
|
|
|
it("empty bodyBase64 produces an empty body response", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const r = unmarshalResponse({
|
|
status: 200,
|
|
headers: [],
|
|
bodyBase64: "",
|
|
});
|
|
expect(r.status).toBe(200);
|
|
const buf = new Uint8Array(await r.arrayBuffer());
|
|
expect(buf.byteLength).toBe(0);
|
|
});
|
|
|
|
it("status 204 drops the body even when bodyBase64 is non-empty", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const r = unmarshalResponse({
|
|
status: 204,
|
|
headers: [],
|
|
bodyBase64: encode([1, 2, 3]),
|
|
});
|
|
expect(r.status).toBe(204);
|
|
});
|
|
|
|
it("non-object value raises UNMARSHAL_FAILED", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
expect(() => unmarshalResponse(null)).toThrow(SandboxVmBridgeError);
|
|
});
|
|
|
|
it("missing status raises UNMARSHAL_FAILED", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
try {
|
|
unmarshalResponse({ headers: [], bodyBase64: "" });
|
|
throw new Error("did not throw");
|
|
} catch (err) {
|
|
expect(err).toBeInstanceOf(SandboxVmBridgeError);
|
|
expect((err as SandboxVmBridgeError).code).toBe(
|
|
"SAND_VM_BRIDGE.UNMARSHAL_FAILED"
|
|
);
|
|
}
|
|
});
|
|
|
|
it("status out of range raises UNMARSHAL_FAILED", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
expect(() =>
|
|
unmarshalResponse({ status: 99, headers: [], bodyBase64: "" })
|
|
).toThrow(SandboxVmBridgeError);
|
|
});
|
|
|
|
it("non-string bodyBase64 raises UNMARSHAL_FAILED", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
expect(() =>
|
|
unmarshalResponse({ status: 200, headers: [], bodyBase64: 42 })
|
|
).toThrow(SandboxVmBridgeError);
|
|
});
|
|
|
|
it("header pairs reach the Response with duplicates preserved", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const r = unmarshalResponse({
|
|
status: 200,
|
|
headers: [
|
|
["set-cookie", "a=1"],
|
|
["set-cookie", "b=2"],
|
|
["content-type", "text/plain"],
|
|
],
|
|
bodyBase64: encode([0x68, 0x69]),
|
|
});
|
|
expect(r.headers.get("content-type")).toBe("text/plain");
|
|
// `Response.headers.get('set-cookie')` returns the
|
|
// comma-joined value on platforms that combine; both values
|
|
// should be present in the joined output.
|
|
const cookie = r.headers.get("set-cookie") ?? "";
|
|
expect(cookie).toContain("a=1");
|
|
expect(cookie).toContain("b=2");
|
|
});
|
|
|
|
it("errorCode + errorMessage parse cleanly", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const result = SerializedResponseSchema.safeParse({
|
|
status: 500,
|
|
headers: [],
|
|
bodyBase64: "",
|
|
errorCode: "DEMO.FAILED",
|
|
errorMessage: "boom",
|
|
});
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it("schema accepts a valid shape", { timeout: 5000 }, () => {
|
|
const r = SerializedResponseSchema.safeParse({
|
|
status: 200,
|
|
headers: [],
|
|
bodyBase64: "",
|
|
});
|
|
expect(r.success).toBe(true);
|
|
});
|
|
});
|