107f9d1633
La correction de nomenclature du 2026-07-30 — en amont un *wallet* n'est qu'un trousseau, ce qui possède des stores est un **user** (un *site*) — s'était faite à la main. `walletInbox` y a échappé et a vécu des semaines, en faisant des dégâts : le nom rendait « une inbox par wallet » évident, masquant qu'un user en a **deux** en amont (repos de store public et protected, les deux seuls `AddInboxCap` du moteur). Une discipline appliquée à la main en oublie un ; un test non. D'où `test/vocabulary.test.ts` : tout nom publié est bâti sur des mots que la CIBLE emploie — vérifiés dans `nextgraph-rs` — ou porte un marqueur disant POURQUOI il n'existe qu'ici (`virtual`, `physical`, `shim`, `emulated`, `polyfill`), ce qui dit aussi quand il disparaît. Un échec n'est pas « renommer pour faire passer le test », c'est une question : la cible a-t-elle un mot pour ça ? la chose n'existe-t-elle qu'ici ? le mot est-il vraiment de la glue ? Ce que le test a trouvé, et les réponses : - `walletInbox` → `userInbox`, avec l'écart de cardinalité écrit noir sur blanc plutôt que caché par le nom. - `accounts` / `AccountRecord` / `AccountStorage` → `virtualUsers` / `VirtualUserRecord` / `VirtualUserStorage`, module `accounts.ts` → `virtual-users.ts`. « account » n'est pas de la cible : c'est notre mot pour l'utilisateur virtuel, et le marqueur le dit désormais. - `readModel` → la fonction `readUnion`, exposée directement. « model » n'était ni de la cible ni de la glue, et le namespace ne tenait qu'une fonction. - Le reste était du vocabulaire légitime à déclarer (`subject`, `base`, `schema`, `connected`, le modèle réactif de l'ORM). Corrigé au passage, sur signalement du contrat interne : l'en-tête d'`open-repo` justifiait son correctif par un mécanisme que le source contredit. Un repo absent de `self.repos` lève bien `RepoNotFound` (`engine/verifier/src/request_processor.rs:264,269`). Les 0 lignes observées viennent d'ailleurs — `Verifier::load` repeuple `self.repos` depuis le stockage sur un profil persistant (`verifier.rs:535-560`), et notre propre `readDoc` attrape toute erreur et rend `[]`. Le correctif est bon, le diagnostic écrit à côté ne l'était pas. 159 tests unitaires, typecheck src/test/e2e vert, e2e 40/40 contre le broker.
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import {
|
|
IdentityStore,
|
|
browserIdentityStore,
|
|
ACCOUNT_STORAGE_KEY,
|
|
type VirtualUserStorage,
|
|
} from "../src/shared-wallet/virtual-users";
|
|
|
|
// In-memory fake of the Storage subset — keeps this framework/DOM-agnostic.
|
|
function fakeStorage(): VirtualUserStorage & { map: Map<string, string> } {
|
|
const map = new Map<string, string>();
|
|
return {
|
|
map,
|
|
getItem: (k) => (map.has(k) ? (map.get(k) as string) : null),
|
|
setItem: (k, v) => void map.set(k, v),
|
|
removeItem: (k) => void map.delete(k),
|
|
};
|
|
}
|
|
|
|
test("IdentityStore: set persists a trimmed id, get reads it back", () => {
|
|
const s = fakeStorage();
|
|
const store = new IdentityStore(s);
|
|
expect(store.get()).toBeNull();
|
|
|
|
expect(store.set(" marie ")).toBe("marie"); // trimmed
|
|
expect(store.get()).toBe("marie");
|
|
expect(s.map.get(ACCOUNT_STORAGE_KEY)).toBe("marie");
|
|
});
|
|
|
|
test("IdentityStore: a blank id is ignored, keeps the previous value", () => {
|
|
const store = new IdentityStore(fakeStorage());
|
|
store.set("bob");
|
|
expect(store.set(" ")).toBe("bob");
|
|
expect(store.get()).toBe("bob");
|
|
});
|
|
|
|
test("IdentityStore: clear removes the id (no throw)", () => {
|
|
const store = new IdentityStore(fakeStorage());
|
|
store.set("bob");
|
|
store.clear();
|
|
expect(store.get()).toBeNull();
|
|
});
|
|
|
|
test("IdentityStore: null storage degrades to non-persisting (SSR-safe)", () => {
|
|
const store = new IdentityStore(null);
|
|
expect(store.get()).toBeNull();
|
|
expect(store.set("bob")).toBe("bob"); // returns the value, just doesn't persist
|
|
expect(store.get()).toBeNull();
|
|
store.clear(); // no throw
|
|
});
|
|
|
|
test("IdentityStore: swallows storage errors on read and write", () => {
|
|
const throwing: VirtualUserStorage = {
|
|
getItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
setItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
removeItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
};
|
|
const store = new IdentityStore(throwing);
|
|
expect(store.get()).toBeNull(); // read error swallowed → null
|
|
expect(() => store.set("bob")).not.toThrow();
|
|
expect(() => store.clear()).not.toThrow();
|
|
});
|
|
|
|
test("browserIdentityStore returns a working store (uses global localStorage if present)", () => {
|
|
const store = browserIdentityStore("ng-eventually.test.account");
|
|
expect(store).toBeInstanceOf(IdentityStore);
|
|
// Behaves regardless of environment: set returns the value.
|
|
expect(store.set("zoe")).toBe("zoe");
|
|
});
|