Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
142 lines
4.1 KiB
TypeScript
142 lines
4.1 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("@rakazo/db", () => ({
|
|
appendEventInTransaction: vi.fn(),
|
|
}));
|
|
|
|
import { botProfileLabelsChanged, commitBotUpdate } from "./bot-update.js";
|
|
|
|
describe("botProfileLabelsChanged", () => {
|
|
it("is true only when name, title, or description is present", () => {
|
|
expect(botProfileLabelsChanged({})).toBe(false);
|
|
expect(botProfileLabelsChanged({ name: "SEO" })).toBe(true);
|
|
expect(botProfileLabelsChanged({ title: "Strategist" })).toBe(true);
|
|
expect(botProfileLabelsChanged({ description: "Helps with SEO" })).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("commitBotUpdate", () => {
|
|
it("writes the bot row and bot.updated in one transaction when labels change", async () => {
|
|
const updated = {
|
|
id: "bot-1",
|
|
name: "SEO Strategist",
|
|
title: "SEO Strategist",
|
|
description: "Helps with keyword research",
|
|
};
|
|
const botUpdate = vi.fn().mockResolvedValue(updated);
|
|
const tx = { bot: { update: botUpdate } };
|
|
const transaction = vi.fn(async (run: (client: typeof tx) => Promise<unknown>) => run(tx));
|
|
const notify = vi.fn().mockResolvedValue(undefined);
|
|
const appendEvent = vi.fn().mockResolvedValue({ seq: 9 });
|
|
const prisma = {
|
|
$transaction: transaction,
|
|
bot: { update: vi.fn() },
|
|
};
|
|
|
|
await expect(
|
|
commitBotUpdate(
|
|
{
|
|
prisma: prisma as never,
|
|
notify,
|
|
spaceId: "space-1",
|
|
threadId: "thread-1",
|
|
botId: "bot-1",
|
|
data: { name: "SEO Strategist", title: "SEO Strategist" },
|
|
emitBotUpdated: true,
|
|
},
|
|
appendEvent,
|
|
),
|
|
).resolves.toEqual(updated);
|
|
|
|
expect(transaction).toHaveBeenCalledOnce();
|
|
expect(botUpdate).toHaveBeenCalledOnce();
|
|
expect(appendEvent).toHaveBeenCalledWith(tx, {
|
|
spaceId: "space-1",
|
|
threadId: "thread-1",
|
|
botId: "bot-1",
|
|
type: "bot.updated",
|
|
payload: {
|
|
botId: "bot-1",
|
|
name: "SEO Strategist",
|
|
title: "SEO Strategist",
|
|
description: "Helps with keyword research",
|
|
},
|
|
});
|
|
expect(notify).toHaveBeenCalledWith("thread-1", 9);
|
|
expect(prisma.bot.update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("fails the whole update when the durable event write fails", async () => {
|
|
const appendEvent = vi.fn().mockRejectedValue(new Error("event store unavailable"));
|
|
const transaction = vi.fn(async (run: (client: unknown) => Promise<unknown>) =>
|
|
run({
|
|
bot: {
|
|
update: vi.fn().mockResolvedValue({
|
|
id: "bot-1",
|
|
name: "SEO",
|
|
title: "SEO",
|
|
description: "",
|
|
}),
|
|
},
|
|
}),
|
|
);
|
|
const notify = vi.fn();
|
|
const prisma = {
|
|
$transaction: transaction,
|
|
bot: { update: vi.fn() },
|
|
};
|
|
|
|
await expect(
|
|
commitBotUpdate(
|
|
{
|
|
prisma: prisma as never,
|
|
notify,
|
|
spaceId: "space-1",
|
|
threadId: "thread-1",
|
|
botId: "bot-1",
|
|
data: { name: "SEO" },
|
|
emitBotUpdated: true,
|
|
},
|
|
appendEvent,
|
|
),
|
|
).rejects.toThrow("event store unavailable");
|
|
expect(notify).not.toHaveBeenCalled();
|
|
expect(prisma.bot.update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("updates without an event when profile labels are unchanged", async () => {
|
|
const update = vi.fn().mockResolvedValue({
|
|
id: "bot-1",
|
|
name: "Chief",
|
|
title: "Chief",
|
|
description: "",
|
|
});
|
|
const prisma = {
|
|
$transaction: vi.fn(),
|
|
bot: { update },
|
|
};
|
|
const notify = vi.fn();
|
|
const appendEvent = vi.fn();
|
|
|
|
await expect(
|
|
commitBotUpdate(
|
|
{
|
|
prisma: prisma as never,
|
|
notify,
|
|
spaceId: "space-1",
|
|
threadId: "thread-1",
|
|
botId: "bot-1",
|
|
data: { pinned: true },
|
|
emitBotUpdated: false,
|
|
},
|
|
appendEvent,
|
|
),
|
|
).resolves.toMatchObject({ id: "bot-1" });
|
|
|
|
expect(prisma.$transaction).not.toHaveBeenCalled();
|
|
expect(notify).not.toHaveBeenCalled();
|
|
expect(appendEvent).not.toHaveBeenCalled();
|
|
expect(update).toHaveBeenCalledOnce();
|
|
});
|
|
});
|