Skip to content

Commit eaa5736

Browse files
committed
feat(api): implement dropOutCandidacies function and related tests
1 parent bc0d506 commit eaa5736

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { prismaClient } from "@/prisma/client";
2+
import { createCandidacyDropOutHelper } from "@/test/helpers/entities/create-candidacy-drop-out-helper";
3+
import { createCandidacyHelper } from "@/test/helpers/entities/create-candidacy-helper";
4+
import { createDropOutReasonHelper } from "@/test/helpers/entities/create-drop-out-reason-helper";
5+
6+
import { dropOutCandidacies } from "./dropOutCandidacies";
7+
8+
describe("drop out candidacies", () => {
9+
test("should throw an error for non-existent candidacies", async () => {
10+
const dropoutReason = await createDropOutReasonHelper();
11+
12+
await expect(async () => {
13+
await dropOutCandidacies({
14+
candidacyIds: ["wr0ng1d", "anoth3r_wr0ng1d"],
15+
dropOutReasonId: dropoutReason.id,
16+
});
17+
}).rejects.toThrow();
18+
});
19+
20+
test("should skip candidacies that are already dropped out and return only processed ones", async () => {
21+
const dropoutReason = await createDropOutReasonHelper();
22+
const candidacy1 = await createCandidacyHelper();
23+
const candidacyDropOut = await createCandidacyDropOutHelper();
24+
25+
// Should process only the valid candidacy and return its ID
26+
const result = await dropOutCandidacies({
27+
candidacyIds: [candidacy1.id, candidacyDropOut.candidacy.id],
28+
dropOutReasonId: dropoutReason.id,
29+
});
30+
31+
expect(result).toEqual([candidacy1.id]);
32+
33+
// Check that candidacy1 was dropped out
34+
const candidacy1DropOut = await prismaClient.candidacyDropOut.findUnique({
35+
where: {
36+
candidacyId: candidacy1.id,
37+
},
38+
});
39+
40+
expect(candidacy1DropOut).not.toBeNull();
41+
expect(candidacy1DropOut?.dropOutReasonId).toEqual(dropoutReason.id);
42+
});
43+
44+
test("should attempt to create drop out with any reason ID (no validation)", async () => {
45+
const candidacy = await createCandidacyHelper();
46+
47+
// The function no longer validates the drop out reason, so it will try to create
48+
// This will likely fail at the database level due to foreign key constraints
49+
await expect(async () => {
50+
await dropOutCandidacies({
51+
candidacyIds: [candidacy.id],
52+
dropOutReasonId: "wr0ng1d",
53+
});
54+
}).rejects.toThrow(); // Will throw due to database constraint, not validation
55+
});
56+
57+
test("should successfully drop out single candidacy and return its ID", async () => {
58+
const dropoutReason = await createDropOutReasonHelper();
59+
const candidacy = await createCandidacyHelper();
60+
61+
const result = await dropOutCandidacies({
62+
candidacyIds: [candidacy.id],
63+
dropOutReasonId: dropoutReason.id,
64+
});
65+
66+
expect(result).toEqual([candidacy.id]);
67+
68+
const candidacyDropOut = await prismaClient.candidacyDropOut.findUnique({
69+
where: {
70+
candidacyId: candidacy.id,
71+
},
72+
include: {
73+
dropOutReason: true,
74+
},
75+
});
76+
77+
expect(candidacyDropOut).not.toBeNull();
78+
expect(candidacyDropOut?.dropOutReason.id).toEqual(dropoutReason.id);
79+
expect(candidacyDropOut?.status).toEqual(candidacy.status);
80+
expect(candidacyDropOut?.otherReasonContent).toBeNull();
81+
});
82+
83+
test("should successfully drop out multiple candidacies and return all IDs", async () => {
84+
const dropoutReason = await createDropOutReasonHelper();
85+
const candidacy1 = await createCandidacyHelper();
86+
const candidacy2 = await createCandidacyHelper();
87+
const candidacy3 = await createCandidacyHelper();
88+
89+
const result = await dropOutCandidacies({
90+
candidacyIds: [candidacy1.id, candidacy2.id, candidacy3.id],
91+
dropOutReasonId: dropoutReason.id,
92+
});
93+
94+
expect(result).toEqual(
95+
expect.arrayContaining([candidacy1.id, candidacy2.id, candidacy3.id]),
96+
);
97+
expect(result).toHaveLength(3);
98+
99+
// Check that all candidacies were dropped out
100+
const candidacyDropOuts = await prismaClient.candidacyDropOut.findMany({
101+
where: {
102+
candidacyId: { in: [candidacy1.id, candidacy2.id, candidacy3.id] },
103+
},
104+
include: {
105+
dropOutReason: true,
106+
},
107+
});
108+
109+
expect(candidacyDropOuts).toHaveLength(3);
110+
candidacyDropOuts.forEach((dropOut) => {
111+
expect(dropOut.dropOutReason.id).toEqual(dropoutReason.id);
112+
expect(dropOut.otherReasonContent).toBeNull();
113+
});
114+
});
115+
116+
test("should successfully drop out candidacy with other reason content and return ID", async () => {
117+
const dropoutReason = await createDropOutReasonHelper();
118+
const candidacy = await createCandidacyHelper();
119+
const otherReasonContent = "Custom reason for dropping out";
120+
121+
const result = await dropOutCandidacies({
122+
candidacyIds: [candidacy.id],
123+
dropOutReasonId: dropoutReason.id,
124+
otherReasonContent,
125+
});
126+
127+
expect(result).toEqual([candidacy.id]);
128+
129+
const candidacyDropOut = await prismaClient.candidacyDropOut.findUnique({
130+
where: {
131+
candidacyId: candidacy.id,
132+
},
133+
include: {
134+
dropOutReason: true,
135+
},
136+
});
137+
138+
expect(candidacyDropOut).not.toBeNull();
139+
expect(candidacyDropOut?.dropOutReason.id).toEqual(dropoutReason.id);
140+
expect(candidacyDropOut?.otherReasonContent).toEqual(otherReasonContent);
141+
});
142+
143+
test("should return empty array when empty candidacy IDs array is provided", async () => {
144+
const dropoutReason = await createDropOutReasonHelper();
145+
146+
const result = await dropOutCandidacies({
147+
candidacyIds: [],
148+
dropOutReasonId: dropoutReason.id,
149+
});
150+
151+
expect(result).toEqual([]);
152+
});
153+
154+
test("should return empty array when no dropOutReasonId is provided", async () => {
155+
const candidacy = await createCandidacyHelper();
156+
157+
const result = await dropOutCandidacies({
158+
candidacyIds: [candidacy.id],
159+
dropOutReasonId: "",
160+
});
161+
162+
expect(result).toEqual([]);
163+
});
164+
165+
test("should preserve candidacy status when dropping out and return ID", async () => {
166+
const dropoutReason = await createDropOutReasonHelper();
167+
const candidacy = await createCandidacyHelper({
168+
candidacyActiveStatus: "DOSSIER_FAISABILITE_ENVOYE",
169+
});
170+
171+
const result = await dropOutCandidacies({
172+
candidacyIds: [candidacy.id],
173+
dropOutReasonId: dropoutReason.id,
174+
});
175+
176+
expect(result).toEqual([candidacy.id]);
177+
178+
const candidacyDropOut = await prismaClient.candidacyDropOut.findUnique({
179+
where: {
180+
candidacyId: candidacy.id,
181+
},
182+
});
183+
184+
expect(candidacyDropOut?.status).toEqual("DOSSIER_FAISABILITE_ENVOYE");
185+
});
186+
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { logger } from "@/modules/shared/logger";
2+
import { prismaClient } from "@/prisma/client";
3+
4+
interface DropOutCandidaciesParams {
5+
candidacyIds: string[];
6+
dropOutReasonId: string;
7+
otherReasonContent?: string;
8+
}
9+
10+
export const dropOutCandidacies = async (
11+
params: DropOutCandidaciesParams,
12+
): Promise<string[]> => {
13+
if (!params.candidacyIds.length || !params.dropOutReasonId) {
14+
return [];
15+
}
16+
17+
try {
18+
const candidacies = await prismaClient.candidacy.findMany({
19+
where: {
20+
id: { in: params.candidacyIds },
21+
},
22+
include: {
23+
candidacyDropOut: true,
24+
},
25+
});
26+
27+
const candidaciesToDropOut = candidacies.filter(
28+
(candidacy) => !candidacy.candidacyDropOut,
29+
);
30+
31+
if (candidaciesToDropOut.length === 0) {
32+
return [];
33+
}
34+
35+
await prismaClient.candidacyDropOut.createMany({
36+
data: candidaciesToDropOut.map((candidacy) => ({
37+
candidacyId: candidacy.id,
38+
status: candidacy.status,
39+
dropOutReasonId: params.dropOutReasonId,
40+
otherReasonContent: params.otherReasonContent || null,
41+
})),
42+
});
43+
44+
return candidaciesToDropOut.map((candidacy) => candidacy.id);
45+
} catch (e) {
46+
logger.error(e);
47+
throw new Error(`error on drop out candidacies: ${(e as Error).message}`);
48+
}
49+
};

0 commit comments

Comments
 (0)