Docker élimine les différences d'environnement entre machines locales et CI. Il empaquète vos tests Playwright, votre version de Node et les dépendances navigateurs dans un conteneur qui s'exécute de façon identique partout.

Pourquoi Docker compte pour QA

Les suites de tests de navigateur sont particulièrement sensibles à leur environnement. Playwright installe des binaires Chromium, Firefox et WebKit qui dépendent de bibliothèques système spécifiques : libglib, libnss, libatk, et une vingtaine d'autres. Sur votre machine, elles sont probablement à la bonne version parce que vous avez installé Playwright récemment. Sur la machine d'un collègue depuis 2022, peut-être pas. Sur un runner CI provisionné il y a six mois avec une image Ubuntu différente, l'incompatibilité devient un build failure à 2h du matin.

Le correctif traditionnel est une page wiki intitulée "Dev Setup" qui devient caduque dès qu'on la rédige. Le correctif Docker est un fichier dans votre dépôt appelé Dockerfile qui décrit l'environnement exact dont vos tests ont besoin. Quiconque lance docker build obtient le même environnement, peu importe son OS ou ce qu'il a installé la semaine dernière.

Pour QA spécifiquement, Docker apporte trois bénéfices concrets. D'abord, la parité d'environnement : vos tests s'exécutent dans le même conteneur en local et en CI, donc un test qui passe en local veut dire quelque chose. Ensuite, un nouveau membre peut lancer toute la suite avec deux commandes, sans installer Node, Playwright ou les navigateurs. Enfin, l'isolation garantit que les runs de tests ne s'interfèrent pas entre eux ni avec la machine hôte.

Docker ne remplace pas la compréhension de vos échecs de tests. Il supprime la catégorie d'échecs causés par les différences d'environnement. Les échecs restants sont de vrais bugs, et c'est exactement ce qu'on cherche.

Les bases de Docker pour les testeurs

Si vous n'avez jamais travaillé avec Docker, le modèle mental est simple. Une image est un snapshot d'un système de fichiers : un système d'exploitation, des paquets installés, votre code et des variables d'environnement, le tout figé à un instant donné. Un conteneur est une instance en cours d'exécution d'une image : l'image est la classe, le conteneur est l'objet.

On construit une image depuis un Dockerfile, un fichier texte qui liste les étapes de construction. On lance un conteneur depuis une image avec docker run. Quand le conteneur se termine, il s'arrête. Rien de ce qu'il a fait ne modifie l'image.

# Télécharger une image existante depuis un registre
docker pull node:20-slim

# Lancer un conteneur depuis cette image et exécuter une commande
docker run node:20-slim node --version

# Construire une image depuis un Dockerfile dans le répertoire courant
docker build -t my-playwright-tests .

# Lancer un conteneur depuis l'image construite
docker run my-playwright-tests

Le concept clé pour les workflows de test : les conteneurs sont éphémères par défaut. Les fichiers créés dans un conteneur disparaissent quand il s'arrête, y compris vos rapports de tests. On résout ça avec des volume mounts, couverts dans la section sur l'exécution des tests.

Les images sont composées de layers. Chaque instruction dans un Dockerfile crée un nouveau layer, et Docker met en cache les layers qui n'ont pas changé. C'est ce qui rend les rebuilds rapides. Si vous modifiez votre code de test mais pas vos dépendances, Docker réutilise le layer mis en cache qui a installé ces dépendances et ne reconstruit que les layers modifiés.

L'image Docker officielle Playwright

L'équipe Playwright publie et maintient une image Docker officielle sur mcr.microsoft.com/playwright. Cette image contient tout ce dont les tests de navigateur ont besoin : Node.js, le package Playwright lui-même, et les trois binaires navigateurs (Chromium, Firefox, WebKit) avec leurs dépendances système pré-installées.

# Télécharger l'image correspondant à votre version Playwright
docker pull mcr.microsoft.com/playwright:v1.52.0-jammy

# Vérifier son contenu
docker run --rm mcr.microsoft.com/playwright:v1.52.0-jammy node --version
docker run --rm mcr.microsoft.com/playwright:v1.52.0-jammy npx playwright --version

Le format du tag est v{version-playwright}-{nom-ubuntu}. jammy correspond à Ubuntu 22.04, l'option la plus stable et la plus utilisée. Il existe aussi une variante noble pour Ubuntu 24.04.

L'image est volumineuse (environ 1,8 Go) parce qu'elle contient trois installations complètes de navigateurs. C'est le coût d'avoir tout pré-installé sans avoir à lancer playwright install --with-deps au démarrage du conteneur. Pour les environnements CI, c'est un bon compromis. Le cache des layers Docker fait qu'on ne télécharge l'image qu'une seule fois par runner, sauf si le tag change.

La règle critique : le tag de l'image doit correspondre à votre version @playwright/test dans package.json. Si vous utilisez v1.52.0-jammy mais que votre projet a "@playwright/test": "1.50.0", les incompatibilités d'API provoqueront des échecs difficiles à diagnostiquer. Épinglez les deux.

Écrire un Dockerfile pour votre projet Playwright

Partez de l'image officielle Playwright comme base. Voici un Dockerfile complet, prêt pour la production :

# Utiliser l'image officielle Playwright — épingler la version pour qu'elle corresponde à package.json
FROM mcr.microsoft.com/playwright:v1.52.0-jammy

# Définir le répertoire de travail dans le conteneur
WORKDIR /app

# Copier les fichiers de package en premier pour un meilleur cache des layers
# Ce layer n'est reconstruit que quand les dépendances changent
COPY package.json package-lock.json ./

# Installer les dépendances du projet (les navigateurs sont déjà dans l'image de base)
RUN npm ci

# Copier le reste du projet
COPY . .

# Commande par défaut : lancer tous les tests
CMD ["npx", "playwright", "test"]

L'ordre des instructions COPY et RUN compte pour le cache. En copiant d'abord package.json et package-lock.json et en lançant npm ci avant de copier le reste, le layer d'installation des dépendances est mis en cache. Il est alors réutilisé à chaque modification de fichier de test. Si vous copiez tout d'abord puis lancez npm ci, n'importe quelle modification invalide le cache des dépendances.

Notez l'absence d'étape npx playwright install. L'image de base contient déjà les navigateurs. Le build est donc nettement plus rapide qu'une configuration qui part d'une image Node simple.

Ajoutez un fichier .dockerignore à côté de votre Dockerfile pour exclure les fichiers qui n'ont pas leur place dans l'image :

# .dockerignore
node_modules
playwright-report
test-results
.git
.github
*.md

Exclure node_modules est particulièrement important. Sans ça, Docker copierait votre node_modules local dans l'image avant de lancer npm ci, ce qui gaspille du temps. Cela peut aussi introduire des binaires spécifiques à une plateforme qui ne fonctionnent pas dans le conteneur Linux.

Construire l'image :

docker build -t playwright-tests:local .

Le flag -t tague l'image avec un nom. playwright-tests:local est une convention pour distinguer les images construites localement des images de registre.

Exécuter les tests dans un conteneur

Une fois l'image construite, lancer les tests se fait en une commande :

docker run --rm playwright-tests:local

--rm supprime automatiquement le conteneur quand il se termine. Sans ce flag, les conteneurs arrêtés s'accumulent et consomment de l'espace disque.

Le problème : les rapports de tests sont écrits dans le conteneur et disparaissent quand il s'arrête. On corrige ça avec un volume mount via -v

docker run --rm \
  -v $(pwd)/playwright-report:/app/playwright-report \
  -v $(pwd)/test-results:/app/test-results \
  playwright-tests:local

Le flag -v associe un répertoire de l'hôte à un répertoire du conteneur. Quand Playwright écrit le rapport HTML dans /app/playwright-report à l'intérieur du conteneur, il écrit en réalité dans $(pwd)/playwright-report sur votre machine hôte. Après l'arrêt du conteneur, le rapport est là, prêt à être ouvert.

Sur Windows, remplacez $(pwd) par %cd% dans Command Prompt ou ${PWD} dans PowerShell :

docker run --rm `
  -v ${PWD}/playwright-report:/app/playwright-report `
  -v ${PWD}/test-results:/app/test-results `
  playwright-tests:local

Pour lancer un sous-ensemble de tests, remplacez la CMD par défaut en ajoutant des arguments :

# Lancer uniquement les tests correspondant à un tag
docker run --rm playwright-tests:local npx playwright test --grep @smoke

# Lancer uniquement Chromium
docker run --rm playwright-tests:local npx playwright test --project=chromium

# Lancer un fichier de test spécifique
docker run --rm playwright-tests:local npx playwright test tests/login.spec.ts

Passez des variables d'environnement avec -e :

docker run --rm \
  -e BASE_URL=https://staging.example.com \
  -e TEST_USER=testuser \
  -e TEST_PASSWORD=secret \
  -v $(pwd)/playwright-report:/app/playwright-report \
  playwright-tests:local

Ajoutez un Makefile ou un script package.json pour la commande docker run complète, afin que votre équipe n'ait pas à mémoriser les flags de volume mount. npm run test:docker est plus facile à documenter et moins sujet aux fautes de frappe que la commande complète.

docker-compose pour les runs de tests locaux

Quand vos tests s'exécutent contre une application, vous avez besoin que l'app et le conteneur de tests tournent en même temps avec un accès réseau entre eux. docker-compose gère les configurations multi-conteneurs avec un seul fichier.

Voici un docker-compose.yml pour un setup typique où les tests Playwright s'exécutent contre une application web qui tourne en local :

# docker-compose.yml
version: '3.8'

services:
  # Votre application sous test
  app:
    image: your-app:latest
    ports:
      - '3000:3000'
    environment:
      NODE_ENV: test
      DATABASE_URL: postgres://user:pass@db:5432/testdb
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
      interval: 5s
      timeout: 5s
      retries: 10

  # Base de données (si votre app en a besoin)
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: testdb
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U user -d testdb']
      interval: 3s
      timeout: 3s
      retries: 15

  # Conteneur de tests Playwright
  tests:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      BASE_URL: http://app:3000
    depends_on:
      app:
        condition: service_healthy
    volumes:
      - ./playwright-report:/app/playwright-report
      - ./test-results:/app/test-results
    # Ne pas démarrer les tests automatiquement — lancer à la demande
    profiles:
      - testing

profiles: [testing] sur le service tests signifie qu'il ne démarrera pas lors d'un docker-compose up seul (qui démarrerait l'app et la base de données). Pour lancer les tests :

# Démarrer l'app et la base de données
docker-compose up -d app db

# Lancer les tests
docker-compose run --rm tests

# Ou tout démarrer et lancer les tests en une commande
docker-compose --profile testing run --rm tests

# Tout arrêter
docker-compose down

Les services communiquent en utilisant leurs noms de service comme noms d'hôte. Le conteneur de tests définit BASE_URL: http://app:3000, et le DNS interne de Docker résout app vers l'adresse IP du conteneur app. Votre playwright.config.ts lit process.env.BASE_URL, donc en local il cible localhost:3000 et dans le conteneur il cible http://app:3000.

depends_on avec condition: service_healthy est important. Sans ça, Playwright démarrerait avant que l'app soit prête à accepter des connexions et chaque test échouerait avec une erreur de connexion. Le healthcheck sonde jusqu'à ce que l'app réponde, puis Docker démarre le conteneur dépendant.

Intégrer Docker dans GitHub Actions

GitHub Actions peut utiliser un conteneur Docker comme environnement d'exécution pour un job entier, ou vous pouvez lancer docker build et docker run comme étapes. Pour Playwright spécifiquement, utiliser le conteneur directement comme environnement du job est l'approche la plus propre.

# .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

    # Utiliser l'image Playwright comme conteneur du job
    container:
      image: mcr.microsoft.com/playwright:v1.52.0-jammy
      options: --user 1001

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install dependencies
        run: npm ci

      - 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: Upload test report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 14

Le bloc container: au niveau du job indique à GitHub Actions d'exécuter chaque étape dans le conteneur Docker spécifié plutôt que directement sur le runner Ubuntu. Les navigateurs sont déjà installés dans l'image, donc l'étape npx playwright install est inutile.

--user 1001 définit l'utilisateur du conteneur pour correspondre à l'UID du runner GitHub Actions. Sans ça, des erreurs de permissions peuvent survenir quand Actions essaie d'écrire des artifacts.

Pour les équipes qui veulent aussi construire et pousser leur propre image de test vers un registre :

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Build test image
        run: docker build -t playwright-tests:${{ github.sha }} .

      - name: Run tests
        run: |
          docker run --rm \
            -e BASE_URL=${{ vars.BASE_URL }} \
            -e TEST_USER=${{ secrets.TEST_USER }} \
            -e TEST_PASSWORD=${{ secrets.TEST_PASSWORD }} \
            -v ${{ github.workspace }}/playwright-report:/app/playwright-report \
            playwright-tests:${{ github.sha }}

      - name: Upload test report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 14

Utiliser ${{ github.sha }} comme tag d'image lie l'image au commit exact, ce qui facilite la corrélation entre les runs de tests et les versions de code si vous poussez vers un registre.

Problèmes courants et comment les résoudre

Les conteneurs Docker introduisent un petit ensemble de problèmes qui reviennent régulièrement avec Playwright.

Erreurs de permissions sur les rapports. Quand Playwright écrit dans un répertoire monté en volume, les fichiers appartiennent à l'utilisateur du conteneur (souvent root). Votre utilisateur hôte ne peut pas les modifier ou les supprimer sans sudo. La solution : définir l'utilisateur du conteneur au moment de l'exécution.

docker run --rm \
  --user $(id -u):$(id -g) \
  -v $(pwd)/playwright-report:/app/playwright-report \
  playwright-tests:local

Le conteneur s'exécute comme votre utilisateur hôte courant, donc les fichiers de rapport vous appartiennent. En CI, utilisez --user 1001 comme montré dans le workflow ci-dessus.

Mode headless et erreurs d'affichage. Playwright s'exécute en mode headless par défaut, ce qui fonctionne dans les conteneurs sans aucune modification. Si vous utilisez le mode headed (pour déboguer) dans un conteneur, vous auriez besoin d'un affichage virtuel. Ne faites pas ça. Utilisez headless dans les conteneurs et headed en local. Si un test se comporte différemment en headed vs. headless, c'est un vrai bug à investiguer, pas un problème Docker. Builds lents faute de cache des layers. Si votre rebuild d'image prend 3+ minutes à chaque fois, le cache ne fonctionne pas. La cause la plus fréquente est de copier l'intégralité du projet avant d'installer les dépendances :

# Lent : n'importe quel changement de fichier invalide le cache npm ci
COPY . .
RUN npm ci

# Rapide : seul un changement de fichier package invalide le cache npm ci
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

En CI, le cache des layers Docker nécessite une configuration explicite. Ajoutez ceci à votre workflow :

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build test image
        uses: docker/build-push-action@v6
        with:
          context: .
          load: true
          tags: playwright-tests:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

cache-from: type=gha et cache-to: type=gha,mode=max utilisent le stockage de cache de GitHub Actions pour le cache des layers Docker. Sans ça, chaque run CI reconstruit l'image depuis zéro.
L'image Docker officielle Playwright inclut les trois navigateurs, ce qui la rend d'environ 1,8 Go. Sur un runner CI lent, le premier téléchargement peut prendre 3 à 4 minutes. Après ce premier pull, le cache des layers Docker rend les démarrages suivants rapides. Si votre registre a un miroir local configuré, utilisez-le.
Les tests ne peuvent pas atteindre l'application. Dans un conteneur Docker, localhost désigne le conteneur lui-même, pas votre machine hôte. Si votre app tourne sur l'hôte à localhost:3000, le conteneur ne peut pas l'atteindre à cette adresse. Utilisez l'IP du bridge Docker de votre hôte (172.17.0.1 sur Linux, host.docker.internal sur Mac et Windows) :

docker run --rm \
  -e BASE_URL=http://host.docker.internal:3000 \
  -v $(pwd)/playwright-report:/app/playwright-report \
  playwright-tests:local

Avec docker-compose, ce problème disparaît parce que tous les services partagent un réseau et communiquent par nom de service.

FAQ

Est-ce que j'ai besoin de Docker si j'utilise déjà GitHub Actions ?

Pas nécessairement. Les runners GitHub Actions fonctionnent bien pour Playwright sans Docker : installez Node, lancez playwright install --with-deps, et c'est parti. Docker devient utile quand vous voulez le même environnement en local et en CI, quand vos tests s'exécutent contre un stack multi-services, ou quand vous accueillez de nouveaux membres. Ces derniers peuvent alors lancer les tests sans installer Node, Playwright ou les navigateurs.

Dois-je construire ma propre image ou utiliser l'image officielle Playwright ?

Partez de l'image officielle comme base FROM. Vous bénéficiez des mises à jour gratuites des versions de navigateurs quand vous changez le tag, et l'image est maintenue par des gens qui connaissent les dépendances de Playwright. Construisez par-dessus uniquement si vous avez besoin d'ajouts spécifiques au projet : des polices personnalisées, une version Node précise, ou des données de test pré-chargées.

Comment déboguer un test qui échoue uniquement dans le conteneur ?

Montez le répertoire test-results et activez l'enregistrement vidéo dans votre config Playwright pour les tests en échec. Après le run, le dossier test-results/ sur votre hôte contiendra vidéos et traces. Ouvrez la trace avec npx playwright show-trace test-results/.../trace.zip pour voir exactement ce qui s'est passé.

Puis-je lancer les tests en parallèle dans un conteneur ?

Oui. Le paramètre workers de Playwright contrôle le parallélisme et fonctionne de la même façon dans un conteneur. La limite pratique est le nombre de CPU du conteneur. Pour les grandes suites, lancez plusieurs conteneurs en parallèle (via le sharding par matrix GitHub Actions) plutôt que de maximiser les workers dans un seul conteneur. C'est plus facile à raisonner et à scaler.

Mon conteneur se construit bien mais les tests échouent avec "executable doesn't exist".

Cela signifie généralement une incompatibilité de version entre le tag de l'image et votre version @playwright/test. Vérifiez que mcr.microsoft.com/playwright:v1.52.0-jammy correspond à "@playwright/test": "1.52.0" dans package.json. Si les versions ne s'alignent pas, Playwright cherche les navigateurs dans un chemin qui n'existe pas dans l'image.

Comment passer un fichier .env au conteneur ?

Utilisez --env-file avec docker run :

docker run --rm \
  --env-file .env.test \
  -v $(pwd)/playwright-report:/app/playwright-report \
  playwright-tests:local

Ne commitez jamais de fichiers .env dans votre dépôt. Ajoutez .env* à .gitignore et utilisez les secrets CI pour les valeurs sensibles.

→ See also: Docker pour les Ingénieurs QA: Lancer des Tests dans des Conteneurs | GitHub Actions pour Tests Playwright: La Configuration Complète (2026) | Exécution Parallèle dans Playwright: Workers, Fragments et Fragmentation pour la Vitesse