feat: enhance testing framework with new test cases and configurations
Test / backend (push) Failing after 9s
Test / frontend (push) Failing after 14s

This commit is contained in:
LaurensBartelds committed 2026-04-26 21:45:02 +02:00
1 parent a37c093cc4
commit ef8fe6f938
18 files changed
+793 -6

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
import { describe, it, expect } from 'vitest'
import { ApiError } from './api'
describe('ApiError', () => {
it('extends Error', () => {
const err = new ApiError(404, 'Not found')
expect(err).toBeInstanceOf(Error)
})
it('sets status and message', () => {
const err = new ApiError(500, 'Server error')
expect(err.status).toBe(500)
expect(err.message).toBe('Server error')
})
it('sets name to ApiError', () => {
const err = new ApiError(401, 'Unauthorized')
expect(err.name).toBe('ApiError')
})
})
+29 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest'
import { slugify } from './slug'
import { slugify, getExamUrlId, extractExamSlug } from './slug'
describe('slugify', () => {
it('lowercases', () => {
@@ -24,3 +24,31 @@ describe('slugify', () => {
expect(slugify('')).toBe('')
})
})
describe('getExamUrlId', () => {
it('returns slug with id when id exists', () => {
expect(getExamUrlId({ id: 'abc12345', title: 'My Exam' })).toBe('my-exam-abc12345')
})
it('returns slug only when id is missing', () => {
expect(getExamUrlId({ title: 'My Exam' })).toBe('my-exam')
})
})
describe('extractExamSlug', () => {
it('extracts slug from slug-id format', () => {
expect(extractExamSlug('my-exam-abc12345')).toBe('my-exam')
})
it('returns full string when no dash', () => {
expect(extractExamSlug('myexam')).toBe('myexam')
})
it('returns full string when suffix is too short to be an id', () => {
expect(extractExamSlug('my-exam-abc')).toBe('my-exam-abc')
})
it('handles slug with multiple dashes', () => {
expect(extractExamSlug('my-cool-exam-abc12345678')).toBe('my-cool-exam')
})
})
+65
View File
@@ -0,0 +1,65 @@
import { describe, it, expect, beforeEach } from 'vitest'
import { loadState, saveState, clearState, loadHistory, appendHistory, clearHistory } from './storage'
const storage: Record<string, string> = {}
beforeEach(() => {
Object.keys(storage).forEach((k) => delete storage[k])
globalThis.localStorage = {
getItem: (key: string) => storage[key] ?? null,
setItem: (key: string, value: string) => { storage[key] = value },
removeItem: (key: string) => { delete storage[key] },
length: 0,
key: () => null,
clear: () => { Object.keys(storage).forEach((k) => delete storage[k]) },
} as Storage
})
describe('loadState / saveState / clearState', () => {
it('returns null when nothing saved', () => {
expect(loadState()).toBeNull()
})
it('returns saved state', () => {
const data = { exam: { id: '1', title: 'E', questions: [] }, state: { currentIdx: 0, answers: {}, flags: {}, notes: '', startedAt: Date.now(), feedbackMode: 'end' as const } }
saveState(data)
expect(loadState()).toEqual(data)
})
it('clears saved state', () => {
saveState({ exam: { id: '1', title: 'E', questions: [] }, state: { currentIdx: 0, answers: {}, flags: {}, notes: '', startedAt: Date.now(), feedbackMode: 'end' as const } })
clearState()
expect(loadState()).toBeNull()
})
it('returns null for corrupted json', () => {
localStorage.setItem('brainwave.exam.state', 'not-json')
expect(loadState()).toBeNull()
})
})
describe('loadHistory / appendHistory / clearHistory', () => {
it('returns empty array when nothing saved', () => {
expect(loadHistory()).toEqual([])
})
it('appends entries and limits to 30', () => {
for (let i = 0; i < 35; i++) {
appendHistory({ id: String(i), title: `Exam ${i}`, completedAt: Date.now(), elapsedMs: 0, gradedCount: 10, correctCount: i, totalPoints: 10, scorePoints: i, passingScore: 5, exam: { title: `Exam ${i}`, questions: [] }, state: { currentIdx: 0, answers: {}, flags: {}, notes: '', startedAt: Date.now(), feedbackMode: 'end' as const } })
}
const hist = loadHistory()
expect(hist.length).toBe(30)
expect(hist[0].id).toBe('34')
})
it('clears history', () => {
appendHistory({ id: '1', title: 'E', completedAt: Date.now(), elapsedMs: 0, gradedCount: 1, correctCount: 1, totalPoints: 1, scorePoints: 1, passingScore: 1, exam: { title: 'E', questions: [] }, state: { currentIdx: 0, answers: {}, flags: {}, notes: '', startedAt: Date.now(), feedbackMode: 'end' as const } })
clearHistory()
expect(loadHistory()).toEqual([])
})
it('returns empty array for corrupted json', () => {
localStorage.setItem('brainwave.exam.history', 'not-json')
expect(loadHistory()).toEqual([])
})
})
+51
View File
@@ -0,0 +1,51 @@
import { describe, it, expect } from 'vitest'
import { validateExam, parseExam } from './validation'
describe('validateExam', () => {
it('returns error for non-object', () => {
expect(validateExam(null)).toBe('Not a JSON object')
expect(validateExam('string')).toBe('Not a JSON object')
expect(validateExam(123)).toBe('Not a JSON object')
})
it('returns error for missing title', () => {
expect(validateExam({ questions: [] })).toBe('Missing "title"')
})
it('returns error for missing questions array', () => {
expect(validateExam({ title: 'Exam' })).toBe('Missing "questions" array')
})
it('returns error for empty questions array', () => {
expect(validateExam({ title: 'Exam', questions: [] })).toBe('Missing "questions" array')
})
it('returns error for question missing id', () => {
expect(validateExam({ title: 'Exam', questions: [{ type: 'essay', prompt: 'Q' }] })).toBe('Question missing id')
})
it('returns error for question missing type', () => {
expect(validateExam({ title: 'Exam', questions: [{ id: '1', prompt: 'Q' }] })).toBe('Question "1" missing type')
})
it('returns error for question missing prompt', () => {
expect(validateExam({ title: 'Exam', questions: [{ id: '1', type: 'essay' }] })).toBe('Question "1" missing prompt')
})
it('returns null for valid exam', () => {
expect(validateExam({ title: 'Exam', questions: [{ id: '1', type: 'essay', prompt: 'Q' }] })).toBe(null)
})
})
describe('parseExam', () => {
it('generates id when missing', () => {
const exam = parseExam({ title: 'T', questions: [] })
expect(exam.id).toBeTruthy()
expect(typeof exam.id).toBe('string')
})
it('preserves existing id', () => {
const exam = parseExam({ id: 'abc123', title: 'T', questions: [] })
expect(exam.id).toBe('abc123')
})
})