Simplify skipped scenario format with placeholder step

Replace @skip tag + placeholder step with just placeholder step.
Skipped scenarios now only need:
  Scénario: Name
    * Scénario non implémenté

- Remove @skip tags from all 26 feature files
- Add step definition returning 'skipped' for placeholder
- Update GherkinHighlighter to hide placeholder and make
  skipped scenarios non-expandable (no chevron, no click)
- Update documentation with new format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-01-19 10:31:42 +01:00
parent ed61c7081f
commit 7827479e9c
35 changed files with 1438 additions and 5621 deletions
+41 -74
View File
@@ -250,12 +250,13 @@ Alors je peux voir le QR code
## Test Outcomes
Every step definition must produce one of two outcomes:
Tests in this project serve to **consolidate features and prevent regressions**. This shapes the testing strategy.
### 1. Pass/Fail (Testable)
### 1. Pass/Fail (Implemented Features)
When we **can verify** the feature through static source analysis:
- The step runs assertions (`expect(...).to.be.true`)
When a feature **exists and can be verified** through static source analysis:
- The scenario has full steps (Given/When/Then)
- Step definitions run assertions (`expect(...).to.be.true`)
- If the assertion passes → test passes
- If the assertion fails → test fails with descriptive error message
@@ -269,58 +270,41 @@ Then('je peux voir la liste des participants', async function (this: FestipodWor
});
```
### 2. Pending (Not Testable)
### 2. Skipped (Not Yet Implemented)
When we **cannot verify** the feature, the step must return `'pending'` with an explanatory message. There are four reasons a test may be pending:
When a feature **is not yet implemented**, the scenario uses a placeholder step.
| Prefix | Reason | Example |
|--------|--------|---------|
| `NOT IMPLEMENTED` | Feature doesn't exist in the UI | Comment functionality not in EventDetailScreen.tsx |
| `CANNOT TEST` | Requires browser automation, backend, or database | Form submission requires browser automation |
| `WRONG STEP` | Step is being used on inappropriate screen type | "le formulaire contient..." on a display screen |
| `NOT ON THIS SCREEN` | Feature exists but on a different screen | QR code is on share-profile, not profile |
**Rationale**: Since tests exist to consolidate features and prevent regressions, there is no value in writing detailed steps for features that don't exist yet. The placeholder step `* Scénario non implémenté` makes it clear this is a planned feature while allowing Cucumber to properly report it as "skipped".
**Format for skipped scenarios:**
```gherkin
Scénario: Modifier ma photo de profil
* Scénario non implémenté
```
The `*` is a Gherkin keyword that matches any step type (Given/When/Then). The step definition returns `'skipped'`:
```typescript
// NOT IMPLEMENTED - feature doesn't exist
Then('je peux ajouter un commentaire', async function (this: FestipodWorld) {
this.attach('NOT IMPLEMENTED: Comment functionality not in EventDetailScreen.tsx', 'text/plain');
return 'pending';
});
// CANNOT TEST - requires browser automation
When('je remplis le champ {string} avec {string}', async function (this: FestipodWorld, fieldName: string, value: string) {
this.attach(`CANNOT TEST: Filling field "${fieldName}" with "${value}" requires browser automation`, 'text/plain');
return 'pending';
});
// WRONG STEP - step used on wrong screen type
Then('le formulaire contient le champ obligatoire {string}', async function (this: FestipodWorld, fieldName: string) {
if (this.currentScreenId !== 'create-event') {
this.attach(`WRONG STEP: "le formulaire contient le champ obligatoire" is for forms. Screen "${this.currentScreenId}" is not a form.`, 'text/plain');
return 'pending';
}
// ... actual test logic ...
});
// NOT ON THIS SCREEN - feature exists elsewhere
Then('je peux voir le QR code', async function (this: FestipodWorld) {
const source = this.getRenderedText();
if (this.currentScreenId === 'share-profile') {
expect(/QR Code/.test(source), 'Share profile should have "QR Code" text').to.be.true;
} else {
this.attach(`NOT ON THIS SCREEN: QR code is on share-profile, not "${this.currentScreenId}"`, 'text/plain');
return 'pending';
}
Given('Scénario non implémenté', async function (this: FestipodWorld) {
return 'skipped';
});
```
### No Silent Tests
**Do NOT write detailed steps for unimplemented features:**
```gherkin
# DON'T DO THIS - speculation about future implementation
Scénario: Modifier ma photo de profil
Étant donné je suis sur la page "mon profil"
Quand je clique sur "Modifier la photo"
Alors je peux sélectionner une nouvelle image
```
**Critical rule**: A test must never do nothing. Every step definition must either:
1. Run assertions that can pass or fail, OR
2. Return `'pending'` with an explanatory message
### UI Behavior for Skipped Scenarios
This ensures the test suite provides clear feedback about what is tested, what is not testable, and why.
In the GherkinHighlighter component:
- Scenarios with skipped status appear with yellow/amber indicator
- They show only the scenario name (the placeholder step is hidden)
- This provides a clear visual distinction between tested and planned features
## Hooks
@@ -329,28 +313,15 @@ Lifecycle hooks in `features/support/hooks.ts`:
| Hook | Purpose |
|------|---------|
| `BeforeAll` | Log test suite start |
| `Before` | Reset World state, mark `@pending` scenarios as pending |
| `Before` | Reset World state |
| `After` | Attach debug info on failure, cleanup |
| `AfterAll` | Log test suite completion |
### Pending Scenarios
### Skipped Scenarios
Scenarios tagged with `@pending` are automatically marked as pending in the Before hook:
Scenarios use the placeholder step `* Scénario non implémenté` which returns `'skipped'`. This is handled by the step definition in `navigation.steps.ts`, not by hooks.
```typescript
Before(async function (this: FestipodWorld, scenario) {
// ... reset state ...
const isPending = scenario.pickle.tags.some(tag => tag.name === '@pending');
if (isPending) {
return 'pending';
}
});
```
Use `@pending` for:
- Features not yet implemented
- Email/notification features that cannot be tested via screen analysis
- Scenarios waiting for UI implementation
Use `* Scénario non implémenté` for scenarios that represent features not yet implemented.
### Debug Information on Failure
@@ -381,9 +352,6 @@ bun run cucumber:run --tags "@NOTIF"
# Run by priority
bun run cucumber:run --tags "@priority-0"
# Exclude pending tests
bun run cucumber:run --tags "not @pending"
```
## Parsing Results
@@ -406,22 +374,21 @@ Fonctionnalité: US-9 Visualiser la photo d'un individu
Je peux visualiser la photo d'un individu
Contexte:
Étant donné je suis connecté en tant qu'utilisateur
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder au profil pour voir la photo
Étant donné je suis sur la page "mon profil"
Étant donné que je suis sur la page "mon profil"
Alors je vois l'écran "profile"
Et l'écran contient une section "Photo de profil"
Scénario: Naviguer vers le profil depuis la liste des participants
Étant donné je suis sur la page "détail événement"
Étant donné que je suis sur la page "détail événement"
Quand je clique sur un participant
Alors je suis redirigé vers "profil utilisateur"
@pending
Scénario: Fonctionnalité non encore implémentée
Étant donné je suis sur la page "mon profil"
Alors je peux modifier ma photo de profil
# Skipped scenarios use placeholder step
Scénario: Modifier ma photo de profil
* Scénario non implémenté
```
## Key Design Decisions
+1 -8
View File
@@ -24,14 +24,7 @@ Fonctionnalité: US-13 Créer/Modifier/Supprimer un événement
| Thématique |
Scénario: Remplir le formulaire de création d'événement
Étant donné que je suis sur la page "créer un événement"
Quand je remplis le champ "Nom de l'événement" avec "Mon événement"
Et je remplis le champ "Date" avec "2025-02-15"
Et je remplis le champ "Heure de début" avec "14:00"
Et je remplis le champ "Lieu" avec "Lyon"
Et je remplis le champ "Thématique" avec "Technologie"
Alors le champ "Nom de l'événement" affiche "Mon événement"
Et le champ "Lieu" affiche "Lyon"
* Scénario non implémenté
Scénario: Vérifier la présence du bouton de création
Étant donné que je suis sur la page "créer un événement"
@@ -22,10 +22,4 @@ Fonctionnalité: US-3 Visualiser un événement terminé
Alors je peux voir la liste des participants
Scénario: Vérifier les données affichées
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Lieu |
| Description |
| Liste des participants |
* Scénario non implémenté
@@ -10,28 +10,13 @@ Fonctionnalité: US-5 Ajouter/modifier/supprimer un commentaire à un événemen
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Voir les commentaires existants
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Notes personnelles"
* Scénario non implémenté
@pending
Scénario: Ajouter un commentaire
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Ajouter un commentaire"
Alors je peux ajouter un commentaire
* Scénario non implémenté
Scénario: Modifier un commentaire
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Modifier"
Alors je peux modifier un commentaire
* Scénario non implémenté
Scénario: Supprimer un commentaire
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Supprimer"
Alors je peux supprimer un commentaire
Scénario: Vérifier les données de l'écran
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Lieu |
* Scénario non implémenté
@@ -14,24 +14,14 @@ Fonctionnalité: US-7 M'inscrire/me désinscrire à un événement
Alors l'écran affiche les informations de l'événement
Scénario: S'inscrire à un événement
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "S'inscrire"
Alors je peux m'inscrire à l'événement
* Scénario non implémenté
Scénario: Se désinscrire d'un événement
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Se désinscrire"
Alors je peux me désinscrire de l'événement
* Scénario non implémenté
Scénario: Rechercher un événement existant
Étant donné que je suis sur la page "découvrir"
Alors je peux voir la liste des événements
Scénario: Vérifier les données de l'écran
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Lieu |
| Description |
| Liste des participants |
* Scénario non implémenté
+4 -13
View File
@@ -10,22 +10,13 @@ Fonctionnalité: US-8 Consulter et m'inscrire à un macro-événement
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Consulter un macro-événement
Étant donné que je suis sur la page "découvrir"
Quand je clique sur un événement
Alors je vois l'écran "event-detail"
Et l'écran contient une section "Événements rattachés"
* Scénario non implémenté
@pending
Scénario: Voir les événements rattachés
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Événements rattachés"
* Scénario non implémenté
Scénario: Rattacher un événement existant
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Rattacher un événement"
Alors l'écran contient une section "Sélection d'événement"
* Scénario non implémenté
Scénario: Voir la consolidation des participants
Étant donné que je suis sur la page "détail événement"
Alors je peux voir la liste des participants
Et l'écran contient une section "Participants consolidés"
* Scénario non implémenté
+4 -16
View File
@@ -15,25 +15,13 @@ Fonctionnalité: US-16 Indiquer un ou plusieurs points de rencontre
Alors je vois l'écran "meeting-points"
Scénario: Créer un point de rencontre
Étant donné que je suis sur la page "points de rencontre"
Quand je clique sur "Ajouter un point de rencontre"
Alors l'écran contient une section "Nouveau point de rencontre"
* Scénario non implémenté
Scénario: Définir le lieu de rencontre
Étant donné que je suis sur la page "points de rencontre"
Alors le champ "Lieu de rencontre" est présent
* Scénario non implémenté
Scénario: Définir l'heure de rencontre
Étant donné que je suis sur la page "points de rencontre"
Alors le champ "Heure" est présent
* Scénario non implémenté
Scénario: Échanger des liens de contact
Étant donné que je suis sur la page "points de rencontre"
Alors l'écran contient une section "Partage de contact"
Et je peux voir le QR code
Scénario: Vérifier les données requises
Étant donné que l'écran "meeting-points" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Lieu de rencontre |
| Heure |
* Scénario non implémenté
@@ -10,31 +10,17 @@ Fonctionnalité: US-17 Informer automatiquement d'autres utilisateurs
Contexte:
Étant donné que je suis connecté en tant qu'utilisateur
@pending
Scénario: Partager un événement auquel je participe
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Partager"
Alors l'écran contient une section "Options de partage"
* Scénario non implémenté
@pending
Scénario: Informer les utilisateurs à proximité
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Notifier à proximité"
Alors l'écran contient une section "Rayon de notification"
* Scénario non implémenté
@pending
Scénario: Informer les utilisateurs par thématique
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Notifier par thématique"
Alors l'écran contient une section "Thématiques"
* Scénario non implémenté
@pending
Scénario: Informer mes abonnés
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Notifier mes abonnés"
Alors l'écran contient une section "Mes abonnés"
* Scénario non implémenté
@pending
Scénario: Combiner les options de notification
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Options de notification"
* Scénario non implémenté
@@ -14,22 +14,10 @@ Fonctionnalité: US-18 Être informé lorsque de nouveaux participants s'inscriv
Alors l'écran contient une section "Notifications"
Scénario: Activer les notifications pour un événement
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Activer les notifications"
Alors l'écran contient une section "Notifications activées"
* Scénario non implémenté
Scénario: Filtrer les notifications par réseau
Étant donné que je suis sur la page "paramètres"
Quand je clique sur "Mon réseau uniquement"
Alors l'écran contient une section "Filtre réseau"
* Scénario non implémenté
Scénario: Voir les nouveaux participants sur l'accueil
Étant donné que je suis sur la page "accueil"
Alors l'écran contient une section "Nouveaux participants"
Scénario: Vérifier les données des paramètres
Étant donné que l'écran "settings" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Notifications |
| Confidentialité |
| Rayon de notification |
* Scénario non implémenté
+4 -14
View File
@@ -15,24 +15,14 @@ Fonctionnalité: US-19 Recevoir un récapitulatif des prochaines rencontres
Étant donné que je suis sur la page "accueil"
Alors l'écran contient une section "Événements à venir"
@pending
Scénario: Voir le récapitulatif par période
Étant donné que je suis sur la page "accueil"
Alors je peux filtrer les événements par période
* Scénario non implémenté
@pending
Scénario: Voir les événements proches géographiquement
Étant donné que je suis sur la page "accueil"
Alors l'écran contient une section "Près de chez moi"
* Scénario non implémenté
@pending
Scénario: Voir mes inscriptions
Étant donné que je suis sur la page "accueil"
Alors l'écran contient une section "Mes inscriptions"
* Scénario non implémenté
@pending
Scénario: Vérifier les données de l'accueil
Étant donné que l'écran "home" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Événements à venir |
| Navigation |
* Scénario non implémenté
@@ -2,6 +2,12 @@ import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';
import type { FestipodWorld } from '../support/world';
// Placeholder step for scenarios that are not yet implemented
// This step indicates the feature is planned but not built yet
Given('Scénario non implémenté', async function (this: FestipodWorld) {
return 'skipped';
});
const screenNameMap: Record<string, string> = {
'accueil': 'home',
'liste des événements': 'events',
+2 -5
View File
@@ -14,11 +14,8 @@ Before(async function (this: FestipodWorld, scenario) {
this.screenSourceContent = '';
this.currentScreen = null;
// Mark @pending scenarios as pending
const isPending = scenario.pickle.tags.some(tag => tag.name === '@pending');
if (isPending) {
return 'pending';
}
// Skipped scenarios use the "* Scénario non implémenté" placeholder step
// which returns 'skipped' - no special handling needed in the hook
});
After(async function (this: FestipodWorld, scenario) {
@@ -22,11 +22,7 @@ Fonctionnalité: US-10 Visualiser la fiche/le profil d'un participant
Alors je peux contacter l'utilisateur
Scénario: Vérifier les informations du profil
Étant donné que l'écran "user-profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
Scénario: Voir les détails du profil utilisateur
Étant donné que je suis sur la page "profil utilisateur"
+4 -14
View File
@@ -10,31 +10,21 @@ Fonctionnalité: US-12 Consulter la carte/tableau des événements
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder à la liste des événements depuis le profil
Étant donné que je suis sur la page "mon profil"
Alors je peux voir la liste des événements
* Scénario non implémenté
Scénario: Accéder à la liste des événements depuis découvrir
Étant donné que je suis sur la page "découvrir"
Alors je peux voir la liste des événements
Scénario: Filtrer par date
Étant donné que je suis sur la page "découvrir"
Quand je clique sur "Filtrer par date"
Alors l'écran contient une section "Filtre par date"
* Scénario non implémenté
Scénario: Filtrer par personne
Étant donné que je suis sur la page "profil utilisateur"
Alors je peux voir les événements auxquels l'utilisateur a participé
Scénario: Vérifier les données de l'écran événements
Étant donné que l'écran "events" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Liste des événements |
| Filtre par date |
* Scénario non implémenté
Scénario: Vérifier les données de l'écran profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
@@ -23,8 +23,4 @@ Fonctionnalité: US-15 Visualiser les inscrits à un atelier/événement
Alors je vois l'écran "user-profile"
Scénario: Vérifier les données de l'écran
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Liste des participants |
* Scénario non implémenté
+2 -7
View File
@@ -15,8 +15,7 @@ Fonctionnalité: US-20 Voir le profil des personnes faisant partie de mon résea
Alors je vois l'écran "profile"
Scénario: Voir mon réseau
Étant donné que je suis sur la page "mon profil"
Alors l'écran contient une section "Mon réseau"
* Scénario non implémenté
Scénario: Voir un profil de mon réseau
Étant donné que je suis sur la page "mon profil"
@@ -29,8 +28,4 @@ Fonctionnalité: US-20 Voir le profil des personnes faisant partie de mon résea
Alors je vois l'écran "event-detail"
Scénario: Vérifier les données du profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
+3 -13
View File
@@ -19,20 +19,10 @@ Fonctionnalité: US-21 Décider que tous les utilisateurs puissent suivre mes ac
Alors l'écran contient une section "Confidentialité"
Scénario: Rendre le profil public
Étant donné que je suis sur la page "paramètres"
Quand je clique sur "Profil public"
Alors l'écran contient une section "Visibilité"
* Scénario non implémenté
Scénario: Vérifier les données des paramètres
Étant donné que l'écran "settings" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Notifications |
| Confidentialité |
| Rayon de notification |
* Scénario non implémenté
Scénario: Vérifier les données du profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
+4 -15
View File
@@ -10,24 +10,13 @@ Fonctionnalité: US-22 Parrainer un nouvel utilisateur
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder au partage de profil
Étant donné que je suis sur la page "mon profil"
Alors l'écran contient une section "Partager mon profil"
* Scénario non implémenté
Scénario: Voir le QR code de parrainage
Étant donné que je suis sur la page "mon profil"
Alors je peux voir le QR code
* Scénario non implémenté
Scénario: Voir le lien de parrainage
Étant donné que je suis sur la page "mon profil"
Alors je peux voir le lien de partage
* Scénario non implémenté
Scénario: Voir les statistiques de parrainage
Étant donné que je suis sur la page "mon profil"
Alors l'écran contient une section "Mes parrainages"
Scénario: Vérifier les données du profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
@@ -14,12 +14,10 @@ Fonctionnalité: US-23 Me connecter avec d'autres utilisateurs
Alors l'écran contient une section "Partager"
Scénario: Voir le QR code
Étant donné que je suis sur la page "mon profil"
Alors je peux voir le QR code
* Scénario non implémenté
Scénario: Voir le lien de partage
Étant donné que je suis sur la page "mon profil"
Alors je peux voir le lien de partage
* Scénario non implémenté
Scénario: Accéder à l'écran de partage dédié
Étant donné que je suis sur la page "mon profil"
@@ -27,8 +25,4 @@ Fonctionnalité: US-23 Me connecter avec d'autres utilisateurs
Alors je vois l'écran "share-profile"
Scénario: Vérifier les données du profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
@@ -17,12 +17,4 @@ Fonctionnalité: US-24 Être notifié des activités de mes contacts
Alors je peux configurer mes notifications
Scénario: Voir les activités de mes contacts sur l'accueil
Étant donné que je suis sur la page "accueil"
Alors l'écran contient une section "Activités de mes contacts"
Scénario: Vérifier les données des paramètres
Étant donné que l'écran "settings" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Notifications |
| Confidentialité |
| Rayon de notification |
* Scénario non implémenté
@@ -14,16 +14,7 @@ Fonctionnalité: US-25 Être averti des événements susceptibles de m'intéress
Alors l'écran contient une section "Notifications"
Scénario: Configurer le rayon de notification
Étant donné que je suis sur la page "paramètres"
Alors je peux définir mon rayon de notification
* Scénario non implémenté
Scénario: Configurer les thématiques d'intérêt
Étant donné que je suis sur la page "paramètres"
Alors je peux définir mes thématiques d'intérêt
Scénario: Vérifier les données des paramètres
Étant donné que l'écran "settings" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Notifications |
| Confidentialité |
| Rayon de notification |
* Scénario non implémenté
+2 -5
View File
@@ -10,13 +10,10 @@ Fonctionnalité: US-26 Définir la portée d'un événement
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder à la création d'événement
Étant donné que je suis sur la page "créer un événement"
Alors l'écran contient une section "Portée de l'événement"
* Scénario non implémenté
Scénario: Définir le rayon d'intérêt
Étant donné que je suis sur la page "créer un événement"
Quand je clique sur "Définir la portée"
Alors l'écran contient une section "Rayon en kilomètres"
* Scénario non implémenté
Scénario: Choisir une thématique
Étant donné que je suis sur la page "créer un événement"
+2 -8
View File
@@ -10,9 +10,7 @@ Fonctionnalité: US-9 Visualiser la photo d'un individu
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder au profil pour voir la photo
Étant donné que je suis sur la page "mon profil"
Alors je vois l'écran "profile"
Et l'écran contient une section "Photo de profil"
* Scénario non implémenté
Scénario: Naviguer vers le profil depuis la liste des participants
Étant donné que je suis sur la page "détail événement"
@@ -25,8 +23,4 @@ Fonctionnalité: US-9 Visualiser la photo d'un individu
Alors je peux voir la liste des participants
Scénario: Vérifier les champs de données du profil
Étant donné que l'écran "profile" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Photo de profil |
| Nom |
| Pseudo |
* Scénario non implémenté
@@ -9,24 +9,10 @@ Fonctionnalité: US-1 Visualiser un événement terminé (ateliers)
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder aux détails d'un événement terminé
Étant donné que je suis sur la page "accueil"
Quand je navigue vers "détail événement"
Alors je vois l'écran "event-detail"
Et l'écran contient une section "Programme des ateliers"
* Scénario non implémenté
Scénario: Consulter la liste des participants d'un atelier
Étant donné que je suis sur la page "détail événement"
Alors je peux voir la liste des participants
* Scénario non implémenté
Scénario: Consulter les ressources d'un atelier
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Ressources"
Et l'écran contient une section "Zone de partage collective"
Scénario: Vérifier les données affichées pour un atelier
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Lieu |
| Liste des participants |
* Scénario non implémenté
@@ -10,22 +10,10 @@ Fonctionnalité: US-11 Visualiser le bilan consolidé de l'événement
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder au bilan consolidé
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Bilan"
* Scénario non implémenté
Scénario: Voir les commentaires regroupés par atelier
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Voir le bilan"
Alors l'écran contient une section "Commentaires par atelier"
* Scénario non implémenté
@pending
Scénario: Voir la synthèse globale
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Synthèse"
Scénario: Vérifier les données du bilan
Étant donné que l'écran "event-detail" est affiché
Alors le formulaire contient les champs obligatoires suivants:
| Titre |
| Date |
| Liste des participants |
* Scénario non implémenté
+4 -11
View File
@@ -10,8 +10,7 @@ Fonctionnalité: US-14 Créer/Modifier/Supprimer un atelier
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder à la création d'atelier
Étant donné que je suis sur la page "créer un événement"
Alors l'écran contient une section "Ateliers"
* Scénario non implémenté
Scénario: Vérifier les champs obligatoires pour créer un atelier
Étant donné que l'écran "create-event" est affiché
@@ -23,16 +22,10 @@ Fonctionnalité: US-14 Créer/Modifier/Supprimer un atelier
| Thématique |
Scénario: Créer un atelier
Étant donné que je suis sur la page "créer un événement"
Quand je clique sur "Ajouter un atelier"
Alors l'écran contient une section "Nouvel atelier"
* Scénario non implémenté
Scénario: Modifier un atelier existant
Étant donné que je suis sur la page "créer un événement"
Quand je clique sur "Modifier l'atelier"
Alors l'écran contient une section "Modifier l'atelier"
* Scénario non implémenté
Scénario: Supprimer un atelier
Étant donné que je suis sur la page "créer un événement"
Quand je clique sur "Supprimer l'atelier"
Alors l'écran contient une section "Confirmation"
* Scénario non implémenté
@@ -9,20 +9,13 @@ Fonctionnalité: US-2 Visualiser un événement terminé (notes)
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Accéder à la zone de notes personnelles
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Notes personnelles"
* Scénario non implémenté
Scénario: Accéder à la zone de partage publique
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Zone de partage publique"
* Scénario non implémenté
@pending
Scénario: Ajouter une note personnelle
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Ajouter une note"
Alors je peux ajouter une note
* Scénario non implémenté
Scénario: Ajouter un lien/ressource
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Ajouter une ressource"
Alors l'écran contient une section "Ressources"
* Scénario non implémenté
@@ -10,21 +10,13 @@ Fonctionnalité: US-4 Ajouter/modifier/supprimer un commentaire à un atelier
Étant donné que je suis connecté en tant qu'utilisateur
Scénario: Voir les commentaires existants d'un atelier
Étant donné que je suis sur la page "détail événement"
Alors l'écran contient une section "Commentaires"
* Scénario non implémenté
@pending
Scénario: Ajouter un commentaire à un atelier
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Ajouter un commentaire"
Alors je peux ajouter un commentaire
* Scénario non implémenté
Scénario: Modifier un commentaire existant
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Modifier"
Alors je peux modifier un commentaire
* Scénario non implémenté
Scénario: Supprimer un commentaire
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Supprimer"
Alors je peux supprimer un commentaire
* Scénario non implémenté
@@ -18,11 +18,7 @@ Fonctionnalité: US-6 M'inscrire/me désinscrire à un événement (atelier)
Alors je peux voir la liste des participants
Scénario: S'inscrire à un atelier
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "S'inscrire"
Alors je peux m'inscrire à l'événement
* Scénario non implémenté
Scénario: Se désinscrire d'un atelier
Étant donné que je suis sur la page "détail événement"
Quand je clique sur "Se désinscrire"
Alors je peux me désinscrire de l'événement
* Scénario non implémenté
File diff suppressed because one or more lines are too long
+1110 -4067
View File
File diff suppressed because it is too large Load Diff
+28 -11
View File
@@ -31,10 +31,13 @@ const keywords = {
given: ['Étant donné que ', "Étant donné qu'", 'Étant donné', 'Etant donné que ', "Etant donné qu'", 'Etant donné', 'Given', 'Soit'],
when: ['Quand', 'When', 'Lorsque'],
then: ['Alors', 'Then'],
and: ['Et', 'And', 'Mais', 'But'],
and: ['Et', 'And', 'Mais', 'But', '* '],
examples: ['Exemples:', 'Examples:'],
};
// Placeholder step text for skipped/not-implemented scenarios
const SKIP_PLACEHOLDER = 'Scénario non implémenté';
export function GherkinHighlighter({ content, scenarioResults = [] }: GherkinHighlighterProps) {
const lines = content.split('\n');
@@ -237,7 +240,12 @@ function BlockRenderer({ block, isCollapsed, onToggle, showDefinitions }: BlockR
const isBackground = block.type === 'background';
// Parse steps from rest lines
const parsedSteps = parseStepsFromLines(restLines);
let parsedSteps = parseStepsFromLines(restLines);
// For skipped scenarios, filter out the placeholder step
if (block.status === 'skipped') {
parsedSteps = parsedSteps.filter(step => step.text !== SKIP_PLACEHOLDER);
}
// Determine border color based on status
const borderColor = block.status === 'passed' ? 'border-l-green-500' :
@@ -254,17 +262,25 @@ function BlockRenderer({ block, isCollapsed, onToggle, showDefinitions }: BlockR
return <Clock className="w-4 h-4 text-zinc-400 shrink-0" />;
};
// Skipped scenarios are not expandable (no steps to show)
const isExpandable = block.status !== 'skipped' && parsedSteps.length > 0;
return (
<Card className={`border-l-4 ${borderColor}`}>
{/* Clickable header */}
{/* Header - clickable only if expandable */}
<CardHeader
className="p-2 cursor-pointer hover:bg-muted/50 transition-colors"
onClick={onToggle}
className={`p-2 ${isExpandable ? 'cursor-pointer hover:bg-muted/50' : ''} transition-colors`}
onClick={isExpandable ? onToggle : undefined}
>
<div className="flex items-center gap-1.5">
<span className="text-muted-foreground shrink-0">
{isCollapsed ? <ChevronRight className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</span>
{/* Show chevron only if expandable */}
{isExpandable ? (
<span className="text-muted-foreground shrink-0">
{isCollapsed ? <ChevronRight className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</span>
) : (
<span className="w-4 shrink-0" /> // Spacer to maintain alignment
)}
<StatusIcon />
<div className="flex-1 min-w-0 flex items-center gap-1.5 flex-wrap">
<span className={`text-xs font-medium px-1.5 py-0.5 rounded shrink-0 ${
@@ -278,7 +294,8 @@ function BlockRenderer({ block, isCollapsed, onToggle, showDefinitions }: BlockR
{block.name}
</span>
</div>
{parsedSteps.length > 0 && (
{/* Show step count only if expandable */}
{isExpandable && parsedSteps.length > 0 && (
<span className="text-xs text-muted-foreground shrink-0 hidden sm:block">
{parsedSteps.length} étapes
</span>
@@ -286,8 +303,8 @@ function BlockRenderer({ block, isCollapsed, onToggle, showDefinitions }: BlockR
</div>
</CardHeader>
{/* Collapsible content */}
{!isCollapsed && (
{/* Collapsible content - only shown if expandable and not collapsed */}
{isExpandable && !isCollapsed && (
<CardContent className="pt-0 px-2 pb-2">
<div className="space-y-0.5 ml-0 sm:ml-6">
{parsedSteps.map((step, index) => (
+108 -1073
View File
File diff suppressed because it is too large Load Diff
+24 -17
View File
@@ -10,124 +10,131 @@ export interface StepDefinitionInfo {
}
export const stepDefinitions: StepDefinitionInfo[] = [
{
"pattern": "Scénario non implémenté",
"keyword": "Given",
"file": "navigation.steps.ts",
"sourceCode": "Given('Scénario non implémenté', async function (this: FestipodWorld) {\n return 'skipped';\n});",
"lineNumber": 7
},
{
"pattern": "je suis sur la page {string}",
"keyword": "Given",
"file": "navigation.steps.ts",
"sourceCode": "Given('je suis sur la page {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n this.navigateTo(`#/demo/${screenId}`);\n});",
"lineNumber": 31
"lineNumber": 37
},
{
"pattern": "je suis connecté en tant qu'utilisateur",
"keyword": "Given",
"file": "navigation.steps.ts",
"sourceCode": "Given('je suis connecté en tant qu\\'utilisateur', async function (this: FestipodWorld) {\n this.isAuthenticated = true;\n});",
"lineNumber": 36
"lineNumber": 42
},
{
"pattern": "je suis connecté",
"keyword": "Given",
"file": "navigation.steps.ts",
"sourceCode": "Given('je suis connecté', async function (this: FestipodWorld) {\n this.isAuthenticated = true;\n});",
"lineNumber": 40
"lineNumber": 46
},
{
"pattern": "je ne suis pas connecté",
"keyword": "Given",
"file": "navigation.steps.ts",
"sourceCode": "Given('je ne suis pas connecté', async function (this: FestipodWorld) {\n this.isAuthenticated = false;\n});",
"lineNumber": 44
"lineNumber": 50
},
{
"pattern": "je navigue vers {string}",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je navigue vers {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n this.navigateTo(`#/demo/${screenId}`);\n});",
"lineNumber": 48
"lineNumber": 54
},
{
"pattern": "je clique sur {string}",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je clique sur {string}', async function (this: FestipodWorld, elementName: string) {\n const source = this.getRenderedText();\n // Check that a clickable element with this text exists (onClick handler + text content)\n const escapedName = elementName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = new RegExp(`onClick[^>]*>[^<]*${escapedName}`, 'i');\n const found = pattern.test(source);\n if (!found) {\n this.attach(`MISSING: Clickable element \"${elementName}\" not found in screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 53
"lineNumber": 59
},
{
"pattern": "je sélectionne {string}",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je sélectionne {string}', async function (this: FestipodWorld, elementName: string) {\n const source = this.getRenderedText();\n // Check that a selectable element with this text exists\n const escapedName = elementName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = new RegExp(`onClick[^>]*>[^<]*${escapedName}`, 'i');\n const found = pattern.test(source);\n if (!found) {\n this.attach(`MISSING: Selectable element \"${elementName}\" not found in screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 65
"lineNumber": 71
},
{
"pattern": "je clique sur le bouton {string}",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je clique sur le bouton {string}', async function (this: FestipodWorld, buttonName: string) {\n const source = this.getRenderedText();\n // Check that a Button component with this label exists\n const escapedName = buttonName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = new RegExp(`<Button[^>]*>[^<]*${escapedName}[^<]*</Button>`, 'i');\n const found = pattern.test(source);\n if (!found) {\n this.attach(`MISSING: Button \"${buttonName}\" not found in screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 77
"lineNumber": 83
},
{
"pattern": "je clique sur un participant",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je clique sur un participant', async function (this: FestipodWorld) {\n this.navigateTo('#/demo/user-profile');\n});",
"lineNumber": 89
"lineNumber": 95
},
{
"pattern": "je clique sur un événement",
"keyword": "When",
"file": "navigation.steps.ts",
"sourceCode": "When('je clique sur un événement', async function (this: FestipodWorld) {\n this.navigateTo('#/demo/event-detail');\n});",
"lineNumber": 93
"lineNumber": 99
},
{
"pattern": "je suis redirigé vers {string}",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('je suis redirigé vers {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n expect(this.currentScreenId).to.equal(screenId);\n});",
"lineNumber": 97
"lineNumber": 103
},
{
"pattern": "je vois l'écran {string}",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('je vois l\\'écran {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n expect(this.currentScreenId).to.equal(screenId);\n});",
"lineNumber": 102
"lineNumber": 108
},
{
"pattern": "je reste sur la page {string}",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('je reste sur la page {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n expect(this.currentScreenId).to.equal(screenId);\n});",
"lineNumber": 107
"lineNumber": 113
},
{
"pattern": "l'écran contient une section {string}",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('l\\'écran contient une section {string}', async function (this: FestipodWorld, sectionName: string) {\n const found = this.hasText(sectionName);\n if (!found) {\n this.attach(`MISSING SECTION: \"${sectionName}\" not found in screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 112
"lineNumber": 118
},
{
"pattern": "je peux annuler et revenir à l'écran précédent",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('je peux annuler et revenir à l\\'écran précédent', async function (this: FestipodWorld) {\n expect(this.currentScreenId).to.equal('create-event');\n const source = this.getRenderedText();\n // Detect ✕ close button with onClick handler that calls navigate()\n const found = /onClick\\s*=\\s*\\{\\s*\\(\\)\\s*=>\\s*navigate\\s*\\(['\"]home['\"]\\)\\s*\\}[^>]*>✕</.test(source);\n expect(found, 'Create event screen should have ✕ button with navigate(\"home\")').to.be.true;\n});",
"lineNumber": 120
"lineNumber": 126
},
{
"pattern": "je peux naviguer vers {string}",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('je peux naviguer vers {string}', async function (this: FestipodWorld, pageName: string) {\n const screenId = resolveScreenId(pageName);\n const source = this.getRenderedText();\n // Check that a navigation link to this screen exists: navigate('screenId') or onClick={() => navigate('screenId')}\n const pattern = new RegExp(`navigate\\\\s*\\\\(\\\\s*['\"]${screenId}['\"]\\\\s*\\\\)`);\n const found = pattern.test(source);\n if (!found) {\n this.attach(`MISSING: Navigation to \"${screenId}\" not found in screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 128
"lineNumber": 134
},
{
"pattern": "la navigation affiche {string} comme actif",
"keyword": "Then",
"file": "navigation.steps.ts",
"sourceCode": "Then('la navigation affiche {string} comme actif', async function (this: FestipodWorld, menuItem: string) {\n const source = this.getRenderedText();\n // Check that NavBar has an item with this label and active: true\n // Pattern: { icon: '...', label: 'menuItem', active: true }\n const escapedItem = menuItem.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = new RegExp(`label:\\\\s*['\"]${escapedItem}['\"][^}]*active:\\\\s*true`, 'i');\n const found = pattern.test(source);\n if (!found) {\n this.attach(`MISSING: Menu item \"${menuItem}\" is not active in NavBar of screen \"${this.currentScreenId}\"`, 'text/plain');\n return 'pending';\n }\n});",
"lineNumber": 140
"lineNumber": 146
},
{
"pattern": "l'écran {string} est affiché",
+44 -76
View File
@@ -19,7 +19,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 4,
"failed": 0,
"skipped": 1,
"lastRun": "2026-01-18T20:32:26.120Z",
"lastRun": "2026-01-19T09:27:22.847Z",
"scenarios": [
{
"name": "Accéder à la création d'événement",
@@ -49,7 +49,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 3,
"failed": 0,
"skipped": 1,
"lastRun": "2026-01-18T20:32:26.120Z",
"lastRun": "2026-01-19T09:27:22.847Z",
"scenarios": [
{
"name": "Accéder aux détails d'un événement terminé",
@@ -71,11 +71,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-5",
"totalScenarios": 5,
"totalScenarios": 4,
"passed": 0,
"failed": 0,
"skipped": 5,
"lastRun": "2026-01-18T20:32:26.120Z",
"skipped": 4,
"lastRun": "2026-01-19T09:27:22.847Z",
"scenarios": [
{
"name": "Voir les commentaires existants",
@@ -92,10 +92,6 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Supprimer un commentaire",
"status": "skipped"
},
{
"name": "Vérifier les données de l'écran",
"status": "skipped"
}
]
},
@@ -105,7 +101,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 3,
"lastRun": "2026-01-18T20:32:26.120Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Consulter un événement avant inscription",
@@ -135,7 +131,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 0,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.120Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Consulter un macro-événement",
@@ -157,11 +153,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-16",
"totalScenarios": 6,
"passed": 2,
"totalScenarios": 5,
"passed": 1,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.120Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder aux points de rencontre",
@@ -177,14 +173,10 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"name": "Définir l'heure de rencontre",
"status": "passed"
},
{
"name": "Échanger des liens de contact",
"status": "skipped"
},
{
"name": "Vérifier les données requises",
"name": "Échanger des liens de contact",
"status": "skipped"
}
]
@@ -195,7 +187,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 0,
"failed": 0,
"skipped": 5,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Partager un événement auquel je participe",
@@ -221,11 +213,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-18",
"totalScenarios": 5,
"totalScenarios": 4,
"passed": 1,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"skipped": 3,
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Configurer les notifications de nouveaux participants",
@@ -242,10 +234,6 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Voir les nouveaux participants sur l'accueil",
"status": "skipped"
},
{
"name": "Vérifier les données des paramètres",
"status": "skipped"
}
]
},
@@ -255,7 +243,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 1,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Voir les événements à venir sur l'accueil",
@@ -285,7 +273,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 4,
"failed": 0,
"skipped": 1,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder au profil d'un participant",
@@ -315,7 +303,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à la liste des événements depuis le profil",
@@ -349,7 +337,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 3,
"failed": 0,
"skipped": 1,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à la liste des inscrits",
@@ -375,7 +363,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 3,
"failed": 0,
"skipped": 2,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à mon profil",
@@ -405,7 +393,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 3,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder aux paramètres de profil",
@@ -431,11 +419,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-22",
"totalScenarios": 5,
"totalScenarios": 4,
"passed": 0,
"failed": 0,
"skipped": 5,
"lastRun": "2026-01-18T20:32:26.121Z",
"skipped": 4,
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder au partage de profil",
@@ -452,10 +440,6 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Voir les statistiques de parrainage",
"status": "skipped"
},
{
"name": "Vérifier les données du profil",
"status": "skipped"
}
]
},
@@ -465,7 +449,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 3,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder au partage depuis le profil",
@@ -491,11 +475,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-24",
"totalScenarios": 4,
"totalScenarios": 3,
"passed": 2,
"failed": 0,
"skipped": 2,
"lastRun": "2026-01-18T20:32:26.121Z",
"skipped": 1,
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder aux paramètres de notification",
@@ -508,20 +492,16 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Voir les activités de mes contacts sur l'accueil",
"status": "skipped"
},
{
"name": "Vérifier les données des paramètres",
"status": "skipped"
}
]
},
{
"featureId": "us-25",
"totalScenarios": 4,
"totalScenarios": 3,
"passed": 1,
"failed": 0,
"skipped": 3,
"lastRun": "2026-01-18T20:32:26.121Z",
"skipped": 2,
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder aux paramètres de notification",
@@ -534,10 +514,6 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Configurer les thématiques d'intérêt",
"status": "skipped"
},
{
"name": "Vérifier les données des paramètres",
"status": "skipped"
}
]
},
@@ -547,7 +523,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 2,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à la création d'événement",
@@ -573,7 +549,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 2,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder au profil pour voir la photo",
@@ -595,11 +571,11 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"featureId": "us-1",
"totalScenarios": 4,
"passed": 1,
"totalScenarios": 3,
"passed": 0,
"failed": 0,
"skipped": 3,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder aux détails d'un événement terminé",
@@ -607,25 +583,21 @@ const rawResults: RawFeatureTestStatus[] = [
},
{
"name": "Consulter la liste des participants d'un atelier",
"status": "passed"
},
{
"name": "Consulter les ressources d'un atelier",
"status": "skipped"
},
{
"name": "Vérifier les données affichées pour un atelier",
"name": "Consulter les ressources d'un atelier",
"status": "skipped"
}
]
},
{
"featureId": "us-11",
"totalScenarios": 4,
"totalScenarios": 3,
"passed": 0,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"skipped": 3,
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder au bilan consolidé",
@@ -638,10 +610,6 @@ const rawResults: RawFeatureTestStatus[] = [
{
"name": "Voir la synthèse globale",
"status": "skipped"
},
{
"name": "Vérifier les données du bilan",
"status": "skipped"
}
]
},
@@ -651,7 +619,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 1,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à la création d'atelier",
@@ -681,7 +649,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 0,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Accéder à la zone de notes personnelles",
@@ -707,7 +675,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 0,
"failed": 0,
"skipped": 4,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Voir les commentaires existants d'un atelier",
@@ -733,7 +701,7 @@ const rawResults: RawFeatureTestStatus[] = [
"passed": 2,
"failed": 0,
"skipped": 2,
"lastRun": "2026-01-18T20:32:26.121Z",
"lastRun": "2026-01-19T09:27:22.848Z",
"scenarios": [
{
"name": "Rechercher un événement public existant",