dd-timer/tests/unit/infrastructure/ImportValidation.test.ts
POL Mickaël 8af626dd66 sécurité: audit commercialisation — hardening + 366 tests (24 E2E)
Sandbox Electron, HTTPS ntfy, validation import structurelle,
suppression executeJavaScript, nettoyage memory leaks, try/catch
sur tous les appels electronAPI. 27 nouveaux tests de sécurité
et validation. README mis à jour avec changelog et couverture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 07:18:28 +02:00

118 lines
3.4 KiB
TypeScript

import { describe, it, expect } from 'vitest';
/**
* Tests de validation structurelle des imports.
* Vérifie que les données importées sont conformes au schéma attendu.
*/
// Réplique de la logique de validation de ParametresView
function validateEnclosData(data: any): boolean {
if (!data || typeof data !== 'object' || data === null) return false;
if (!Array.isArray(data.enclos)) return false;
return data.enclos.every((enc: any) =>
enc && typeof enc === 'object' &&
typeof enc.id === 'number' &&
typeof enc.name === 'string' &&
Array.isArray(enc.dragodindes) &&
enc.gaugeLevels && typeof enc.gaugeLevels === 'object' &&
enc.timer && typeof enc.timer === 'object',
);
}
describe('Validation import — validateEnclosData', () => {
it('accepte un state valide', () => {
const data = {
enclos: [{
id: 1, name: 'Enclos 1',
dragodindes: [],
gaugeLevels: { baffeur: 0 },
timer: { running: false },
}],
};
expect(validateEnclosData(data)).toBe(true);
});
it('accepte un state avec plusieurs enclos', () => {
const data = {
enclos: [
{ id: 1, name: 'A', dragodindes: [], gaugeLevels: {}, timer: {} },
{ id: 2, name: 'B', dragodindes: [{ id: 1 }], gaugeLevels: {}, timer: {} },
],
};
expect(validateEnclosData(data)).toBe(true);
});
it('rejette null', () => {
expect(validateEnclosData(null)).toBe(false);
});
it('rejette undefined', () => {
expect(validateEnclosData(undefined)).toBe(false);
});
it('rejette une chaîne', () => {
expect(validateEnclosData('hello')).toBe(false);
});
it('rejette un objet sans enclos', () => {
expect(validateEnclosData({ foo: 'bar' })).toBe(false);
});
it('rejette enclos non-array', () => {
expect(validateEnclosData({ enclos: 'not array' })).toBe(false);
});
it('rejette enclos avec id manquant', () => {
const data = {
enclos: [{ name: 'A', dragodindes: [], gaugeLevels: {}, timer: {} }],
};
expect(validateEnclosData(data)).toBe(false);
});
it('rejette enclos avec name non-string', () => {
const data = {
enclos: [{ id: 1, name: 123, dragodindes: [], gaugeLevels: {}, timer: {} }],
};
expect(validateEnclosData(data)).toBe(false);
});
it('rejette enclos sans dragodindes', () => {
const data = {
enclos: [{ id: 1, name: 'A', gaugeLevels: {}, timer: {} }],
};
expect(validateEnclosData(data)).toBe(false);
});
it('rejette enclos sans gaugeLevels', () => {
const data = {
enclos: [{ id: 1, name: 'A', dragodindes: [], timer: {} }],
};
expect(validateEnclosData(data)).toBe(false);
});
it('rejette enclos sans timer', () => {
const data = {
enclos: [{ id: 1, name: 'A', dragodindes: [], gaugeLevels: {} }],
};
expect(validateEnclosData(data)).toBe(false);
});
it('rejette si un seul enclos est invalide dans le tableau', () => {
const data = {
enclos: [
{ id: 1, name: 'A', dragodindes: [], gaugeLevels: {}, timer: {} },
{ id: 'bad' }, // invalide
],
};
expect(validateEnclosData(data)).toBe(false);
});
it('accepte un tableau enclos vide', () => {
expect(validateEnclosData({ enclos: [] })).toBe(true);
});
it('rejette un objet backup avec data: null', () => {
expect(validateEnclosData({ app: 'minuteur-dragodinde', data: null })).toBe(false);
});
});