import { test, describe, beforeEach, afterEach } from 'node:test'; import { strict as assert } from 'node:assert'; import { createMockDOM, cleanupMockDOM, createLogCapture } from '../utils/test-helpers.js'; // Tests d'edge cases simplifiés qui ne dépendent pas du chargement des modules describe('Edge Cases - Tests Simplifiés', () => { let logCapture; beforeEach(() => { createMockDOM(); logCapture = createLogCapture(); }); afterEach(() => { logCapture.restore(); cleanupMockDOM(); }); describe('Cas de Données Corrompues', () => { test('devrait gérer JSON malformé', async () => { const malformedJson = '{"name": "Incomplete JSON"'; try { JSON.parse(malformedJson); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error instanceof SyntaxError); assert.ok(error.message.includes('Unexpected')); } }); test('devrait gérer caractères Unicode', () => { const unicodeText = "Café naïve 🚀 测试 العربية"; assert.ok(typeof unicodeText === 'string'); assert.ok(unicodeText.length > 0); // Test JSON avec Unicode const jsonData = JSON.stringify({ text: unicodeText }); const parsed = JSON.parse(jsonData); assert.equal(parsed.text, unicodeText); }); test('devrait gérer références circulaires', () => { const obj = { name: "Test" }; obj.self = obj; try { JSON.stringify(obj); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('circular') || error.message.includes('Converting')); } }); test('devrait gérer objets très profonds', () => { let deepObj = {}; let current = deepObj; // Créer une structure profonde for (let i = 0; i < 1000; i++) { current.nested = { level: i }; current = current.nested; } // Vérifier que l'objet existe assert.ok(deepObj.nested); assert.equal(deepObj.nested.level, 0); }); }); describe('Cas de Réseau et Fetch', () => { test('devrait gérer fetch inexistant', async () => { const originalFetch = global.fetch; delete global.fetch; try { await fetch('http://test.com'); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('fetch is not defined') || error.name === 'ReferenceError'); } finally { global.fetch = originalFetch; } }); test('devrait gérer timeouts de réseau', async () => { global.fetch = async () => { await new Promise(resolve => setTimeout(resolve, 100)); throw new Error('Network timeout'); }; try { await fetch('http://test.com'); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('timeout') || error.message.includes('Network')); } }); test('devrait gérer réponses HTTP malformées', async () => { global.fetch = async () => ({ ok: false, status: 999, // Code de statut invalide json: async () => { throw new Error('Invalid JSON response'); } }); const response = await fetch('http://test.com'); assert.equal(response.ok, false); assert.equal(response.status, 999); try { await response.json(); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('Invalid JSON')); } }); }); describe('Cas de Mémoire et Performance', () => { test('devrait gérer grandes quantités de données', () => { const largeArray = new Array(100000).fill('test'); assert.equal(largeArray.length, 100000); assert.equal(largeArray[0], 'test'); assert.equal(largeArray[99999], 'test'); }); test('devrait nettoyer variables après utilisation', () => { let testVar = { data: new Array(1000).fill('test') }; assert.ok(testVar.data); testVar = null; assert.equal(testVar, null); }); test('devrait gérer calculs intensifs', () => { const startTime = Date.now(); // Calcul qui prend du temps let result = 0; for (let i = 0; i < 100000; i++) { result += Math.sqrt(i); } const endTime = Date.now(); assert.ok(result > 0); assert.ok(endTime - startTime < 5000); // Moins de 5 secondes }); }); describe('Cas de Compatibilité API', () => { test('devrait détecter localStorage manquant', () => { const originalLocalStorage = global.localStorage; delete global.localStorage; try { localStorage.setItem('test', 'value'); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('localStorage is not defined')); } finally { global.localStorage = originalLocalStorage; } }); test('devrait détecter crypto manquant', () => { const originalCrypto = global.crypto; delete global.crypto; try { crypto.subtle.digest('SHA-256', new Uint8Array()); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('crypto is not defined')); } finally { global.crypto = originalCrypto; } }); test('devrait détecter URLSearchParams manquant', () => { const originalURLSearchParams = global.URLSearchParams; delete global.URLSearchParams; try { new URLSearchParams('test=value'); assert.fail('Should have thrown an error'); } catch (error) { assert.ok(error.message.includes('URLSearchParams is not defined')); } finally { global.URLSearchParams = originalURLSearchParams; } }); }); describe('Cas de Sécurité', () => { test('devrait rejeter tentatives XSS', () => { const maliciousInput = ''; // Test d'échappement HTML basique const escaped = maliciousInput .replace(//g, '>'); assert.equal(escaped, '<script>alert("xss")</script>'); assert.ok(!escaped.includes('', 'file:///etc/passwd' ]; for (const url of invalidUrls) { try { new URL(url); // Si c'est une URL valide selon le browser, vérifier le protocole const urlObj = new URL(url); assert.ok(['http:', 'https:'].includes(urlObj.protocol), `Invalid protocol: ${urlObj.protocol}`); } catch (error) { // URLs invalides - c'est normal qu'elles échouent assert.ok(error instanceof TypeError); } } }); test('devrait limiter profondeur d'objets', () => { function checkDepth(obj, maxDepth = 100, currentDepth = 0) { if (currentDepth > maxDepth) { throw new Error('Object too deep'); } if (typeof obj === 'object' && obj !== null) { for (const key in obj) { if (obj.hasOwnProperty(key)) { checkDepth(obj[key], maxDepth, currentDepth + 1); } } } } // Objet normal - devrait passer const normalObj = { a: { b: { c: 'value' } } }; assert.doesNotThrow(() => checkDepth(normalObj)); // Objet trop profond - devrait échouer let deepObj = {}; let current = deepObj; for (let i = 0; i < 150; i++) { current.nested = {}; current = current.nested; } assert.throws(() => checkDepth(deepObj), /Object too deep/); }); }); describe('Cas de Concurrence', () => { test('devrait gérer Promises simultanées', async () => { const promises = []; for (let i = 0; i < 10; i++) { promises.push( new Promise(resolve => setTimeout(() => resolve(i), Math.random() * 50) ) ); } const results = await Promise.all(promises); assert.equal(results.length, 10); assert.ok(results.includes(0)); assert.ok(results.includes(9)); }); test('devrait gérer race conditions', async () => { let counter = 0; const incrementer = async () => { const current = counter; await new Promise(resolve => setTimeout(resolve, 1)); counter = current + 1; }; // Lancer plusieurs incréments en parallèle const promises = Array(5).fill().map(() => incrementer()); await Promise.all(promises); // Le résultat peut varier selon les race conditions assert.ok(counter >= 1 && counter <= 5); }); }); describe('Cas de Données Extrêmes', () => { test('devrait gérer chaînes très longues', () => { const longString = 'x'.repeat(1000000); // 1MB de texte assert.equal(longString.length, 1000000); assert.equal(longString[0], 'x'); assert.equal(longString[999999], 'x'); }); test('devrait gérer nombres en limite de précision', () => { const maxSafeInt = Number.MAX_SAFE_INTEGER; const beyondMax = maxSafeInt + 1; assert.equal(maxSafeInt, 9007199254740991); assert.notEqual(beyondMax - 1, maxSafeInt); // Perte de précision }); test('devrait gérer tableaux très volumineux', () => { const largeArray = new Array(1000000); largeArray.fill(42); assert.equal(largeArray.length, 1000000); assert.equal(largeArray[0], 42); assert.equal(largeArray[999999], 42); // Test de performance - devrait être rapide const startTime = Date.now(); const sum = largeArray.reduce((acc, val) => acc + val, 0); const endTime = Date.now(); assert.equal(sum, 42000000); assert.ok(endTime - startTime < 1000); // Moins d'1 seconde }); }); });