110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
/**
|
|
* 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<string, unknown>();
|
|
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([]);
|
|
});
|
|
});
|