Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/loaders.middleware.test.ts
T

139 lines
5.0 KiB
TypeScript

// @vitest-environment node
import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@toolctrl/config", async () => {
const actual = await vi.importActual<typeof import("@toolctrl/config")>("@toolctrl/config");
return {
...actual,
loadRequiredWebConfig: () => ({ nodeEnv: "production" }),
};
});
vi.mock("./db/tenants.db.server", () => ({
getTenantUserType: vi.fn(),
}));
vi.mock("./services/.server/urlService", async () => {
const actual = await vi.importActual<typeof import("./services/.server/urlService")>("./services/.server/urlService");
return {
...actual,
getTenantIdFromUrl: vi.fn(),
};
});
vi.mock("./session.server", () => ({
getUserInfo: vi.fn(),
}));
vi.mock("./db.server", () => ({
db: {
adminUser: {
findUnique: vi.fn(),
},
},
}));
vi.mock("./db/permissions/userRoles.db.server", () => ({
getUserRoleInTenant: vi.fn(),
}));
vi.mock("./cache.server", () => ({
cachified: vi.fn(),
clearCacheKey: vi.fn(),
}));
import { getTenantUserType } from "./db/tenants.db.server";
import { db } from "./db.server";
import { getUserRoleInTenant } from "./db/permissions/userRoles.db.server";
import { getTenantIdFromUrl } from "./services/.server/urlService";
import { getUserInfo } from "./session.server";
import { requireAuth } from "./loaders.middleware";
const env = {
APP_BASE_DOMAIN: "localhost:3000",
WEB_APP_HOST: "app.localhost:3000",
ADMIN_APP_HOST: "admin.localhost:3000",
API_HOST: "api.localhost:3000",
APP_PROTOCOL: "http",
};
const userSession = { userId: "user-1", lightOrDarkMode: "light", lng: "en", cookies: [] };
function makeRequest(host: string, pathname: string) {
return new Request(`http://localhost:3000${pathname}`, {
headers: {
host,
},
});
}
async function expectUnauthorized(promise: Promise<unknown>) {
try {
await promise;
throw new Error("Expected unauthorized response");
} catch (error) {
expect(error).toBeInstanceOf(Response);
expect((error as Response).status).toBe(401);
}
}
describe("requireAuth tenant-source routing", () => {
beforeEach(() => {
vi.stubEnv("APP_BASE_DOMAIN", env.APP_BASE_DOMAIN);
vi.stubEnv("WEB_APP_HOST", env.WEB_APP_HOST);
vi.stubEnv("ADMIN_APP_HOST", env.ADMIN_APP_HOST);
vi.stubEnv("API_HOST", env.API_HOST);
vi.stubEnv("APP_PROTOCOL", env.APP_PROTOCOL);
vi.clearAllMocks();
vi.mocked(getUserInfo).mockResolvedValue(userSession);
vi.mocked(getTenantIdFromUrl).mockResolvedValue("tenant-1");
vi.mocked(getTenantUserType).mockResolvedValue({ status: 2, type: 1 });
vi.mocked(db.adminUser.findUnique).mockResolvedValue(null);
vi.mocked(getUserRoleInTenant).mockResolvedValue(null);
});
it("requires tenant membership for app-host tenant route params", async () => {
await expect(requireAuth({ request: makeRequest(env.WEB_APP_HOST, "/acme/dashboard"), params: { tenant: "acme" } })).resolves.toEqual(
userSession,
);
expect(getTenantIdFromUrl).toHaveBeenCalledWith({ tenant: "acme" });
expect(getTenantUserType).toHaveBeenCalledWith("user-1", "tenant-1");
});
it("rejects non-member app-host tenant requests", async () => {
vi.mocked(getTenantUserType).mockResolvedValueOnce(null);
await expectUnauthorized(requireAuth({ request: makeRequest(env.WEB_APP_HOST, "/acme/dashboard"), params: { tenant: "acme" } }));
expect(getTenantUserType).toHaveBeenCalledWith("user-1", "tenant-1");
expect(db.adminUser.findUnique).toHaveBeenCalledWith({ where: { userId: "user-1" } });
});
it("allows operator admins to inspect app-host tenant requests without membership", async () => {
vi.mocked(getTenantUserType).mockResolvedValueOnce(null);
vi.mocked(db.adminUser.findUnique).mockResolvedValueOnce({ userId: "user-1" });
await expect(requireAuth({ request: makeRequest(env.WEB_APP_HOST, "/acme/dashboard"), params: { tenant: "acme" } })).resolves.toEqual(userSession);
expect(getTenantUserType).toHaveBeenCalledWith("user-1", "tenant-1");
expect(db.adminUser.findUnique).toHaveBeenCalledWith({ where: { userId: "user-1" } });
});
it("keeps admin-host paths on the super-admin branch", async () => {
vi.mocked(db.adminUser.findUnique).mockResolvedValueOnce({ userId: "user-1" });
await expect(requireAuth({ request: makeRequest(env.ADMIN_APP_HOST, "/settings"), params: {} })).resolves.toEqual({
...userSession,
isSuperAdmin: { userId: "user-1" },
});
expect(db.adminUser.findUnique).toHaveBeenCalledWith({ where: { userId: "user-1" } });
expect(getTenantUserType).not.toHaveBeenCalled();
});
it("does not classify admin-prefixed non-admin paths as admin host routes", async () => {
await expect(requireAuth({ request: makeRequest(env.WEB_APP_HOST, "/adminish/dashboard"), params: { tenant: "adminish" } })).resolves.toEqual(
userSession,
);
expect(getTenantIdFromUrl).toHaveBeenCalledWith({ tenant: "adminish" });
expect(getTenantUserType).toHaveBeenCalledWith("user-1", "tenant-1");
expect(db.adminUser.findUnique).not.toHaveBeenCalled();
});
});