/** * Pins per-row error reporting + skipDuplicates against real SurrealDB. */ import "@suaveplan/api-plugin-auth"; import { OpenAPIHono } from "@hono/zod-openapi"; import { createPluginContext } from "@suaveplan/api-plugin"; import { EventBus } from "@suaveplan/events"; import { SurrealAdapter } from "@suaveplan/surrealdb"; import { afterAll, beforeAll, describe, expect, it, } from "@suaveplan/testing/runner"; import { SurrealDBFixture } from "@suaveplan/testing-integration-surrealdb"; import { applyContactsSchema, createContactsPlugin } from "../../src/index.js"; let fixture: SurrealDBFixture | null = null; let client: SurrealAdapter | null = null; const noopLogger = { debug: () => undefined, info: () => undefined, warn: () => undefined, error: () => undefined, }; beforeAll(async () => { fixture = new SurrealDBFixture(); const cfg = await fixture.start(); client = new SurrealAdapter({ url: cfg.url, namespace: cfg.namespace, database: cfg.database, username: cfg.username, password: cfg.password, }); await client.connect(); await applyContactsSchema({ db: client }); }, 180_000); afterAll(async () => { if (client !== null) { await client.disconnect(); client = null; } if (fixture !== null) { await fixture.stop(); fixture = null; } }, 60_000); describe("api-plugin-contacts bulk-import integration", () => { it("per-row errors are reported with the original index against real SurrealDB", { timeout: 60_000, }, async () => { if (client === null) throw new Error("client not ready"); const app = new OpenAPIHono(); const services = new Map(); services.set("app", app); services.set("db", client); const ctx = createPluginContext({ logger: noopLogger, eventBus: new EventBus(), signal: new AbortController().signal, config: {} as never, services, }); const desc = createContactsPlugin({ applySchemaOnInit: false, maxImportBatchSize: 5, }); await desc.onInit?.(ctx as never); // Mount a fake auth middleware that injects a tenantId. const wrapped = new OpenAPIHono(); wrapped.use("*", async (c, next) => { c.set("user", { id: "u", tenantId: "t-import" } as never); await next(); }); wrapped.route("/", app); const res = await wrapped.request("/contacts/import", { method: "POST", body: JSON.stringify({ contacts: [ { displayName: "ok", channels: [{ type: "email", value: "ok@example.com" }], }, { displayName: "ok2", channels: [{ type: "email", value: "ok2@example.com" }], }, ], }), headers: { "content-type": "application/json" }, }); expect(res.status).toBe(200); const body = (await res.json()) as { data: { imported: number; skipped: number; errors: unknown[] }; }; expect(body.data.imported).toBe(2); expect(body.data.errors).toEqual([]); }); });