/** * Unit tests for CosmosDB client. * * Validates the exact proto JSON structure passed to executeQuery for each * CosmosDB operation: query, read, create, replace, upsert, deleteItem. */ import { describe, it, expect, vi } from "vitest"; import { z } from "zod"; import type { IntegrationConfig } from "../types.js"; import { CosmosDBClientImpl } from "./client.js"; /** Minimal integration config for testing. */ const TEST_CONFIG: IntegrationConfig = { id: "cosmosdb-test-id", name: "Test CosmosDB", pluginId: "cosmosdb", configuration: {}, }; function createClient(mockResult: unknown = []) { const executeQuery = vi.fn().mockResolvedValue(mockResult); const client = new CosmosDBClientImpl(TEST_CONFIG, executeQuery); return { client, executeQuery }; } describe("CosmosDBClientImpl", () => { describe("query", () => { it("passes the correct proto JSON structure to executeQuery", async () => { const { client, executeQuery } = createClient([{ id: "doc-1" }]); await client.query( "my-container", "SELECT * FROM c", z.array(z.object({ id: z.string() }).passthrough()), { crossPartition: true, partitionKey: "pk-1" }, ); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { sql: { singleton: { containerId: "my-container", query: "SELECT * FROM c", crossPartition: true, partitionKey: "pk-1", }, }, }, undefined, undefined, ); }); it("defaults crossPartition to false when not specified", async () => { const { client, executeQuery } = createClient([]); await client.query( "container-1", "SELECT TOP 1 * FROM c", z.array(z.unknown()), ); const request = executeQuery.mock.calls[0][0]; expect(request.sql.singleton.crossPartition).toBe(false); expect(request.sql.singleton.partitionKey).toBeUndefined(); }); }); describe("read", () => { it("passes the correct proto JSON structure to executeQuery", async () => { const { client, executeQuery } = createClient({ id: "doc-1", name: "test", }); await client.read( "my-container", "doc-1", z.object({ id: z.string(), name: z.string() }), "pk-value", ); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { pointOperation: { containerId: "my-container", read: { id: "doc-1", partitionKey: "pk-value" }, }, }, undefined, undefined, ); }); }); describe("create", () => { it("passes the correct proto JSON structure with object body", async () => { const body = { id: "new-doc", value: 42 }; const { client, executeQuery } = createClient(body); await client.create("my-container", body, "pk-value"); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { pointOperation: { containerId: "my-container", create: { body: JSON.stringify(body), partitionKey: "pk-value", }, }, }, undefined, undefined, ); }); it("passes string body as-is", async () => { const bodyStr = '{"id":"doc-str"}'; const { client, executeQuery } = createClient({}); await client.create("my-container", bodyStr); const request = executeQuery.mock.calls[0][0]; expect(request.pointOperation.create.body).toBe(bodyStr); }); }); describe("replace", () => { it("passes the correct proto JSON structure to executeQuery", async () => { const body = { id: "doc-1", value: "updated" }; const { client, executeQuery } = createClient(body); await client.replace("my-container", body, "pk-value"); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { pointOperation: { containerId: "my-container", replace: { body: JSON.stringify(body), partitionKey: "pk-value", }, }, }, undefined, undefined, ); }); }); describe("upsert", () => { it("passes the correct proto JSON structure to executeQuery", async () => { const body = { id: "doc-1", value: "upserted" }; const { client, executeQuery } = createClient(body); await client.upsert("my-container", body, "pk-value"); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { pointOperation: { containerId: "my-container", upsert: { body: JSON.stringify(body), partitionKey: "pk-value", }, }, }, undefined, undefined, ); }); }); describe("deleteItem", () => { it("passes the correct proto JSON structure to executeQuery", async () => { const { client, executeQuery } = createClient({}); await client.deleteItem("my-container", "doc-to-delete", "pk-value"); expect(executeQuery).toHaveBeenCalledOnce(); expect(executeQuery).toHaveBeenCalledWith( { pointOperation: { containerId: "my-container", delete: { id: "doc-to-delete", partitionKey: "pk-value" }, }, }, undefined, undefined, ); }); it("passes undefined partitionKey when not specified", async () => { const { client, executeQuery } = createClient({}); await client.deleteItem("my-container", "doc-1"); const request = executeQuery.mock.calls[0][0]; expect(request.pointOperation.delete.partitionKey).toBeUndefined(); }); }); });