Aller au contenu principal

Tester l'application : recette et tests

Vérifier que l'application résiste aux situations qui cassent (réseau coupé, double clic, adresse falsifiée) avant de la mettre en ligne.

Objectifs de la séance​

  • distinguer les vérifications automatiques (typage, tests, configuration) de la recette (tests faits à la main) ;
  • rédiger un cahier de recette dans le dépôt et le dérouler méthodiquement ;
  • provoquer volontairement les situations qui « cassent » une application ;
  • regrouper les vérifications dans un script npm run verifier ;
  • vérifier qu'aucun secret n'est publié dans le dépôt.

Petite vérification​

Avant de commencer, vérifiez si vous savez...

  1. lancer l'application, ouvrir l'écran Classement depuis l'accueil et lire les deux lignes de filtres affichées (le filtre actif de chaque ligne est en bleu plein)
  2. sur l'écran Classement, choisir « Réseaux et Wi-Fi » et « Débutant », et vérifier que la partie que vous avez jouée apparaît avec votre pseudo et un score du type « 2/3 »
  3. citer le composant React Native qui affiche la liste des parties, et la propriété qui fournit une clé unique à chaque ligne
📌 Réponse attendue

TP pour réfléchir et résoudre des problèmes​

L'application fonctionne : elle est prête à être mise en ligne. Avant cela, vous jouez le rôle d'un testeur : vous écrivez la liste des vérifications à faire (le cahier de recette), puis vous les déroulez une à une, en cherchant à casser l'application. Le serveur de développement doit être lancé (npx expo start, touche w).

Étape 1 — Créer la branche du tutoriel​

Ce tutoriel se fait sur la branche feature/deploiement. Après avoir fusionné le tutoriel précédent, revenez sur main, mettez-la à jour, puis créez la nouvelle branche :

git switch main
git pull

Bonne pratique - Une branche par objectif

La branche feature/deploiement regroupera tout ce qui prépare la mise en ligne : recette, configuration Web et configuration Android. Son nom dit pourquoi elle existe.

Étape 2 — Rédiger le cahier de recette​

Créez le dossier docs à la racine du projet, puis le fichier docs/RECETTE.md. Un cahier de recette est un tableau : chaque ligne décrit une action, le résultat attendu, et une colonne où l'on note OK ou KO. Écrivez-le en suivant ce modèle (quatre parties : vérifications automatiques, parcours normal, robustesse, sécurité) :

# Cahier de recette (tests manuels) du Quiz Cyber

À dérouler avant chaque mise en ligne. Cochez chaque ligne : **OK** ou **KO** (+ description du problème).

## 1. Vérifications automatiques

| # | Commande | Résultat attendu | OK / KO |
|---|----------|------------------|---------|
| 1.1 | `npx tsc --noEmit` | aucune erreur | |
| 1.2 | `npm test` | tous les tests passent (`fail 0`) | |
| 1.3 | `npx expo-doctor` | aucun problème détecté | |

## 2. Parcours normal

| # | Action | Résultat attendu | OK / KO |
|---|--------|------------------|---------|
| 2.1 | Premier lancement de l'application | « Choisir un pseudo pour jouer » s'affiche | |
| 2.2 | Saisir le pseudo `ab` | message « au moins 3 caractères », bouton désactivé | |
| 2.3 | Saisir un pseudo valide puis Enregistrer | retour à l'accueil, « Bonjour ... ! » | |
| 2.4 | Générateur : Réseaux, Débutant | « 3 question(s) disponible(s) », choix 5 et 10 grisés | |
| 2.5 | Générer un quiz de 3 questions et y répondre | chaque réponse est corrigée (vert / rouge + explication) | |
| 2.6 | Voir le résultat | score et temps calculés par le serveur | |
| 2.7 | Voir le classement | la partie apparaît avec le bon pseudo | |

## 3. Robustesse (les tests qui « cassent »)

| # | Action | Résultat attendu | OK / KO |
|---|--------|------------------|---------|
| 3.1 | Appuyer très vite 2 fois sur une réponse | une seule réponse est prise en compte | |
| 3.2 | Appuyer 2 fois vite sur « Enregistrer » (pseudo) | un seul envoi | |
| 3.3 | Changer de thème très vite plusieurs fois | le nombre affiché correspond TOUJOURS au dernier thème | |
| 3.4 | Couper le réseau (mode avion), ouvrir le générateur | message d'erreur + bouton « Réessayer » | |
| 3.5 | Réseau coupé pendant une partie, choisir une réponse | message d'erreur, on peut réessayer une fois le réseau revenu | |
| 3.6 | Quitter une partie (retour) pendant la vérification d'une réponse | aucun plantage, aucun message d'erreur | |
| 3.7 | (Web) Ouvrir `/partie?theme=pirate&niveau=9&nombre=999` | « Les réglages de la partie sont invalides. » | |
| 3.8 | (Web) Recharger la page du résultat (F5) | même score affiché (pas de 2e enregistrement) | |
| 3.9 | Prendre un pseudo déjà utilisé par un autre joueur | « Ce pseudo est déjà pris » | |

## 4. Sécurité

| # | Action | Résultat attendu | OK / KO |
|---|--------|------------------|---------|
| 4.1 | Chercher `secret` ou `service_role` dans le code (`git grep -i service_role`) | aucun résultat | |
| 4.2 | `git status` : le fichier `.env.local` n'apparaît pas | ignoré par Git | |
| 4.3 | Avec la clé publishable, demander `reponse?select=est_correcte` (voir cours) | erreur `permission denied` | |
| 4.4 | Appeler `terminer_partie` sur la partie d'un autre joueur | « Partie introuvable » | |

Complétez la ligne 1.2, qui vérifie les tests automatiques :


Bonne pratique - Écrire les tests avant de les passer

Un test écrit dans un cahier est reproductible : un camarade peut le refaire demain, sans vous poser de questions, et obtenir le même verdict. Le résultat attendu est écrit avant le test, pour ne pas se laisser convaincre que « ça a l'air de marcher ».

Étape 3 — Regrouper les vérifications dans un script npm​

Les vérifications 1.1 et 1.2 se lancent à la main, l'une après l'autre. Ouvrez package.json et ajoutez, à la fin de la section "scripts", deux nouveaux scripts (pensez à ajouter la virgule à la fin de la ligne précédente) :

Lancez-le dans le terminal :

npm run verifier

Bonne pratique - && arrête à la première erreur

Avec commande1 && commande2, la seconde commande ne s'exécute que si la première a réussi. Si le typage échoue, les tests ne se lancent même pas : vous corrigez les erreurs dans l'ordre, sans être noyé par les messages.

Étape 4 — Lancer les vérifications automatiques​

Lancez, dans l'ordre, les trois vérifications de la partie 1 du cahier. Aucune ne doit signaler de problème :

npx tsc --noEmit
npm test
npx expo-doctor

npx expo-doctor compare la configuration du projet avec ce qu'attend la version d'Expo installée (versions des bibliothèques, fichiers de configuration, etc.).


Bonne pratique - Corriger les alertes tout de suite

Une alerte ignorée aujourd'hui devient une panne le jour de la mise en ligne. Si expo-doctor propose de corriger une version, faites-le maintenant, avec npx expo install --fix, puis relancez npm run verifier.

Étape 5 — Dérouler le parcours normal et casser l'application​

Ouvrez docs/RECETTE.md et déroulez les parties 2, 3 et 4, ligne par ligne. Notez OK ou KO à chaque ligne. Voici comment provoquer les situations les plus délicates :

  • Réseau coupé (3.4 et 3.5) : sur téléphone, activez le mode avion. Dans le navigateur, ouvrez les outils de développement (F12), onglet Network (Réseau), et choisissez Offline dans la liste « No throttling ».
  • Double clic (3.1 et 3.2) : cliquez deux fois très vite sur une réponse, puis sur « Enregistrer ». Dans la partie, une seule réponse doit être comptée.
  • Adresse falsifiée (3.7) : dans la barre d'adresse du navigateur, remplacez le chemin par /partie?theme=pirate&niveau=9&nombre=999. L'écran doit afficher « Les réglages de la partie sont invalides. »
  • Rechargement (3.8) : sur l'écran de résultat, appuyez sur F5 : le score est identique et la partie n'est pas enregistrée une deuxième fois.
  • Pseudo déjà pris (3.9) : ouvrez l'application dans une fenêtre de navigation privée (c'est un autre joueur anonyme) et choisissez le pseudo d'un joueur existant.
  • Droits (4.3) : demandez les bonnes réponses à l'API avec la clé publishable (remplacez l'adresse et la clé par les vôtres) :
curl "https://votre-projet.supabase.co/rest/v1/reponse?select=question_id,est_correcte" \
-H "apikey: sb_publishable_xxxxxxxxxxxxxxxxxxxx"

La réponse doit être une erreur contenant permission denied (code 42501) : la colonne est_correcte n'est plus lisible.

  • Partie d'un autre joueur (4.4) : dans l'éditeur SQL de Supabase, exécutez select public.terminer_partie(1); (remplacez 1 par l'identifiant d'une partie de la table partie). Dans l'éditeur, auth.uid() ne correspond à aucun joueur : la fonction répond « Partie introuvable ».

Pour la ligne 4.1, cherchez une clé secrète oubliée dans le code. Complétez la commande Git qui cherche le texte service_role dans tous les fichiers du dépôt, sans tenir compte des majuscules :

Si une ligne est KO, notez le problème dans la colonne, corrigez le code, puis refaites tout le test, pas seulement la ligne corrigée : une correction peut en casser une autre.


Bonne pratique - Casser pour mieux protéger

Les utilisateurs réels ne suivent jamais le parcours idéal : ils cliquent deux fois, perdent leur réseau dans le métro, modifient une adresse. Chaque test de la partie 3 correspond à une protection écrite dans les tutoriels précédents ; la recette prouve qu'elle fonctionne encore.

Étape 6 — Enregistrer votre travail​

Une fois toutes les lignes à OK, enregistrez le cahier de recette (et les fichiers éventuellement créés par le lint) :


Bonne pratique - Garder la recette dans le dépôt

Le cahier de recette est versionné comme le code : il évolue avec l'application, et son historique montre quand chaque vérification a été ajoutée.

📌 Une solution

Notions théoriques​

Vérifications automatiques et recette​

Il existe deux familles de contrôles, qui se complètent :

Vérifications automatiquesRecette (tests manuels)
Qui les lanceune commande (npm run verifier)une personne, avec un cahier
Vitessequelques secondesplusieurs minutes
Ce qu'elles trouventerreurs de type, régressions de la logique pure, mauvaise configurationproblèmes d'usage : réseau, double clic, affichage, parcours complet
Quandà chaque modificationavant chaque mise en ligne

Les tests automatiques de ce projet ne couvrent que la logique « pure » (validation, reducer, conversions). Ce qui touche à l'écran, au réseau, à la base de données ou à la sécurité n'est vérifié que par la recette.

Les situations qui cassent​

Un testeur ne reproduit pas le parcours idéal : il cherche ce que le développeur n'a pas prévu.

  • le réseau disparaît ou ralentit (métro, Wi-Fi saturé) ;
  • l'utilisateur agit trop vite (double clic), quitte un écran en pleine requête, recharge une page ;
  • les données reçues ou saisies sont fausses (pseudo trop court, adresse falsifiée) ;
  • un autre joueur utilise la même application en même temps (pseudo déjà pris, partie d'un autre).

Chacun de ces cas correspond à une protection du code : disabled et verrou useRef, AbortController, EtatChargement, validation des paramètres, contraintes de la base, RLS. Sans la recette, on ne sait pas si elles marchent encore.

Le typage comme filet de sécurité​

La commande npx tsc --noEmit lit tout le code TypeScript, sans rien produire (--noEmit), et signale chaque incohérence de type. Elle attrape en quelques secondes ce qu'une recette manuelle ne verrait qu'en passant sur tous les écrans (une propriété mal orthographiée, un paramètre oublié). Elle ne remplace pourtant ni les tests (qui vérifient le comportement) ni la recette (qui vérifie l'usage).

Les secrets et la recette de sécurité​

Une recette doit aussi contrôler la sécurité : aucune clé secrète dans le code (git grep), .env.local ignoré par Git (git status), données protégées côté base (test avec la clé publishable). Ces vérifications sont rapides, et une faille découverte avant la mise en ligne ne coûte rien ; après, elle peut coûter très cher.

Limite de cette recette

Tous ces tests ont été prévus pour le navigateur. Une recette complète devrait aussi être déroulée sur un vrai téléphone (à la séance sur la version Android), car certains comportements (clavier, vibrations, sauvegarde de la session) diffèrent.


Test de mémorisation/compréhension​


Quelle est la différence principale entre un test automatique et la recette ?


Que signifie l'option --noEmit dans la commande npx tsc --noEmit ?


Dans le script "verifier": "tsc --noEmit && npm test", que fait && ?


Quel test de la recette vérifie la protection contre le double clic ?


Le résultat de git grep -i service_role contient une ligne dans src/lib/supabase.ts. Que faire ?


Pourquoi refait-on toute la recette après avoir corrigé une ligne KO ?



Exercices complémentaires​

Exercice A : ajouter vos propres tests​

Ajoutez trois lignes à la partie 3 du cahier de recette : un test qui casse et son résultat attendu (par exemple : ouvrir /classement?theme=pirate, ou appuyer plusieurs fois sur « Actualiser »). Déroulez-les.

Exercice B : la recette sur téléphone​

Si vous avez un téléphone avec Expo Go (voir la note de la première séance sur la version d'Expo Go), déroulez les parties 2 et 3 sur le téléphone. Notez les différences avec le navigateur.


Ce qu'il faut retenir​

NotionRésumé
Vérifications automatiquesnpx tsc --noEmit, npm test, npx expo-doctor : rapides, à lancer souvent.
Cahier de recetteTableau versionné : action, résultat attendu, OK / KO. À dérouler avant chaque mise en ligne.
Tests qui cassentRéseau coupé, double clic, adresse falsifiée, rechargement : on vérifie les protections du code.
npm run verifierEnchaîne le typage puis les tests ; && s'arrête à la première erreur.
git grep -i service_roleDoit ne rien trouver : une clé secrète publiée est une clé compromise.
Corriger puis tout refaireUne correction peut en casser une autre : on rejoue toute la recette.

Aperçu de la prochaine séance​

Votre application a réussi sa recette dans le navigateur de développement. Dans la prochaine séance, vous allez la publier sur le Web : exporter une version statique, la tester en local, puis la déployer avec EAS Hosting pour obtenir une adresse que vous pouvez envoyer à vos camarades.