Initial Commit
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user