569 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			569 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Plan de tests manuels - Bookmarks
 | ||
| 
 | ||
| ## Préparation
 | ||
| 
 | ||
| ### Environnement
 | ||
| 
 | ||
| - [X] Installer les dépendances: `npm install`
 | ||
| - [X] Builder l'app: `npm run build`
 | ||
| - [X] Lancer le serveur: `node server/index.mjs`
 | ||
| - [X] Ouvrir http://localhost:3000
 | ||
| - [X] Ouvrir les DevTools (F12)
 | ||
| 
 | ||
| ### État initial
 | ||
| 
 | ||
| - [X] Vider `.obsidian/bookmarks.json` ou le supprimer
 | ||
| - [X] Créer quelques notes de test dans `vault/`:
 | ||
|   - `vault/test1.md`
 | ||
|   - `vault/folder/test2.md`
 | ||
|   - `vault/deep/path/test3.md`
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## Tests critiques
 | ||
| 
 | ||
| ### ✅ Test 1: Basename fallback (Affichage du titre)
 | ||
| 
 | ||
| **Objectif**: Vérifier que le basename s'affiche si `title` manque.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Naviguer vers la vue Bookmarks
 | ||
| 2. Ouvrir une note (ex: `vault/folder/test2.md`)
 | ||
| 3. Cliquer sur l'icône bookmark dans la toolbar
 | ||
| 4. **NE PAS** remplir le champ "Title"
 | ||
| 5. Cliquer sur "Save"
 | ||
| 6. Observer le panneau Bookmarks
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le bookmark affiche "test2.md" (basename uniquement)
 | ||
| - ❌ Le bookmark n'affiche PAS "folder/test2.md" (path complet)
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 2: Bouton Supprimer dans la modal
 | ||
| 
 | ||
| **Objectif**: Vérifier que le bouton "Delete" apparaît et fonctionne.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Ajouter un bookmark pour `test1.md`
 | ||
| 2. Fermer la modal
 | ||
| 3. Rouvrir `test1.md`
 | ||
| 4. Cliquer à nouveau sur l'icône bookmark
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ La modal affiche le bouton "Delete" (rouge, à gauche)
 | ||
| - ✅ Le bouton "Save" est toujours présent (bleu, à droite)
 | ||
| 
 | ||
| **Étapes suite**:
 | ||
| 5. Cliquer sur "Delete"
 | ||
| 6. Confirmer la suppression
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le bookmark disparaît du panneau
 | ||
| - ✅ La modal se ferme
 | ||
| - ✅ Si on rouvre la modal, le bouton "Delete" n'est plus là
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 3: Drag vers la racine (zone "Drop here to move to root")
 | ||
| 
 | ||
| **Objectif**: Vérifier que la zone de drop racine fonctionne.
 | ||
| 
 | ||
| **Préparation**:
 | ||
| 
 | ||
| 1. Créer un groupe "Test Group"
 | ||
| 2. Ajouter 2 bookmarks dans ce groupe
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Observer la zone "Drop here to move to root" en haut de la liste
 | ||
| 2. Drag un bookmark depuis le groupe
 | ||
| 3. Survoler la zone "Drop here to move to root"
 | ||
| 4. Drop dans cette zone
 | ||
| 
 | ||
| **Résultat attendu pendant le drag**:
 | ||
| 
 | ||
| - ✅ La zone change de couleur (highlight bleu)
 | ||
| - ✅ Le texte reste visible
 | ||
| 
 | ||
| **Résultat attendu après le drop**:
 | ||
| 
 | ||
| - ✅ Le bookmark apparaît à la racine (hors du groupe)
 | ||
| - ✅ Le groupe contient maintenant 1 seul bookmark
 | ||
| - ✅ La modification est persistée (recharger la page pour vérifier)
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ✅ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 4: Drag entre groupes
 | ||
| 
 | ||
| **Objectif**: Vérifier le drag & drop hiérarchique entre groupes.
 | ||
| 
 | ||
| **Préparation**:
 | ||
| 
 | ||
| 1. Créer 2 groupes: "Groupe A" et "Groupe B"
 | ||
| 2. Ajouter un bookmark "Item 1" dans Groupe A
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Drag "Item 1" depuis Groupe A
 | ||
| 2. Survoler Groupe B (la bordure du groupe)
 | ||
| 3. Drop dans Groupe B
 | ||
| 
 | ||
| **Résultat attendu pendant le drag**:
 | ||
| 
 | ||
| - ✅ Groupe B affiche un highlight (bordure bleue ou fond coloré)
 | ||
| 
 | ||
| **Résultat attendu après le drop**:
 | ||
| 
 | ||
| - ✅ "Item 1" est maintenant dans Groupe B
 | ||
| - ✅ Groupe A est vide (ou affiche "Drop items here")
 | ||
| - ✅ La modification persiste après reload
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ✅ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 5: Détection de cycles (groupe dans lui-même)
 | ||
| 
 | ||
| **Objectif**: Empêcher de créer des boucles infinies.
 | ||
| 
 | ||
| **Préparation**:
 | ||
| 
 | ||
| 1. Créer Groupe A
 | ||
| 2. Créer Groupe B **dans** Groupe A
 | ||
| 3. Ajouter un bookmark dans Groupe B
 | ||
| 
 | ||
| Structure:
 | ||
| 
 | ||
| ```
 | ||
| - Groupe A
 | ||
|   - Groupe B
 | ||
|     - Item
 | ||
| ```
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Drag Groupe A
 | ||
| 2. Tenter de le drop dans Groupe B
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le drop est **rejeté** (rien ne se passe)
 | ||
| - ✅ Un warning apparaît dans la console: "Cannot move a parent into its own descendant"
 | ||
| - ✅ La structure reste inchangée
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ✅ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 6: Réordonnancement au sein d'un conteneur
 | ||
| 
 | ||
| **Objectif**: Vérifier qu'on peut changer l'ordre des items.
 | ||
| 
 | ||
| **Préparation**:
 | ||
| 
 | ||
| 1. Créer 3 bookmarks à la racine:
 | ||
|    - Bookmark 1
 | ||
|    - Bookmark 2
 | ||
|    - Bookmark 3
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Drag "Bookmark 3"
 | ||
| 2. Drop entre "Bookmark 1" et "Bookmark 2"
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ L'ordre devient: Bookmark 1, Bookmark 3, Bookmark 2
 | ||
| - ✅ Aucun groupe n'est créé par erreur
 | ||
| - ✅ L'ordre persiste après reload
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 7: Sauvegarde atomique et backup
 | ||
| 
 | ||
| **Objectif**: Vérifier que la sauvegarde crée un backup et est atomique.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Ajouter un bookmark
 | ||
| 2. Attendre la sauvegarde automatique (800ms)
 | ||
| 3. Naviguer vers `vault/.obsidian/`
 | ||
| 4. Vérifier les fichiers
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ `bookmarks.json` existe
 | ||
| - ✅ `bookmarks.json.bak` existe (backup)
 | ||
| - ✅ Les deux fichiers sont valides JSON
 | ||
| - ✅ `bookmarks.json` contient le nouveau bookmark
 | ||
| 
 | ||
| **Test d'intégrité**:
 | ||
| 5. Corrompre manuellement `bookmarks.json` (ajouter du texte invalide)
 | ||
| 6. Renommer `bookmarks.json.bak` → `bookmarks.json`
 | ||
| 7. Recharger l'app
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ L'app charge le backup sans erreur
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 8: Préservation de l'ordre JSON
 | ||
| 
 | ||
| **Objectif**: Vérifier que l'ordre n'est pas modifié.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Créer 3 bookmarks dans cet ordre:
 | ||
|    - Z-bookmark.md
 | ||
|    - A-bookmark.md
 | ||
|    - M-bookmark.md
 | ||
| 2. Sauvegarder
 | ||
| 3. Ouvrir `vault/.obsidian/bookmarks.json`
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ L'ordre dans le JSON est identique: Z, A, M
 | ||
| - ❌ L'ordre n'est PAS alphabétique (A, M, Z)
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 9: Groupes sans titre
 | ||
| 
 | ||
| **Objectif**: Vérifier le fallback pour les groupes.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Dans le JSON, créer manuellement un groupe sans `title`:
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "type": "group",
 | ||
|   "ctime": 1234567890,
 | ||
|   "items": []
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| 2. Recharger l'app
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le groupe affiche "(Sans nom)"
 | ||
| - ✅ Le groupe est toujours fonctionnel (on peut y ajouter des items)
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 10: Fichiers avec path complexe
 | ||
| 
 | ||
| **Objectif**: Tester le basename avec différents formats.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Créer des bookmarks sans title pour:
 | ||
|    - `simple.md`
 | ||
|    - `folder/nested.md`
 | ||
|    - `deep/very/long/path/document.md`
 | ||
|    - `path with spaces/file.md`
 | ||
|    - `accents/éléphant.md`
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ "simple.md" affiche "simple.md"
 | ||
| - ✅ "folder/nested.md" affiche "nested.md"
 | ||
| - ✅ "deep/very/long/path/document.md" affiche "document.md"
 | ||
| - ✅ "path with spaces/file.md" affiche "file.md"
 | ||
| - ✅ "accents/éléphant.md" affiche "éléphant.md"
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 11: Suppression d'un path présent plusieurs fois
 | ||
| 
 | ||
| **Objectif**: `removePathEverywhere()` doit retirer toutes les occurrences.
 | ||
| 
 | ||
| **Préparation**:
 | ||
| 
 | ||
| 1. Ajouter manuellement le même path dans 2 groupes différents:
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "items": [
 | ||
|     {
 | ||
|       "type": "group",
 | ||
|       "ctime": 1,
 | ||
|       "title": "Group A",
 | ||
|       "items": [
 | ||
|         { "type": "file", "ctime": 10, "path": "test.md" }
 | ||
|       ]
 | ||
|     },
 | ||
|     {
 | ||
|       "type": "group",
 | ||
|       "ctime": 2,
 | ||
|       "title": "Group B",
 | ||
|       "items": [
 | ||
|         { "type": "file", "ctime": 20, "path": "test.md" }
 | ||
|       ]
 | ||
|     }
 | ||
|   ]
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Ouvrir `test.md`
 | ||
| 2. Ouvrir la modal bookmark
 | ||
| 3. Cliquer sur "Delete"
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le bookmark disparaît de Group A
 | ||
| - ✅ Le bookmark disparaît de Group B
 | ||
| - ✅ Les deux groupes sont maintenant vides
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 12: Responsive (Desktop vs Mobile)
 | ||
| 
 | ||
| **Objectif**: Vérifier l'adaptabilité.
 | ||
| 
 | ||
| **Desktop (>1024px)**:
 | ||
| 
 | ||
| 1. Ouvrir l'app en plein écran
 | ||
| 2. Naviguer vers Bookmarks
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Panel latéral visible (fixe)
 | ||
| - ✅ Largeur ~320-400px
 | ||
| - ✅ Barre de recherche visible
 | ||
| - ✅ Boutons d'action visibles
 | ||
| 
 | ||
| **Mobile (<1024px)**:
 | ||
| 
 | ||
| 1. Réduire la fenêtre ou utiliser DevTools mode mobile
 | ||
| 2. Naviguer vers Bookmarks
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Panel en plein écran (drawer)
 | ||
| - ✅ Navigation facile (pas de scroll horizontal)
 | ||
| - ✅ Boutons assez grands pour le tactile (≥44px)
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 13: Thème dark/light
 | ||
| 
 | ||
| **Objectif**: Vérifier le respect des thèmes.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Basculer en mode dark (si disponible)
 | ||
| 2. Observer le panneau Bookmarks
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Fond sombre (`bg-gray-900`)
 | ||
| - ✅ Texte clair (`text-gray-100`)
 | ||
| - ✅ Bordures visibles
 | ||
| - ✅ Contraste suffisant (lisible)
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 3. Basculer en mode light
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Fond clair (`bg-white`)
 | ||
| - ✅ Texte sombre (`text-gray-900`)
 | ||
| - ✅ Pas de vestiges du mode dark
 | ||
| 
 | ||
| **Résultat**: ✅ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 14: Validation JSON (données corrompues)
 | ||
| 
 | ||
| **Objectif**: Vérifier que l'app ne crash pas avec un JSON invalide.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Modifier `bookmarks.json` pour le corrompre:
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "items": [
 | ||
|     {
 | ||
|       "type": "invalid-type",
 | ||
|       "ctime": "not-a-number"
 | ||
|     }
 | ||
|   ]
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| 2. Recharger l'app
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Un message d'erreur clair s'affiche
 | ||
| - ✅ L'app ne crash pas
 | ||
| - ✅ On peut créer un nouveau bookmark (qui réinitialise le fichier)
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ✅ Test 15: Auto-save (debounce)
 | ||
| 
 | ||
| **Objectif**: Vérifier que l'auto-save fonctionne.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Ajouter un bookmark
 | ||
| 2. Observer le panneau (indicateur "Saving...")
 | ||
| 3. Attendre 800ms
 | ||
| 4. Vérifier que le fichier a été écrit
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ "Saving..." apparaît brièvement
 | ||
| - ✅ Après 800ms, le fichier est mis à jour
 | ||
| - ✅ `isDirty` passe à `false`
 | ||
| 
 | ||
| **Test de debounce**:
 | ||
| 5. Faire 3 modifications rapides (<800ms entre chaque)
 | ||
| 6. Attendre 800ms après la dernière
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Une seule sauvegarde est déclenchée (pas 3)
 | ||
| - ✅ Le fichier final contient toutes les modifications
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## Tests de régression
 | ||
| 
 | ||
| ### ⚠️ Test R1: Compatibilité Obsidian
 | ||
| 
 | ||
| **Objectif**: S'assurer qu'Obsidian peut lire le fichier généré.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Créer plusieurs bookmarks dans ObsiViewer
 | ||
| 2. Ouvrir la vault dans Obsidian
 | ||
| 3. Ouvrir le panneau Bookmarks dans Obsidian
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Tous les bookmarks sont visibles
 | ||
| - ✅ La hiérarchie est respectée
 | ||
| - ✅ Les titres sont corrects
 | ||
| - ✅ Cliquer sur un bookmark ouvre le bon fichier
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ⚠️ Test R2: Modifications depuis Obsidian
 | ||
| 
 | ||
| **Objectif**: Vérifier la bidirectionnalité.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Dans Obsidian, créer un nouveau bookmark
 | ||
| 2. Ajouter un groupe et y placer le bookmark
 | ||
| 3. Sauvegarder dans Obsidian
 | ||
| 4. Recharger ObsiViewer
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ Le nouveau bookmark apparaît
 | ||
| - ✅ Le groupe est visible
 | ||
| - ✅ Pas de corruption de données
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ### ⚠️ Test R3: Champs inconnus préservés
 | ||
| 
 | ||
| **Objectif**: Ne pas perdre les extensions Obsidian.
 | ||
| 
 | ||
| **Étapes**:
 | ||
| 
 | ||
| 1. Ajouter manuellement dans `bookmarks.json`:
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "type": "file",
 | ||
|   "ctime": 123,
 | ||
|   "path": "test.md",
 | ||
|   "color": "#ff0000",
 | ||
|   "icon": "star"
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| 2. Charger dans ObsiViewer
 | ||
| 3. Modifier le titre du bookmark
 | ||
| 4. Sauvegarder
 | ||
| 5. Vérifier le JSON
 | ||
| 
 | ||
| **Résultat attendu**:
 | ||
| 
 | ||
| - ✅ `color` et `icon` sont toujours présents
 | ||
| - ✅ Seul `title` a été modifié
 | ||
| 
 | ||
| **Résultat**: ⬜ PASS / ⬜ FAIL
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## Récapitulatif
 | ||
| 
 | ||
| ### Statistiques
 | ||
| 
 | ||
| - Tests critiques: **15**
 | ||
| - Tests de régression: **3**
 | ||
| - **Total**: **18 tests**
 | ||
| 
 | ||
| ### Résultats
 | ||
| 
 | ||
| - ✅ PASS: ___ / 18
 | ||
| - ❌ FAIL: ___ / 18
 | ||
| - ⏭️ SKIP: ___ / 18
 | ||
| 
 | ||
| ### Notes
 | ||
| 
 | ||
| _Ajouter ici toute observation, bug trouvé, ou amélioration suggérée._
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| **Date du test**: ___________
 | ||
| **Testeur**: ___________
 | ||
| **Version**: 2.0.0
 | ||
| **Environnement**: Node v___ / Browser ___________
 |