79 lines
3.8 KiB
TypeScript
79 lines
3.8 KiB
TypeScript
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 })');
|
|
}
|
|
});
|
|
});
|