Aller au contenu principal
Logo GiwiSoft
scenarii — Automatisez et surveillez vos scénarios web en YAML

scenarii — Automatisez et surveillez vos scénarios web en YAML

Xavier MARIN Xavier MARIN DevOps, Réalisations, Monitoring 7 min

Scenarii est un outil de monitoring et de test E2E que j’ai conçu pour automatiser la vérification de scénarios web complexes. Le principe est simple : vous décrivez vos scénarios en YAML, Scenarii les exécute périodiquement, stocke les métriques dans SQLite, et expose le tout sur un dashboard avec alertes multi-canaux (Telegram, Slack, Discord, webhook, email).

Pourquoi scenarii ?

Les outils de monitoring classiques (Prometheus + blackbox-exporter, Uptime Kuma, Checkmk) brillent pour les vérifications simples : un port qui répond, un certificat SSL qui expire, une page HTTP qui renvoie 200. Mais dès qu’on veut enchaîner plusieurs étapes — par exemple : je me connecte, je navigue, je remplis un formulaire, je vérifie le résultat — ces outils deviennent limités.

Scenarii répond à ce besoin : une succession d’étapes, HTTP ou navigateur, avec extraction de variables, validation par assertions, et notification en cas de changement d’état.

Architecture

L’application suit une architecture monolithe modulaire :

Architecture

Points clés de l’architecture

  • Queue split : Les scénarios HTTP-only s’exécutent en parallèle via fetch natif. Les scénarios navigateur sont sérialisés sur une queue Promise-chain, car Lightpanda ne supporte qu’une connexion CDP à la fois.
  • Graceful degradation : Si @lightpanda/browser n’est pas installé, les scénarios HTTP continuent de fonctionner. Le binaire manquant est détecté au lancement avec un simple require.resolve.
  • Retry : Les steps navigateur réessayent automatiquement 2 fois (backoff 1s, 2s) en cas d’échec. Les notifications Telegram/Mailgun tentent 3 fois avec backoff exponentiel.
  • Hot-reload : Le fichier settings.yaml est surveillé via fs.watchFile et rechargé sans redémarrage.

Écrire un scénario

Un scénario est un fichier YAML. Voici un exemple complet :

name: Ma Boutique
base_url: https://ma-boutique.example.com
schedule: "*/10 * * * *"
timeout: 60000
ignoreHTTPSErrors: false
tags: [production, critique] # tags pour filtrer le dashboard
alert: # règle d'alerte optionnelle
consecutive_failures: 3 # alerter après 3 échecs consécutifs

steps:
- name: Page d'accueil
action: http.get
path: /
expect:
status: 200
body_contains: "Bienvenue"
variables:
csrf: { json_path: "$.csrf_token" }

- name: Connexion
action: http.post
path: /api/login
headers:
Content-Type: application/json
body: |
{"email": "admin@test.com", "password": "test123", "_token": "{{csrf}}"}
expect:
status: 200
json_path: "$.token"
variables:
session: { json_path: "$.token" }

- name: Dashboard
action: browser.navigate
url: /dashboard
headers:
Authorization: "Bearer {{session}}"

- name: Vérifier le tableau
action: browser.wait_for
selector: "#stats"
timeout: 5000
expect:
has_text: "Commandes du jour"

Actions HTTP

Les actions HTTP utilisent l’API fetch native de Node.js — aucune dépendance navigateur n’est nécessaire. Idéal pour les APIs REST, les health checks, et les parcours critiques sans rendu JavaScript.

Action Description
http.get / http.post / http.put / http.patch / http.delete Requêtes HTTP avec headers, body, et assertions

Assertions disponibles : status, status_in, body_contains, body_matches, header_contains, header_matches, json_path, json_value, response_time_under

Chaque step peut aussi définir un timeout individuel et une condition d’exécution basée sur le résultat d’une step précédente :

- name: API sensible
action: http.get
url: /api/slow
timeout: 10000 # timeout individuel (défaut = timeout du scénario)
condition: # exécuter uniquement si...
if_step: "Login" # la step "Login" a réussi
if_success: true
expect:
status: 200

Les variables sont extraites via json_path et réinjectées dans les steps suivantes avec {{variable_name}}.

Actions navigateur

Les actions navigateur utilisent Lightpanda, un navigateur headless en WebAssembly qui parle le protocole CDP de Playwright. Il est léger (~20 Mo) et démarre en ~200ms.

Action Description
browser.navigate Navigation vers une URL
browser.fill Remplir un champ (selector, value)
browser.type Saisie caractère par caractère
browser.click Clic sur un élément
browser.wait_for Attente d’un sélecteur avec assertions (has_text, not_has_text, url_contains)
browser.select Sélection dans une liste déroulante
browser.evaluate Exécution de JavaScript dans la page
browser.check / browser.uncheck Checkbox
browser.screenshot Capture d’écran
browser.screenshot_compare Capture et comparaison avec un baseline (alerte visuelle en cas de régression)

Dashboard

Le dashboard propose deux vues :

  • Liste des scénarios : Vue d’ensemble avec statut (pass/fail), badges de tags, filtre par tag, boutons Run Now et Pause/Resume. Mise à jour temps réel via WebSocket.
  • Détail d’un scénario : Graphique de tendance des temps de réponse, taux de succès glissant, détail par step, historique paginé, export JSON/CSV/YAML, panneau de logs en direct.
  • Live logs : Pendant l’exécution, chaque step est diffusé en temps réel via WebSocket et affiché dans un panneau défilant.
  • Thème dark/light : Bascule en navbar, preference persistée dans localStorage.

Le dashboard reçoit les mises à jour en temps réel via WebSocket (/ws). Après chaque exécution, un message JSON est broadcast à tous les clients connectés, ce qui permet une mise à jour instantanée sans polling.

API et monitoring

Endpoints REST

Endpoint Description
GET /api/scenarios Liste des scénarios (?tag=critical)
GET /api/scenarios/:name Détail avec historique paginé (?limit=&offset=&days=)
GET /api/scenarios/:name/history Historique brut
POST /api/scenarios/:name/run Déclencher une exécution immédiate
POST /api/scenarios/:name/pause Mettre en pause un scénario planifié
POST /api/scenarios/:name/resume Reprendre un scénario planifié
GET /api/scenarios/:name/config Télécharger la configuration YAML
PUT /api/scenarios/:name/config Sauvegarder/modifier le YAML
DELETE /api/scenarios/:name/config Supprimer un scénario
GET /api/scenarios/:name/export/json Export JSON de l’historique
GET /api/scenarios/:name/export/csv Export CSV de l’historique
GET /api/tags Liste des tags distincts
GET /api/status Statistiques publiques (healthy/unhealthy)
GET /api/health Health check
GET /api/metrics Format Prometheus/OpenMetrics

Métriques Prometheus

L’endpoint /api/metrics expose au format OpenMetrics :

# HELP scenarii_scenario_runs_total Total number of scenario runs
# TYPE scenarii_scenario_runs_total counter
scenarii_scenario_runs_total{scenario="Ma Boutique"} 142

# HELP scenarii_scenario_duration_ms Latest scenario duration in milliseconds
# TYPE scenarii_scenario_duration_ms gauge
scenarii_scenario_duration_ms{scenario="Ma Boutique"} 2340

# HELP scenarii_scenario_success Latest run success (1=pass, 0=fail)
# TYPE scenarii_scenario_success gauge
scenarii_scenario_success{scenario="Ma Boutique"} 1

# HELP scenarii_step_duration_ms Step execution duration in milliseconds
# TYPE scenarii_step_duration_ms gauge
scenarii_step_duration_ms{scenario="Ma Boutique",step="Page d'accueil",action="http.get"} 320

# HELP scenarii_notification_delivery_total Notification delivery count
# TYPE scenarii_notification_delivery_total counter
scenarii_notification_delivery_total{scenario="Ma Boutique",channel="telegram",status="success"} 12

Idéal pour Grafana : vous pouvez superposer les temps de réponse de vos scénarios avec les métriques système ou suivre le taux de délivrance de vos notifications.

Notifications

scenarii notifie en cas de changement d’état : passage de succès à échec (failure), ou de échec à succès (recovery). Pas de spam — uniquement les transitions. Il est aussi possible de définir une règle d’alerte par scénario avec alert.consecutive_failures pour n’être notifié qu’après N échecs consécutifs.

Canaux disponibles

Canal Configuration Environnement
Telegram bot_token + chat_id TELEGRAM_BOT_TOKEN
Slack webhook_url SLACK_WEBHOOK_URL
Discord webhook_url DISCORD_WEBHOOK_URL
Webhook url + optionnel headers WEBHOOK_URL
Email mailgun.api_key + domain + from + to MAILGUN_API_KEY

Configuration

notifications:
telegram:
enabled: true
bot_token: "VOTRE_TOKEN"
chat_id: "VOTRE_CHAT_ID"
slack:
enabled: true
webhook_url: "https://hooks.slack.com/services/xxx"
discord:
enabled: true
webhook_url: "https://discord.com/api/webhooks/xxx"
webhook:
enabled: true
url: "https://votre-serveur/alerte"
headers:
X-Signature: "mon-secret"
email:
enabled: true
mailgun:
api_key: "VOTRE_API_KEY"
domain: "VOTRE_DOMAIN"
from: "scenarii <noreply@domain.com>"
to:
- "admin@domain.com"

Les tokens peuvent aussi être passés en variables d’environnement (TELEGRAM_BOT_TOKEN, MAILGUN_API_KEY, SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL, WEBHOOK_URL) pour éviter de stocker des secrets dans le dépôt.

Un rapport quotidien est également envoyé chaque matin à 8h, résumant l’état de tous les scénarios.

Gestion des scénarios par scénario

Il est possible de surcharger les paramètres par scénario :

scenarios:
mon-scenario-lent:
timeout: 120000
ignoreHTTPSErrors: true
notifications:
enabled: false

Conteneurisation

L’image Docker est construite en multi-stage Alpine (Node.js 26), avec dumb-init pour la gestion des signaux et USER node pour la sécurité :

docker pull ghcr.io/giwi/giwisoft-scenarii:latest

docker run -d \
--name scenarii \
-p 3000:3000 \
-v /chemin/scenarios:/scenarios \
-v /chemin/db:/app/db \
-v /chemin/settings.yaml:/app/settings.yaml:ro \
ghcr.io/giwi/giwisoft-scenarii:latest

Le conteneur expose un HEALTHCHECK qui ping /api/health toutes les 30s, et un volume pour monter vos fichiers YAML de scénarios.

CLI

En plus du mode serveur, scenarii propose plusieurs commandes :

# Valider un fichier YAML
node dist/index.js validate scenarios/mon-test.yml

# Exécuter un scénario immédiatement
node dist/index.js trigger scenarios/mon-test.yml --json

# Voir l'état courant
node dist/index.js status

# Générer un template settings.yaml
node dist/index.js config --init

Conclusion

scenarii est un outil que j’utilise quotidiennement pour m’assurer que mes applications web fonctionnent correctement. Il remplace avantageusement une batterie de scripts shell ou de checks Prometheus quand on a besoin de scénarios multi-étapes.

Ce qui le distingue :

  • YAML comme DSL — facile à versionner, à lire, à écrire
  • HTTP sans navigateur — pas de surcharge pour les scénarios simples
  • Exécution conditionnelle — timeout par step, conditions between steps
  • Alertes multi-canaux — Telegram, Slack, Discord, webhook, email
  • Métriques temps réel — WebSocket + Prometheus + dashboard
  • API complète — CRUD, tags, status public, export YAML
  • Conteneurisé — un docker run et c’est prêt

Le code est disponible sur GitHub. Contributions et retours bienvenus !