Phase 4 complete
This commit is contained in:
parent
0cc099c00c
commit
66f15b49b2
9 changed files with 710 additions and 37 deletions
|
|
@ -168,6 +168,264 @@ async function runTests() {
|
|||
await request('GET', `/api/quizzes/${createdQuizId}`, undefined, 404);
|
||||
});
|
||||
|
||||
console.log('\nQuiz Validation Tests:');
|
||||
await test('POST /api/quizzes without title returns 400', async () => {
|
||||
const invalidQuiz = {
|
||||
source: 'manual',
|
||||
questions: [
|
||||
{
|
||||
text: 'Question?',
|
||||
options: [
|
||||
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
await request('POST', '/api/quizzes', invalidQuiz, 400);
|
||||
});
|
||||
|
||||
await test('POST /api/quizzes without source returns 400', async () => {
|
||||
const invalidQuiz = {
|
||||
title: 'Missing Source Quiz',
|
||||
questions: [
|
||||
{
|
||||
text: 'Question?',
|
||||
options: [
|
||||
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
await request('POST', '/api/quizzes', invalidQuiz, 400);
|
||||
});
|
||||
|
||||
await test('POST /api/quizzes without questions returns 400', async () => {
|
||||
const invalidQuiz = {
|
||||
title: 'No Questions Quiz',
|
||||
source: 'manual',
|
||||
questions: [],
|
||||
};
|
||||
await request('POST', '/api/quizzes', invalidQuiz, 400);
|
||||
});
|
||||
|
||||
await test('POST /api/quizzes with empty body returns 400', async () => {
|
||||
await request('POST', '/api/quizzes', {}, 400);
|
||||
});
|
||||
|
||||
console.log('\nQuiz Not Found Tests:');
|
||||
await test('GET /api/quizzes/:id with non-existent ID returns 404', async () => {
|
||||
await request('GET', '/api/quizzes/non-existent-uuid-12345', undefined, 404);
|
||||
});
|
||||
|
||||
await test('PUT /api/quizzes/:id with non-existent ID returns 404', async () => {
|
||||
const quiz = {
|
||||
title: 'Update Non-Existent',
|
||||
questions: [
|
||||
{
|
||||
text: 'Q?',
|
||||
options: [{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
await request('PUT', '/api/quizzes/non-existent-uuid-12345', quiz, 404);
|
||||
});
|
||||
|
||||
await test('DELETE /api/quizzes/:id with non-existent ID returns 404', async () => {
|
||||
await request('DELETE', '/api/quizzes/non-existent-uuid-12345', undefined, 404);
|
||||
});
|
||||
|
||||
console.log('\nQuiz Source Types Tests:');
|
||||
let aiQuizId: string | null = null;
|
||||
|
||||
await test('POST /api/quizzes with ai_generated source and aiTopic', async () => {
|
||||
const aiQuiz = {
|
||||
title: 'AI Generated Quiz',
|
||||
source: 'ai_generated',
|
||||
aiTopic: 'Space Exploration',
|
||||
questions: [
|
||||
{
|
||||
text: 'What planet is known as the Red Planet?',
|
||||
timeLimit: 20,
|
||||
options: [
|
||||
{ text: 'Venus', isCorrect: false, shape: 'triangle', color: 'red' },
|
||||
{ text: 'Mars', isCorrect: true, shape: 'diamond', color: 'blue' },
|
||||
{ text: 'Jupiter', isCorrect: false, shape: 'circle', color: 'yellow' },
|
||||
{ text: 'Saturn', isCorrect: false, shape: 'square', color: 'green' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data } = await request('POST', '/api/quizzes', aiQuiz, 201);
|
||||
const result = data as { id: string };
|
||||
if (!result.id) throw new Error('Missing quiz id');
|
||||
aiQuizId = result.id;
|
||||
});
|
||||
|
||||
await test('GET /api/quizzes/:id returns aiTopic for AI quiz', async () => {
|
||||
if (!aiQuizId) throw new Error('No AI quiz created');
|
||||
const { data } = await request('GET', `/api/quizzes/${aiQuizId}`);
|
||||
const quiz = data as Record<string, unknown>;
|
||||
if (quiz.source !== 'ai_generated') throw new Error('Wrong source');
|
||||
if (quiz.aiTopic !== 'Space Exploration') throw new Error('Missing or wrong aiTopic');
|
||||
});
|
||||
|
||||
await test('GET /api/quizzes list includes source and questionCount', async () => {
|
||||
const { data } = await request('GET', '/api/quizzes');
|
||||
const quizzes = data as Record<string, unknown>[];
|
||||
if (quizzes.length === 0) throw new Error('Expected at least one quiz');
|
||||
const quiz = quizzes.find((q) => q.id === aiQuizId);
|
||||
if (!quiz) throw new Error('AI quiz not in list');
|
||||
if (quiz.source !== 'ai_generated') throw new Error('Missing source in list');
|
||||
if (typeof quiz.questionCount !== 'number') throw new Error('Missing questionCount');
|
||||
if (quiz.questionCount !== 1) throw new Error('Wrong questionCount');
|
||||
});
|
||||
|
||||
await test('DELETE cleanup AI quiz', async () => {
|
||||
if (!aiQuizId) throw new Error('No AI quiz to delete');
|
||||
await request('DELETE', `/api/quizzes/${aiQuizId}`, undefined, 204);
|
||||
});
|
||||
|
||||
console.log('\nQuiz with Multiple Questions Tests:');
|
||||
let multiQuizId: string | null = null;
|
||||
|
||||
await test('POST /api/quizzes with multiple questions', async () => {
|
||||
const multiQuiz = {
|
||||
title: 'Multi-Question Quiz',
|
||||
source: 'manual',
|
||||
questions: [
|
||||
{
|
||||
text: 'Question 1?',
|
||||
timeLimit: 15,
|
||||
options: [
|
||||
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
|
||||
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Question 2?',
|
||||
timeLimit: 25,
|
||||
options: [
|
||||
{ text: 'X', isCorrect: false, shape: 'circle', color: 'yellow' },
|
||||
{ text: 'Y', isCorrect: true, shape: 'square', color: 'green' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Question 3?',
|
||||
timeLimit: 30,
|
||||
options: [
|
||||
{ text: 'P', isCorrect: false, shape: 'triangle', color: 'red', reason: 'Wrong because...' },
|
||||
{ text: 'Q', isCorrect: true, shape: 'diamond', color: 'blue', reason: 'Correct because...' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data } = await request('POST', '/api/quizzes', multiQuiz, 201);
|
||||
const result = data as { id: string };
|
||||
multiQuizId = result.id;
|
||||
});
|
||||
|
||||
await test('GET /api/quizzes/:id returns all questions with correct order', async () => {
|
||||
if (!multiQuizId) throw new Error('No multi-question quiz created');
|
||||
const { data } = await request('GET', `/api/quizzes/${multiQuizId}`);
|
||||
const quiz = data as { questions: { text: string; timeLimit: number; options: { reason?: string }[] }[] };
|
||||
if (quiz.questions.length !== 3) throw new Error(`Expected 3 questions, got ${quiz.questions.length}`);
|
||||
if (quiz.questions[0].text !== 'Question 1?') throw new Error('Wrong order for Q1');
|
||||
if (quiz.questions[1].text !== 'Question 2?') throw new Error('Wrong order for Q2');
|
||||
if (quiz.questions[2].text !== 'Question 3?') throw new Error('Wrong order for Q3');
|
||||
if (quiz.questions[0].timeLimit !== 15) throw new Error('Wrong timeLimit for Q1');
|
||||
if (quiz.questions[2].options[1].reason !== 'Correct because...') throw new Error('Missing reason field');
|
||||
});
|
||||
|
||||
await test('GET /api/quizzes shows correct questionCount for multi-question quiz', async () => {
|
||||
const { data } = await request('GET', '/api/quizzes');
|
||||
const quizzes = data as Record<string, unknown>[];
|
||||
const quiz = quizzes.find((q) => q.id === multiQuizId);
|
||||
if (!quiz) throw new Error('Multi-question quiz not in list');
|
||||
if (quiz.questionCount !== 3) throw new Error(`Expected questionCount 3, got ${quiz.questionCount}`);
|
||||
});
|
||||
|
||||
await test('PUT /api/quizzes/:id replaces all questions', async () => {
|
||||
if (!multiQuizId) throw new Error('No multi-question quiz created');
|
||||
const updatedQuiz = {
|
||||
title: 'Updated Multi Quiz',
|
||||
questions: [
|
||||
{
|
||||
text: 'Only One Question Now',
|
||||
timeLimit: 10,
|
||||
options: [
|
||||
{ text: 'Solo', isCorrect: true, shape: 'triangle', color: 'red' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
await request('PUT', `/api/quizzes/${multiQuizId}`, updatedQuiz);
|
||||
const { data } = await request('GET', `/api/quizzes/${multiQuizId}`);
|
||||
const quiz = data as { title: string; questions: unknown[] };
|
||||
if (quiz.title !== 'Updated Multi Quiz') throw new Error('Title not updated');
|
||||
if (quiz.questions.length !== 1) throw new Error(`Expected 1 question after update, got ${quiz.questions.length}`);
|
||||
});
|
||||
|
||||
await test('DELETE cleanup multi-question quiz', async () => {
|
||||
if (!multiQuizId) throw new Error('No multi-question quiz to delete');
|
||||
await request('DELETE', `/api/quizzes/${multiQuizId}`, undefined, 204);
|
||||
});
|
||||
|
||||
console.log('\nTimestamp Tests:');
|
||||
let timestampQuizId: string | null = null;
|
||||
|
||||
await test('POST /api/quizzes returns quiz with timestamps', async () => {
|
||||
const quiz = {
|
||||
title: 'Timestamp Test Quiz',
|
||||
source: 'manual',
|
||||
questions: [
|
||||
{
|
||||
text: 'Timestamp Q?',
|
||||
options: [{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data: createData } = await request('POST', '/api/quizzes', quiz, 201);
|
||||
timestampQuizId = (createData as { id: string }).id;
|
||||
|
||||
const { data } = await request('GET', `/api/quizzes/${timestampQuizId}`);
|
||||
const result = data as Record<string, unknown>;
|
||||
if (!result.createdAt) throw new Error('Missing createdAt');
|
||||
if (!result.updatedAt) throw new Error('Missing updatedAt');
|
||||
});
|
||||
|
||||
await test('PUT /api/quizzes/:id updates updatedAt timestamp', async () => {
|
||||
if (!timestampQuizId) throw new Error('No timestamp quiz created');
|
||||
|
||||
const { data: beforeData } = await request('GET', `/api/quizzes/${timestampQuizId}`);
|
||||
const beforeUpdatedAt = (beforeData as Record<string, unknown>).updatedAt;
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1100));
|
||||
|
||||
await request('PUT', `/api/quizzes/${timestampQuizId}`, {
|
||||
title: 'Updated Timestamp Quiz',
|
||||
questions: [
|
||||
{
|
||||
text: 'Updated Q?',
|
||||
options: [{ text: 'B', isCorrect: true, shape: 'diamond', color: 'blue' }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { data: afterData } = await request('GET', `/api/quizzes/${timestampQuizId}`);
|
||||
const afterUpdatedAt = (afterData as Record<string, unknown>).updatedAt;
|
||||
|
||||
if (beforeUpdatedAt === afterUpdatedAt) throw new Error('updatedAt should have changed');
|
||||
});
|
||||
|
||||
await test('DELETE cleanup timestamp quiz', async () => {
|
||||
if (!timestampQuizId) throw new Error('No timestamp quiz to delete');
|
||||
await request('DELETE', `/api/quizzes/${timestampQuizId}`, undefined, 204);
|
||||
});
|
||||
|
||||
console.log('\n=== Results ===');
|
||||
const passed = results.filter((r) => r.passed).length;
|
||||
const failed = results.filter((r) => !r.passed).length;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue