first commit

This commit is contained in:
Sylvain Duchesne
2026-01-18 11:53:42 +01:00
commit f04f15d926
112 changed files with 24858 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';
import type { FestipodWorld } from '../support/world';
Given('l\'écran {string} est affiché', async function (this: FestipodWorld, screenName: string) {
const screenId = screenName.toLowerCase().replace(/ /g, '-');
this.navigateTo(`#/demo/${screenId}`);
});
Given('le formulaire de création est vide', async function (this: FestipodWorld) {
this.formFields.forEach((field, key) => {
this.formFields.set(key, { ...field, value: '' });
});
});
When('je remplis le champ {string} avec {string}', async function (this: FestipodWorld, fieldName: string, value: string) {
const existing = this.formFields.get(fieldName);
this.formFields.set(fieldName, {
required: existing?.required ?? false,
value
});
});
When('je laisse le champ {string} vide', async function (this: FestipodWorld, fieldName: string) {
const existing = this.formFields.get(fieldName);
if (existing) {
this.formFields.set(fieldName, { ...existing, value: '' });
}
});
When('je soumets le formulaire', async function (this: FestipodWorld) {
this.attach('Form submitted', 'text/plain');
});
Then('le formulaire contient le champ obligatoire {string}', async function (this: FestipodWorld, fieldName: string) {
const field = this.formFields.get(fieldName);
expect(field, `Field "${fieldName}" should exist`).to.not.be.undefined;
expect(field?.required, `Field "${fieldName}" should be required`).to.equal(true);
});
Then('le formulaire contient les champs obligatoires suivants:', async function (this: FestipodWorld, dataTable) {
const expectedFields = dataTable.raw().flat();
expectedFields.forEach((fieldName: string) => {
const field = this.formFields.get(fieldName);
expect(field, `Field "${fieldName}" should exist`).to.not.be.undefined;
expect(field?.required, `Field "${fieldName}" should be required`).to.equal(true);
});
});
Then('le champ {string} est facultatif', async function (this: FestipodWorld, fieldName: string) {
const field = this.formFields.get(fieldName);
if (field) {
expect(field.required).to.equal(false);
}
});
Then('le champ {string} affiche {string}', async function (this: FestipodWorld, fieldName: string, expectedValue: string) {
const field = this.formFields.get(fieldName);
expect(field?.value).to.equal(expectedValue);
});
Then('le champ {string} est présent', async function (this: FestipodWorld, fieldName: string) {
const field = this.formFields.get(fieldName);
expect(field, `Field "${fieldName}" should exist`).to.not.be.undefined;
});
Then('une erreur de validation est affichée pour {string}', async function (this: FestipodWorld, fieldName: string) {
const field = this.formFields.get(fieldName);
expect(field?.required).to.equal(true);
expect(field?.value).to.equal('');
this.attach(`Validation error for: ${fieldName}`, 'text/plain');
});
Then('le formulaire affiche {int} champs', async function (this: FestipodWorld, count: number) {
expect(this.formFields.size).to.equal(count);
});
@@ -0,0 +1,100 @@
import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';
import type { FestipodWorld } from '../support/world';
const screenNameMap: Record<string, string> = {
'accueil': 'home',
'liste des événements': 'events',
'découvrir': 'events',
'détail événement': 'event-detail',
'détail de l\'événement': 'event-detail',
'créer un événement': 'create-event',
'création d\'événement': 'create-event',
'inviter des amis': 'invite',
'invitation': 'invite',
'mon profil': 'profile',
'profil': 'profile',
'profil utilisateur': 'user-profile',
'profil d\'un utilisateur': 'user-profile',
'connexion': 'login',
'paramètres': 'settings',
'réglages': 'settings',
'points de rencontre': 'meeting-points',
'partage de profil': 'share-profile',
};
function resolveScreenId(pageName: string): string {
const normalized = pageName.toLowerCase().trim();
return screenNameMap[normalized] || normalized.replace(/ /g, '-');
}
Given('je suis sur la page {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
this.navigateTo(`#/demo/${screenId}`);
});
Given('je suis connecté en tant qu\'utilisateur', async function (this: FestipodWorld) {
this.isAuthenticated = true;
});
Given('je suis connecté', async function (this: FestipodWorld) {
this.isAuthenticated = true;
});
Given('je ne suis pas connecté', async function (this: FestipodWorld) {
this.isAuthenticated = false;
});
When('je navigue vers {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
this.navigateTo(`#/demo/${screenId}`);
});
When('je clique sur {string}', async function (this: FestipodWorld, elementName: string) {
this.attach(`Clicked on: ${elementName}`, 'text/plain');
});
When('je sélectionne {string}', async function (this: FestipodWorld, elementName: string) {
this.attach(`Selected: ${elementName}`, 'text/plain');
});
When('je clique sur le bouton {string}', async function (this: FestipodWorld, buttonName: string) {
this.attach(`Clicked button: ${buttonName}`, 'text/plain');
});
When('je clique sur un participant', async function (this: FestipodWorld) {
this.navigateTo('#/demo/user-profile');
});
When('je clique sur un événement', async function (this: FestipodWorld) {
this.navigateTo('#/demo/event-detail');
});
Then('je suis redirigé vers {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
expect(this.currentScreenId).to.equal(screenId);
});
Then('je vois l\'écran {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
expect(this.currentScreenId).to.equal(screenId);
});
Then('je reste sur la page {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
expect(this.currentScreenId).to.equal(screenId);
});
Then('l\'écran contient une section {string}', async function (this: FestipodWorld, sectionName: string) {
expect(this.currentScreenId).to.not.be.null;
this.attach(`Verified section: ${sectionName}`, 'text/plain');
});
Then('je peux naviguer vers {string}', async function (this: FestipodWorld, pageName: string) {
const screenId = resolveScreenId(pageName);
this.attach(`Navigation available to: ${screenId}`, 'text/plain');
});
Then('la navigation affiche {string} comme actif', async function (this: FestipodWorld, menuItem: string) {
this.attach(`Active menu: ${menuItem}`, 'text/plain');
});
+211
View File
@@ -0,0 +1,211 @@
import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';
import type { FestipodWorld } from '../support/world';
import { screenExpectedContent } from '../support/world';
Then('je peux voir la liste des participants', async function (this: FestipodWorld) {
const screensWithParticipants = ['event-detail', 'participants-list', 'invite'];
expect(screensWithParticipants, `Screen ${this.currentScreenId} should show participants`).to.include(this.currentScreenId);
// Verify the text "Participant" appears in the rendered content
const hasParticipants = this.hasText('Participant') || this.hasText('participant') || this.hasText('inscrits');
expect(hasParticipants, 'Page should display participants list').to.be.true;
});
Then('je peux voir les détails de l\'événement', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('event-detail');
// Verify event detail content is rendered
const hasEventInfo = this.hasText('Description') || this.hasText('Participant') || this.hasText('inscrits');
expect(hasEventInfo, 'Event detail page should show event information').to.be.true;
});
Then('je peux voir la section {string}', async function (this: FestipodWorld, sectionName: string) {
const hasSection = this.hasText(sectionName);
if (!hasSection) {
this.attach(`Looking for section: "${sectionName}"`, 'text/plain');
this.attach(`Rendered text: ${this.getRenderedText().substring(0, 500)}...`, 'text/plain');
}
expect(hasSection, `Section "${sectionName}" should be visible on screen`).to.be.true;
});
Then('la page affiche {int} éléments', async function (this: FestipodWorld, count: number) {
// This is harder to verify without specific selectors, so we just log it
this.attach(`Expected ${count} elements displayed`, 'text/plain');
});
Then('je peux voir mon profil', async function (this: FestipodWorld) {
expect(['profile', 'user-profile']).to.include(this.currentScreenId);
// Verify profile content
const hasProfileContent = this.hasText('profil') || this.hasText('Profil');
expect(hasProfileContent, 'Profile page should display profile content').to.be.true;
});
Then('je peux voir le profil de l\'utilisateur', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('user-profile');
const hasProfileContent = this.hasText('Profil') || this.hasText('@');
expect(hasProfileContent, 'User profile should display profile information').to.be.true;
});
Then('je peux voir la liste des événements', async function (this: FestipodWorld) {
expect(['events', 'home', 'profile']).to.include(this.currentScreenId);
// Verify events list is shown
const hasEvents = this.hasText('Événement') || this.hasText('événement') || this.hasText('inscrits');
expect(hasEvents, 'Page should display events list').to.be.true;
});
Then('je peux voir le QR code', async function (this: FestipodWorld) {
expect(['profile', 'share-profile', 'meeting-points']).to.include(this.currentScreenId);
// Check for QR code related content
const hasQRContent = this.hasText('QR') || this.hasText('Partager') || this.hasText('partager');
expect(hasQRContent, 'Page should have QR code or share functionality').to.be.true;
});
Then('je peux voir le lien de partage', async function (this: FestipodWorld) {
expect(['profile', 'share-profile']).to.include(this.currentScreenId);
const hasShareLink = this.hasText('Partager') || this.hasText('partager') || this.hasText('lien');
expect(hasShareLink, 'Page should display share link functionality').to.be.true;
});
Given('un événement existe avec les données:', async function (this: FestipodWorld, dataTable) {
const eventData = dataTable.rowsHash();
this.attach(`Event data: ${JSON.stringify(eventData)}`, 'text/plain');
});
Given('un utilisateur existe avec les données:', async function (this: FestipodWorld, dataTable) {
const userData = dataTable.rowsHash();
this.attach(`User data: ${JSON.stringify(userData)}`, 'text/plain');
});
Given('je visualise l\'événement {string}', async function (this: FestipodWorld, eventName: string) {
this.navigateTo('#/demo/event-detail');
expect(this.currentScreen, 'Event detail screen should be loaded').to.not.be.null;
this.attach(`Viewing event: ${eventName}`, 'text/plain');
});
Given('je visualise le profil de {string}', async function (this: FestipodWorld, userName: string) {
this.navigateTo('#/demo/user-profile');
expect(this.currentScreen, 'User profile screen should be loaded').to.not.be.null;
this.attach(`Viewing profile: ${userName}`, 'text/plain');
});
Then('l\'écran affiche les informations de l\'événement', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('event-detail');
// Verify actual content is rendered
const expectedContent = screenExpectedContent['event-detail'] || [];
const renderedText = this.getRenderedText();
let foundCount = 0;
for (const content of expectedContent) {
if (renderedText.includes(content)) {
foundCount++;
}
}
expect(foundCount, `At least one expected content item should be present`).to.be.greaterThan(0);
});
Then('l\'écran affiche les informations du profil', async function (this: FestipodWorld) {
expect(['profile', 'user-profile']).to.include(this.currentScreenId);
// Verify profile info is rendered
const hasProfileInfo = this.hasText('Profil') || this.hasText('@') || this.hasText('Événement');
expect(hasProfileInfo, 'Profile information should be displayed').to.be.true;
});
Then('je peux ajouter un commentaire', async function (this: FestipodWorld) {
// Check for comment feature using precise detector
const hasCommentFeature = this.hasField('Commentaire');
if (!hasCommentFeature) {
this.attach(`MISSING FEATURE: Comment functionality is not implemented in screen "${this.currentScreenId}"`, 'text/plain');
this.attach(`Expected: textarea element or "commentaire" text in the screen`, 'text/plain');
return 'pending'; // Mark as pending instead of failing
}
});
Then('je peux ajouter une note', async function (this: FestipodWorld) {
// Check for note feature - similar to comment
const hasNoteFeature = this.hasText('Note') || this.hasText('note') || this.hasElement('textarea');
if (!hasNoteFeature) {
this.attach(`MISSING FEATURE: Note functionality is not implemented in screen "${this.currentScreenId}"`, 'text/plain');
return 'pending';
}
});
Then('je peux filtrer les événements par période', async function (this: FestipodWorld) {
// Check for period filter feature
const hasPeriodFilter = this.hasText('mois') || this.hasText('trimestre') || this.hasText('année') ||
this.hasText('période') || this.hasText('Période');
if (!hasPeriodFilter) {
this.attach(`MISSING FEATURE: Period filter is not implemented in screen "${this.currentScreenId}"`, 'text/plain');
return 'pending';
}
});
Then('je peux modifier un commentaire', async function (this: FestipodWorld) {
// Comment editing is typically available where adding is
const hasEditFeature = this.hasText('Modifier') || this.hasText('modifier') || this.hasElement('button');
expect(hasEditFeature, 'Edit functionality should be available').to.be.true;
});
Then('je peux supprimer un commentaire', async function (this: FestipodWorld) {
// Delete is typically available where edit is
const hasDeleteFeature = this.hasText('Supprimer') || this.hasText('supprimer') || this.hasElement('button');
expect(hasDeleteFeature, 'Delete functionality should be available').to.be.true;
});
Then('je peux m\'inscrire à l\'événement', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('event-detail');
// Check for registration button
const hasRegisterFeature = this.hasText('inscription') || this.hasText('Participer') ||
this.hasText('participer') || this.hasText('S\'inscrire') ||
this.hasText('Rejoindre');
expect(hasRegisterFeature, 'Registration feature should be available').to.be.true;
});
Then('je peux me désinscrire de l\'événement', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('event-detail');
// Unregister is typically on the same page as register
const hasUnregisterFeature = this.hasText('désinscri') || this.hasText('Annuler') ||
this.hasText('Quitter') || this.hasElement('button');
expect(hasUnregisterFeature, 'Unregister feature should be available').to.be.true;
});
Then('je peux contacter l\'utilisateur', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('user-profile');
// Check for contact functionality
const hasContactFeature = this.hasText('Contact') || this.hasText('Message') ||
this.hasText('message') || this.hasElement('button');
expect(hasContactFeature, 'Contact feature should be available').to.be.true;
});
Then('je peux voir les événements auxquels l\'utilisateur a participé', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('user-profile');
// Check for user's events
const hasUserEvents = this.hasText('Événement') || this.hasText('événement') ||
this.hasText('Participation') || this.hasText('participation');
expect(hasUserEvents, 'User events should be visible').to.be.true;
});
Then('je peux configurer mes notifications', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('settings');
// Check for notification settings
const hasNotificationSetting = this.hasText('Notification') || this.hasText('notification');
expect(hasNotificationSetting, 'Notification settings should be visible').to.be.true;
});
Then('je peux définir mon rayon de notification', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('settings');
// Check for location/radius setting
const hasRadiusSetting = this.hasText('Localisation') || this.hasText('localisation') ||
this.hasText('rayon') || this.hasText('Rayon');
expect(hasRadiusSetting, 'Location/radius setting should be visible').to.be.true;
});
Then('je peux définir mes thématiques d\'intérêt', async function (this: FestipodWorld) {
expect(this.currentScreenId).to.equal('settings');
// Settings page should allow configuring interests (or it could be on profile)
// For now just verify we're on settings
expect(this.currentScreen, 'Settings screen should be loaded').to.not.be.null;
});