Class_generator/tests/utils/test-helpers.js
StillHammer cb614a439d Add comprehensive test suite with unit tests and integration tests
- Complete test infrastructure with runners, helpers, and fixtures
- Unit tests for core modules: EnvConfig, ContentScanner, GameLoader
- Integration tests for proxy, content loading, and navigation
- Edge case tests covering data corruption, network failures, security
- Stress tests with 100+ concurrent requests and performance monitoring
- Test fixtures with malicious content samples and edge case data
- Comprehensive README with usage instructions and troubleshooting

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-16 11:37:08 +08:00

203 lines
5.7 KiB
JavaScript

import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Helper pour créer un environnement DOM simulé
export function createMockDOM() {
// Mock global objects pour les tests
global.window = {
location: { protocol: 'http:', hostname: 'localhost', port: '8080' },
addEventListener: () => {},
dispatchEvent: () => {},
ContentModules: {},
GameModules: {},
fetch: async (url) => {
// Mock fetch pour les tests
if (url.includes('sbs-level-7-8-new.json')) {
return {
ok: true,
json: async () => ({
name: "SBS Level 7-8 (New)",
description: "Test content",
vocabulary: { "test": "test translation" }
})
};
}
throw new Error(`Mock fetch: URL not handled: ${url}`);
}
};
global.document = {
createElement: (tag) => ({
src: '',
onload: null,
onerror: null,
addEventListener: () => {}
}),
querySelector: () => null,
head: { appendChild: () => {} }
};
global.console = {
log: () => {},
warn: () => {},
error: () => {},
info: () => {},
debug: () => {}
};
// Mock pour logSh
global.logSh = (message, level = 'INFO') => {
// Silent dans les tests sauf si on veut debug
if (process.env.TEST_VERBOSE) {
console.log(`[TEST ${level}] ${message}`);
}
};
}
// Helper pour nettoyer l'environnement après tests
export function cleanupMockDOM() {
delete global.window;
delete global.document;
delete global.console;
delete global.logSh;
}
// Helper pour charger un fichier JS en tant que module dans les tests
export async function loadModuleForTest(relativePath) {
const fullPath = path.resolve(__dirname, '../../', relativePath);
// Lire le fichier et l'évaluer dans le contexte global
const code = readFileSync(fullPath, 'utf8');
// Remplacer les exports/require pour le navigateur
const browserCode = code
.replace(/export\s+default\s+/g, 'window.TestModule = ')
.replace(/export\s+\{([^}]+)\}/g, '')
.replace(/import\s+.*?from\s+['"].*?['"];?\s*/g, '');
// Évaluer dans le contexte global
eval(browserCode);
return global.window.TestModule;
}
// Helper pour créer des données de test
export function createTestContent() {
return {
name: "Test Content",
description: "Content pour les tests",
difficulty: "medium",
vocabulary: {
"hello": "bonjour",
"world": "monde",
"test": "test"
},
sentences: [
{
english: "Hello world",
chinese: "你好世界",
prononciation: "nǐ hǎo shì jiè"
}
]
};
}
// Helper pour simuler des requêtes réseau
export function createMockFetch(responses = {}) {
return async (url, options = {}) => {
if (responses[url]) {
const response = responses[url];
return {
ok: response.ok !== false,
status: response.status || 200,
json: async () => response.data,
text: async () => JSON.stringify(response.data)
};
}
// Réponse par défaut
return {
ok: false,
status: 404,
json: async () => ({ error: 'Not found in mock' }),
text: async () => 'Not found in mock'
};
};
}
// Helper pour attendre un délai
export function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Helper pour capturer les logs
export function createLogCapture() {
const logs = [];
const originalLogSh = global.logSh;
global.logSh = (message, level = 'INFO') => {
logs.push({ message, level, timestamp: Date.now() });
if (originalLogSh) originalLogSh(message, level);
};
return {
logs,
restore: () => {
global.logSh = originalLogSh;
},
getLogs: (level) => level ? logs.filter(l => l.level === level) : logs,
clear: () => logs.length = 0
};
}
// Helper pour les assertions personnalisées
export function assertContains(actual, expected, message) {
if (!actual.includes(expected)) {
throw new Error(message || `Expected "${actual}" to contain "${expected}"`);
}
}
export function assertInstanceOf(actual, expectedClass, message) {
if (!(actual instanceof expectedClass)) {
throw new Error(message || `Expected instance of ${expectedClass.name}, got ${actual.constructor.name}`);
}
}
// Helper pour mocquer les timers
export function createTimerMock() {
const timers = new Map();
let timerId = 1;
const originalSetTimeout = global.setTimeout;
const originalClearTimeout = global.clearTimeout;
global.setTimeout = (callback, delay) => {
const id = timerId++;
timers.set(id, { callback, delay, type: 'timeout' });
return id;
};
global.clearTimeout = (id) => {
timers.delete(id);
};
return {
tick: (ms) => {
for (const [id, timer] of timers.entries()) {
if (timer.delay <= ms) {
timer.callback();
timers.delete(id);
}
}
},
restore: () => {
global.setTimeout = originalSetTimeout;
global.clearTimeout = originalClearTimeout;
timers.clear();
}
};
}