carbon-tokenization / backend /tests /agent-chat.test.ts
tfrere's picture
tfrere HF Staff
feat(agent): switch AI backend from OpenRouter to HF Inference Providers
6b6afea
Raw
History Blame Contribute Delete
3.82 kB
/**
* Agent Chat Tests
*
* Tests for /api/chat and /api/embed-chat routes:
* - Input validation (missing messages)
* - Missing HF token handling
* - Model list endpoint
*/
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import request from "supertest";
import { mkdtempSync, rmSync } from "fs";
import { mkdirSync } from "fs";
import { tmpdir } from "os";
import { join } from "path";
import { setDataDir } from "../src/utils.js";
import { createApp, resetSaveTimers } from "../src/create-app.js";
let tmpDir: string;
let app: ReturnType<typeof createApp>["app"];
let httpServer: ReturnType<typeof createApp>["httpServer"];
let hocuspocus: ReturnType<typeof createApp>["hocuspocus"];
beforeEach(() => {
tmpDir = mkdtempSync(join(tmpdir(), "collab-agent-test-"));
mkdirSync(tmpDir, { recursive: true });
setDataDir(tmpDir);
const result = createApp();
app = result.app;
httpServer = result.httpServer;
hocuspocus = result.hocuspocus;
});
afterEach(async () => {
resetSaveTimers();
try { await hocuspocus.destroy(); } catch {}
try { httpServer.close(); } catch {}
setDataDir(undefined);
try { rmSync(tmpDir, { recursive: true, force: true }); } catch {}
vi.restoreAllMocks();
});
describe("/api/models", () => {
it("returns a non-empty array of models", async () => {
const res = await request(app).get("/api/models").expect(200);
expect(Array.isArray(res.body)).toBe(true);
expect(res.body.length).toBeGreaterThan(0);
expect(res.body[0]).toHaveProperty("id");
expect(res.body[0]).toHaveProperty("label");
expect(res.body[0]).toHaveProperty("context");
expect(res.body[0]).toHaveProperty("cost");
});
});
describe("/api/chat - validation", () => {
it("rejects request without messages", async () => {
const res = await request(app)
.post("/api/chat")
.send({ context: {} })
.expect(400);
expect(res.body).toHaveProperty("error");
expect(res.body.error).toContain("messages");
});
it("rejects request with non-array messages", async () => {
const res = await request(app)
.post("/api/chat")
.send({ messages: "not-an-array" })
.expect(400);
expect(res.body).toHaveProperty("error");
});
it("returns 500 when no HF token is available", async () => {
const original = process.env.HF_TOKEN;
delete process.env.HF_TOKEN;
const res = await request(app)
.post("/api/chat")
.send({
messages: [{ id: "1", role: "user", parts: [{ type: "text", text: "hello" }] }],
})
.expect(500);
expect(res.body).toHaveProperty("error");
expect(res.body.error).toContain("Hugging Face token");
if (original) process.env.HF_TOKEN = original;
});
});
describe("/api/embed-chat - validation", () => {
it("rejects request without messages", async () => {
const res = await request(app)
.post("/api/embed-chat")
.send({ context: {} })
.expect(400);
expect(res.body).toHaveProperty("error");
expect(res.body.error).toContain("messages");
});
it("rejects request with non-array messages", async () => {
const res = await request(app)
.post("/api/embed-chat")
.send({ messages: 42 })
.expect(400);
expect(res.body).toHaveProperty("error");
});
it("returns 500 when no HF token is available", async () => {
const original = process.env.HF_TOKEN;
delete process.env.HF_TOKEN;
const res = await request(app)
.post("/api/embed-chat")
.send({
messages: [{ id: "1", role: "user", parts: [{ type: "text", text: "make a chart" }] }],
})
.expect(500);
expect(res.body).toHaveProperty("error");
expect(res.body.error).toContain("Hugging Face token");
if (original) process.env.HF_TOKEN = original;
});
});