Skip to content

Commit 5fc7a39

Browse files
authored
Merge pull request #160 from HackYourFutureProjects/QA/reviews
Qa/reviews
2 parents 21afa4d + 98b71e3 commit 5fc7a39

1 file changed

Lines changed: 325 additions & 0 deletions

File tree

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
import {
2+
describe,
3+
it,
4+
expect,
5+
beforeAll,
6+
afterAll,
7+
beforeEach,
8+
} from "@jest/globals";
9+
import {
10+
setupTestDatabase,
11+
teardownTestDatabase,
12+
clearTestDatabase,
13+
} from "../setup/database.setup.js";
14+
import {
15+
createTestStudent,
16+
createTestTeacher,
17+
} from "../helpers/test.helpers.js";
18+
import { StudentTypeDB } from "../../src/db/schemes/types/student.types.js";
19+
import { TeacherTypeDB } from "../../src/db/schemes/types/teacher.types.js";
20+
import { ReviewModel } from "../../src/db/schemes/review.schema.js";
21+
import { AppointmentModel } from "../../src/db/schemes/appointmentSchema.js";
22+
import { randomUUID } from "node:crypto";
23+
24+
describe("Review Integration Tests", () => {
25+
let testStudent: StudentTypeDB;
26+
let testTeacher: TeacherTypeDB;
27+
28+
beforeAll(async () => {
29+
await setupTestDatabase();
30+
});
31+
32+
afterAll(async () => {
33+
await teardownTestDatabase();
34+
});
35+
36+
beforeEach(async () => {
37+
await clearTestDatabase();
38+
testStudent = await createTestStudent();
39+
testTeacher = await createTestTeacher();
40+
});
41+
42+
describe("ReviewModel CRUD Operations", () => {
43+
it("should create review in database", async () => {
44+
const appointment = await AppointmentModel.create({
45+
id: randomUUID(),
46+
studentId: testStudent.id,
47+
teacherId: testTeacher.id,
48+
lesson: "Math",
49+
level: "Beginner",
50+
teacher: testTeacher.id,
51+
student: testStudent.id,
52+
price: "25",
53+
date: "2024-12-15",
54+
time: "10:00",
55+
description: "Test",
56+
status: "approved" as const,
57+
videoCall: "https://meet.google.com/test",
58+
isRegularStudent: false,
59+
weeklySchedule: [],
60+
createdAt: new Date(),
61+
updatedAt: new Date(),
62+
});
63+
64+
const review = await ReviewModel.create({
65+
teacherId: testTeacher.id,
66+
studentId: testStudent.id,
67+
bookingId: appointment.id,
68+
rating: 5,
69+
review: "Excellent teacher!",
70+
subject: "Mathematics",
71+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
72+
...(testStudent.profileImageUrl && {
73+
studentAvatar: testStudent.profileImageUrl,
74+
}),
75+
createdAt: new Date(),
76+
updatedAt: new Date(),
77+
});
78+
79+
expect(review.teacherId).toBe(testTeacher.id);
80+
expect(review.studentId).toBe(testStudent.id);
81+
expect(review.rating).toBe(5);
82+
expect(review.subject).toBe("Mathematics");
83+
});
84+
85+
it("should find review by id", async () => {
86+
const appointment = await AppointmentModel.create({
87+
id: randomUUID(),
88+
studentId: testStudent.id,
89+
teacherId: testTeacher.id,
90+
lesson: "Math",
91+
level: "Beginner",
92+
teacher: testTeacher.id,
93+
student: testStudent.id,
94+
price: "25",
95+
date: "2024-12-15",
96+
time: "10:00",
97+
description: "Test",
98+
status: "approved" as const,
99+
videoCall: "https://meet.google.com/test",
100+
isRegularStudent: false,
101+
weeklySchedule: [],
102+
createdAt: new Date(),
103+
updatedAt: new Date(),
104+
});
105+
106+
const created = await ReviewModel.create({
107+
teacherId: testTeacher.id,
108+
studentId: testStudent.id,
109+
bookingId: appointment.id,
110+
rating: 4,
111+
review: "Good",
112+
subject: "Math",
113+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
114+
createdAt: new Date(),
115+
updatedAt: new Date(),
116+
});
117+
118+
const found = await ReviewModel.findById(created._id).exec();
119+
120+
expect(found?.teacherId).toBe(testTeacher.id);
121+
expect(found?.rating).toBe(4);
122+
});
123+
124+
it("should find reviews by teacher id", async () => {
125+
const appointment = await AppointmentModel.create({
126+
id: randomUUID(),
127+
studentId: testStudent.id,
128+
teacherId: testTeacher.id,
129+
lesson: "Math",
130+
level: "Beginner",
131+
teacher: testTeacher.id,
132+
student: testStudent.id,
133+
price: "25",
134+
date: "2024-12-15",
135+
time: "10:00",
136+
description: "Test",
137+
status: "approved" as const,
138+
videoCall: "https://meet.google.com/test",
139+
isRegularStudent: false,
140+
weeklySchedule: [],
141+
createdAt: new Date(),
142+
updatedAt: new Date(),
143+
});
144+
145+
await ReviewModel.create({
146+
teacherId: testTeacher.id,
147+
studentId: testStudent.id,
148+
bookingId: appointment.id,
149+
rating: 5,
150+
review: "Great!",
151+
subject: "Math",
152+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
153+
createdAt: new Date(),
154+
updatedAt: new Date(),
155+
});
156+
157+
const reviews = await ReviewModel.find({
158+
teacherId: testTeacher.id,
159+
}).exec();
160+
161+
expect(reviews).toHaveLength(1);
162+
expect(reviews[0].teacherId).toBe(testTeacher.id);
163+
});
164+
165+
it("should calculate average rating", async () => {
166+
const appointment1 = await AppointmentModel.create({
167+
id: randomUUID(),
168+
studentId: testStudent.id,
169+
teacherId: testTeacher.id,
170+
lesson: "Math",
171+
level: "Beginner",
172+
teacher: testTeacher.id,
173+
student: testStudent.id,
174+
price: "25",
175+
date: "2024-12-15",
176+
time: "10:00",
177+
description: "Test",
178+
status: "approved" as const,
179+
videoCall: "https://meet.google.com/test1",
180+
isRegularStudent: false,
181+
weeklySchedule: [],
182+
createdAt: new Date(),
183+
updatedAt: new Date(),
184+
});
185+
186+
const appointment2 = await AppointmentModel.create({
187+
id: randomUUID(),
188+
studentId: testStudent.id,
189+
teacherId: testTeacher.id,
190+
lesson: "Math",
191+
level: "Beginner",
192+
teacher: testTeacher.id,
193+
student: testStudent.id,
194+
price: "25",
195+
date: "2024-12-15",
196+
time: "11:00",
197+
description: "Test",
198+
status: "approved" as const,
199+
videoCall: "https://meet.google.com/test2",
200+
isRegularStudent: false,
201+
weeklySchedule: [],
202+
createdAt: new Date(),
203+
updatedAt: new Date(),
204+
});
205+
206+
await ReviewModel.create({
207+
teacherId: testTeacher.id,
208+
studentId: testStudent.id,
209+
bookingId: appointment1.id,
210+
rating: 5,
211+
review: "Excellent",
212+
subject: "Math",
213+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
214+
createdAt: new Date(),
215+
updatedAt: new Date(),
216+
});
217+
218+
await ReviewModel.create({
219+
teacherId: testTeacher.id,
220+
studentId: testStudent.id,
221+
bookingId: appointment2.id,
222+
rating: 3,
223+
review: "Good",
224+
subject: "Math",
225+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
226+
createdAt: new Date(),
227+
updatedAt: new Date(),
228+
});
229+
230+
const result = await ReviewModel.aggregate([
231+
{ $match: { teacherId: testTeacher.id } },
232+
{
233+
$group: {
234+
_id: "$teacherId",
235+
averageRating: { $avg: "$rating" },
236+
totalReviews: { $sum: 1 },
237+
},
238+
},
239+
]);
240+
241+
expect(result[0].averageRating).toBe(4);
242+
expect(result[0].totalReviews).toBe(2);
243+
});
244+
245+
it("should delete review", async () => {
246+
const appointment = await AppointmentModel.create({
247+
id: randomUUID(),
248+
studentId: testStudent.id,
249+
teacherId: testTeacher.id,
250+
lesson: "Math",
251+
level: "Beginner",
252+
teacher: testTeacher.id,
253+
student: testStudent.id,
254+
price: "25",
255+
date: "2024-12-15",
256+
time: "10:00",
257+
description: "Test",
258+
status: "approved" as const,
259+
videoCall: "https://meet.google.com/test",
260+
isRegularStudent: false,
261+
weeklySchedule: [],
262+
createdAt: new Date(),
263+
updatedAt: new Date(),
264+
});
265+
266+
const created = await ReviewModel.create({
267+
teacherId: testTeacher.id,
268+
studentId: testStudent.id,
269+
bookingId: appointment.id,
270+
rating: 5,
271+
review: "Great",
272+
subject: "Math",
273+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
274+
createdAt: new Date(),
275+
updatedAt: new Date(),
276+
});
277+
278+
await ReviewModel.findByIdAndDelete(created._id).exec();
279+
280+
const deleted = await ReviewModel.findById(created._id).exec();
281+
expect(deleted).toBeNull();
282+
});
283+
284+
it("should prevent duplicate reviews for same appointment", async () => {
285+
const appointment = await AppointmentModel.create({
286+
id: randomUUID(),
287+
studentId: testStudent.id,
288+
teacherId: testTeacher.id,
289+
lesson: "Math",
290+
level: "Beginner",
291+
teacher: testTeacher.id,
292+
student: testStudent.id,
293+
price: "25",
294+
date: "2024-12-15",
295+
time: "10:00",
296+
description: "Test",
297+
status: "approved" as const,
298+
videoCall: "https://meet.google.com/test",
299+
isRegularStudent: false,
300+
weeklySchedule: [],
301+
createdAt: new Date(),
302+
updatedAt: new Date(),
303+
});
304+
305+
await ReviewModel.create({
306+
teacherId: testTeacher.id,
307+
studentId: testStudent.id,
308+
bookingId: appointment.id,
309+
rating: 5,
310+
review: "First review",
311+
subject: "Math",
312+
studentName: `${testStudent.firstName} ${testStudent.lastName}`,
313+
createdAt: new Date(),
314+
updatedAt: new Date(),
315+
});
316+
317+
const existingReview = await ReviewModel.findOne({
318+
bookingId: appointment.id,
319+
}).exec();
320+
321+
expect(existingReview).not.toBeNull();
322+
expect(existingReview?.bookingId).toBe(appointment.id);
323+
});
324+
});
325+
});

0 commit comments

Comments
 (0)