test: add frontend unit suite + fix mixed local/UTC timestamps
Two CODE_AUDIT items in one session. §3.2 — Frontend regression net (js/tests/, 35 tests, node:test, zero deps): - harness.js loads app.js (monofile, no exports) into a node:vm with browser globals stubbed, surfacing internals via an export epilogue. - crypto: deriveKeyAndVerifier (AES key == raw PBKDF2, cross-checked vs Node pbkdf2Sync), legacy-vs-v2 verifier decoupling, encrypt/decrypt round-trip, IV uniqueness, AEAD tamper/wrong-key. - csv: parseCSV tokenizer, findColumn heuristics, Bitwarden/KeePass mapping. - merge: applyRemoteSnapshot add/update/skip (LWW), tombstone delete, resurrection arbitration (both NaN branches), local-tombstone veto, additive folder merge. Only api() is stubbed; loadEntries/encryptImportEntry run for real. - Wired as a build gate in BuildAssets.ps1 (after node --check, bypass PM_SKIP_TESTS=1). §2.2 — Unify timestamps on UTC: - Entry created_at/updated_at were written via Delphi FormatDateTime(Now) = LOCAL, while deleted_at/tombstones use SQLite CURRENT_TIMESTAMP = UTC. The tombstone-resurrection arbitration compared the two zones, skewing by the machine's UTC offset even single-device. - Add NowUTC/NowUTCStr to PM.Database, swap in at every entry/attachment write site (Entries create/update/bulk, Attachments POST echo). - No JS change needed: arbitration now compares same-zone values. - Existing rows self-heal on next edit (no destructive migration). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,17 @@ lieu d'embarquer un bundle mort qui ne se révèle qu'après un rebuild
|
||||
Delphi complet). Node optionnel — absent = warning, on continue. Toujours
|
||||
`node --check js/app.js` après un gros edit JS.
|
||||
|
||||
Ensuite (même gate, node requis) il lance la **suite de tests frontend**
|
||||
(`node --test js/tests/**/*.test.js`, ~1.7 s, zéro dépendance) : un
|
||||
invariant crypto/merge cassé avorte le build comme une erreur de syntaxe.
|
||||
`PM_SKIP_TESTS=1` pour bypasser en itération rapide. Lancer manuellement
|
||||
via `npm test`. Voir [js/tests/README.md](js/tests/README.md) — le harness
|
||||
charge `app.js` (monofichier sans exports) dans un `node:vm` avec les
|
||||
globals navigateur stubbés, puis expose les internals via un épilogue
|
||||
d'export. Couvre : round-trip crypto + dérivation verifier (legacy vs -v2),
|
||||
parsing CSV d'import, et l'arbitrage merge/tombstone de sync
|
||||
(`applyRemoteSnapshot`, seule `api()` est stubbée).
|
||||
|
||||
## Carte des fichiers
|
||||
|
||||
| Rôle | Path |
|
||||
@@ -800,6 +811,12 @@ le vide ET vide `FPendingURL` → écran noir permanent sur cold-start lent.
|
||||
nécessite `AttachThreadInput` pour cross-process.
|
||||
- **`updated_at`** est bumpé à chaque PUT entry → sort par défaut =
|
||||
`name` asc pour que modifier une entry ne change pas sa position.
|
||||
- **Timestamps = UTC partout** : tout `created_at`/`updated_at`/`deleted_at`
|
||||
écrit côté Delphi passe par `NowUTC`/`NowUTCStr` (`PM.Database`) — JAMAIS
|
||||
`FormatDateTime(..., Now)` (heure locale). SQLite `CURRENT_TIMESTAMP` /
|
||||
`datetime('now')` sont déjà UTC. Mélanger les deux décalait l'arbitrage
|
||||
sync (résurrection tombstone) de l'offset UTC de la machine, même en solo.
|
||||
Côté JS, générer les timestamps via `toISOString()` (UTC) uniquement.
|
||||
- **TMS render-time vs DOM-attachment** : pattern courant — fonctions
|
||||
qui rendent un widget (`soTagsField`, `soTotpField`) appellent un
|
||||
helper (`renderSoChips`, `startTotpTick`) qui fait `$('#id')` sur un
|
||||
|
||||
Reference in New Issue
Block a user