Add offline monthly insights with Ollama
This commit is contained in:
91
src/lib/insights.test.ts
Normal file
91
src/lib/insights.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/lib/db", () => {
|
||||
const monthlyInsight = {
|
||||
upsert: vi.fn(async ({ where, update, create }: { where: { month: string }; update: Record<string, unknown>; create: Record<string, unknown> }) => ({
|
||||
id: "insight-1",
|
||||
month: where.month,
|
||||
year: (update.year ?? create.year) as number,
|
||||
summary: (update.summary ?? create.summary) as string,
|
||||
recommendations: (update.recommendations ?? create.recommendations) as string,
|
||||
inputSnapshot: (update.inputSnapshot ?? create.inputSnapshot) as string,
|
||||
generatedAt: new Date("2026-03-23T12:00:00.000Z"),
|
||||
})),
|
||||
findUnique: vi.fn(),
|
||||
};
|
||||
|
||||
return {
|
||||
db: {
|
||||
expense: { findMany: vi.fn() },
|
||||
paycheck: { findMany: vi.fn() },
|
||||
monthlyInsight,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe("generateMonthlyInsight", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("stores a fallback for sparse months", async () => {
|
||||
const { db } = await import("@/lib/db");
|
||||
const { generateMonthlyInsight } = await import("@/lib/insights");
|
||||
|
||||
vi.mocked(db.expense.findMany).mockResolvedValue([]);
|
||||
vi.mocked(db.paycheck.findMany).mockResolvedValue([]);
|
||||
|
||||
const result = await generateMonthlyInsight("2026-03");
|
||||
|
||||
expect(result.source).toBe("fallback");
|
||||
expect(result.insight.summary).toContain("not enough activity");
|
||||
});
|
||||
|
||||
it("stores model output when Ollama responds", async () => {
|
||||
const { db } = await import("@/lib/db");
|
||||
const { generateMonthlyInsight } = await import("@/lib/insights");
|
||||
|
||||
vi.mocked(db.expense.findMany).mockResolvedValue([
|
||||
{
|
||||
id: "expense-1",
|
||||
title: "Groceries",
|
||||
date: "2026-03-23",
|
||||
amountCents: 3200,
|
||||
category: "FOOD",
|
||||
createdAt: new Date("2026-03-23T10:00:00.000Z"),
|
||||
},
|
||||
{
|
||||
id: "expense-2",
|
||||
title: "Rent",
|
||||
date: "2026-03-02",
|
||||
amountCents: 120000,
|
||||
category: "RENT",
|
||||
createdAt: new Date("2026-03-02T10:00:00.000Z"),
|
||||
},
|
||||
]);
|
||||
vi.mocked(db.paycheck.findMany).mockResolvedValue([
|
||||
{
|
||||
id: "paycheck-1",
|
||||
payDate: "2026-03-01",
|
||||
amountCents: 180000,
|
||||
createdAt: new Date("2026-03-01T10:00:00.000Z"),
|
||||
},
|
||||
]);
|
||||
|
||||
vi.spyOn(globalThis, "fetch").mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
response: JSON.stringify({
|
||||
summary: "Spending is stable.",
|
||||
recommendations: "Keep food spending under watch.",
|
||||
}),
|
||||
}),
|
||||
} as Response);
|
||||
|
||||
const result = await generateMonthlyInsight("2026-03");
|
||||
|
||||
expect(result.source).toBe("model");
|
||||
expect(result.insight.summary).toBe("Spending is stable.");
|
||||
expect(result.insight.recommendations).toBe("Keep food spending under watch.");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user