test: unit test for display services (#1832)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Dhruwang Jariwala
2024-01-15 21:51:33 +05:30
committed by GitHub
parent f6f45d74d5
commit 82302360fa
5 changed files with 367 additions and 7 deletions

View File

@@ -34,6 +34,7 @@ const selectDisplay = {
surveyId: true,
responseId: true,
personId: true,
status: true,
};
export const getDisplay = async (displayId: string): Promise<TDisplay | null> => {
@@ -42,7 +43,7 @@ export const getDisplay = async (displayId: string): Promise<TDisplay | null> =>
validateInputs([displayId, ZId]);
try {
const display = await prisma.response.findUnique({
const display = await prisma.display.findUnique({
where: {
id: displayId,
},
@@ -143,7 +144,6 @@ export const updateDisplayLegacy = async (
data,
select: selectDisplay,
});
displayCache.revalidate({
id: display.id,
surveyId: display.surveyId,
@@ -164,7 +164,6 @@ export const createDisplay = async (displayInput: TDisplayCreateInput): Promise<
validateInputs([displayInput, ZDisplayCreateInput]);
const { environmentId, userId, surveyId } = displayInput;
try {
let person;
if (userId) {
@@ -191,13 +190,11 @@ export const createDisplay = async (displayInput: TDisplayCreateInput): Promise<
},
select: selectDisplay,
});
displayCache.revalidate({
id: display.id,
personId: display.personId,
surveyId: display.surveyId,
});
return display;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
@@ -337,7 +334,6 @@ export const deleteDisplayByResponseId = async (
personId: display.personId,
surveyId,
});
return display;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {

View File

@@ -0,0 +1,76 @@
import {
TDisplay,
TDisplayCreateInput,
TDisplayLegacyCreateInput,
TDisplayLegacyUpdateInput,
TDisplayUpdateInput,
} from "@formbricks/types/displays";
export const mockEnvironmentId = "clqkr5961000108jyfnjmbjhi";
export const mockSingleUseId = "qj57j3opsw8b5sxgea20fgcq";
export const mockSurveyId = "clqkr8dlv000308jybb08evgr";
export const mockUserId = "qwywazmugeezyfr3zcg9jk8a";
export const mockDisplayId = "clqkr5smu000208jy50v6g5k4";
export const mockId = "ars2tjk8hsi8oqk1uac00mo8";
export const mockPersonId = "clqnj99r9000008lebgf8734j";
export const mockResponseId = "clqnfg59i000208i426pb4wcv";
function createMockDisplay(overrides = {}) {
return {
id: mockDisplayId,
createdAt: new Date(),
updatedAt: new Date(),
surveyId: mockSurveyId,
responseId: null,
personId: null,
status: null,
...overrides,
};
}
export const mockDisplay: TDisplay = createMockDisplay();
export const mockDisplayWithPersonId: TDisplay = createMockDisplay({ personId: mockPersonId });
export const mockDisplayWithResponseId: TDisplay = createMockDisplay({
personId: mockPersonId,
responseId: mockResponseId,
});
export const mockDisplayInput: TDisplayCreateInput = {
environmentId: mockEnvironmentId,
surveyId: mockSurveyId,
};
export const mockDisplayInputWithUserId: TDisplayCreateInput = {
...mockDisplayInput,
userId: mockUserId,
};
export const mockDisplayInputWithResponseId: TDisplayCreateInput = {
...mockDisplayInputWithUserId,
responseId: mockResponseId,
};
export const mockDisplayLegacyInput: TDisplayLegacyCreateInput = {
responseId: mockResponseId,
surveyId: mockSurveyId,
};
export const mockDisplayLegacyInputWithPersonId: TDisplayLegacyCreateInput = {
...mockDisplayLegacyInput,
personId: mockPersonId,
};
export const mockDisplayUpdate: TDisplayUpdateInput = {
environmentId: mockEnvironmentId,
userId: mockUserId,
responseId: mockResponseId,
};
export const mockDisplayLegacyUpdateInput: TDisplayLegacyUpdateInput = {
personId: mockPersonId,
responseId: mockResponseId,
};
export const mockDisplayLegacyWithRespondedStatus: TDisplay = {
...mockDisplayWithPersonId,
status: "responded",
};

View File

@@ -0,0 +1,287 @@
import { mockPerson } from "../../response/tests/__mocks__/data.mock";
import {
mockDisplay,
mockDisplayInput,
mockDisplayInputWithUserId,
mockDisplayLegacyInput,
mockDisplayLegacyInputWithPersonId,
mockDisplayLegacyUpdateInput,
mockDisplayLegacyWithRespondedStatus,
mockDisplayUpdate,
mockDisplayWithPersonId,
mockDisplayWithResponseId,
mockResponseId,
mockSurveyId,
} from "./__mocks__/data.mock";
import { Prisma } from "@prisma/client";
import { prismaMock } from "@formbricks/database/src/jestClient";
import { DatabaseError, ValidationError } from "@formbricks/types/errors";
import {
createDisplay,
createDisplayLegacy,
deleteDisplayByResponseId,
getDisplay,
getDisplayCountBySurveyId,
getDisplaysByPersonId,
markDisplayRespondedLegacy,
updateDisplay,
updateDisplayLegacy,
} from "../service";
const testInputValidation = async (service: Function, ...args: any[]): Promise<void> => {
it("it should throw a ValidationError if the inputs are invalid", async () => {
await expect(service(...args)).rejects.toThrow(ValidationError);
});
};
beforeEach(() => {
prismaMock.person.findFirst.mockResolvedValue(mockPerson);
});
describe("Tests for getDisplay", () => {
describe("Happy Path", () => {
it("Returns display associated with a given display ID", async () => {
prismaMock.display.findUnique.mockResolvedValue(mockDisplay);
const display = await getDisplay(mockDisplay.id);
expect(display).toEqual(mockDisplay);
});
it("Returns all displays associated with a given person ID", async () => {
prismaMock.display.findMany.mockResolvedValue([mockDisplayWithPersonId]);
const displays = await getDisplaysByPersonId(mockPerson.id);
expect(displays).toEqual([mockDisplayWithPersonId]);
});
it("Returns an empty array when no displays are found for the given person ID", async () => {
prismaMock.display.findMany.mockResolvedValue([]);
const displays = await getDisplaysByPersonId(mockPerson.id);
expect(displays).toEqual([]);
});
it("Returns display count for the given survey ID", async () => {
prismaMock.display.count.mockResolvedValue(1);
const displaCount = await getDisplayCountBySurveyId(mockSurveyId);
expect(displaCount).toEqual(1);
});
});
describe("Sad Path", () => {
testInputValidation(getDisplaysByPersonId, "123", 1);
it("Throws a DatabaseError error if there is a PrismaClientKnownRequestError", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.findMany.mockRejectedValue(errToThrow);
await expect(getDisplaysByPersonId(mockPerson.id)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for unexpected exceptions", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.findMany.mockRejectedValue(new Error(mockErrorMessage));
await expect(getDisplaysByPersonId(mockPerson.id)).rejects.toThrow(Error);
});
});
});
describe("Tests for createDisplay service", () => {
describe("Happy Path", () => {
it("Creates a new display when a userId exists", async () => {
prismaMock.display.create.mockResolvedValue(mockDisplayWithPersonId);
const display = await createDisplay(mockDisplayInputWithUserId);
expect(display).toEqual(mockDisplayWithPersonId);
});
it("Creates a new display when a userId does not exists", async () => {
prismaMock.display.create.mockResolvedValue(mockDisplay);
const display = await createDisplay(mockDisplayInput);
expect(display).toEqual(mockDisplay);
});
});
describe("Sad Path", () => {
testInputValidation(createDisplay, "123");
it("Throws DatabaseError on PrismaClientKnownRequestError occurrence", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.create.mockRejectedValue(errToThrow);
await expect(createDisplay(mockDisplayInputWithUserId)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for other exceptions", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.create.mockRejectedValue(new Error(mockErrorMessage));
await expect(createDisplay(mockDisplayInput)).rejects.toThrow(Error);
});
});
});
describe("Tests for updateDisplay Service", () => {
describe("Happy Path", () => {
it("Updates a display (responded)", async () => {
prismaMock.display.update.mockResolvedValue(mockDisplayWithResponseId);
const display = await updateDisplay(mockDisplay.id, mockDisplayUpdate);
expect(display).toEqual(mockDisplayWithResponseId);
});
});
describe("Sad Path", () => {
testInputValidation(updateDisplay, "123", "123");
it("Throws DatabaseError on PrismaClientKnownRequestError", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.update.mockRejectedValue(errToThrow);
await expect(updateDisplay(mockDisplay.id, mockDisplayUpdate)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for other unexpected issues", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.update.mockRejectedValue(new Error(mockErrorMessage));
await expect(updateDisplay(mockDisplay.id, mockDisplayUpdate)).rejects.toThrow(Error);
});
});
});
describe("Tests for createDisplayLegacy service", () => {
describe("Happy Path", () => {
it("Creates a display when a person ID exist", async () => {
prismaMock.display.create.mockResolvedValue(mockDisplayWithPersonId);
const display = await createDisplayLegacy(mockDisplayLegacyInputWithPersonId);
expect(display).toEqual(mockDisplayWithPersonId);
});
it("Creates a display when a person ID does not exist", async () => {
prismaMock.display.create.mockResolvedValue(mockDisplay);
const display = await createDisplayLegacy(mockDisplayLegacyInput);
expect(display).toEqual(mockDisplay);
});
});
describe("Sad Path", () => {
testInputValidation(createDisplayLegacy, "123");
it("Throws DatabaseError on PrismaClientKnownRequestError occurrence", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.create.mockRejectedValue(errToThrow);
await expect(createDisplayLegacy(mockDisplayLegacyInputWithPersonId)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for other exceptions", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.create.mockRejectedValue(new Error(mockErrorMessage));
await expect(createDisplayLegacy(mockDisplayLegacyInputWithPersonId)).rejects.toThrow(Error);
});
});
});
describe("Tests for updateDisplayLegacy Service", () => {
describe("Happy Path", () => {
it("Updates a display", async () => {
prismaMock.display.update.mockResolvedValue(mockDisplayWithPersonId);
const display = await updateDisplayLegacy(mockDisplay.id, mockDisplayLegacyUpdateInput);
expect(display).toEqual(mockDisplayWithPersonId);
});
it("marks display as responded legacy", async () => {
prismaMock.display.update.mockResolvedValue(mockDisplayLegacyWithRespondedStatus);
const display = await markDisplayRespondedLegacy(mockDisplay.id);
expect(display).toEqual(mockDisplayLegacyWithRespondedStatus);
});
});
describe("Sad Path", () => {
testInputValidation(updateDisplayLegacy, "123", "123");
it("Throws DatabaseError on PrismaClientKnownRequestError", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.update.mockRejectedValue(errToThrow);
await expect(updateDisplayLegacy(mockDisplay.id, mockDisplayLegacyUpdateInput)).rejects.toThrow(
DatabaseError
);
});
it("Throws a generic Error for other unexpected issues", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.update.mockRejectedValue(new Error(mockErrorMessage));
await expect(updateDisplayLegacy(mockDisplay.id, mockDisplayLegacyUpdateInput)).rejects.toThrow(Error);
});
});
});
describe("Tests for deleteDisplayByResponseId service", () => {
describe("Happy Path", () => {
it("Deletes a display when a response associated to it is deleted", async () => {
prismaMock.display.delete.mockResolvedValue(mockDisplayWithResponseId);
const display = await deleteDisplayByResponseId(mockResponseId, mockSurveyId);
expect(display).toEqual(mockDisplayWithResponseId);
});
});
describe("Sad Path", () => {
testInputValidation(createDisplayLegacy, "123");
it("Throws DatabaseError on PrismaClientKnownRequestError occurrence", async () => {
const mockErrorMessage = "Mock error message";
const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
code: "P2002",
clientVersion: "0.0.1",
});
prismaMock.display.delete.mockRejectedValue(errToThrow);
await expect(deleteDisplayByResponseId(mockResponseId, mockSurveyId)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for other exceptions", async () => {
const mockErrorMessage = "Mock error message";
prismaMock.display.delete.mockRejectedValue(new Error(mockErrorMessage));
await expect(deleteDisplayByResponseId(mockResponseId, mockSurveyId)).rejects.toThrow(Error);
});
});
});

View File

@@ -89,6 +89,7 @@ export const mockDisplay: TDisplay = {
surveyId: mockSurveyId,
personId: mockPersonId,
responseId: mockResponseId,
status: null,
};
export const mockResponse: ResponseMock = {

View File

@@ -7,7 +7,7 @@ export const ZDisplay = z.object({
personId: z.string().cuid().nullable(),
surveyId: z.string().cuid(),
responseId: z.string().cuid().nullable(),
status: z.enum(["seen", "responded"]).optional(),
status: z.enum(["seen", "responded"]).nullable(),
});
export type TDisplay = z.infer<typeof ZDisplay>;