Tests et qualité
Chaque projet du monorepo a ses propres commandes de vérification. La CI (.github/workflows/ci.yml) les rejoue sur chaque pull request, en ne lançant que les jobs des projets modifiés. Cette page donne, projet par projet, ce qu'il faut lancer avant de pousser et ce que la CI exige pour qu'une pull request soit fusionnable.
Avant d'ouvrir une pull request
Une commande par projet modifié, les mêmes que dans CONTRIBUTING.md. Elles rejouent en local l'essentiel des contrôles de la CI.
cd backend && npm run typecheck && npm run lint && npm run env:check && npm testcd frontend-web && npm run lint && npm run typecheck && npm testcd mobile-app && npm run typecheck && npm run lintcd smart-contract && npm run lint && npm run test:coverage && npm run coverage:checkcd documentation-officielle && npm run checkPour l'Office de Tourisme, depuis frontend-office-tourisme/ :
node ../.github/scripts/check-static-links.mjs .Vue d'ensemble de la CI
flowchart LR
CH["changes : dossiers modifiés"] --> BE["backend"]
CH --> SC["contracts"]
CH --> WE["web"]
CH --> MO["mobile"]
CH --> TO["tourisme"]
SC --> CI["chain : backend sur un vrai nœud"]
BE --> CI
BE --> DO["docker : images, Compose, Trivy"]
SC --> DO
WE --> DO
TO --> DO
GL["secrets : gitleaks"]
DOC["documentation"]| Job | Se lance si | Durée maximale |
|---|---|---|
changes |
toujours | 5 min |
secrets |
toujours | 10 min |
documentation |
toujours | 10 min |
backend |
backend/** modifié |
15 min |
contracts |
smart-contract/** ou backend/** modifié |
20 min |
chain |
contrats ou backend modifiés, et contracts et backend sans échec |
20 min |
web |
frontend-web/** modifié |
15 min |
mobile |
mobile-app/** modifié |
15 min |
tourisme |
frontend-office-tourisme/** modifié |
5 min |
docker |
infrastructure, backend, contrats, web ou tourisme modifiés, et les jobs précédents sans échec | 20 min |
Une modification de .github/workflows/ci.yml déclenche tous les jobs. Le job contracts tourne aussi quand seul le backend change, parce que le backend embarque les ABI des contrats. Toutes les actions GitHub sont épinglées par empreinte de commit (actions/checkout@11d5960a...) et non par étiquette, ce qui empêche une étiquette déplacée d'injecter du code dans la CI.
La liste générée des jobs est dans Intégration continue.
Smart contracts
| Commande | Ce qu'elle fait | Exigé en CI |
|---|---|---|
npm run build |
Compile les contrats (Hardhat 3, Solidity 0.8.34) | indirectement |
npm run typecheck |
Compile puis vérifie le TypeScript des tests et scripts | oui |
npm run lint |
solhint avec --max-warnings 0 sur contracts/*.sol |
oui, zéro avertissement |
npm test |
50 tests TypeScript (mocha et ethers), dont 7 sur la répartition des rôles des scripts de déploiement (test/roles.test.ts), et 4 tests de fuzzing Solidity |
via test:coverage |
npm run test:coverage |
Mêmes tests avec mesure de couverture, rapport dans coverage/lcov.info |
oui |
npm run coverage:check |
Échoue si un contrat de production a moins de 100 % de lignes couvertes ; seuil réglable par COVERAGE_MIN_LINES |
oui, 100 % |
node scripts/export-abi.mjs --check |
Compare les ABI compilées à celles de backend/src/blockchain/abi/ |
oui |
npm run slither |
Slither 0.11.6 dans Docker, échec dès un constat de niveau Medium non consigné dans slither.db.json |
oui |
npm run test:gas |
Coût en gaz de chaque fonction | non |
npm audit --omit=dev --audit-level=critical |
Vulnérabilités critiques des dépendances de production | oui, seuil critique (voir Dépendances) |
Les tests sont décrits dans Tests, fuzzing et couverture.
Backend
| Commande | Ce qu'elle fait | Exigé en CI |
|---|---|---|
npm audit --omit=dev --audit-level=high |
Vulnérabilités hautes et critiques des dépendances de production | oui |
npx prisma generate |
Génère le client Prisma | oui |
npm run env:check |
Compare les clés du schéma de env.config.ts et de .env.example |
oui |
npm run typecheck |
tsc --noEmit |
oui |
npm run lint |
ESLint, dont no-floating-promises |
oui |
npx prisma migrate deploy |
Applique toutes les migrations sur une base PostgreSQL 15 vierge | oui |
npx prisma migrate diff --from-config-datasource --to-schema prisma/schema.prisma --exit-code |
Échoue si schema.prisma décrit un état que les migrations ne produisent pas |
oui |
npm test |
Jest en série (--runInBand), avec Prisma et Redis simulés en mémoire : 108 tests dans 19 fichiers |
oui, avec --ci |
npm run test:coverage |
Mêmes tests avec couverture | non |
npm run compile |
Compile vers dist/ et copie les gabarits d'emails |
oui |
npm run test:chain |
Tests de bout en bout sur un nœud Hardhat réel | job chain |
Tests unitaires et d'API
Les tests de backend/__tests__/ appellent l'application Express avec Supertest. Prisma et Redis y sont remplacés par des doublures en mémoire (prisma.mock.ts, redis.mock.ts) ; setup-env.ts force BLOCKCHAIN_MODE=simulated et désactive le code de connexion par email, la double authentification des administrateurs et la vérification d'âge (AGE_VERIFICATION_REQUIRED=false). Les tests du refus 403 des comptes non vérifiés, dans lottery.test.ts et marketplace.test.ts, réactivent le contrôle en modifiant env.AGE_VERIFICATION_REQUIRED le temps du test ; identity.test.ts couvre l'envoi des pièces et la décision de la Mairie. Ces tests n'ont donc besoin ni de base, ni de Redis, ni de blockchain.
Attention
La doublure Prisma est écrite à la main : elle ne connaît que les modèles et les méthodes déjà utilisés. Un nouveau modèle ou une nouvelle méthode Prisma (groupBy, aggregate...) appelés dans une route testée demandent d'étendre prisma.mock.ts, sinon le test échoue sur une fonction indéfinie.
Tests sur une vraie blockchain
Le job chain construit l'image de smart-contract/, qui démarre un nœud Hardhat, déploie les contrats et lance un oracle VRF local, puis exécute npm run test:chain avec PostgreSQL et Redis réels. Le scénario de onchain-lottery.chain.ts couvre l'achat, le cadeau, l'avance du temps (evm_increaseTime), le tirage par le keeper, le versement de la cagnotte, le POAP et le disjoncteur. En local :
docker compose up -d --wait
cd backend && npm run test:chainVoir Tests sur une vraie chaîne.
Frontend web
| Commande | Ce qu'elle fait | Exigé en CI |
|---|---|---|
npm audit --omit=dev --audit-level=high |
Vulnérabilités des dépendances de production | oui |
npm run lint |
ESLint de Next.js | oui |
npm run typecheck |
tsc --noEmit |
oui |
npm test |
Vitest en environnement jsdom, fichiers __tests__/**/*.test.{ts,tsx} : 21 tests dans 3 fichiers, dont 8 pour le consentement à la mesure d'audience et son bandeau (consent.test.tsx) |
oui |
npm run build |
Build de production Next.js, télémétrie désactivée | oui |
| Contrôle du bundle | Échoue si .next/static contient une clé sk_live_, une clé AWS, une clé privée PEM ou la clé du compte Hardhat n° 0, ou un fichier .map |
oui |
Voir Tests et build.
Application mobile
| Commande | Ce qu'elle fait | Exigé en CI |
|---|---|---|
npm audit --omit=dev --audit-level=high |
Vulnérabilités des dépendances de production | oui |
npm run typecheck |
tsc --noEmit |
oui |
npm run lint |
ESLint universe |
oui |
npx expo config --type public |
Valide la configuration Expo publique | oui |
Danger
Le dossier mobile-app/__tests__/ contient trois fichiers de tests (compte à rebours, écran d'achat, formateurs), mais le projet n'a ni script test, ni Jest dans ses dépendances. Ces tests ne sont exécutés nulle part. Les rendre exécutables demande d'ajouter jest, jest-expo et @testing-library/react-native, un script test et l'étape correspondante dans le job mobile.
Office de Tourisme
| Commande | Ce qu'elle fait | Exigé en CI |
|---|---|---|
find assets/js \( -name '*.js' -o -name '*.mjs' \) -exec node --check {} \; |
Syntaxe de chaque module | oui |
node ../.github/scripts/check-static-links.mjs . |
Existence de chaque ressource locale citée dans les pages HTML | oui |
Il n'y a pas de test fonctionnel : les parcours (filtres, panier, commande) se vérifient à la main. Voir Servir et déployer.
Documentation
npm run check, depuis documentation-officielle/, construit le site dans un dossier temporaire, le compare à site/, vérifie les liens, les ancres et les descriptions des tableaux générés. Le job tourne sur chaque pull request, même sans modification de la documentation, parce qu'un changement du code peut rendre une page générée obsolète. Voir Écrire la documentation.
Contrôles transverses
| Contrôle | Outil | Seuil |
|---|---|---|
| Secrets dans tout l'historique Git | gitleaks 8.30.1, configuration .gitleaks.toml |
tout secret détecté hors liste blanche |
Validité de docker-compose.yml |
docker compose --profile app config -q |
erreur de syntaxe ou de référence |
| Construction des images | backend (cible runtime), frontend web, blockchain locale, Office de Tourisme |
échec de construction |
| Vulnérabilités des images | Trivy 0.76.2 sur les images backend, web et tourisme, --ignore-unfixed |
toute vulnérabilité HIGH ou CRITICAL corrigeable |
| Analyse statique de sécurité | CodeQL, requêtes security-extended |
alerte de sécurité |
La liste blanche de gitleaks ne contient que deux valeurs publiques de développement, refusées par le backend en production : la clé ENCRYPTION_KEY de démonstration et la clé privée du compte Hardhat n° 0. L'image de la blockchain locale n'est pas analysée par Trivy : elle sert au développement et à la CI, jamais en production.
Tests de charge
Les scénarios k6 de load-tests/ ne sont pas lancés par la CI. Ils servent avant un événement à fort trafic (ouverture des ventes, tirage public) :
docker run --rm -i -e BASE_URL=http://host.docker.internal:2053 grafana/k6 run - < load-tests/smoke.jsVoir Tests de charge.
Quand la CI échoue
| Symptôme | Cause habituelle | Correction |
|---|---|---|
Variables absentes de .env.example |
Variable ajoutée au schéma seulement | L'ajouter à backend/.env.example |
prisma migrate diff en échec |
schema.prisma modifié sans migration |
npx prisma migrate dev --create-only --name <nom> puis relire le SQL |
ABI du backend différente du contrat compilé |
Contrat modifié sans export | npm run export:abi dans smart-contract/ |
KO contracts/BlockLucky.sol |
Ligne non couverte par un test | Ajouter le test manquant |
| Slither en échec | Nouveau constat Medium ou plus | Corriger, ou consigner un faux positif justifié dans slither.db.json |
documentation en échec |
Page générée obsolète ou lien cassé | npm run build dans documentation-officielle/, commiter site/ |
| Trivy en échec | Correctif publié pour l'image de base | Mettre à jour l'image, souvent via la pull request Dependabot |
Secret détecté dans .next/static |
Secret exposé par une variable NEXT_PUBLIC_* |
Retirer la variable, révoquer le secret |