-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_frontend.js
More file actions
358 lines (301 loc) · 11.8 KB
/
test_frontend.js
File metadata and controls
358 lines (301 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/**
* Frontend JavaScript Tests for Quiz Application
* Tests timer functionality, category selection, and UI interactions
*/
// Mock DOM elements for testing
class MockElement {
constructor(id) {
this.id = id;
this.innerHTML = '';
this.textContent = '';
this.style = {};
this.classList = {
add: () => {},
remove: () => {},
contains: () => false
};
this.onclick = null;
this.disabled = false;
}
addEventListener(event, callback) {
this[`on${event}`] = callback;
}
click() {
if (this.onclick) this.onclick();
}
}
// Mock document object
const mockDocument = {
getElementById: (id) => new MockElement(id),
querySelectorAll: () => [],
createElement: (tag) => new MockElement(tag)
};
// Mock window object
const mockWindow = {
location: { href: '' },
fetch: async (url, options) => ({
ok: true,
json: async () => ({ session_id: 'test-session', category: 'general' })
})
};
// Test Suite for Timer Functionality
class TimerTests {
constructor() {
this.passed = 0;
this.failed = 0;
this.tests = [];
}
assert(condition, message) {
if (condition) {
this.passed++;
console.log(`✓ ${message}`);
} else {
this.failed++;
console.error(`✗ ${message}`);
}
this.tests.push({ passed: condition, message });
}
// Test timer initialization
testTimerInitialization() {
console.log('\n--- Testing Timer Initialization ---');
// Mock timer variables
let timerInterval = null;
let startTime = null;
let elapsedTime = 0;
let isPaused = false;
// Test initial state
this.assert(timerInterval === null, 'Timer interval should be null initially');
this.assert(startTime === null, 'Start time should be null initially');
this.assert(elapsedTime === 0, 'Elapsed time should be 0 initially');
this.assert(isPaused === false, 'Timer should not be paused initially');
}
// Test timer start functionality
testTimerStart() {
console.log('\n--- Testing Timer Start ---');
let timerStarted = false;
let startTime = null;
// Mock startTimer function
function startTimer() {
if (!timerStarted) {
startTime = Date.now();
timerStarted = true;
return true;
}
return false;
}
const result = startTimer();
this.assert(result === true, 'Timer should start successfully');
this.assert(timerStarted === true, 'Timer started flag should be set');
this.assert(startTime !== null, 'Start time should be recorded');
// Test that timer cannot be started twice
const secondStart = startTimer();
this.assert(secondStart === false, 'Timer should not start if already running');
}
// Test timer pause functionality
testTimerPause() {
console.log('\n--- Testing Timer Pause/Resume ---');
let isPaused = false;
let pauseTime = 0;
// Mock pauseTimer function
function pauseTimer() {
if (!isPaused) {
isPaused = true;
pauseTime = Date.now();
return 'paused';
} else {
isPaused = false;
return 'resumed';
}
}
const pauseResult = pauseTimer();
this.assert(pauseResult === 'paused', 'Timer should pause successfully');
this.assert(isPaused === true, 'Paused flag should be set');
const resumeResult = pauseTimer();
this.assert(resumeResult === 'resumed', 'Timer should resume successfully');
this.assert(isPaused === false, 'Paused flag should be cleared on resume');
}
// Test timer color warnings
testTimerColorWarnings() {
console.log('\n--- Testing Timer Color Warnings ---');
function getTimerColor(seconds) {
if (seconds >= 600) { // 10 minutes
return 'red';
} else if (seconds >= 300) { // 5 minutes
return 'yellow';
} else {
return 'green';
}
}
this.assert(getTimerColor(120) === 'green', 'Timer should be green under 5 minutes');
this.assert(getTimerColor(360) === 'yellow', 'Timer should be yellow between 5-10 minutes');
this.assert(getTimerColor(720) === 'red', 'Timer should be red over 10 minutes');
}
// Test time formatting
testTimeFormatting() {
console.log('\n--- Testing Time Formatting ---');
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
this.assert(formatTime(65) === '01:05', 'Should format 65 seconds as 01:05');
this.assert(formatTime(3661) === '61:01', 'Should format 3661 seconds as 61:01');
this.assert(formatTime(0) === '00:00', 'Should format 0 seconds as 00:00');
}
}
// Test Suite for Category Selection
class CategoryTests {
constructor() {
this.passed = 0;
this.failed = 0;
this.tests = [];
}
assert(condition, message) {
if (condition) {
this.passed++;
console.log(`✓ ${message}`);
} else {
this.failed++;
console.error(`✗ ${message}`);
}
this.tests.push({ passed: condition, message });
}
// Test category parameter generation
testCategoryParameters() {
console.log('\n--- Testing Category Parameters ---');
function getCategoryParam(category) {
switch(category) {
case 'general':
return 'general';
case 'pspo1':
return 'PSPO1';
case 'nursing':
return 'Verpleegkundig Rekenen';
default:
return 'general';
}
}
this.assert(getCategoryParam('general') === 'general', 'General category should map correctly');
this.assert(getCategoryParam('pspo1') === 'PSPO1', 'PSPO1 category should map correctly');
this.assert(getCategoryParam('nursing') === 'Verpleegkundig Rekenen', 'Nursing category should map correctly');
this.assert(getCategoryParam('invalid') === 'general', 'Invalid category should default to general');
}
// Test API URL construction
testAPIURLConstruction() {
console.log('\n--- Testing API URL Construction ---');
function buildStartURL(category) {
const baseURL = '/api/start';
if (category) {
return `${baseURL}?category=${encodeURIComponent(category)}`;
}
return baseURL;
}
const generalURL = buildStartURL('general');
this.assert(generalURL === '/api/start?category=general', 'General URL should be constructed correctly');
const nursingURL = buildStartURL('Verpleegkundig Rekenen');
this.assert(nursingURL.includes('Verpleegkundig%20Rekenen'), 'Nursing URL should be URL-encoded');
const noCategory = buildStartURL(null);
this.assert(noCategory === '/api/start', 'URL without category should be base URL');
}
}
// Test Suite for UI Interactions
class UITests {
constructor() {
this.passed = 0;
this.failed = 0;
this.tests = [];
}
assert(condition, message) {
if (condition) {
this.passed++;
console.log(`✓ ${message}`);
} else {
this.failed++;
console.error(`✗ ${message}`);
}
this.tests.push({ passed: condition, message });
}
// Test button state management
testButtonStates() {
console.log('\n--- Testing Button State Management ---');
const mockButton = new MockElement('test-button');
function disableButton(button) {
button.disabled = true;
button.textContent = 'Loading...';
}
function enableButton(button, text) {
button.disabled = false;
button.textContent = text;
}
disableButton(mockButton);
this.assert(mockButton.disabled === true, 'Button should be disabled');
this.assert(mockButton.textContent === 'Loading...', 'Button text should show loading');
enableButton(mockButton, 'Start Quiz');
this.assert(mockButton.disabled === false, 'Button should be enabled');
this.assert(mockButton.textContent === 'Start Quiz', 'Button text should be restored');
}
// Test quiz progress tracking
testQuizProgress() {
console.log('\n--- Testing Quiz Progress ---');
function updateProgress(current, total) {
const percentage = Math.round((current / total) * 100);
return {
percentage,
text: `Vraag ${current} van ${total}`,
isComplete: current >= total
};
}
const progress1 = updateProgress(5, 20);
this.assert(progress1.percentage === 25, 'Progress should be 25% for question 5 of 20');
this.assert(progress1.text === 'Vraag 5 van 20', 'Progress text should be formatted correctly');
this.assert(progress1.isComplete === false, 'Quiz should not be complete');
const progress2 = updateProgress(20, 20);
this.assert(progress2.percentage === 100, 'Progress should be 100% when complete');
this.assert(progress2.isComplete === true, 'Quiz should be complete');
}
}
// Test Runner
class TestRunner {
static runAllTests() {
console.log('🧪 Starting Frontend JavaScript Tests...\n');
const timerTests = new TimerTests();
const categoryTests = new CategoryTests();
const uiTests = new UITests();
// Run timer tests
timerTests.testTimerInitialization();
timerTests.testTimerStart();
timerTests.testTimerPause();
timerTests.testTimerColorWarnings();
timerTests.testTimeFormatting();
// Run category tests
categoryTests.testCategoryParameters();
categoryTests.testAPIURLConstruction();
// Run UI tests
uiTests.testButtonStates();
uiTests.testQuizProgress();
// Summarize results
const totalPassed = timerTests.passed + categoryTests.passed + uiTests.passed;
const totalFailed = timerTests.failed + categoryTests.failed + uiTests.failed;
const totalTests = totalPassed + totalFailed;
console.log('\n📊 Test Results Summary:');
console.log(`✓ Passed: ${totalPassed}/${totalTests}`);
console.log(`✗ Failed: ${totalFailed}/${totalTests}`);
console.log(`📈 Success Rate: ${Math.round((totalPassed/totalTests)*100)}%`);
if (totalFailed === 0) {
console.log('\n🎉 All tests passed!');
return true;
} else {
console.log('\n❌ Some tests failed. Please review the failures above.');
return false;
}
}
}
// Export for Node.js testing or run directly in browser
if (typeof module !== 'undefined' && module.exports) {
module.exports = { TestRunner, TimerTests, CategoryTests, UITests };
} else {
// Run tests if in browser
document.addEventListener('DOMContentLoaded', () => {
TestRunner.runAllTests();
});
}