Vous n'avez pas besoin de devenir développeur JavaScript pour écrire des tests Playwright. Vous devez comprendre un sous-ensemble précis du langage, et vouloir tout apprendre d'un coup est une erreur fréquente.

Pourquoi JavaScript pour les QA

Les tests Playwright sont des fichiers JavaScript (ou TypeScript). Quand vous écrivez :

await page.click('.submit-button');

Ce mot-clé await, cette fonction fléchée, cet argument de type string : tout ça c'est du JavaScript. Sans comprendre ce que fait await, on ne peut pas déboguer un test qui se bloque. Sans comprendre les variables, on ne peut pas extraire une valeur de la page pour la vérifier.

La bonne nouvelle : l'automatisation QA n'utilise qu'une petite tranche prévisible de JavaScript. On ne construit pas des applications web. On écrit des scripts qui interagissent avec elles. Les patterns de code se répètent.

Variables : let et const

Deux façons de stocker des valeurs :

// const : la valeur ne change pas après l'assignation
const baseUrl = 'https://lab.becomeqa.com';
const timeout = 5000;

// let : la valeur peut changer
let loginAttempts = 0;
loginAttempts = loginAttempts + 1;

Dans le code de test, utilisez const par défaut. Passez à let uniquement quand vous devez réassigner. Vous verrez aussi var dans du code ancien. Ignorez-le. Il a un comportement de portée qui cause des bugs. const et let l'ont remplacé.

Types de données

Les types que vous utiliserez réellement dans le code de test :

// String : texte
const username = 'admin@becomeqa.com';
const password = 'testpass123';

// Number : pour les timeouts, les comptages, les vérifications de prix
const timeout = 30000; // 30 secondes en ms
const itemCount = 5;

// Boolean : pour les conditions
const isLoggedIn = true;
const hasError = false;

// null / undefined : absence de valeur
// Vous verrez ces types dans les assertions
const itemTitle = null; // intentionnellement vide

Dans les tests Playwright, les strings et les numbers apparaissent partout. Les booleans se retrouvent dans les conditions. null apparaît quand quelque chose n'est pas trouvé.

Fonctions

Les fonctions regroupent du code pour le réutiliser. Deux styles que vous rencontrerez :

// Fonction classique (style plus ancien, encore courant)
function generateEmail() {
  return `user_${Date.now()}@test.com`;
}

// Fonction fléchée (moderne, courante dans le code Playwright)
const generateEmail = () => `user_${Date.now()}@test.com`;

// Fonction fléchée avec un corps (plusieurs lignes)
const login = async (page, email, password) => {
  await page.getByRole('button', { name: 'Login' }).click();
  await page.getByLabel('Email').fill(email);
  await page.getByLabel('Password').fill(password);
  await page.getByRole('button', { name: 'Submit' }).click();
};

Les fonctions fléchées sont le standard dans le code Playwright moderne. async avant la fonction signifie qu'elle utilise await à l'intérieur, ce qui est couvert dans l'Async/Await en Termes Simples (pour les Testeurs Perdus avec les Promesses).

Objets

Les objets regroupent des données liées :

// Un objet avec des propriétés
const user = {
  email: 'admin@becomeqa.com',
  password: 'testpass123',
  role: 'admin',
};

// Accéder à une propriété avec la notation par point
console.log(user.email);  // 'admin@becomeqa.com'

// Ou avec la notation par crochet
console.log(user['email']);  // même résultat

Dans Playwright, les objets apparaissent en permanence comme options passées aux fonctions :

// { name: 'Login' } est un objet
await page.getByRole('button', { name: 'Login' }).click();

// { data: { title: 'Tokyo' } } est un objet imbriqué
await request.post('/api/items', { data: { title: 'Tokyo' } });

Tableaux

Les tableaux stockent des listes de valeurs :

const statuses = ['Planned', 'In Progress', 'Completed'];
const prices = [9.99, 14.99, 29.99];

// Accès par index (commence à 0)
console.log(statuses[0]);  // 'Planned'
console.log(statuses[2]);  // 'Completed'

// Longueur
console.log(statuses.length);  // 3

Dans les tests, les tableaux apparaissent quand on récupère plusieurs éléments de la page :

// Récupérer tous les textes des lignes d'un tableau
const rows = await page.getByRole('row').allTextContents();
// rows est maintenant un tableau : ['Tokyo', 'Paris', 'London']
expect(rows).toContain('Tokyo');

if / else : prendre des décisions

// Condition simple
if (user.role === 'admin') {
  await page.goto('/admin');
} else {
  await page.goto('/dashboard');
}

// Vérifier si quelque chose est absent
const errorMessage = await page.getByText('Invalid credentials').isVisible();
if (errorMessage) {
  console.log('Login failed as expected');
}

La comparaison === (triple égal) vérifie à la fois la valeur ET le type. Toujours utiliser === plutôt que == en JavaScript.

Littéraux de gabarit : construire des strings

Ancienne façon (difficile à lire avec beaucoup de variables) :

const url = 'https://' + environment + '.lab.becomeqa.com/item/' + itemId;

Façon moderne avec les backticks :

const url = `https://${environment}.lab.becomeqa.com/item/${itemId}`;

Les littéraux de gabarit (strings avec backticks) permettent d'intégrer des variables avec ${}. On les voit en permanence dans le code de test pour construire des URLs, des messages et des données de test.

Déstructuration : extraire depuis des objets et des tableaux

Ce pattern apparaît partout dans les fixtures Playwright et le code du Page Object Model :

// Au lieu de ça :
const email = user.email;
const password = user.password;

// On peut faire ça (déstructuration) :
const { email, password } = user;

Avec les tableaux :

const [first, second] = ['Tokyo', 'Paris', 'London'];
// first = 'Tokyo', second = 'Paris'

Dans Playwright, c'est omniprésent dans les paramètres de test :

// Le { page, request } ici est une déstructuration depuis l'objet fixture
test('should work', async ({ page, request }) => {
  // page et request sont disponibles directement
});

Modules : import et export

Les fichiers de tests Playwright importent depuis le framework et depuis votre propre code :

// Import depuis le package Playwright
import { test, expect } from '@playwright/test';

// Import de votre page object
import { LoginPage } from '../pages/LoginPage';

// Import de données de test
import { testUsers } from '../data/users';

Quand vous créez un fichier utilitaire, vous en exportez le contenu :

// Dans utils/helpers.ts
export const baseUrl = 'https://lab.becomeqa.com';

export function generateTestEmail() {
  return `test_${Date.now()}@example.com`;
}

import fait entrer les choses. export les rend disponibles pour être importées ailleurs. C'est tout le système.

Et les boucles ?

Vous aurez parfois besoin de boucles dans le code de test, mais moins souvent qu'on ne le croit. Les cas principaux :

// Boucler sur un tableau de données de test
const destinations = ['Tokyo', 'Paris', 'London'];

for (const destination of destinations) {
  await page.getByLabel('Destination').fill(destination);
  await page.getByRole('button', { name: 'Save' }).click();
}

La boucle for...of est la plus lisible pour itérer sur des tableaux. forEach, map, filter sont couverts dans un article dédié aux méthodes de tableaux.

Le point qui confond tout le monde : async/await

Presque chaque ligne de code Playwright a await devant elle :

await page.goto('https://lab.becomeqa.com');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page.getByText('Dashboard')).toBeVisible();

La règle est simple : toute méthode Playwright qui interagit avec le navigateur retourne une Promise, et vous avez besoin de await pour attendre qu'elle se termine.

Sans await, le test passe généralement à la ligne suivante avant que l'action en cours soit terminée. Le résultat : des échecs intermittents difficiles à comprendre.

C'est assez important pour avoir Async/Await en Termes Simples (pour les Testeurs Perdus avec les Promesses). Version courte : mettez toujours await avant les appels Playwright. TypeScript vous avertira si vous oubliez.

Ce dont vous n'avez pas besoin (pour l'instant)

Des choses que les ingénieurs QA cherchent souvent à apprendre avant d'en avoir besoin, ce qui crée une confusion inutile :

  • Classes : utiles pour le Page Object Model, mais vous pouvez comprendre le POM sans maîtriser les classes en profondeur d'abord
  • Promises/then/catch : async/await est le remplacement moderne ; apprenez await en premier
  • Closures, prototypes, event loop : les mécanismes internes de JavaScript qui affectent rarement le code de test
  • Manipulation du DOM : vous utilisez Playwright pour interagir avec le DOM, vous ne le manipulez pas directement

Apprenez ces concepts quand un problème précis les réclame. Pas avant.

Un test complet qui utilise tout ce qui précède

Voici un test Playwright qui utilise chaque concept de cet article :

import { test, expect } from '@playwright/test';

// Objet : données utilisateur
const testUser = {
  email: 'admin@becomeqa.com',
  password: 'testpass123',
};

// Littéral de gabarit : URL dynamique
const baseUrl = 'https://lab.becomeqa.com';

test('user can add a travel item', async ({ page }) => {
  // Déstructuration : extraire email et password depuis l'objet
  const { email, password } = testUser;

  // Fonctions (méthodes Playwright) avec await
  await page.goto(baseUrl);
  await page.getByRole('button', { name: 'Login' }).click();
  await page.getByLabel('Username').fill(email);
  await page.getByLabel('Password').fill(password);
  await page.getByRole('button', { name: 'Submit' }).click();

  // Variable string
  const destination = 'Tokyo';

  await page.getByRole('button', { name: 'Add Item' }).click();
  await page.getByLabel('Destination').fill(destination);

  // Boolean : vérifier si quelque chose est visible
  const saveButton = page.getByRole('button', { name: 'Save' });

  // Condition
  if (await saveButton.isVisible()) {
    await saveButton.click();
  }

  // Tableau : allTextContents retourne un tableau
  const rows = await page.getByRole('row').allTextContents();

  // expect sur le tableau
  expect(rows.some(row => row.includes(destination))).toBeTruthy();
});

C'est un vrai test complet. Le JavaScript qu'il utilise est exactement ce qui est couvert dans cet article. Rien de plus.

FAQ

Dois-je terminer un cours JavaScript complet avant de commencer avec Playwright ?

Non. Apprenez les concepts JavaScript au fur et à mesure des besoins. Commencez à écrire des tests Playwright immédiatement en utilisant les patterns ci-dessus, et cherchez quand vous êtes bloqué. "Apprendre JS d'abord, puis Playwright" pousse de nombreuses personnes à étudier JavaScript pendant des mois sans jamais arriver à Playwright.

JavaScript ou TypeScript pour Playwright ?

TypeScript. La documentation officielle de Playwright utilise TypeScript. TypeScript ajoute des types à JavaScript, ce qui permet à l'éditeur de détecter les erreurs avant d'exécuter les tests. La différence est faible pour les débutants. Consultez TypeScript pour QA: Pourquoi les Types Statiques Améliorent Vos Tests pour les détails.

Que faire si je ne comprends pas un morceau de code Playwright ?

Cherchez. MDN Web Docs (developer.mozilla.org) est la meilleure référence pour les fonctionnalités du langage JavaScript. La documentation Playwright (playwright.dev) couvre les APIs propres à Playwright. Entre ces deux sources, toutes les questions sur le code de test trouvent une réponse.

Combien de temps faut-il pour apprendre assez de JavaScript pour écrire des tests Playwright ?

2 à 4 semaines de pratique quotidienne suffisent généralement pour être productif. Vous continuerez à apprendre des choses spécifiques au fil des rencontres. Mais 2 à 4 semaines de travail ciblé sur les concepts de cet article suffisent à écrire et comprendre de vrais tests.

Le concept qui bloque le plus souvent les débutants est async/await. Il est sous-jacent à chaque interaction Playwright. Le comprendre débloque le débogage.

→ See also: Async/Await en Termes Simples (pour les Testeurs Perdus avec les Promesses) | TypeScript pour QA: Pourquoi les Types Statiques Améliorent Vos Tests