La mise en place prend environ 30 minutes et produit un pipeline prêt pour la production qu'on peut intégrer dans n'importe quel projet.
Pourquoi GitHub Actions
GitHub Actions est la plateforme CI dominante pour les nouveaux projets. L'enquête JetBrains State of CI/CD 2025 indique que 62 % des développeurs l'utilisent pour des projets personnels et 41 % dans leurs organisations, deux chiffres supérieurs à n'importe quel autre outil.
Les raisons pratiques sont simples : gratuit pour les dépôts publics, gratuit pour 2 000 minutes par mois sur les privés, et intégré à GitHub. Pas de serveur séparé à provisionner, pas de compte tiers à connecter, pas de configuration de webhook. Vous poussez un fichier YAML et les tests se lancent.
Pour Playwright spécifiquement, GitHub Actions fonctionne bien parce que les runners Ubuntu fournis ont tout ce dont Playwright a besoin. Les dépendances de navigateur, les polices et les bibliothèques système sont disponibles via --with-deps. L'équipe officielle Playwright teste sur ces runners. Vous êtes dans le chemin supporté.
Le workflow minimal fonctionnel
Créez le fichier .github/workflows/playwright.yml à la racine de votre projet. C'est là que GitHub cherche les définitions de workflow.
mkdir -p .github/workflowsVoici le workflow minimal complet :
# .github/workflows/playwright.yml
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 14Committez ce fichier, poussez, et ouvrez l'onglet Actions dans votre dépôt GitHub. Vous verrez le workflow apparaître et se lancer en quelques secondes.
Quelques détails à comprendre. npm ci au lieu de npm install installe exactement ce qui est dans package-lock.json sans le modifier. C'est la bonne commande pour les environnements CI car elle donne des builds reproductibles. npx playwright install --with-deps installe les navigateurs avec leurs dépendances système (libgtk, libnss, etc.) qui ne sont pas présentes sur un runner Ubuntu vierge. Omettre --with-deps est la cause la plus fréquente d'échec de Playwright en CI quand ça fonctionne en local.
Le if: always() sur l'étape d'upload est important. Sans lui, l'artifact n'est uploadé qu'en cas de succès du workflow, ce qui signifie qu'on perd le rapport exactement quand les tests échouent et qu'on en a le plus besoin.
Le timeout-minutes: 60 sur le job est un garde-fou. Un test bloqué peut autrement consommer tout votre quota mensuel de minutes avant que vous ne vous en rendiez compte.
Stocker et télécharger les rapports de test
L'étape upload-artifact dans le workflow ci-dessus sauvegarde tout le répertoire playwright-report/ sous forme de zip téléchargeable. Après la fin d'un run, allez sur la page du run du workflow, puis Summary, puis Artifacts, puis playwright-report. Téléchargez et décompressez, puis ouvrez index.html dans un navigateur.
Le rapport HTML montre quels tests ont passé, lequel ont échoué, les captures d'échec, les traces, et les vidéos si l'enregistrement est activé. C'est comme ça qu'on investigue les échecs sans accéder directement au runner CI.
Si vous générez plusieurs rapports (un par navigateur dans un run matrix), donnez à chaque artifact un nom unique :
- name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.browser }}
path: playwright-report/
retention-days: 14retention-days: 14 conserve les rapports deux semaines, ce qui est suffisant pour la plupart des workflows de débogage sans accumuler des coûts de stockage inutiles. GitHub permet jusqu'à 90 jours.
Variables d'environnement et secrets
Ne mettez jamais des identifiants ou des URLs spécifiques à l'environnement dans le fichier YAML du workflow. Les GitHub Secrets sont le bon endroit pour tout ce qui est sensible.
Allez dans votre dépôt, puis Settings, puis Secrets and variables, puis Actions, puis New repository secret. Ajoutez les secrets dont vos tests ont besoin : TEST_USER, TEST_PASSWORD, et toute clé d'API.
Référencez-les dans le workflow sous env: sur l'étape de test :
- name: Run Playwright tests
run: npx playwright test
env:
BASE_URL: https://staging.example.com
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}Dans vos tests, lisez-les avec process.env :
const baseURL = process.env.BASE_URL ?? 'http://localhost:3000';
const user = process.env.TEST_USER ?? '';
const password = process.env.TEST_PASSWORD ?? '';GitHub masque les valeurs secrètes dans les logs. Si un secret apparaît dans la sortie, il est remplacé par *. Les valeurs non sensibles comme BASE_URL peuvent aussi être stockées comme variables de dépôt (pas des secrets), visibles dans l'interface. Utilisez les variables pour les URLs et les feature flags, les secrets pour les identifiants.
pull_request_target, mais comprenez les implications de sécurité avant de l'utiliser.Cache pour des runs plus rapides
Un run de workflow frais installe les modules Node et les navigateurs Playwright depuis zéro à chaque fois. Sur un runner froid, c'est 2 à 3 minutes avant qu'un seul test ne se lance. Le cache réduit ça significativement.
L'action setup-node avec cache: 'npm' gère déjà automatiquement le cache de node_modules. Pour les navigateurs Playwright, ajoutez une étape de cache dédiée :
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
run: npx playwright install --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'La clé de cache inclut un hash de package-lock.json. Quand vous mettez à niveau Playwright, le lock file change, le hash change, le cache rate, et les navigateurs se réinstallent. Quand rien ne change, le cache est valide et l'installation des navigateurs est sautée.
Cette optimisation compte surtout sur les grandes suites. Une suite de 200 tests avec le cache activé peut passer de 8 minutes à 4 minutes simplement en évitant des téléchargements répétés.
Lancer uniquement sur des branches spécifiques
La section on: contrôle quand votre workflow se lance. L'exemple minimal filtre déjà sur main et develop. Vous pouvez être plus précis :
on:
push:
branches:
- main
- develop
- 'release/**'
pull_request:
branches:
- main
- develop
workflow_dispatch:workflow_dispatch: ajoute un bouton "Run workflow" dans l'onglet Actions, vous permettant de le déclencher manuellement. Utile pour lancer les tests sur une branche spécifique à la demande sans pousser un commit.
Vous pouvez aussi lancer les tests selon un planning. Des runs de smoke tests nocturnes détectent les problèmes qui n'apparaissent que dans certaines fenêtres horaires ou après accumulation de données :
on:
schedule:
- cron: '0 3 * * *' # 3h UTC chaque nuit
push:
branches: [main]
pull_request:
branches: [main]Dans un job, vous pouvez ajouter des conditions de branche sur des étapes spécifiques avec if: :
- name: Run full suite
run: npx playwright test
if: github.ref == 'refs/heads/main'
- name: Run smoke tests only
run: npx playwright test --grep @smoke
if: github.event_name == 'pull_request'Ce pattern donne aux pull requests un retour rapide avec une suite smoke, tandis que les runs sur la branche main reçoivent la suite complète.
Stratégie matrix pour les tests cross-browser
Playwright supporte Chromium, Firefox et WebKit. Lancer les trois sur chaque PR coûte cher en temps et en minutes, mais vous voulez quand même une couverture cross-browser. La stratégie matrix lance des jobs parallèles avec des configurations différentes :
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ matrix.browser }}-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
run: npx playwright install ${{ matrix.browser }} --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Run tests
run: npx playwright test --project=${{ matrix.browser }}
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Upload report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.browser }}
path: playwright-report/
retention-days: 14fail-fast: false signifie que si Firefox échoue, les jobs Chromium et WebKit continuent. Avec fail-fast: true (la valeur par défaut), tout échec de job matrix annule le reste, généralement pas ce qu'on veut quand on débogue des problèmes cross-browser.
npx playwright install ${{ matrix.browser }} --with-deps installe uniquement le navigateur pour ce job, pas les trois. C'est plus rapide que tout installer dans chaque job.
if: github.ref == 'refs/heads/main' sur le job ou utilisez le filtre de branche sur le déclencheur on.push. Vos PRs restent rapides ; votre branche main reçoit la couverture complète.Sharding : diviser les tests sur plusieurs jobs
Le sharding divise votre suite de tests sur plusieurs jobs parallèles. Là où la stratégie matrix lance des configurations différentes, le sharding lance les mêmes tests plus vite en les divisant :
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Run shard
run: npx playwright test --shard=${{ matrix.shard }}/4
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Upload shard report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-shard-${{ matrix.shard }}
path: playwright-report/
retention-days: 14Playwright distribue les tests équitablement entre les shards selon les données de timing des runs précédents si vous fournissez un rapport blob, ou par ordre de fichier sinon. Avec quatre shards, une suite de 20 minutes tourne en environ 5 minutes.
Vous pouvez combiner sharding et stratégie matrix. Un pattern courant : quatre shards par navigateur pour les grandes suites :
strategy:
matrix:
browser: [chromium, firefox]
shard: [1, 2, 3, 4]Ça crée 8 jobs parallèles. Attention : chaque job consomme des minutes de runner. 8 jobs tournant 5 minutes chacun coûtent 40 minutes de quota, pareil qu'en série. L'avantage est le temps d'exécution réel, pas la consommation de quota.
Fusionner les rapports de shards en un seul rapport HTML nécessite le reporter blob. Définissez reporter: 'blob' dans votre config Playwright pour les runs CI, puis ajoutez un job de fusion :
merge-reports:
if: always()
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload merged report
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 14Publier les résultats en commentaires de PR
Avoir les résultats de tests directement dans la pull request rend les échecs bien plus visibles. Ça nécessite une action séparée après la fin du run de tests.
L'approche la plus simple utilise l'action dawidd6/action-junit-report, qui lit la sortie JUnit XML et poste un commentaire. Ajoutez d'abord le reporter JUnit à votre config Playwright :
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
reporter: [
['html'],
['junit', { outputFile: 'results.xml' }],
],
});Puis ajoutez une étape de reporting à votre workflow :
- name: Run Playwright tests
run: npx playwright test
env:
BASE_URL: ${{ vars.BASE_URL }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
- name: Post test results to PR
uses: dawidd6/action-junit-report@v4
if: always()
with:
report_paths: results.xml
github_token: ${{ secrets.GITHUB_TOKEN }}
check_name: Playwright Test ResultsGITHUB_TOKEN est automatiquement disponible dans chaque workflow. Pas de configuration de secret manuelle nécessaire.
Le commentaire montre les compteurs pass/fail, les noms des tests, et les messages d'erreur directement dans la conversation PR. Les reviewers n'ont pas besoin de naviguer jusqu'à l'onglet Actions pour savoir si les tests ont passé.
FAQ
Les tests passent en local mais échouent dans GitHub Actions. Par où commencer ?Vérifiez dans cet ordre : les variables d'environnement, le BASE_URL, et le timing. Un secret non défini dans Actions vaudra undefined sans erreur. Si BASE_URL pointe vers localhost, ça ne fonctionnera pas en CI. Les runners CI sont plus lents que les machines de développement. Augmentez les timeouts dans votre playwright.config.ts ou ajoutez retries: 1 spécifiquement pour CI avec process.env.CI ? 1 : 0.
Allez sur le run du workflow en échec, puis Summary, puis faites défiler jusqu'à Artifacts, puis téléchargez playwright-report. Extrayez le zip et ouvrez index.html dans un navigateur. Le rapport inclut captures d'écran et traces pour les tests en échec.
Non. Le workflow les installe à l'exécution via npx playwright install. Avec le cache configuré, les runs suivants sautent le téléchargement. Commiter les binaires de navigateurs gonflerait votre dépôt de plusieurs centaines de mégaoctets.
Le cache est la première optimisation : sauvegarder les navigateurs Playwright réduit de 1 à 2 minutes par run. Le sharding est la deuxième, en divisant une suite de 15 minutes sur 3 shards pour la ramener à 5 minutes. La troisième est de lancer uniquement Chromium sur les PRs et la matrix complète sur main, ce qui triple la vitesse de chaque run de PR.
Puis-je utiliser l'image Docker Playwright au lieu d'installer les navigateurs ?Oui. Définissez container: mcr.microsoft.com/playwright:v1.52.0-jammy sur le job et sautez l'étape d'installation. Le compromis : les conteneurs Docker démarrent plus lentement que les runners Ubuntu nus, et vous êtes bloqué sur une version spécifique de Playwright dans le tag de l'image. C'est un choix raisonnable pour les équipes qui veulent éviter l'étape d'installation.
Playwright ne supporte pas ça nativement. Certaines équipes utilisent des filtres basés sur les chemins dans le workflow, ne déclenchant le job de test que quand des fichiers dans certains répertoires changent. Ajoutez paths: sous on.pull_request pour limiter quand le workflow se lance. La sélection de tests complète basée sur les changements de code nécessite des outils externes et est rarement rentable avant que votre suite ne dépasse 10 minutes.