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:
@@ -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
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
+24
-17
@@ -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
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user