Skip to content

Commit 4e3bd1d

Browse files
feat: add integration tests for API routes and setup test environment for Vitest
1 parent d0c70c6 commit 4e3bd1d

4 files changed

Lines changed: 171 additions & 23 deletions

File tree

edurate/backend/index.test.js

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
/**
22
* index.test.js
33
*
4-
* Tests for backend API endpoints.
5-
* Validates route handling, error responses, and input validation.
4+
* Integration tests for backend API endpoints.
5+
* Tests actual route handling, database interactions, and input validation.
66
*/
77

8-
import { describe, it, expect, vi } from 'vitest';
8+
import { describe, it, expect, beforeAll } from 'vitest';
99
import request from 'supertest';
1010
import express from 'express';
1111
import cors from 'cors';
12-
13-
// Mock the supabase config to avoid requiring env vars
14-
vi.mock('./config/supabase.js', () => ({
15-
supabase: {}
16-
}));
17-
18-
// Import routes AFTER mocking
19-
const courseRoutes = await import('./routes/courses.js').then(m => m.default);
12+
import 'dotenv/config';
13+
import courseRoutes from './routes/courses.js';
2014

2115
// Create test app instance
2216
const app = express();
@@ -52,6 +46,62 @@ describe('Backend API Tests', () => {
5246
});
5347
});
5448

49+
describe('API Routes Integration Tests', () => {
50+
51+
describe('GET /api/courses', () => {
52+
it('should return list of courses with ratings', async () => {
53+
const response = await request(app)
54+
.get('/api/courses')
55+
.expect(200);
56+
57+
expect(response.body).toHaveProperty('success', true);
58+
expect(response.body).toHaveProperty('data');
59+
expect(Array.isArray(response.body.data)).toBe(true);
60+
61+
// Check structure of first course if any exist
62+
if (response.body.data.length > 0) {
63+
const course = response.body.data[0];
64+
expect(course).toHaveProperty('id');
65+
expect(course).toHaveProperty('Course_name');
66+
expect(course).toHaveProperty('rating');
67+
expect(course).toHaveProperty('numReviews');
68+
}
69+
});
70+
});
71+
72+
describe('GET /api/courses/:id', () => {
73+
it('should return a single course with rating', async () => {
74+
const response = await request(app)
75+
.get('/api/courses/1')
76+
.expect(200);
77+
78+
expect(response.body).toHaveProperty('success', true);
79+
expect(response.body.data).toHaveProperty('id', 1);
80+
expect(response.body.data).toHaveProperty('rating');
81+
expect(response.body.data).toHaveProperty('numReviews');
82+
});
83+
84+
it('should return 404 for non-existent course', async () => {
85+
const response = await request(app)
86+
.get('/api/courses/99999')
87+
.expect(404);
88+
89+
expect(response.body).toHaveProperty('success', false);
90+
});
91+
});
92+
93+
describe('GET /api/courses/:id/reviews', () => {
94+
it('should return reviews for a course', async () => {
95+
const response = await request(app)
96+
.get('/api/courses/1/reviews')
97+
.expect(200);
98+
99+
expect(response.body).toHaveProperty('success', true);
100+
expect(Array.isArray(response.body.data)).toBe(true);
101+
});
102+
});
103+
});
104+
55105
describe('Review Validation Tests', () => {
56106
it('should reject review with missing rating', async () => {
57107
const response = await request(app)
@@ -100,4 +150,62 @@ describe('Review Validation Tests', () => {
100150
expect(response.body.success).toBe(false);
101151
expect(response.body.error).toContain('required');
102152
});
153+
154+
it('should create a new review with valid data', async () => {
155+
const newReview = {
156+
rating: 5,
157+
comment: 'Automated test review - excellent course!',
158+
student_name: 'Test Student'
159+
};
160+
161+
const response = await request(app)
162+
.post('/api/courses/1/reviews')
163+
.send(newReview)
164+
.expect(201);
165+
166+
expect(response.body).toHaveProperty('success', true);
167+
expect(response.body.data).toHaveProperty('id');
168+
expect(response.body.data.rating).toBe(5);
169+
expect(response.body.data.comment).toBe('Automated test review - excellent course!');
170+
});
171+
});
172+
173+
describe('Vote System Tests', () => {
174+
let testReviewId;
175+
176+
// Get a review ID for testing votes
177+
beforeAll(async () => {
178+
const response = await request(app).get('/api/courses/1/reviews');
179+
if (response.body.data && response.body.data.length > 0) {
180+
testReviewId = response.body.data[0].id;
181+
}
182+
});
183+
184+
it('should increment upvote count', async () => {
185+
if (!testReviewId) {
186+
console.log('Skipping upvote test - no reviews available');
187+
return;
188+
}
189+
190+
const response = await request(app)
191+
.post(`/api/courses/1/reviews/${testReviewId}/upvote`)
192+
.expect(200);
193+
194+
expect(response.body).toHaveProperty('success', true);
195+
expect(response.body.data).toHaveProperty('upvotes');
196+
});
197+
198+
it('should increment downvote count', async () => {
199+
if (!testReviewId) {
200+
console.log('Skipping downvote test - no reviews available');
201+
return;
202+
}
203+
204+
const response = await request(app)
205+
.post(`/api/courses/1/reviews/${testReviewId}/downvote`)
206+
.expect(200);
207+
208+
expect(response.body).toHaveProperty('success', true);
209+
expect(response.body.data).toHaveProperty('downvotes');
210+
});
103211
});

edurate/backend/package-lock.json

Lines changed: 35 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

edurate/backend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
"devDependencies": {
1717
"nodemon": "^3.0.2",
18-
"supertest": "^7.1.4",
18+
"supertest": "^7.2.2",
1919
"vitest": "^4.0.15"
2020
}
21-
}
21+
}

edurate/frontend/src/setupTests.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* setupTests.js
3+
*
4+
* Test environment setup for Vitest.
5+
* Runs before all test files.
6+
*/
7+
8+
import { expect, afterEach } from 'vitest';
9+
import { cleanup } from '@testing-library/react';
10+
import '@testing-library/jest-dom';
11+
12+
// Cleanup after each test
13+
afterEach(() => {
14+
cleanup();
15+
});

0 commit comments

Comments
 (0)