Andrea Grossi
← Retour aux projets

Travail · 2026

Ce site : un portfolio trilingue dont les tests tournent sur le build

Astro 5, trois langues avec des URL localisées, et une suite de tests qui lit dist/ plutôt que les sources. Y compris le bug que cette suite ne pouvait pas voir, et qui a envoyé du lorem ipsum en production.

Le site que vous êtes en train de lire. C’est un site Astro 5, prérendu en HTML statique, publié en anglais, en italien et en français. Je le raconte ici surtout pour une décision et un échec.

Des URL qui appartiennent à leur langue

L’anglais occupe la racine sans préfixe ; l’italien vit sous /it/, le français sous /fr/. Ce qui coûte du vrai travail, c’est que les segments de chemin sont traduits eux aussi, pas seulement le contenu :

AnglaisItalienFrançais
/projects//it/progetti//fr/projets/
/about//it/chi-sono//fr/a-propos/
/hobbies//it/hobby//fr/loisirs/

Un projet, c’est un fichier Markdown par langue partageant un même slug, et c’est lui qui permet aux trois versions de se pointer mutuellement. Une page n’a besoin d’exister que dans les langues pour lesquelles il y a du contenu : le hreflang est émis vers les traductions qui existent réellement, jamais vers une URL qui renverrait un 404. Chaque page se référence aussi elle-même, ce que la spécification exige et qui est la règle la plus souvent oubliée.

Les tests lisent le build, pas les sources

La suite — quinze fichiers, 64 tests sur le lanceur de tests de Node — exécute d’abord npm run build, puis lit dist/. Rien n’est simulé, parce que ce qui mérite d’être vérifié, c’est le HTML qu’un navigateur recevra vraiment.

Elle vérifie qu’aucun lien interne n’est cassé, que chaque page a un titre et une description non vides et que celles de premier niveau sont distinctes, que chaque image référencée localement existe sur le disque, que les ensembles hreflang sont complets et auto-référencés, que les brouillons n’atteignent jamais le build, et que le thème est appliqué avant le premier rendu pour que la page ne clignote pas en blanc.

Vérifier sur le build attrape toute une catégorie de bugs que les tests au niveau des sources ratent : un lien correct dans un composant et faux après le routage, un chemin d’image qui se résolvait en développement et pas dans la sortie.

Le bug que les tests ne pouvaient pas voir

Voici la partie qui mérite d’être racontée. Pendant des semaines, ce site a servi cinq projets intitulés des choses comme « Lorem ipsum ingestion pipeline », et le pied de page de chaque page affichait « Lorem ipsum dolor sit amet ». La suite de tests est restée verte tout du long.

Elle était verte parce que chaque assertion était structurelle. Les fixtures que les tests utilisaient pour vérifier le comportement — un projet publié, un non mis en avant, un brouillon — étaient les fichiers mêmes qui partaient en production comme contenu. La suite demandait y a-t-il un projet listé sur cette page, et un projet était listé. Elle n’avait aucun avis sur ce que ce projet racontait.

C’est le piège qu’il y a à utiliser ses fixtures comme contenu. Les tests continuent de passer, avec précision et honnêteté, pendant que le site ne dit rien de vrai. Une suite verte vous dit que la structure tient ; elle ne peut pas vous dire que cette structure soutient quelque chose de réel.

Ce qui a corrigé cela n’est pas une assertion plus maligne, c’est la suppression des fixtures et le repointage des tests vers des projets qui existent. La couverture comportementale est inchangée — il faut toujours que quelque chose soit publié-mais-pas-mis-en-avant pour que ce test veuille dire quelque chose, et ce quelque chose, c’est désormais cette page.

La page projets du temps où les fixtures étaient encore en ligne Ce que /projects/ a servi pendant des semaines, reconstruit depuis le commit précédant le nettoyage. Tous les tests étaient verts sur cette page.

Publier exprès

Le build est synchronisé par rsync vers son hébergeur, et npm run deploy s’exécute en --dry-run par défaut. Publier pour de vrai exige un -- --live explicite, après quoi le script demande à l’opérateur de taper le nom de domaine avant de continuer.

Cette friction est voulue, parce que rsync tourne avec --delete : tout ce qui se trouve sur le serveur sans être dans dist/ disparaît. Un drapeau aussi destructeur ne devrait pas être à une faute de frappe d’un soir de fatigue.

Des visuels de couverture sans appel réseau

Chaque projet, article et page affiche une couverture. Si le champ cover: n’est pas renseigné, on retombe sur un SVG plat généré de façon déterministe à partir du slug par un script — même slug, même visuel, à chaque fois, sans télécharger la moindre police ni la moindre image. Un test fait échouer le build si une page référence une couverture inexistante : c’est ainsi qu’une couverture manquante devient un test rouge plutôt qu’une image cassée.