Add tests and edit works

This commit is contained in:
Joey Yakimowich-Payne 2026-01-13 23:52:04 -07:00
commit bc4b0e2df7
No known key found for this signature in database
GPG key ID: 6BFE655FA5ABD1E1
12 changed files with 2415 additions and 20 deletions

View file

@ -941,6 +941,322 @@ async function runTests() {
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
console.log('\nPUT Endpoint Edge Case Tests:');
await test('PUT /api/quizzes/:id with whitespace-only title returns 400', async () => {
const validQuiz = {
title: 'Quiz for PUT whitespace test',
source: 'manual',
questions: [
{
text: 'Question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const invalidUpdate = {
title: ' ',
questions: [
{
text: 'Q?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, invalidUpdate, 400);
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id with question without text returns 400', async () => {
const validQuiz = {
title: 'Quiz for PUT empty question test',
source: 'manual',
questions: [
{
text: 'Original question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const invalidUpdate = {
title: 'Updated title',
questions: [
{
text: '',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, invalidUpdate, 400);
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id with single option returns 400', async () => {
const validQuiz = {
title: 'Quiz for PUT single option test',
source: 'manual',
questions: [
{
text: 'Original question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const invalidUpdate = {
title: 'Updated title',
questions: [
{
text: 'Question with one option?',
options: [
{ text: 'Only one', isCorrect: true, shape: 'triangle', color: 'red' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, invalidUpdate, 400);
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id with no correct answer returns 400', async () => {
const validQuiz = {
title: 'Quiz for PUT no correct test',
source: 'manual',
questions: [
{
text: 'Original question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const invalidUpdate = {
title: 'Updated title',
questions: [
{
text: 'Question with no correct?',
options: [
{ text: 'A', isCorrect: false, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, invalidUpdate, 400);
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id with null questions returns 400', async () => {
const validQuiz = {
title: 'Quiz for PUT null questions test',
source: 'manual',
questions: [
{
text: 'Original question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const invalidUpdate = {
title: 'Updated title',
questions: null,
};
await request('PUT', `/api/quizzes/${quizId}`, invalidUpdate, 400);
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id preserves source and aiTopic', async () => {
const aiQuiz = {
title: 'AI Quiz for PUT preserve test',
source: 'ai_generated',
aiTopic: 'History',
questions: [
{
text: 'Original question?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', aiQuiz, 201);
const quizId = (data as { id: string }).id;
const update = {
title: 'Updated AI Quiz',
questions: [
{
text: 'New question?',
options: [
{ text: 'X', isCorrect: true, shape: 'circle', color: 'yellow' },
{ text: 'Y', isCorrect: false, shape: 'square', color: 'green' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, update);
const { data: getResult } = await request('GET', `/api/quizzes/${quizId}`);
const quiz = getResult as Record<string, unknown>;
if (quiz.source !== 'ai_generated') throw new Error('Source should be preserved');
if (quiz.aiTopic !== 'History') throw new Error('aiTopic should be preserved');
if (quiz.title !== 'Updated AI Quiz') throw new Error('Title should be updated');
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id on another users quiz returns 404', async () => {
const quiz = {
title: 'User isolation test',
questions: [
{
text: 'Q?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
await request('PUT', '/api/quizzes/non-existent-user-quiz-id', quiz, 404);
});
await test('PUT /api/quizzes/:id with many questions succeeds', async () => {
const validQuiz = {
title: 'Quiz for PUT many questions test',
source: 'manual',
questions: [
{
text: 'Original?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const manyQuestions = Array.from({ length: 30 }, (_, i) => ({
text: `Updated question ${i + 1}?`,
timeLimit: 15,
options: [
{ text: `A${i}`, isCorrect: true, shape: 'triangle', color: 'red' },
{ text: `B${i}`, isCorrect: false, shape: 'diamond', color: 'blue' },
],
}));
const update = {
title: 'Quiz with 30 questions',
questions: manyQuestions,
};
await request('PUT', `/api/quizzes/${quizId}`, update);
const { data: getResult } = await request('GET', `/api/quizzes/${quizId}`);
const quiz = getResult as { questions: unknown[] };
if (quiz.questions.length !== 30) {
throw new Error(`Expected 30 questions, got ${quiz.questions.length}`);
}
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
await test('PUT /api/quizzes/:id preserves reason fields in options', async () => {
const validQuiz = {
title: 'Quiz for PUT reason test',
source: 'manual',
questions: [
{
text: 'Original?',
options: [
{ text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
{ text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
],
},
],
};
const { data } = await request('POST', '/api/quizzes', validQuiz, 201);
const quizId = (data as { id: string }).id;
const updateWithReasons = {
title: 'Quiz with reasons',
questions: [
{
text: 'Why is the sky blue?',
options: [
{ text: 'Rayleigh scattering', isCorrect: true, shape: 'triangle', color: 'red', reason: 'Light scatters in atmosphere' },
{ text: 'Paint', isCorrect: false, shape: 'diamond', color: 'blue', reason: 'That is not how it works' },
],
},
],
};
await request('PUT', `/api/quizzes/${quizId}`, updateWithReasons);
const { data: getResult } = await request('GET', `/api/quizzes/${quizId}`);
const quiz = getResult as { questions: { options: { reason?: string }[] }[] };
const correctOpt = quiz.questions[0].options.find((o: any) => o.isCorrect);
if (correctOpt?.reason !== 'Light scatters in atmosphere') {
throw new Error('Reason not preserved on update');
}
await request('DELETE', `/api/quizzes/${quizId}`, undefined, 204);
});
console.log('\nPhase 6 - Duplicate/Idempotency Tests:');
await test('POST /api/quizzes with same data creates separate quizzes', async () => {