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); // 3Tout 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: charlieDans 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();
});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 }]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 3Filtrer 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);
}
}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');
// undefinedTrouver 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);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 = 350Ou 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
Utilisermap 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);
});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 undefinedmap :
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