mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-21 03:09:54 -06:00
187 lines
6.6 KiB
TypeScript
187 lines
6.6 KiB
TypeScript
import { Prisma } from "@prisma/client";
|
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
import { prisma } from "@formbricks/database";
|
|
import { logger } from "@formbricks/logger";
|
|
import { StorageErrorCode } from "@formbricks/storage";
|
|
import { TEnvironment } from "@formbricks/types/environment";
|
|
import { DatabaseError, InvalidInputError, ValidationError } from "@formbricks/types/errors";
|
|
import { ZProject } from "@formbricks/types/project";
|
|
import { createEnvironment } from "@/lib/environment/service";
|
|
import { deleteFilesByEnvironmentId } from "@/modules/storage/service";
|
|
import { createProject, deleteProject, updateProject } from "./project";
|
|
|
|
const baseProject = {
|
|
id: "p1",
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
name: "Project 1",
|
|
organizationId: "org1",
|
|
languages: [],
|
|
recontactDays: 0,
|
|
linkSurveyBranding: false,
|
|
inAppSurveyBranding: false,
|
|
config: { channel: null, industry: null },
|
|
placement: "bottomRight",
|
|
clickOutsideClose: false,
|
|
darkOverlay: false,
|
|
environments: [
|
|
{
|
|
id: "cmi2sra0j000004l73fvh7lhe",
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
type: "production" as TEnvironment["type"],
|
|
projectId: "p1",
|
|
appSetupCompleted: false,
|
|
},
|
|
{
|
|
id: "cmi2srt9q000104l7127e67v7",
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
type: "development" as TEnvironment["type"],
|
|
projectId: "p1",
|
|
appSetupCompleted: false,
|
|
},
|
|
],
|
|
styling: { allowStyleOverwrite: true },
|
|
logo: null,
|
|
};
|
|
|
|
vi.mock("@formbricks/database", () => ({
|
|
prisma: {
|
|
project: {
|
|
update: vi.fn(),
|
|
create: vi.fn(),
|
|
delete: vi.fn(),
|
|
},
|
|
projectTeam: {
|
|
createMany: vi.fn(),
|
|
},
|
|
},
|
|
}));
|
|
|
|
vi.mock("@formbricks/logger", () => ({
|
|
logger: {
|
|
error: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
vi.mock("@/modules/storage/service", () => ({
|
|
deleteFilesByEnvironmentId: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib/environment/service", () => ({
|
|
createEnvironment: vi.fn(),
|
|
}));
|
|
|
|
describe("project lib", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("updateProject", () => {
|
|
test("updates project and revalidates cache", async () => {
|
|
vi.mocked(prisma.project.update).mockResolvedValueOnce(baseProject as any);
|
|
const result = await updateProject("p1", { name: "Project 1", environments: baseProject.environments });
|
|
expect(result).toEqual(ZProject.parse(baseProject));
|
|
expect(prisma.project.update).toHaveBeenCalled();
|
|
});
|
|
|
|
test("throws DatabaseError on Prisma error", async () => {
|
|
vi.mocked(prisma.project.update).mockRejectedValueOnce(
|
|
new (class extends Error {
|
|
constructor() {
|
|
super();
|
|
this.message = "fail";
|
|
}
|
|
})()
|
|
);
|
|
await expect(updateProject("p1", { name: "Project 1" })).rejects.toThrow();
|
|
});
|
|
|
|
test("throws ValidationError on Zod error", async () => {
|
|
vi.mocked(prisma.project.update).mockResolvedValueOnce({ ...baseProject, id: 123 } as any);
|
|
await expect(
|
|
updateProject("p1", { name: "Project 1", environments: baseProject.environments })
|
|
).rejects.toThrow(ValidationError);
|
|
});
|
|
});
|
|
|
|
describe("createProject", () => {
|
|
test("creates project, environments, and revalidates cache", async () => {
|
|
vi.mocked(prisma.project.create).mockResolvedValueOnce({ ...baseProject, id: "p2" } as any);
|
|
vi.mocked(prisma.projectTeam.createMany).mockResolvedValueOnce({} as any);
|
|
vi.mocked(createEnvironment).mockResolvedValueOnce(baseProject.environments[0] as any);
|
|
vi.mocked(createEnvironment).mockResolvedValueOnce(baseProject.environments[1] as any);
|
|
vi.mocked(prisma.project.update).mockResolvedValueOnce(baseProject as any);
|
|
const result = await createProject("org1", { name: "Project 1", teamIds: ["t1"] });
|
|
expect(result).toEqual(baseProject);
|
|
expect(prisma.project.create).toHaveBeenCalled();
|
|
expect(prisma.projectTeam.createMany).toHaveBeenCalled();
|
|
expect(createEnvironment).toHaveBeenCalled();
|
|
});
|
|
|
|
test("throws ValidationError if name is missing", async () => {
|
|
await expect(createProject("org1", {})).rejects.toThrow(ValidationError);
|
|
});
|
|
|
|
test("throws InvalidInputError on unique constraint", async () => {
|
|
const prismaError = new Prisma.PrismaClientKnownRequestError("Test Prisma Error", {
|
|
code: "P2002",
|
|
clientVersion: "5.0.0",
|
|
});
|
|
vi.mocked(prisma.project.create).mockRejectedValueOnce(prismaError);
|
|
await expect(createProject("org1", { name: "Project 1" })).rejects.toThrow(InvalidInputError);
|
|
});
|
|
|
|
test("throws DatabaseError on Prisma error", async () => {
|
|
const prismaError = new Prisma.PrismaClientKnownRequestError("Test Prisma Error", {
|
|
code: "P2001",
|
|
clientVersion: "5.0.0",
|
|
});
|
|
vi.mocked(prisma.project.create).mockRejectedValueOnce(prismaError);
|
|
await expect(createProject("org1", { name: "Project 1" })).rejects.toThrow(DatabaseError);
|
|
});
|
|
|
|
test("throws unknown error", async () => {
|
|
vi.mocked(prisma.project.create).mockRejectedValueOnce(new Error("fail"));
|
|
await expect(createProject("org1", { name: "Project 1" })).rejects.toThrow("fail");
|
|
});
|
|
});
|
|
|
|
describe("deleteProject", () => {
|
|
test("deletes project, deletes files, and revalidates cache", async () => {
|
|
vi.mocked(prisma.project.delete).mockResolvedValueOnce(baseProject as any);
|
|
|
|
vi.mocked(deleteFilesByEnvironmentId).mockResolvedValue({ ok: true, data: undefined });
|
|
const result = await deleteProject("p1");
|
|
expect(result).toEqual(baseProject);
|
|
expect(deleteFilesByEnvironmentId).toHaveBeenCalledWith("cmi2sra0j000004l73fvh7lhe");
|
|
});
|
|
|
|
test("logs error if file deletion fails", async () => {
|
|
vi.mocked(prisma.project.delete).mockResolvedValueOnce(baseProject as any);
|
|
vi.mocked(deleteFilesByEnvironmentId).mockResolvedValue({
|
|
ok: false,
|
|
error: { code: StorageErrorCode.Unknown },
|
|
} as any);
|
|
vi.mocked(logger.error).mockImplementation(() => {});
|
|
await deleteProject("p1");
|
|
expect(logger.error).toHaveBeenCalled();
|
|
});
|
|
|
|
test("throws DatabaseError on Prisma error", async () => {
|
|
const err = new Prisma.PrismaClientKnownRequestError("Test Prisma Error", {
|
|
code: "P2001",
|
|
clientVersion: "5.0.0",
|
|
});
|
|
vi.mocked(prisma.project.delete).mockRejectedValueOnce(err as any);
|
|
await expect(deleteProject("p1")).rejects.toThrow(DatabaseError);
|
|
});
|
|
|
|
test("throws unknown error", async () => {
|
|
vi.mocked(prisma.project.delete).mockRejectedValueOnce(new Error("fail"));
|
|
await expect(deleteProject("p1")).rejects.toThrow("fail");
|
|
});
|
|
});
|
|
});
|