feat(web): infra IDE réutilisable (persisted-ref, splitter, bootstrap temps réel)
Extrait persistedRef dans lib/persisted-ref.ts (partagé, testable en node). Ajoute useSplitter + components/ide/PanelSplitter.vue (poignée de resize générique par pointer events, largeur/hauteur persistable), généralisant le resize souris de WorkspaceView. Hisse le chargement initial et les abonnements temps réel dans useRealtimeBootstrap (monté par App.vue) : un seul propriétaire actif sur TOUS les layouts, y compris la vue IDE plein écran. AppShell et WorkspaceView n'en portent plus la responsabilité. Tests unitaires persisted-ref et useSplitter (10).
This commit is contained in:
47
packages/web/test/persisted-ref.test.ts
Normal file
47
packages/web/test/persisted-ref.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
// persistedRef : lecture initiale depuis localStorage, repli sur défaut, réécriture, robustesse.
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { nextTick } from 'vue';
|
||||
import { persistedRef } from '../src/lib/persisted-ref';
|
||||
|
||||
function fakeStorage() {
|
||||
const m = new Map<string, string>();
|
||||
return {
|
||||
getItem: (k: string) => (m.has(k) ? (m.get(k) as string) : null),
|
||||
setItem: (k: string, v: string) => void m.set(k, v),
|
||||
removeItem: (k: string) => void m.delete(k),
|
||||
clear: () => m.clear(),
|
||||
};
|
||||
}
|
||||
|
||||
describe('persistedRef', () => {
|
||||
beforeEach(() => {
|
||||
(globalThis as unknown as { localStorage: unknown }).localStorage = fakeStorage();
|
||||
});
|
||||
|
||||
it('lit la valeur initiale depuis localStorage si présente', () => {
|
||||
localStorage.setItem('k', JSON.stringify(42));
|
||||
expect(persistedRef('k', 0).value).toBe(42);
|
||||
});
|
||||
|
||||
it('retombe sur le défaut si la clé est absente', () => {
|
||||
expect(persistedRef('missing', 7).value).toBe(7);
|
||||
});
|
||||
|
||||
it('retombe sur le défaut si le JSON est corrompu', () => {
|
||||
localStorage.setItem('bad', '{not json');
|
||||
expect(persistedRef('bad', 'def').value).toBe('def');
|
||||
});
|
||||
|
||||
it('réécrit en localStorage au changement', async () => {
|
||||
const r = persistedRef('w', 1);
|
||||
r.value = 99;
|
||||
await nextTick();
|
||||
expect(JSON.parse(localStorage.getItem('w') as string)).toBe(99);
|
||||
});
|
||||
|
||||
it('ne jette pas si localStorage est absent (env node sans DOM)', () => {
|
||||
delete (globalThis as unknown as { localStorage?: unknown }).localStorage;
|
||||
expect(() => persistedRef('x', 5)).not.toThrow();
|
||||
expect(persistedRef('x', 5).value).toBe(5);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user