Files
WRNexusJS/packages/ai/test/ai.test.ts
T
2026-07-12 15:55:18 +05:30

57 lines
2.0 KiB
TypeScript

import { afterEach, expect, test } from "bun:test";
import { AIError, createAI } from "../src/index.ts";
const originalFetch = globalThis.fetch;
afterEach(() => {
globalThis.fetch = originalFetch;
});
test("requires an API key before making a request", async () => {
const previous = process.env.ANTHROPIC_API_KEY;
delete process.env.ANTHROPIC_API_KEY;
await expect(createAI().generate("hello")).rejects.toBeInstanceOf(AIError);
if (previous !== undefined) process.env.ANTHROPIC_API_KEY = previous;
});
test("builds a bounded messages request and joins text blocks", async () => {
let request: RequestInit | undefined;
globalThis.fetch = (async (_url, init) => {
request = init;
return Response.json({ content: [{ type: "text", text: "Hello" }, { type: "tool_use" }] });
}) as typeof fetch;
const text = await createAI({ apiKey: "secret", model: "test-model", maxTokens: 123 }).generate(
"Hi",
);
expect(text).toBe("Hello");
expect(JSON.parse(String(request?.body))).toMatchObject({
model: "test-model",
max_tokens: 123,
messages: [{ role: "user", content: "Hi" }],
stream: false,
});
});
test("streams fragmented SSE and keeps a final event without a newline", async () => {
const encoder = new TextEncoder();
globalThis.fetch = (async () =>
new Response(
new ReadableStream({
start(controller) {
controller.enqueue(
encoder.encode('data: {"type":"content_block_delta","delta":{"type":"text_'),
);
controller.enqueue(encoder.encode('delta","text":"A"}}\n'));
controller.enqueue(
encoder.encode(
'data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"B"}}',
),
);
controller.close();
},
}),
)) as unknown as typeof fetch;
const chunks: string[] = [];
for await (const chunk of createAI({ apiKey: "secret" }).stream("Hi")) chunks.push(chunk);
expect(chunks).toEqual(["A", "B"]);
});