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 ___________
|