Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/api/.server/EntitiesApi.test.ts
T

89 lines
3.6 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { EntitiesApi } from "./EntitiesApi";
import { findEntityByName, findEntityBySlug, getEntityByPrefix } from "../../db/entities/entities.db.server";
vi.mock("../../db/entities/entities.db.server", () => ({
findEntityByName: vi.fn(),
findEntityBySlug: vi.fn(),
getEntityByIdOrName: vi.fn(),
getEntityByPrefix: vi.fn(),
}));
vi.mock("../../services/.server/subscriptionService", () => ({
getPlanFeatureUsage: vi.fn(),
}));
describe("EntitiesApi.validateEntity", () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(findEntityByName).mockResolvedValue(null);
vi.mocked(findEntityBySlug).mockResolvedValue(null);
vi.mocked(getEntityByPrefix).mockResolvedValue(null);
});
it("rejects entity slugs that would collide with canonical tenant child routes", async () => {
await expect(
EntitiesApi.validateEntity({
tenantId: null,
name: "settings",
slug: " Settings ",
order: null,
prefix: "set",
})
).resolves.toContain("Reserved entity slug ' Settings ' conflicts with a workspace route");
});
});
describe("EntitiesApi.getNoCodeRoutes", () => {
it("does not classify tenant slugs that only start with admin as admin routes", () => {
const routes = EntitiesApi.getNoCodeRoutes({
request: new Request("http://app.localhost:3000/adminish/g/sales/contact"),
params: { tenant: "adminish", group: "sales" },
});
expect(routes.list).toBe("/adminish/g/sales/:entity");
expect(routes.overview).toBe("/adminish/g/sales/:entity/:id");
});
it("uses existing no-code entity routes for admin grouped entity contexts", () => {
const routes = EntitiesApi.getNoCodeRoutes({
request: new Request("http://admin.localhost:3000/g/sales/contact"),
params: { group: "sales" },
});
expect(routes.list).toBe("/entities/:entity/no-code/:entity");
expect(routes.new).toBe("/entities/:entity/no-code/:entity/new");
expect(routes.overview).toBe("/entities/:entity/no-code/:entity/:id");
expect(routes.edit).toBe("/entities/:entity/no-code/:entity/:id/edit");
expect(routes.import).toBe("/entities/:entity/no-code/:entity/import");
expect(routes.export).toBe("/entities/:entity/no-code/:entity/export");
expect(routes.group).toBe("/entities/groups");
});
it("uses host context instead of removed admin path prefixes", () => {
const request = new Request("https://unknown.example.test/admin/entities/company/no-code/company");
const routes = EntitiesApi.getNoCodeRoutes({ request, params: { tenant: "acme" } });
expect(routes.list).toBe("/acme/:entity");
expect(routes.list).not.toBe("/entities/:entity/no-code/:entity");
});
it("does not treat removed tenant-prefixed runtime paths as app context for grouped routes", () => {
const request = new Request("https://unknown.example.test/app/acme/g/sales/company");
const routes = EntitiesApi.getNoCodeRoutes({ request, params: { tenant: "acme", group: "sales" } });
expect(routes.group).toBeUndefined();
expect(routes.list).toBe("/acme/:entity");
});
it("matches tenant CRM routes by exact path segment", () => {
const crmRequest = new Request("https://app.example.test/acme/crm/company");
const crmishRequest = new Request("https://app.example.test/acme/crmish/company");
expect(EntitiesApi.getNoCodeRoutes({ request: crmRequest, params: { tenant: "acme" } }).list).toBe("/acme/crm/:entity");
expect(EntitiesApi.getNoCodeRoutes({ request: crmishRequest, params: { tenant: "acme" } }).list).toBe("/acme/:entity");
});
});