Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/integrations/fileVisibility.boundary.test.ts
T

62 lines
3.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { resolveRepoPath } from "~/utils/testing/repoPaths";
const fileService = readFileSync(resolveRepoPath("apps/web/app/utils/integrations/fileService.server.ts"), "utf8");
const searchService = readFileSync(resolveRepoPath("apps/web/app/services/search/globalSearch.server.ts"), "utf8");
const mediaRoute = readFileSync(resolveRepoPath("apps/web/app/routes/app.$tenant/media.$fileId.$variant.tsx"), "utf8");
const browserRoute = readFileSync(resolveRepoPath("apps/web/app/routes/app.$tenant/files._index.tsx"), "utf8");
function section(source: string, start: string, end: string): string {
return source.split(start)[1]?.split(end)[0] ?? "";
}
describe("central file visibility boundary", () => {
it("routes detail visibility through the authoritative scope without owner/read_all fast paths", () => {
const detailGuard = section(fileService, "async function getVisibleFileOrThrowWithTx", "/** Load a single file");
expect(detailGuard).toContain("fileReadScopeWhereWithTx(tx, tenantId, ctx, [fileId], queryState)");
expect(detailGuard.match(/tx\.file\.findFirst/g)).toHaveLength(1);
});
it("shares one project-principal query state across detail and linked-target visibility", () => {
const linkedDetail = section(fileService, "export async function getVisibleFileWithLinks", "export type ListFilesFilter");
expect(linkedDetail).toContain("const queryState = createFileVisibilityQueryState()");
expect(linkedDetail).toContain("getVisibleFileOrThrowWithTx(tx, tenantId, fileId, ctx, queryState)");
expect(linkedDetail).toContain("filterVisibleFileLinksWithTx(tx, tenantId, links, ctx, queryState)");
});
it("routes the browser rows and filter metadata through the same scope", () => {
const browser = section(fileService, "export async function loadFileBrowserData", "// --- Bulk ZIP");
expect(browser.match(/fileReadScopeWhereWithTx\(tx, input\.tenantId, input\.ctx\)/g)).toHaveLength(1);
expect(browser).toContain("listFilesForBrowserWithTx(tx, input, visibility)");
expect(browser).toContain("loadFileFilterRowsWithTx(tx, input.tenantId, visibility)");
expect(browserRoute).toContain("await loadFileBrowserData({");
expect(browserRoute).not.toContain("listFileFilterOptions");
});
it("routes bulk ZIP candidate selection through the same scope", () => {
const bulkZip = section(fileService, "export async function collectFilesForZip", "/** Ensure a zip entry name is unique");
expect(bulkZip).toContain("fileReadScopeWhereWithTx(tx, input.tenantId, input.ctx, ids)");
});
it("routes SQL search and Meilisearch revalidation through the same scope", () => {
const sqlFiles = section(searchService, "async function searchFiles", "type TaskVisibilityCondition");
const revalidation = section(searchService, 'case "file": {', 'case "task": {');
expect(sqlFiles).toContain("fileReadScopeWhereWithTx(database, ctx.tenantId, ctx)");
expect(revalidation).toContain("fileReadScopeWhereWithTx(input.database, input.ctx.tenantId, input.ctx, ids)");
});
it("requires the visibility-checked file loader before media signing", () => {
const visibility = mediaRoute.indexOf("await getVisibleFileOrThrow(ctx.tenantId, fileId, ctx)");
const signing = mediaRoute.indexOf("await createMediaDownloadUrl");
expect(visibility).toBeGreaterThan(-1);
expect(signing).toBeGreaterThan(visibility);
});
});