Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/modules/rows/services/rowSearch.test.ts
T

84 lines
2.8 KiB
TypeScript

/**
* Unit tests for searchRows — covers the SQL fallback contract: tenant
* + entity scoping, value-text predicate, limit, and total accounting.
*/
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("~/utils/db.server", () => ({
db: {
row: {
findMany: vi.fn(),
},
},
}));
import { db } from "~/utils/db.server";
import { searchRows } from "./rowSearch.server";
const dbMock = db as unknown as {
row: {
findMany: ReturnType<typeof vi.fn>;
};
};
const originalMeili = process.env.MEILI_URL;
const originalBackend = process.env.SEARCH_BACKEND;
afterAll(() => {
if (originalMeili === undefined) delete process.env.MEILI_URL;
else process.env.MEILI_URL = originalMeili;
if (originalBackend === undefined) delete process.env.SEARCH_BACKEND;
else process.env.SEARCH_BACKEND = originalBackend;
});
describe("searchRows (sql fallback)", () => {
beforeEach(() => {
delete process.env.MEILI_URL;
delete process.env.SEARCH_BACKEND;
dbMock.row.findMany.mockReset();
});
it("scopes by tenantId + entityId and maps results", async () => {
dbMock.row.findMany.mockResolvedValueOnce([
{ id: "row-1", folio: 12, entity: { name: "deal" } },
{ id: "row-2", folio: 7, entity: { name: "deal" } },
]);
const result = await searchRows({ tenantId: "tenant-1", entityId: "entity-1", query: "acme" });
expect(dbMock.row.findMany).toHaveBeenCalledTimes(1);
const where = dbMock.row.findMany.mock.calls[0][0].where as Record<string, unknown>;
expect(where.tenantId).toBe("tenant-1");
expect(where.entityId).toBe("entity-1");
expect(where.deletedAt).toBeNull();
expect(where.values).toBeDefined();
expect(result.fellBack).toBe(true);
expect(result.hits).toEqual([
{ id: "row-1", folio: 12, entityName: "deal" },
{ id: "row-2", folio: 7, entityName: "deal" },
]);
expect(result.total).toBe(2);
});
it("omits value-text predicate when the query is empty", async () => {
dbMock.row.findMany.mockResolvedValueOnce([]);
await searchRows({ tenantId: "tenant-1", entityId: "entity-1", query: "" });
const where = dbMock.row.findMany.mock.calls[0][0].where as Record<string, unknown>;
expect(where.values).toBeUndefined();
});
it("honours the limit option", async () => {
dbMock.row.findMany.mockResolvedValueOnce([]);
await searchRows({ tenantId: "tenant-1", entityId: "entity-1", query: "x", limit: 25 });
expect(dbMock.row.findMany.mock.calls[0][0].take).toBe(25);
});
it("defaults folio to 0 when missing on the row", async () => {
dbMock.row.findMany.mockResolvedValueOnce([{ id: "row-x", folio: null, entity: null }]);
const result = await searchRows({ tenantId: "tenant-1", entityId: "entity-1", query: "x" });
expect(result.hits[0]).toEqual({ id: "row-x", folio: 0, entityName: "" });
});
});