// @vitest-environment jsdom import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { saveAvatar, getAvatar, purgeLegacyHistory } from './storage'; const LEGACY_HISTORY_KEY = 'aisthetix-history'; const AVATAR_KEY = 'aisthetix-avatar'; /** * jsdom non lascia intercettare Storage.prototype in modo affidabile, quindi * sostituisco l'intero localStorage con un finto che controllo: `pieno` decide * quando setItem deve comportarsi come una quota esaurita. */ function fintoStorage() { const dati = new Map(); const s = { pieno: false, getItem: ( k: string ) => ( dati.has( k ) ? dati.get( k )! : null ), setItem: ( k: string, v: string ) => { if ( s.pieno ) { const e = new Error( 'quota' ); e.name = 'QuotaExceededError'; throw e; } dati.set( k, v ); }, removeItem: ( k: string ) => { dati.delete( k ); }, clear: () => dati.clear(), }; return s; } let finto: ReturnType; const vero = globalThis.localStorage; beforeEach( () => { finto = fintoStorage(); Object.defineProperty( globalThis, 'localStorage', { value: finto, configurable: true } ); } ); afterEach( () => { Object.defineProperty( globalThis, 'localStorage', { value: vero, configurable: true } ); } ); describe( 'purgeLegacyHistory', () => { it( 'rimuove la chiave lasciata dalle versioni vecchie del widget', () => { finto.setItem( LEGACY_HISTORY_KEY, JSON.stringify( [ { resultImage: 'x' } ] ) ); expect( purgeLegacyHistory() ).toBe( true ); expect( finto.getItem( LEGACY_HISTORY_KEY ) ).toBeNull(); } ); it( 'non tocca nessun altra chiave e dice che non c era niente da togliere', () => { finto.setItem( AVATAR_KEY, 'tienimi' ); finto.setItem( 'aisthetix-visitor-id', 'anon_1' ); expect( purgeLegacyHistory() ).toBe( false ); expect( finto.getItem( AVATAR_KEY ) ).toBe( 'tienimi' ); expect( finto.getItem( 'aisthetix-visitor-id' ) ).toBe( 'anon_1' ); } ); } ); describe( 'saveAvatar con la quota esaurita', () => { it( 'butta la cronologia vecchia e riesce al secondo tentativo', () => { finto.setItem( LEGACY_HISTORY_KEY, 'un-vecchio-blob-enorme' ); finto.pieno = true; // Togliere la cronologia libera spazio: e' esattamente cio che succede // in un browser che si porta dietro megabyte di render mai letti. const rimuoviReale = finto.removeItem; finto.removeItem = ( k: string ) => { rimuoviReale( k ); if ( k === LEGACY_HISTORY_KEY ) { finto.pieno = false; } }; expect( () => saveAvatar( 'data:image/png;base64,AAAA' ) ).not.toThrow(); expect( finto.getItem( LEGACY_HISTORY_KEY ) ).toBeNull(); expect( getAvatar()?.imageData ).toBe( 'data:image/png;base64,AAAA' ); } ); it( 'segnala comunque il fallimento se non c e niente da recuperare', () => { finto.pieno = true; expect( () => saveAvatar( 'data:image/png;base64,AAAA' ) ).toThrow( /quota/i ); } ); } );