Files
omniai-ds-code-package/src/api/dtoParsers.test.ts
T

185 lines
6.4 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
parseAiTaskStatus,
parseTaskCreateResponse,
parseImageTaskCreateResponse,
parseAiTaskStatusList,
parseSseTaskFrame,
} from "./dtoParsers";
describe("parseAiTaskStatus", () => {
it("parses a well-formed camelCase DTO", () => {
const result = parseAiTaskStatus({
taskId: "task-1",
type: "video",
status: "running",
progress: 42,
resultUrl: "https://example.com/r.mp4",
error: null,
createdAt: "2026-01-01T00:00:00Z",
updatedAt: "2026-01-01T00:01:00Z",
});
expect(result.taskId).toBe("task-1");
expect(result.type).toBe("video");
expect(result.status).toBe("running");
expect(result.progress).toBe(42);
expect(result.resultUrl).toBe("https://example.com/r.mp4");
});
it("tolerates snake_case field names", () => {
const result = parseAiTaskStatus({
task_id: "task-2",
result_url: "https://example.com/x.png",
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-01T00:00:00Z",
});
expect(result.taskId).toBe("task-2");
expect(result.resultUrl).toBe("https://example.com/x.png");
});
it("falls back to safe defaults for missing fields", () => {
const result = parseAiTaskStatus({});
expect(result.taskId).toBe("");
expect(result.type).toBe("image");
expect(result.status).toBe("failed");
expect(result.progress).toBe(0);
expect(result.resultUrl).toBeNull();
expect(result.error).toBeNull();
});
it("rejects unknown status/type values", () => {
const result = parseAiTaskStatus({ status: "weird", type: "audio" });
expect(result.status).toBe("failed");
expect(result.type).toBe("image");
});
it("clamps progress to [0, 100]", () => {
expect(parseAiTaskStatus({ progress: 150 }).progress).toBe(100);
expect(parseAiTaskStatus({ progress: -10 }).progress).toBe(0);
expect(parseAiTaskStatus({ progress: "not-a-number" }).progress).toBe(0);
});
it("preserves numeric conversationId and nulls others", () => {
expect(parseAiTaskStatus({ conversationId: 7 }).conversationId).toBe(7);
expect(parseAiTaskStatus({ conversation_id: 9 }).conversationId).toBe(9);
expect(parseAiTaskStatus({ conversationId: "nope" }).conversationId).toBeNull();
expect(parseAiTaskStatus({}).conversationId).toBeNull();
});
it("returns empty string for a non-record payload", () => {
const result = parseAiTaskStatus("garbage");
expect(result.taskId).toBe("");
expect(result.status).toBe("failed");
});
});
describe("parseTaskCreateResponse", () => {
it("extracts taskId from a create response", () => {
expect(parseTaskCreateResponse({ taskId: "abc" }).taskId).toBe("abc");
expect(parseTaskCreateResponse({ task_id: "def" }).taskId).toBe("def");
expect(parseTaskCreateResponse({ id: "ghi" }).taskId).toBe("ghi");
});
it("throws when taskId is missing", () => {
expect(() => parseTaskCreateResponse({})).toThrow();
expect(() => parseTaskCreateResponse({ taskId: "" })).toThrow();
expect(() => parseTaskCreateResponse({ taskId: " " })).toThrow();
});
});
describe("parseImageTaskCreateResponse", () => {
it("includes providerDebug when present", () => {
const result = parseImageTaskCreateResponse({
taskId: "img-1",
providerDebug: {
requestedModel: "gpt-image",
effectiveModel: "dall-e-3",
route: ["primary", "fallback"],
candidates: [{ provider: "openai", model: "dall-e-3" }],
},
});
expect(result.taskId).toBe("img-1");
expect(result.providerDebug?.effectiveModel).toBe("dall-e-3");
expect(result.providerDebug?.route).toEqual(["primary", "fallback"]);
expect(result.providerDebug?.candidates?.[0]?.model).toBe("dall-e-3");
});
it("omits providerDebug when absent", () => {
const result = parseImageTaskCreateResponse({ taskId: "img-2" });
expect(result.taskId).toBe("img-2");
expect(result.providerDebug).toBeUndefined();
});
it("tolerates snake_case providerDebug fields", () => {
const result = parseImageTaskCreateResponse({
taskId: "img-3",
provider_debug: { requested_model: "x", primary_provider: "openai" },
});
expect(result.providerDebug?.requestedModel).toBe("x");
expect(result.providerDebug?.primaryProvider).toBe("openai");
});
it("throws when taskId missing even if providerDebug present", () => {
expect(() => parseImageTaskCreateResponse({ providerDebug: {} })).toThrow();
});
});
describe("parseAiTaskStatusList", () => {
it("parses a bare array", () => {
const result = parseAiTaskStatusList([{ taskId: "a" }, { taskId: "b" }]);
expect(result).toHaveLength(2);
expect(result[0].taskId).toBe("a");
});
it("parses an envelope { tasks: [...] }", () => {
const result = parseAiTaskStatusList({ tasks: [{ taskId: "a" }, { task_id: "b" }] });
expect(result).toHaveLength(2);
expect(result[1].taskId).toBe("b");
});
it("parses an envelope { items: [...] }", () => {
const result = parseAiTaskStatusList({ items: [{ taskId: "a" }] });
expect(result).toHaveLength(1);
});
it("drops rows with no taskId rather than crashing", () => {
const result = parseAiTaskStatusList([{ taskId: "keep" }, { status: "running" }, {}]);
expect(result).toHaveLength(1);
expect(result[0].taskId).toBe("keep");
});
it("returns empty array for non-array non-record payload", () => {
expect(parseAiTaskStatusList(null)).toEqual([]);
expect(parseAiTaskStatusList("nope")).toEqual([]);
expect(parseAiTaskStatusList({})).toEqual([]);
});
});
describe("parseSseTaskFrame", () => {
it("parses a well-formed SSE frame", () => {
const frame = parseSseTaskFrame({
taskId: "sse-1",
status: "completed",
progress: 100,
resultUrl: "https://example.com/done.png",
});
expect(frame.taskId).toBe("sse-1");
expect(frame.status).toBe("completed");
expect(frame.progress).toBe(100);
expect(frame.resultUrl).toBe("https://example.com/done.png");
});
it("clamps progress and rejects unknown status", () => {
const frame = parseSseTaskFrame({ taskId: "sse-2", status: "oops", progress: 999 });
expect(frame.status).toBe("failed");
expect(frame.progress).toBe(100);
});
it("handles a non-object payload", () => {
const frame = parseSseTaskFrame("garbage");
expect(frame.taskId).toBe("");
expect(frame.status).toBe("failed");
expect(frame.progress).toBe(0);
});
});