· 4 months ago · May 22, 2025, 12:00 PM
1const request = require("supertest");
2const mongoose = require("mongoose");
3const { MongoMemoryServer } = require("mongodb-memory-server");
4const app = require("../server");
5
6// Set test environment
7process.env.NODE_ENV = "test";
8
9jest.setTimeout(10000);
10
11let mongoServer;
12let instructorToken;
13let studentToken;
14let courseId;
15let newCourseId;
16
17describe("Advanced E-Learning API Integration Tests", () => {
18 beforeAll(async () => {
19 try {
20 // Connect to the in-memory MongoDB database before running the tests
21 mongoServer = await MongoMemoryServer.create();
22 const mongoUri = mongoServer.getUri();
23 console.log("Attempting to connect to MongoDB at:", mongoUri);
24
25 await mongoose.connect(mongoUri, {
26 serverSelectionTimeoutMS: 5000, // 5 second timeout
27 });
28
29 console.log("Successfully connected to MongoDB");
30 } catch (error) {
31 console.error("Failed to connect to MongoDB:", error);
32 throw error; // Re-throw to fail the test
33 }
34 });
35
36 // Clean up database and close the connection after all tests are done
37 afterAll(async () => {
38 if (mongoServer) {
39 await mongoose.connection.dropDatabase();
40 await mongoose.connection.close();
41 await mongoServer.stop();
42 }
43 });
44
45 describe("User Authentication", () => {
46 const instructorData = {
47 name: "Test Instructor",
48 email: "instructor@test.com",
49 password: "password123",
50 role: "instructor",
51 };
52
53 const studentData = {
54 name: "Test Student",
55 email: "student@test.com",
56 password: "password123",
57 role: "student",
58 };
59
60 // Test user registration
61 describe("POST /api/auth/signup", () => {
62 it("should register a new instructor", async () => {
63 const res = await request(app)
64 .post("/api/auth/signup")
65 .send(instructorData);
66
67 expect(res.status).toBe(201);
68 expect(res.body.message).toBe("User created successfully");
69 expect(res.body.user).toHaveProperty("email", instructorData.email);
70 });
71
72 it("should register a new student", async () => {
73 const res = await request(app)
74 .post("/api/auth/signup")
75 .send(studentData);
76
77 expect(res.status).toBe(201);
78 expect(res.body.message).toBe("User created successfully");
79 expect(res.body.user).toHaveProperty("email", studentData.email);
80 });
81
82 it("should not register a user with existing email", async () => {
83 const res = await request(app)
84 .post("/api/auth/signup")
85 .send(instructorData);
86
87 expect(res.status).toBe(400);
88 expect(res.body.message).toBe("User already exists");
89 });
90 });
91
92 // Test user login
93 describe("POST /api/auth/login", () => {
94 it("should login an instructor and return token", async () => {
95 const res = await request(app).post("/api/auth/login").send({
96 email: instructorData.email,
97 password: instructorData.password,
98 });
99
100 expect(res.status).toBe(200);
101 expect(res.body).toHaveProperty("token");
102 instructorToken = res.body.token;
103 });
104
105 it("should login a student and return token", async () => {
106 const res = await request(app).post("/api/auth/login").send({
107 email: studentData.email,
108 password: studentData.password,
109 });
110
111 expect(res.status).toBe(200);
112 expect(res.body).toHaveProperty("token");
113 studentToken = res.body.token;
114 });
115
116 it("should not login with invalid credentials", async () => {
117 const res = await request(app).post("/api/auth/login").send({
118 email: instructorData.email,
119 password: "wrongpassword",
120 });
121
122 expect(res.status).toBe(400);
123 expect(res.body.message).toBe("Invalid credentials");
124 });
125 });
126 });
127
128 describe("Course Management", () => {
129 const courseData = {
130 title: "Test Course",
131 description: "This is a test course",
132 duration: "10 weeks",
133 price: 99.99,
134 };
135
136 // Test course creation
137 describe("POST /api/courses", () => {
138 it("should create a new course (instructor only)", async () => {
139 const res = await request(app)
140 .post("/api/courses")
141 .set("Authorization", `Bearer ${instructorToken}`)
142 .send(courseData);
143
144 expect(res.status).toBe(201);
145 expect(res.body.message).toBe("Course created successfully");
146 expect(res.body.course).toHaveProperty("title", courseData.title);
147 courseId = res.body.course._id;
148 });
149
150 it("should not allow student to create course", async () => {
151 const res = await request(app)
152 .post("/api/courses")
153 .set("Authorization", `Bearer ${studentToken}`)
154 .send(courseData);
155
156 expect(res.status).toBe(403);
157 });
158 });
159
160 // Test course retrieval
161 describe("GET /api/courses", () => {
162 it("should get all courses", async () => {
163 const res = await request(app).get("/api/courses");
164
165 expect(res.status).toBe(200);
166 expect(Array.isArray(res.body)).toBeTruthy();
167 expect(res.body.length).toBeGreaterThan(0);
168 });
169 });
170
171 // Test course update
172 describe("PATCH /api/courses/:courseId", () => {
173 it("should update course (instructor only)", async () => {
174 const updateData = {
175 title: "Updated Test Course",
176 price: 149.99,
177 };
178
179 const res = await request(app)
180 .patch(`/api/courses/${courseId}`)
181 .set("Authorization", `Bearer ${instructorToken}`)
182 .send(updateData);
183
184 expect(res.status).toBe(200);
185 expect(res.body.course).toHaveProperty("title", updateData.title);
186 expect(res.body.course).toHaveProperty("price", updateData.price);
187 });
188
189 it("should not allow student to update course", async () => {
190 const res = await request(app)
191 .patch(`/api/courses/${courseId}`)
192 .set("Authorization", `Bearer ${studentToken}`)
193 .send({ title: "Hacked Course" });
194
195 expect(res.status).toBe(403);
196 });
197 });
198 });
199
200 describe("Course Enrollment", () => {
201 // Test course enrollment
202 describe("POST /api/courses/:courseId/enroll", () => {
203 it("should allow student to enroll in course", async () => {
204 const res = await request(app)
205 .post(`/api/courses/${courseId}/enroll`)
206 .set("Authorization", `Bearer ${studentToken}`);
207
208 expect(res.status).toBe(201);
209 expect(res.body.message).toBe("Enrolled successfully");
210 });
211
212 it("should not allow instructor to enroll", async () => {
213 const res = await request(app)
214 .post(`/api/courses/${courseId}/enroll`)
215 .set("Authorization", `Bearer ${instructorToken}`);
216
217 expect(res.status).toBe(403);
218 });
219
220 it("should not allow duplicate enrollment", async () => {
221 const res = await request(app)
222 .post(`/api/courses/${courseId}/enroll`)
223 .set("Authorization", `Bearer ${studentToken}`);
224
225 expect(res.status).toBe(400);
226 expect(res.body.message).toBe("Already enrolled to this course");
227 });
228 });
229 });
230
231 describe("Course Analytics", () => {
232 describe("GET /api/courses/analytics/summary", () => {
233 it("should get course analytics (instructor only)", async () => {
234 const res = await request(app)
235 .get("/api/courses/analytics/summary")
236 .set("Authorization", `Bearer ${instructorToken}`);
237
238 expect(res.status).toBe(200);
239 expect(res.body).toHaveProperty("totalCourses");
240 expect(res.body).toHaveProperty("totalEnrollments");
241 });
242
243 it("should not allow student to access analytics", async () => {
244 const res = await request(app)
245 .get("/api/courses/analytics/summary")
246 .set("Authorization", `Bearer ${studentToken}`);
247
248 expect(res.status).toBe(403);
249 });
250 });
251 });
252});
253