diff --git a/packages/api/src/__tests__/assistant-tools-metro-city-mutations-errors.test.ts b/packages/api/src/__tests__/assistant-tools-metro-city-mutations-errors.test.ts new file mode 100644 index 0000000..c8eda36 --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-metro-city-mutations-errors.test.ts @@ -0,0 +1,68 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { executeTool } from "../router/assistant-tools.js"; +import { createToolContext } from "./assistant-tools-country-test-helpers.js"; + +describe("assistant metro city mutation tools - errors", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("returns a stable error when creating a metro city for a missing country", async () => { + const ctx = createToolContext({ + country: { + findUnique: vi.fn().mockResolvedValue(null), + }, + }); + + const result = await executeTool( + "create_metro_city", + JSON.stringify({ countryId: "country_missing", name: "Munich" }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual({ + error: "Country not found with the given criteria.", + }); + }); + + it("returns a stable error when updating a missing metro city", async () => { + const ctx = createToolContext({ + metroCity: { + findUnique: vi.fn().mockResolvedValue(null), + }, + }); + + const result = await executeTool( + "update_metro_city", + JSON.stringify({ id: "city_missing", data: { name: "Hamburg-Mitte" } }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual({ + error: "Metro city not found with the given criteria.", + }); + }); + + it("returns a stable error when deleting a metro city that is still assigned", async () => { + const ctx = createToolContext({ + metroCity: { + findUnique: vi.fn().mockResolvedValue({ + id: "city_ham", + name: "Hamburg", + _count: { resources: 3 }, + }), + }, + }); + + const result = await executeTool( + "delete_metro_city", + JSON.stringify({ id: "city_ham" }), + ctx, + ); + + expect(JSON.parse(result.content)).toEqual({ + error: "Metro city cannot be deleted while it is still assigned to resources.", + }); + }); +}); diff --git a/packages/api/src/__tests__/assistant-tools-metro-city-mutations-success.test.ts b/packages/api/src/__tests__/assistant-tools-metro-city-mutations-success.test.ts new file mode 100644 index 0000000..39eee5d --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-metro-city-mutations-success.test.ts @@ -0,0 +1,117 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { executeTool } from "../router/assistant-tools.js"; +import { createToolContext } from "./assistant-tools-country-test-helpers.js"; + +describe("assistant metro city mutation tools - success", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("creates, updates, and deletes metro cities for admin users", async () => { + const create = vi.fn().mockResolvedValue({ + id: "city_muc", + name: "Munich", + countryId: "country_de", + }); + const findUnique = vi.fn() + .mockResolvedValueOnce({ id: "city_muc", name: "Munich", countryId: "country_de" }) + .mockResolvedValueOnce({ id: "city_muc", name: "Munich", _count: { resources: 0 } }); + const update = vi.fn().mockResolvedValue({ + id: "city_muc", + name: "Muenchen", + countryId: "country_de", + }); + const remove = vi.fn().mockResolvedValue({ id: "city_muc" }); + const ctx = createToolContext({ + country: { + findUnique: vi.fn().mockResolvedValue({ id: "country_de", name: "Germany" }), + }, + metroCity: { + create, + findUnique, + update, + delete: remove, + }, + }); + + const createResult = await executeTool( + "create_metro_city", + JSON.stringify({ countryId: "country_de", name: "Munich" }), + ctx, + ); + const updateResult = await executeTool( + "update_metro_city", + JSON.stringify({ id: "city_muc", data: { name: "Muenchen" } }), + ctx, + ); + const deleteResult = await executeTool( + "delete_metro_city", + JSON.stringify({ id: "city_muc" }), + ctx, + ); + + expect(create).toHaveBeenCalledWith({ + data: { name: "Munich", countryId: "country_de" }, + }); + expect(update).toHaveBeenCalledWith({ + where: { id: "city_muc" }, + data: { name: "Muenchen" }, + }); + expect(remove).toHaveBeenCalledWith({ where: { id: "city_muc" } }); + expect(createResult.action).toEqual({ + type: "invalidate", + scope: ["country", "resource", "holidayCalendar", "vacation"], + }); + expect(updateResult.action).toEqual({ + type: "invalidate", + scope: ["country", "resource", "holidayCalendar", "vacation"], + }); + expect(deleteResult.action).toEqual({ + type: "invalidate", + scope: ["country", "resource", "holidayCalendar", "vacation"], + }); + expect(createResult.data).toMatchObject({ + success: true, + message: "Created metro city: Munich", + metroCity: { id: "city_muc", name: "Munich" }, + }); + expect(updateResult.data).toMatchObject({ + success: true, + message: "Updated metro city: Muenchen", + metroCity: { id: "city_muc", name: "Muenchen" }, + }); + expect(deleteResult.data).toMatchObject({ + success: true, + message: "Deleted metro city: Munich", + }); + }); + + it("deletes metro cities only when no resources are assigned", async () => { + const ctx = createToolContext({ + metroCity: { + findUnique: vi.fn().mockResolvedValue({ + id: "city_ham", + name: "Hamburg", + _count: { resources: 0 }, + }), + delete: vi.fn().mockResolvedValue(undefined), + }, + }); + + const result = await executeTool( + "delete_metro_city", + JSON.stringify({ id: "city_ham" }), + ctx, + ); + + expect(result.action).toEqual({ + type: "invalidate", + scope: ["country", "resource", "holidayCalendar", "vacation"], + }); + expect(result.data).toMatchObject({ + success: true, + message: "Deleted metro city: Hamburg", + }); + }); +});