add changes
This commit is contained in:
650
backend/tests/test-review-quiz.js
Normal file
650
backend/tests/test-review-quiz.js
Normal file
@@ -0,0 +1,650 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const API_URL = 'http://localhost:3000/api';
|
||||
|
||||
// Test data
|
||||
let testUser = {
|
||||
email: 'reviewtest@example.com',
|
||||
password: 'Test@123',
|
||||
username: 'reviewtester'
|
||||
};
|
||||
|
||||
let secondUser = {
|
||||
email: 'otherreviewer@example.com',
|
||||
password: 'Test@123',
|
||||
username: 'otherreviewer'
|
||||
};
|
||||
|
||||
let userToken = null;
|
||||
let secondUserToken = null;
|
||||
let guestToken = null;
|
||||
let guestId = null;
|
||||
let testCategory = null;
|
||||
let completedSessionId = null;
|
||||
let inProgressSessionId = null;
|
||||
let guestCompletedSessionId = null;
|
||||
|
||||
// Helper to add delay between tests
|
||||
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
// Helper to create and complete a quiz
|
||||
async function createAndCompleteQuiz(token, isGuest = false, questionCount = 3) {
|
||||
const headers = isGuest
|
||||
? { 'X-Guest-Token': token }
|
||||
: { 'Authorization': `Bearer ${token}` };
|
||||
|
||||
// Get categories
|
||||
const categoriesRes = await axios.get(`${API_URL}/categories`, { headers });
|
||||
const categories = categoriesRes.data.data;
|
||||
const category = categories.find(c => c.questionCount >= questionCount);
|
||||
|
||||
if (!category) {
|
||||
throw new Error('No category with enough questions found');
|
||||
}
|
||||
|
||||
// Start quiz
|
||||
const startRes = await axios.post(`${API_URL}/quiz/start`, {
|
||||
categoryId: category.id,
|
||||
questionCount,
|
||||
difficulty: 'mixed',
|
||||
quizType: 'practice'
|
||||
}, { headers });
|
||||
|
||||
const sessionId = startRes.data.data.sessionId;
|
||||
const questions = startRes.data.data.questions;
|
||||
|
||||
// Submit answers for all questions
|
||||
for (const question of questions) {
|
||||
let answer;
|
||||
if (question.questionType === 'multiple') {
|
||||
answer = question.options[0].id;
|
||||
} else if (question.questionType === 'trueFalse') {
|
||||
answer = 'true';
|
||||
} else {
|
||||
answer = 'Sample answer';
|
||||
}
|
||||
|
||||
await axios.post(`${API_URL}/quiz/submit`, {
|
||||
quizSessionId: sessionId,
|
||||
questionId: question.id,
|
||||
userAnswer: answer,
|
||||
timeTaken: Math.floor(Math.random() * 20) + 5 // 5-25 seconds
|
||||
}, { headers });
|
||||
|
||||
await delay(100);
|
||||
}
|
||||
|
||||
// Complete quiz
|
||||
await axios.post(`${API_URL}/quiz/complete`, {
|
||||
sessionId
|
||||
}, { headers });
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
// Test setup
|
||||
async function setup() {
|
||||
console.log('Setting up test data...\n');
|
||||
|
||||
try {
|
||||
// Register first user
|
||||
try {
|
||||
const registerRes = await axios.post(`${API_URL}/auth/register`, testUser);
|
||||
userToken = registerRes.data.data.token;
|
||||
console.log('✓ First user registered');
|
||||
} catch (error) {
|
||||
const loginRes = await axios.post(`${API_URL}/auth/login`, {
|
||||
email: testUser.email,
|
||||
password: testUser.password
|
||||
});
|
||||
userToken = loginRes.data.data.token;
|
||||
console.log('✓ First user logged in');
|
||||
}
|
||||
|
||||
// Register second user
|
||||
try {
|
||||
const registerRes = await axios.post(`${API_URL}/auth/register`, secondUser);
|
||||
secondUserToken = registerRes.data.data.token;
|
||||
console.log('✓ Second user registered');
|
||||
} catch (error) {
|
||||
const loginRes = await axios.post(`${API_URL}/auth/login`, {
|
||||
email: secondUser.email,
|
||||
password: secondUser.password
|
||||
});
|
||||
secondUserToken = loginRes.data.data.token;
|
||||
console.log('✓ Second user logged in');
|
||||
}
|
||||
|
||||
// Create guest session
|
||||
const guestRes = await axios.post(`${API_URL}/guest/start-session`);
|
||||
guestToken = guestRes.data.data.sessionToken;
|
||||
guestId = guestRes.data.data.guestId;
|
||||
console.log('✓ Guest session created');
|
||||
|
||||
// Get a test category
|
||||
const categoriesRes = await axios.get(`${API_URL}/categories`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
const categories = categoriesRes.data.data;
|
||||
// Sort by questionCount descending to get category with most questions
|
||||
categories.sort((a, b) => b.questionCount - a.questionCount);
|
||||
testCategory = categories.find(c => c.questionCount >= 3);
|
||||
|
||||
if (!testCategory) {
|
||||
throw new Error('No category with enough questions found');
|
||||
}
|
||||
console.log(`✓ Test category selected: ${testCategory.name} (${testCategory.questionCount} questions)`);
|
||||
|
||||
await delay(500);
|
||||
|
||||
// Create completed quiz for user (use available question count, max 5)
|
||||
const quizQuestionCount = Math.min(testCategory.questionCount, 5);
|
||||
completedSessionId = await createAndCompleteQuiz(userToken, false, quizQuestionCount);
|
||||
console.log(`✓ User completed session created (${quizQuestionCount} questions)`);
|
||||
|
||||
await delay(500);
|
||||
|
||||
// Create in-progress quiz for user
|
||||
const startRes = await axios.post(`${API_URL}/quiz/start`, {
|
||||
categoryId: testCategory.id,
|
||||
questionCount: 3,
|
||||
difficulty: 'easy',
|
||||
quizType: 'practice'
|
||||
}, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
inProgressSessionId = startRes.data.data.sessionId;
|
||||
|
||||
// Submit one answer to make it in-progress
|
||||
const questions = startRes.data.data.questions;
|
||||
let answer = questions[0].questionType === 'multiple'
|
||||
? questions[0].options[0].id
|
||||
: 'true';
|
||||
|
||||
await axios.post(`${API_URL}/quiz/submit`, {
|
||||
quizSessionId: inProgressSessionId,
|
||||
questionId: questions[0].id,
|
||||
userAnswer: answer,
|
||||
timeTaken: 10
|
||||
}, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
console.log('✓ User in-progress session created');
|
||||
|
||||
await delay(500);
|
||||
|
||||
// Create completed quiz for guest
|
||||
guestCompletedSessionId = await createAndCompleteQuiz(guestToken, true, 3);
|
||||
console.log('✓ Guest completed session created\n');
|
||||
|
||||
await delay(500);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Setup failed:', error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Test cases
|
||||
const tests = [
|
||||
{
|
||||
name: 'Test 1: Review completed quiz (user)',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
if (response.status !== 200) throw new Error('Expected 200 status');
|
||||
if (!response.data.success) throw new Error('Expected success true');
|
||||
|
||||
const { session, summary, questions } = response.data.data;
|
||||
|
||||
// Validate session
|
||||
if (!session.id || session.id !== completedSessionId) throw new Error('Invalid session id');
|
||||
if (session.status !== 'completed') throw new Error('Expected completed status');
|
||||
if (!session.category || !session.category.name) throw new Error('Missing category info');
|
||||
|
||||
// Validate summary
|
||||
if (typeof summary.score.earned !== 'number') throw new Error('Score.earned should be number');
|
||||
if (typeof summary.accuracy !== 'number') throw new Error('Accuracy should be number');
|
||||
if (typeof summary.isPassed !== 'boolean') throw new Error('isPassed should be boolean');
|
||||
if (summary.questions.total < 3) throw new Error('Expected at least 3 total questions');
|
||||
|
||||
// Validate questions
|
||||
if (questions.length < 3) throw new Error('Expected at least 3 questions');
|
||||
|
||||
// All questions should have correct answers shown
|
||||
questions.forEach((q, idx) => {
|
||||
if (q.correctAnswer === undefined) {
|
||||
throw new Error(`Question ${idx + 1} should show correct answer`);
|
||||
}
|
||||
if (q.resultStatus === undefined) {
|
||||
throw new Error(`Question ${idx + 1} should have resultStatus`);
|
||||
}
|
||||
if (q.showExplanation !== true) {
|
||||
throw new Error(`Question ${idx + 1} should have showExplanation`);
|
||||
}
|
||||
});
|
||||
|
||||
return '✓ Completed quiz review correct';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 2: Review guest completed quiz',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${guestCompletedSessionId}`, {
|
||||
headers: { 'X-Guest-Token': guestToken }
|
||||
});
|
||||
|
||||
if (response.status !== 200) throw new Error('Expected 200 status');
|
||||
|
||||
const { session, summary, questions } = response.data.data;
|
||||
|
||||
if (session.id !== guestCompletedSessionId) throw new Error('Invalid session id');
|
||||
if (session.status !== 'completed') throw new Error('Expected completed status');
|
||||
if (questions.length !== 3) throw new Error('Expected 3 questions');
|
||||
|
||||
return '✓ Guest quiz review works';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 3: Cannot review in-progress quiz (400)',
|
||||
run: async () => {
|
||||
try {
|
||||
await axios.get(`${API_URL}/quiz/review/${inProgressSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
throw new Error('Should have failed with 400');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 400) {
|
||||
throw new Error(`Expected 400, got ${error.response?.status}`);
|
||||
}
|
||||
if (!error.response?.data?.message?.includes('completed')) {
|
||||
throw new Error('Error message should mention completed status');
|
||||
}
|
||||
return '✓ In-progress quiz review blocked';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 4: Missing session ID returns 400',
|
||||
run: async () => {
|
||||
try {
|
||||
await axios.get(`${API_URL}/quiz/review/`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
throw new Error('Should have failed');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 404 && error.response?.status !== 400) {
|
||||
throw new Error(`Expected 400 or 404, got ${error.response?.status}`);
|
||||
}
|
||||
return '✓ Missing session ID handled';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 5: Invalid UUID format returns 400',
|
||||
run: async () => {
|
||||
try {
|
||||
await axios.get(`${API_URL}/quiz/review/invalid-uuid`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
throw new Error('Should have failed with 400');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 400) {
|
||||
throw new Error(`Expected 400, got ${error.response?.status}`);
|
||||
}
|
||||
return '✓ Invalid UUID returns 400';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 6: Non-existent session returns 404',
|
||||
run: async () => {
|
||||
try {
|
||||
const fakeUuid = '00000000-0000-0000-0000-000000000000';
|
||||
await axios.get(`${API_URL}/quiz/review/${fakeUuid}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
throw new Error('Should have failed with 404');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 404) {
|
||||
throw new Error(`Expected 404, got ${error.response?.status}`);
|
||||
}
|
||||
return '✓ Non-existent session returns 404';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 7: Cannot access other user\'s quiz review (403)',
|
||||
run: async () => {
|
||||
try {
|
||||
await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${secondUserToken}` }
|
||||
});
|
||||
throw new Error('Should have failed with 403');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 403) {
|
||||
throw new Error(`Expected 403, got ${error.response?.status}`);
|
||||
}
|
||||
return '✓ Cross-user access blocked';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 8: Unauthenticated request returns 401',
|
||||
run: async () => {
|
||||
try {
|
||||
await axios.get(`${API_URL}/quiz/review/${completedSessionId}`);
|
||||
throw new Error('Should have failed with 401');
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 401) {
|
||||
throw new Error(`Expected 401, got ${error.response?.status}`);
|
||||
}
|
||||
return '✓ Unauthenticated request blocked';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 9: Response includes all required session fields',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { session } = response.data.data;
|
||||
|
||||
const requiredFields = [
|
||||
'id', 'status', 'quizType', 'difficulty', 'category',
|
||||
'startedAt', 'completedAt', 'timeSpent'
|
||||
];
|
||||
|
||||
requiredFields.forEach(field => {
|
||||
if (!(field in session)) {
|
||||
throw new Error(`Missing required session field: ${field}`);
|
||||
}
|
||||
});
|
||||
|
||||
return '✓ All required session fields present';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 10: Response includes all required summary fields',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { summary } = response.data.data;
|
||||
|
||||
// Score fields
|
||||
if (!summary.score || typeof summary.score.earned !== 'number') {
|
||||
throw new Error('Missing or invalid score.earned');
|
||||
}
|
||||
if (typeof summary.score.total !== 'number') {
|
||||
throw new Error('Missing or invalid score.total');
|
||||
}
|
||||
if (typeof summary.score.percentage !== 'number') {
|
||||
throw new Error('Missing or invalid score.percentage');
|
||||
}
|
||||
|
||||
// Questions summary
|
||||
const qFields = ['total', 'answered', 'correct', 'incorrect', 'unanswered'];
|
||||
qFields.forEach(field => {
|
||||
if (typeof summary.questions[field] !== 'number') {
|
||||
throw new Error(`Missing or invalid questions.${field}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Other fields
|
||||
if (typeof summary.accuracy !== 'number') {
|
||||
throw new Error('Missing or invalid accuracy');
|
||||
}
|
||||
if (typeof summary.isPassed !== 'boolean') {
|
||||
throw new Error('Missing or invalid isPassed');
|
||||
}
|
||||
|
||||
// Time statistics
|
||||
if (!summary.timeStatistics) {
|
||||
throw new Error('Missing timeStatistics');
|
||||
}
|
||||
if (typeof summary.timeStatistics.totalTime !== 'number') {
|
||||
throw new Error('Missing or invalid timeStatistics.totalTime');
|
||||
}
|
||||
|
||||
return '✓ All required summary fields present';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 11: Questions include all required fields',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { questions } = response.data.data;
|
||||
|
||||
if (questions.length === 0) throw new Error('Should have questions');
|
||||
|
||||
const requiredFields = [
|
||||
'id', 'questionText', 'questionType', 'difficulty', 'points',
|
||||
'explanation', 'order', 'correctAnswer', 'userAnswer', 'isCorrect',
|
||||
'resultStatus', 'pointsEarned', 'pointsPossible', 'timeTaken',
|
||||
'answeredAt', 'showExplanation', 'wasAnswered'
|
||||
];
|
||||
|
||||
questions.forEach((q, idx) => {
|
||||
requiredFields.forEach(field => {
|
||||
if (!(field in q)) {
|
||||
throw new Error(`Question ${idx + 1} missing field: ${field}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return '✓ Questions have all required fields';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 12: Result status correctly marked',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { questions } = response.data.data;
|
||||
|
||||
questions.forEach((q, idx) => {
|
||||
if (q.wasAnswered) {
|
||||
const expectedStatus = q.isCorrect ? 'correct' : 'incorrect';
|
||||
if (q.resultStatus !== expectedStatus) {
|
||||
throw new Error(
|
||||
`Question ${idx + 1} has wrong resultStatus: expected ${expectedStatus}, got ${q.resultStatus}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (q.resultStatus !== 'unanswered') {
|
||||
throw new Error(`Question ${idx + 1} should have resultStatus 'unanswered'`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return '✓ Result status correctly marked';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 13: Explanations always shown in review',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { questions } = response.data.data;
|
||||
|
||||
questions.forEach((q, idx) => {
|
||||
if (q.showExplanation !== true) {
|
||||
throw new Error(`Question ${idx + 1} should have showExplanation=true`);
|
||||
}
|
||||
// Explanation field should exist (can be null if not provided)
|
||||
if (!('explanation' in q)) {
|
||||
throw new Error(`Question ${idx + 1} missing explanation field`);
|
||||
}
|
||||
});
|
||||
|
||||
return '✓ Explanations shown for all questions';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 14: Points tracking accurate',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { summary, questions } = response.data.data;
|
||||
|
||||
// Calculate points from questions
|
||||
let totalPointsPossible = 0;
|
||||
let totalPointsEarned = 0;
|
||||
|
||||
questions.forEach(q => {
|
||||
totalPointsPossible += q.pointsPossible;
|
||||
totalPointsEarned += q.pointsEarned;
|
||||
|
||||
// Points earned should match: correct answers get full points, incorrect get 0
|
||||
if (q.wasAnswered) {
|
||||
const expectedPoints = q.isCorrect ? q.pointsPossible : 0;
|
||||
if (q.pointsEarned !== expectedPoints) {
|
||||
throw new Error(
|
||||
`Question points mismatch: expected ${expectedPoints}, got ${q.pointsEarned}`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Totals should match summary
|
||||
if (totalPointsEarned !== summary.score.earned) {
|
||||
throw new Error(
|
||||
`Score mismatch: calculated ${totalPointsEarned}, summary shows ${summary.score.earned}`
|
||||
);
|
||||
}
|
||||
|
||||
return '✓ Points tracking accurate';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 15: Time statistics calculated correctly',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { summary, questions } = response.data.data;
|
||||
|
||||
// Calculate total time from questions
|
||||
let calculatedTotalTime = 0;
|
||||
let answeredCount = 0;
|
||||
|
||||
questions.forEach(q => {
|
||||
if (q.wasAnswered && q.timeTaken) {
|
||||
calculatedTotalTime += q.timeTaken;
|
||||
answeredCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Check total time
|
||||
if (calculatedTotalTime !== summary.timeStatistics.totalTime) {
|
||||
throw new Error(
|
||||
`Total time mismatch: calculated ${calculatedTotalTime}, summary shows ${summary.timeStatistics.totalTime}`
|
||||
);
|
||||
}
|
||||
|
||||
// Check average
|
||||
const expectedAverage = answeredCount > 0
|
||||
? Math.round(calculatedTotalTime / answeredCount)
|
||||
: 0;
|
||||
|
||||
if (expectedAverage !== summary.timeStatistics.averageTimePerQuestion) {
|
||||
throw new Error(
|
||||
`Average time mismatch: expected ${expectedAverage}, got ${summary.timeStatistics.averageTimePerQuestion}`
|
||||
);
|
||||
}
|
||||
|
||||
return '✓ Time statistics accurate';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Test 16: Multiple choice options have feedback',
|
||||
run: async () => {
|
||||
const response = await axios.get(`${API_URL}/quiz/review/${completedSessionId}`, {
|
||||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||||
});
|
||||
|
||||
const { questions } = response.data.data;
|
||||
|
||||
const mcQuestions = questions.filter(q => q.questionType === 'multiple');
|
||||
|
||||
if (mcQuestions.length === 0) {
|
||||
console.log(' Note: No multiple choice questions in this quiz');
|
||||
return '✓ Test skipped (no multiple choice questions)';
|
||||
}
|
||||
|
||||
mcQuestions.forEach((q, idx) => {
|
||||
if (!Array.isArray(q.options)) {
|
||||
throw new Error(`MC Question ${idx + 1} should have options array`);
|
||||
}
|
||||
|
||||
q.options.forEach((opt, optIdx) => {
|
||||
if (!('isCorrect' in opt)) {
|
||||
throw new Error(`Option ${optIdx + 1} missing isCorrect field`);
|
||||
}
|
||||
if (!('isSelected' in opt)) {
|
||||
throw new Error(`Option ${optIdx + 1} missing isSelected field`);
|
||||
}
|
||||
if (!('feedback' in opt)) {
|
||||
throw new Error(`Option ${optIdx + 1} missing feedback field`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return '✓ Multiple choice options have feedback';
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Run all tests
|
||||
async function runTests() {
|
||||
console.log('='.repeat(60));
|
||||
console.log('QUIZ REVIEW API TESTS');
|
||||
console.log('='.repeat(60) + '\n');
|
||||
|
||||
await setup();
|
||||
|
||||
console.log('Running tests...\n');
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const test of tests) {
|
||||
try {
|
||||
const result = await test.run();
|
||||
console.log(`${result}`);
|
||||
passed++;
|
||||
await delay(500); // Delay between tests
|
||||
} catch (error) {
|
||||
console.log(`✗ ${test.name}`);
|
||||
console.log(` Error: ${error.response?.data?.message || error.message}`);
|
||||
if (error.response?.data && process.env.VERBOSE) {
|
||||
console.log(` Response:`, JSON.stringify(error.response.data, null, 2));
|
||||
}
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log(`RESULTS: ${passed} passed, ${failed} failed out of ${tests.length} tests`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
runTests();
|
||||
Reference in New Issue
Block a user