Les méthodes map, filter, find et forEach de JavaScript apparaissent constamment dans le code de tests Playwright. Vous les utiliserez pour transformer des données de test, filtrer des réponses API, trouver des éléments spécifiques dans une liste, et itérer sur des datasets de fixtures.

Les tableaux : récapitulatif en une minute

Un tableau est une liste ordonnée de valeurs :

const users = ['Alice', 'Bob', 'Charlie'];
const prices = [12.99, 5.50, 29.00, 8.75];
const testCases = [
  { input: 'valid@email.com', shouldPass: true },
  { input: 'not-an-email',    shouldPass: false },
  { input: '',                shouldPass: false },
];

Vous accédez aux éléments par index (à partir de 0) :

console.log(users[0]);   // 'Alice'
console.log(users[2]);   // 'Charlie'
console.log(users.length); // 3

Tout ce qui suit dans ce guide repose sur ça.

forEach : faire quelque chose avec chaque élément

forEach exécute une fonction une fois pour chaque élément du tableau. Utilisez-le quand vous voulez faire quelque chose avec chaque élément sans avoir besoin d'un résultat en retour.

const usernames = ['alice', 'bob', 'charlie'];

usernames.forEach((name) => {
  console.log(`Testing user: ${name}`);
});

// Affichage :
// Testing user: alice
// Testing user: bob
// Testing user: charlie

Dans les tests Playwright

const loginUrls = [
  '/en/login',
  '/ru/login',
  '/es/login',
];

// Vérifier que toutes les pages de connexion par locale chargent
loginUrls.forEach(async (url) => {
  await page.goto(url);
  await expect(page.locator('h1')).toBeVisible();
});

Quand utiliser forEach : quand vous voulez des effets de bord (logs, clics sur des boutons, remplissage de formulaires). Pour transformer ou filtrer des données, un meilleur outil existe.

map : transformer chaque élément

map crée un nouveau tableau en appliquant une fonction à chaque élément. Le tableau original ne change pas.

Pensez-y ainsi : "pour chaque élément, donne-moi quelque chose de différent en retour."

const prices = [10, 20, 30];
const discounted = prices.map((price) => price * 0.9);

console.log(discounted); // [9, 18, 27]
console.log(prices);     // [10, 20, 30]  ← inchangé

Exemple pratique : extraire le texte d'une liste d'éléments

Vous récupérez souvent un tableau de locators depuis Playwright et avez besoin d'extraire le texte de chacun :

// Récupérer tous les textes des cellules de tableau
const cells = await page.locator('table tbody td').all();
const texts = await Promise.all(
  cells.map((cell) => cell.textContent())
);
// texts = ['Alice', '28', 'Admin', 'Bob', '34', 'User', ...]

Construire des données de test avec map

const userIds = [1, 2, 3, 4, 5];

const testUsers = userIds.map((id) => ({
  id,
  username: `user_${id}`,
  email: `user${id}@test.com`,
  role: id === 1 ? 'admin' : 'member',
}));

/*
[
  { id: 1, username: 'user_1', email: 'user1@test.com', role: 'admin' },
  { id: 2, username: 'user_2', email: 'user2@test.com', role: 'member' },
  ...
]
*/

Transformer les données d'une réponse API

// L'API retourne des données brutes
const apiUsers = [
  { first_name: 'Alice', last_name: 'Smith', is_active: 1 },
  { first_name: 'Bob',   last_name: 'Jones', is_active: 0 },
];

// Transformer pour correspondre à ce que l'UI affiche
const displayUsers = apiUsers.map((u) => ({
  name: `${u.first_name} ${u.last_name}`,
  active: u.is_active === 1,
}));

// [{ name: 'Alice Smith', active: true }, { name: 'Bob Jones', active: false }]

Quand utiliser map : quand vous voulez transformer chaque élément d'un tableau en quelque chose d'autre. Le résultat a toujours la même longueur que l'entrée.

filter : garder uniquement ce dont vous avez besoin

filter crée un nouveau tableau contenant uniquement les éléments qui passent un test. Les éléments qui échouent sont supprimés.

const prices = [5, 12, 3, 25, 8, 40, 1];
const expensive = prices.filter((price) => price > 10);

console.log(expensive); // [12, 25, 40]
console.log(prices);    // [5, 12, 3, 25, 8, 40, 1]  ← inchangé

Filtrer des cas de test

C'est là que filter brille en automatisation de tests. Quand vous avez une grande liste de cas de test, vous pouvez les diviser :

const allTestCases = [
  { input: 'valid@email.com', shouldPass: true },
  { input: 'another@test.org', shouldPass: true },
  { input: 'not-an-email',    shouldPass: false },
  { input: '',                shouldPass: false },
  { input: 'missing@',       shouldPass: false },
];

const validCases   = allTestCases.filter((tc) => tc.shouldPass);
const invalidCases = allTestCases.filter((tc) => !tc.shouldPass);

// validCases a 2 éléments, invalidCases en a 3

Filtrer des résultats API

// Toutes les commandes depuis l'API
const orders = [
  { id: 1, status: 'completed', amount: 99 },
  { id: 2, status: 'pending',   amount: 45 },
  { id: 3, status: 'completed', amount: 12 },
  { id: 4, status: 'cancelled', amount: 75 },
];

// Garder uniquement les commandes terminées pour la vérification
const completedOrders = orders.filter((o) => o.status === 'completed');
// [{ id: 1, ... }, { id: 3, ... }]

Filtrer des éléments de page par texte

// Toutes les lignes d'un tableau
const rows = await page.locator('table tbody tr').all();

// Uniquement les lignes contenant 'Admin'
const adminRows = [];
for (const row of rows) {
  const text = await row.textContent();
  if (text?.includes('Admin')) {
    adminRows.push(row);
  }
}

Quand utiliser filter : quand vous voulez un sous-ensemble d'un tableau. Le résultat peut être plus court que l'entrée, ou même vide.

find : obtenir la première correspondance

find retourne le premier élément qui passe un test. Si rien ne correspond, il retourne undefined. Contrairement à filter, il arrête la recherche dès qu'il trouve une correspondance.

const users = [
  { id: 1, name: 'Alice', role: 'admin' },
  { id: 2, name: 'Bob',   role: 'member' },
  { id: 3, name: 'Carol', role: 'admin' },
];

const firstAdmin = users.find((u) => u.role === 'admin');
// { id: 1, name: 'Alice', role: 'admin' }

const missingUser = users.find((u) => u.name === 'Dave');
// undefined

Trouver des données de test par ID

const products = [
  { id: 'PROD-001', name: 'Laptop', price: 999 },
  { id: 'PROD-002', name: 'Mouse',  price: 29  },
  { id: 'PROD-003', name: 'Desk',   price: 349 },
];

const targetProduct = products.find((p) => p.id === 'PROD-002');
// { id: 'PROD-002', name: 'Mouse', price: 29 }

Toujours vérifier undefined

const product = products.find((p) => p.id === 'PROD-999');

if (!product) {
  throw new Error('Test data not found: PROD-999');
}

// Maintenant sûr d'utiliser product
await page.fill('[data-testid="search"]', product.name);

Quand utiliser find : quand vous avez besoin d'exactement un élément d'un tableau et que vous savez ce que vous cherchez. Si vous avez besoin de toutes les correspondances, utilisez filter.

Les combiner

La vraie puissance vient du chaînage :

const apiOrders = [
  { id: 1, user: 'alice', status: 'completed', amount: 150, items: 3 },
  { id: 2, user: 'bob',   status: 'pending',   amount: 50,  items: 1 },
  { id: 3, user: 'alice', status: 'completed', amount: 200, items: 5 },
  { id: 4, user: 'carol', status: 'cancelled', amount: 75,  items: 2 },
  { id: 5, user: 'alice', status: 'pending',   amount: 30,  items: 1 },
];

// Obtenir le montant total des commandes terminées d'Alice
const aliceCompletedTotal = apiOrders
  .filter((o) => o.user === 'alice' && o.status === 'completed')
  .map((o) => o.amount)
  .reduce((sum, amount) => sum + amount, 0);

// 150 + 200 = 350

Ou pour la vérification :

// Vérifier que tous les prix de produits visibles sont supérieurs à zéro
const priceLocators = await page.locator('[data-testid="product-price"]').all();
const prices = await Promise.all(
  priceLocators.map(async (el) => {
    const text = await el.textContent();
    return parseFloat(text?.replace('$', '') ?? '0');
  })
);

const hasNegativePrice = prices.some((p) => p <= 0);
expect(hasNegativePrice).toBe(false);

Référence rapide

| Méthode | Ce qu'elle retourne | Quand l'utiliser |

|---------|---------------------|-----------------|

| forEach | Rien (undefined) | Effets de bord (logs, actions) |

| map | Nouveau tableau, même longueur | Transformer chaque élément |

| filter | Nouveau tableau, plus court ou égal | Obtenir un sous-ensemble d'éléments |

| find | Un élément ou undefined | Trouver la première correspondance |

Erreurs fréquentes

Utiliser map quand vous voulez forEach :

// Incorrect — map sert à retourner des valeurs, pas à des effets de bord
users.map((user) => {
  console.log(user.name); // fonctionne mais inutilement coûteux
});

// Correct
users.forEach((user) => {
  console.log(user.name);
});

Oublier que find peut retourner undefined :

// Cela lèvera une erreur si l'utilisateur n'est pas trouvé
const user = users.find((u) => u.id === 99);
user.name; // TypeError: Cannot read properties of undefined

Muter le tableau original avec map :

Si vous faites users.map((u) => { u.role = 'admin'; return u; }), vous avez muté les objets originaux, pas créé de nouveaux. Créez de nouveaux objets :

// Correct — crée de nouveaux objets
users.map((u) => ({ ...u, role: 'admin' }));

Note sur l'async dans Playwright

Quand votre callback est async (ce qui arrive constamment avec Playwright), enveloppez avec Promise.all :

// Ne fonctionne pas — forEach ignore les promises
cells.forEach(async (cell) => {
  const text = await cell.textContent();  // fire-and-forget
});

// Fonctionne — attend toutes les promises
const texts = await Promise.all(
  cells.map(async (cell) => await cell.textContent())
);

C'est le piège le plus courant de l'async dans les tableaux avec Playwright. En cas de doute, utilisez Promise.all avec map.

map, filter, find et forEach couvrent 90 % de ce dont vous aurez besoin pour travailler avec des données de test, des réponses API et des tableaux d'éléments de page. → See also: JavaScript pour les QA Engineers: Le Minimum pour Commencer à Automatiser | Async/Await en Termes Simples (pour les Testeurs Perdus avec les Promesses) | Objets JavaScript et Déstructuration pour les Ingénieurs QA