import { describe, expect, it } from "vitest"; import ActivityApiTemplate from "./routes/api/CodeTemplate.Routes.Activity.Api"; import EditApiTemplate from "./routes/api/CodeTemplate.Routes.Edit.Api"; import ShareApiTemplate from "./routes/api/CodeTemplate.Routes.Share.Api"; import TagsApiTemplate from "./routes/api/CodeTemplate.Routes.Tags.Api"; import ServiceTemplate from "./services/CodeTemplate.Service"; import type { EntityWithDetails } from "~/utils/db/entities/entities.db.server"; const entity = { name: "tickets", title: "Tickets", titlePlural: "Tickets", prefix: "TCK", hasTasks: true, properties: [], } as unknown as EntityWithDetails; describe("generated entity route tenant scope", () => { it("generates edit actions through scoped services and validates task row ownership", () => { const source = EditApiTemplate.generate({ entity }); expect(source).not.toContain('import { getRowById } from "~/utils/db/entities/rows.db.server"'); expect(source).toContain("const item = await TicketsService.get(params.id!, {"); expect(source).toContain("tenantId,"); expect(source).toContain("userId,"); expect(source).toContain("getRowTaskInRow({ id: taskId, rowId: item.row.id })"); expect(source).toContain("updateRowTaskInRow({ id: taskId, rowId: item.row.id }"); expect(source).toContain("deleteRowTaskInRow({ id: taskId, rowId: item.row.id })"); expect(source).toContain("if (!task)"); expect(source).not.toContain("getRowTask(taskId)"); expect(source).toContain("to: item.row.createdByUser"); expect(source).toContain("tenantId,"); expect(source.match(/if \(!rowPermissions\.canUpdate\)/g)).toHaveLength(3); expect(source).toContain('return Response.json({ error: t("shared.unauthorized") }, { status: 403 });'); expect(source).not.toContain('Response.json({ error: t("shared.notFound"), status: 404 })'); expect(source).not.toContain('Response.json({ error: t("shared.unauthorized"), status: 404 })'); }); it("generates update services through RowsApi tenant and permission checks", () => { const source = ServiceTemplate.generate({ entity }); expect(source).not.toContain("getRowById"); expect(source).toContain("const { item: row, rowPermissions } = await RowsApi.get(id, {"); expect(source).toContain("tenantId: session.tenantId"); expect(source).toContain("userId: session.userId"); expect(source).toContain("if (!row || !rowPermissions.canUpdate)"); }); it("generates activity comment mutations with row-scoped lookups", () => { const source = ActivityApiTemplate.generate({ entity }); expect(source).toContain("tenantId,"); expect(source).toContain("getRowCommentInRow({ id: rowCommentId, rowId: rowData.item.id })"); expect(source).toContain("updateRowCommentInRow({ id: rowCommentId, rowId: rowData.item.id }"); expect(source).toContain('t("models.row.activity.errors.commentForbidden")'); expect(source).toContain('t("models.row.activity.errors.updateCommentForbidden")'); expect(source).toContain('t("models.row.activity.errors.deleteCommentForbidden")'); expect(source).toContain('t("notifications.messages.row.commented"'); expect(source).not.toContain("getRowComment(rowCommentId)"); expect(source).not.toContain("You don't have access"); expect(source).not.toContain("commented on"); }); it("generates missing-record responses with HTTP status init", () => { const sources = [ EditApiTemplate.generate({ entity }), TagsApiTemplate.generate({ entity }), ShareApiTemplate.generate({ entity }), ActivityApiTemplate.generate({ entity }), ]; for (const source of sources) { expect(source).not.toContain('Response.json({ error: t("shared.notFound"), status: 404 })'); expect(source).not.toContain('Response.json({ error: t("shared.unauthorized"), status: 403 })'); } }); });