Selenium vs Playwright : principales différences, code comparé et lequel choisir

  1. Accueil
  2. Blog
  3. Automatisation des tests

Automatisation des tests

Selenium vs Playwright : Différences clés, code comparé et lequel choisir

Le sélénium a deux décennies d’histoire et un immense écosystème. Playwright est plus récent et comprend davantage de contenus prêts à l’emploi. Comparez-les sur ce qui compte au quotidien, lisez un test dans les deux et décidez en toute confiance.

9 min de lecture
Selenium vs Playwright : principales différences, code comparé et lequel choisir

À retenir

  • Selenium est une bibliothèque d’automatisation de navigateur mature construite sur la norme W3C WebDriver.
  • Playwright est un framework plus récent avec attente automatique, traçage et exécuteur de test inclus.
  • Pour un nouveau projet Web, Playwright est généralement plus rapide à devenir productif.
  • Selenium reste un choix judicieux pour les grandes suites existantes, les besoins linguistiques plus larges et les tests dans les navigateurs de véritables fournisseurs.

Si vous démarrez un projet d’automatisation de tests, la question Selenium vs Playwright se posera rapidement. Les résultats de recherche peuvent donner l’impression que c’est une affaire réglée, mais la bonne réponse dépend de votre équipe, de vos tests existants et des navigateurs que vous devez prendre en charge.

Ce guide les compare sur les choses que vous ressentirez réellement dans votre travail quotidien. Les exemples de code montrent le style typique de chaque outil et nous ne les avons pas exécutés pour cet article. Nous évitons également de citer des pourcentages de vitesse, car les références publiées varient considérablement et proviennent souvent de fournisseurs. Mesurez sur votre propre application si la vitesse décidera de la question.

La réponse courte

Choisissez Playwright pour la plupart des nouveaux projets de tests Web, en particulier si votre équipe peut travailler avec JavaScript, TypeScript, Python, Java ou .NET. Vous bénéficiez de plus de fonctionnalités prêtes à l’emploi, et vous passez moins de temps sur l’infrastructure et les attentes instables.

Choisissez Selenium si vous disposez déjà d’une grande suite fonctionnelle, si vous avez besoin d’un langage que Playwright ne prend pas officiellement en charge, comme Ruby, ou si vous devez tester sur les versions de navigateur et les plates-formes réelles disponibles via une grille Selenium ou un cloud d’appareils.

Sélénium vs Dramaturge côte à côte

Aspect Sélénium Dramaturge
Première sortie 2004 2020, par Microsoft
Qu’est-ce que c’est Bibliothèque d’automatisation du navigateur Framework, avec un runner dans Node.js
Langues Java, Python, C#, Ruby, JavaScript TypeScript, JavaScript, Python, Java, .NET
Navigateurs Chrome, Firefox, Bord, Safari Chrome, Firefox, WebKit
En attente Les attentes explicites que vous écrivez Attente automatique intégrée
Testeur Apportez le vôtre, comme pytest ou JUnit Inclus pour Node.js, plugin pytest pour Python
Exécutions parallèles Selenium Grid ou le framework de test Intégré à son coureur
Débogage Journaux du framework, captures d’écran que vous ajoutez Visionneuse de traces, mode interface utilisateur, codegen
Moquerie du réseau Outillage limité, souvent supplémentaire Intégré
Communauté Très grand et établi de longue date Grand et en croissance rapide

Architecture : comment chacun communique avec le navigateur

Selenium envoie des commandes à l’aide du protocole W3C WebDriver, une norme formelle. Votre code communique avec un pilote, tel que ChromeDriver, qui contrôle le navigateur, chaque commande étant généralement une requête HTTP distincte. Étant donné que les fournisseurs de navigateurs prennent en charge cette norme, celle-ci offre une large compatibilité. Un protocole plus récent, WebDriver BiDi, ajoute à la norme la communication bidirectionnelle et le streaming d’événements.

Playwright maintient une connexion persistante au navigateur et utilise ses propres versions corrigées de Chromium, Firefox et WebKit. La connexion étant directe et bidirectionnelle, elle peut réagir aux événements du navigateur et chaque test peut s’exécuter dans son propre contexte de navigateur léger. C’est pourquoi la plupart des comparaisons évaluent Playwright comme étant plus rapide, bien que l’écart réel dépende de votre application et de vos tests.

Un test dans les deux outils

Voici le même test de connexion, écrit en Python, sur un site de pratique publique.

Sélénium

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def test_login(driver):
    driver.get("https://the-internet.herokuapp.com/login")
    driver.find_element(By.ID, "username").send_keys("tomsmith")
    driver.find_element(By.ID, "password").send_keys("SuperSecretPassword!")
    driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()

    message = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, "flash"))
    )
    assert "You logged into a secure area" in message.text

Vous avez également besoin d’un appareil pour créer et fermer le pilote, comme nous le montrons dans notre Tutoriel Selenium Python.

Dramaturge

from playwright.sync_api import Page, expect

def test_login(page: Page):
    page.goto("https://the-internet.herokuapp.com/login")
    page.get_by_label("Username").fill("tomsmith")
    page.get_by_label("Password").fill("SuperSecretPassword!")
    page.get_by_role("button", name="Login").click()

    expect(page.locator("#flash")).to_contain_text("You logged into a secure area")

Cela repose sur le plugin pytest-playwright, qui fournit le luminaire page. Il est plus court, principalement parce que l’attente est intégrée dans expect, et parce que les localisateurs comme get_by_role décrivent la page telle qu’un utilisateur la voit. Avec Selenium, vous pouvez réduire considérablement ce passe-partout avec des assistants et le Page Object Model, que nous recommandons dans l’un ou l’autre outil.

Tests d’attente et floconneux

Le timing est la principale cause des tests de navigateur irréguliers, et c’est là que les deux outils diffèrent le plus dans l’utilisation quotidienne.

Dans Selenium, vous êtes responsable de la synchronisation. Les attentes explicites fonctionnent bien, mais quelqu’un doit s’en souvenir partout, et les équipes qui les oublient se tournent souvent vers time.sleep. Notre guide sur les Selenium waits explique comment procéder correctement.

Dans Playwright, les actions vérifient automatiquement qu’un élément est visible, stable, activé et capable de recevoir des événements avant d’agir. Les assertions Web-First continuent de réessayer jusqu’à expiration du délai d’attente. Vous pouvez toujours écrire des tests irréguliers, par exemple avec des données de test médiocres, mais une source majeure de problèmes est gérée par défaut.

Navigateurs et langues

C’est là que Selenium garde un réel avantage. La version WebKit de Playwright est proche du moteur de Safari, mais ce n’est pas la même chose que Safari sur Mac ou iPhone. Si le comportement réel de Safari est critique, Selenium avec SafariDriver, ou un véritable cloud d’appareils, vous rapproche de ce que vos utilisateurs exécutent réellement.

De même, Playwright teste ses versions de navigateur fournies, bien qu’il puisse également piloter les canaux Chrome et Edge installés. Selenium pilote les navigateurs que vous installez, ce qui est utile si vous devez prendre en charge des versions spécifiques. Pour les applications mobiles natives, la réponse complète n’est pas non plus : Appium, qui repose sur les concepts WebDriver, est l’outil habituel.

Concernant les langages, Selenium prend officiellement en charge Ruby et a une très longue histoire dans les équipes Java. La version Node.js de Playwright dispose également de l’outillage le plus complet, puisque le programme d’exécution de test complet est présent. D’autres langages obtiennent la bibliothèque principale et s’intègrent à leurs propres frameworks de test.

Débogage

Le dramaturge a ici une avance évidente. Son visualiseur de traces enregistre chaque action, ainsi que les instantanés DOM, les appels réseau et les journaux de console, afin que vous puissiez parcourir une exécution de CI ayant échoué une fois celle-ci terminée. Son mode UI et son codegen vous aident également à écrire des tests plus rapidement. Consultez notre Tutoriel dramaturge pour débutants pour savoir comment les utiliser.

Avec Selenium, vous assemblez cela vous-même, à partir de captures d’écran d’échec, de journaux de navigateur, de vidéos de votre fournisseur de grille et de rapports de votre framework de test. Cela fonctionne bien et de nombreuses équipes ont d’excellentes configurations, mais cela demande des efforts de construction.

Fonctionnalités réseau et API

Playwright peut intercepter et simuler les requêtes réseau avec quelques lignes de code, ce qui est utile pour tester les états d’erreur :

page.route("**/api/orders", lambda route: route.fulfill(status=500))

Il comprend également un client de requête API, vous permettant ainsi de créer des données de test via une API avant de piloter le navigateur. Selenium 4 a ajouté certaines fonctionnalités réseau via le protocole Chrome DevTools et BiDi, mais la prise en charge et la commodité varient selon le navigateur et la langue. De nombreux utilisateurs de Selenium ajoutent un proxy ou une bibliothèque HTTP distincte, comme dans les outils de test d’API.

Conseil : Quel que soit l’outil que vous choisissez, concentrez les tests du navigateur sur les parcours critiques et poussez les détails vers les niveaux inférieurs. Une suite plus petite compte plus qu’un outil plus rapide. Consultez nos bonnes pratiques en matière de tests de bout en bout.

Exécutions parallèles et mise à l’échelle

Le programme d’exécution de Playwright gère les travailleurs parallèles et le partitionnement sur les machines CI avec des options simples. Les contextes de navigateur sont bon marché, donc l’isolation ne nécessite pas un tout nouveau navigateur pour chaque test.

Selenium utilise Selenium Grid pour distribuer les tests sur les machines et les versions de navigateur, et les frameworks de test gèrent le parallélisme. Grid est plus complexe à exécuter, mais il a fait ses preuves à très grande échelle et de nombreux cloud d’appareils commerciaux le prennent directement en charge.

Devriez-vous migrer de Selenium vers Playwright ?

Pas automatiquement. Une suite de travail est précieuse et une réécriture prend du temps pour tester le produit. Posez d’abord ces questions :

  1. Y a-t-il un problème mesurable ? Des tests irréguliers ou un débogage lent sont de bonnes raisons. “C’est plus récent” ne l’est pas.
  2. Quelle est la taille de la suite ? Une centaine de tests peuvent être déplacés. Dix mille est un projet majeur.
  3. Les objets de votre page sont-ils propres ? De bonnes abstractions rendent le déplacement beaucoup moins cher.
  4. Comptez-vous sur des fonctionnalités spécifiques à Selenium ? Vérifiez d’abord les besoins de votre réseau et de vos appareils.

Si vous bougez, allez-y progressivement. Écrivez de nouveaux tests dans Playwright, migrez d’abord les anciens tests les plus instables et exécutez les deux côte à côte jusqu’à ce que l’ancienne suite soit suffisamment petite pour être retirée. Ne traduisez pas les tests ligne par ligne, car cela répercute les mises en veille et les anciens localisateurs. Évitez également les erreurs décrites dans les erreurs d’automatisation des tests.

Comment choisir

Votre situation Choix raisonnable
Nouvelle application web, équipe moderne Dramaturge
Grande suite Sélénium stable Restez avec Selenium et améliorez-le
L’équipe écrit Ruby Sélénium
Une véritable couverture Safari est essentielle Selenium, ou un cloud d’appareils
Tests irréguliers et débogage CI dur Essayez Playwright sur un pilote
Applications mobiles natives Appium

Mieux encore, lancez un court pilote. Automatisez vos trois parcours les plus délicats dans chaque outil par rapport à votre propre application, dans votre propre CI, et comparez le code, la vitesse et la facilité avec laquelle vous pouvez déboguer une panne. Une semaine de preuves bat n’importe quel article comparatif, y compris celui-ci. Si Cypress figure également sur votre liste restreinte, lisez Playwright vs Cypress.

Pour conclure

Le dramaturge est généralement le point de départ le plus facile, et Selenium reste une norme fiable avec une large portée. Ni l’un ni l’autre ne sauvera une suite de tests mal conçue. Choisissez en fonction de vos contraintes réelles, investissez dans des localisateurs stables et de bonnes données de test, et concentrez votre suite sur ce qui compte le plus pour vos utilisateurs.

Questions fréquentes

Playwright est-il meilleur que Selenium ?

Pour de nombreux nouveaux projets Web, oui, grâce à l’attente automatique et aux outils intégrés. Selenium peut être la meilleure solution pour les suites existantes, les besoins linguistiques plus larges ou les vrais navigateurs spécifiques.

Playwright est-il plus rapide que Selenium ?

Il est généralement signalé comme plus rapide en raison de sa connexion persistante au navigateur et de ses contextes légers. La vraie différence dépend de votre application, alors mesurez-la sur vos propres tests.

Le sélénium est-il obsolète ?

Non. Selenium est activement maintenu et construit sur une norme W3C, et il est toujours largement utilisé. Selenium 4 et WebDriver BiDi continuent de le moderniser.

Playwright peut-il tester le vrai Safari ?

Playwright teste avec sa propre version WebKit, proche du moteur de Safari mais pas identique. Pour un comportement réel de Safari ou iOS, utilisez de vrais appareils ou SafariDriver.

Un débutant devrait-il apprendre Selenium ou Playwright ?

De nombreux débutants trouvent Playwright plus facile à démarrer. Le sélénium apparaît toujours dans de nombreuses offres d’emploi, alors vérifiez votre marché local. Les concepts de base se transmettent entre eux.

Continuez à apprendre

Travailler avec Stack Quora

Besoin d’aide pour les tests, WordPress ou le référencement ?

Nous aidons les équipes à proposer de meilleurs logiciels et à développer leurs sites. Dites-nous sur quoi vous travaillez et nous vous proposerons une prochaine étape claire.

Continuez à lire

Plus de guides sur tests, IA et développement moderne

Vous avez apprécié cet article ? Choisissez un sujet et accédez directement à nos nouveaux didacticiels.

Intelligence artificielle

Les hallucinations de l'IA expliquées : pourquoi les modèles de langage inventent les choses et comment les réduire

Les hallucinations de l'IA ont expliqué : ce qu'elles sont, pourquoi les modèles de langage les produisent, les types courants, comment les réduire …

Lire l'article →
DevOps

Variables d'environnement expliquées : fichiers .env, secrets et configuration correctement effectués

Variables d'environnement expliquées avec des exemples Python que nous avons exécutés : lecture et définition, pourquoi chaque valeur est une chaîne…

Lire l'article →
Développement logiciel

Limitation du débit de l'API expliquée : algorithmes, en-têtes et gestion des erreurs 429

Limitation du débit de l'API expliquée avec une simulation que nous avons exécutée : compartiment de jetons, fenêtre fixe, fenêtre glissante, 429 ré…

Lire l'article →
Automatisation des tests

Se moquer en Python : unittest.mock, patch et les erreurs qui font mentir les tests

Moquerie en Python avec unittest.mock, testée : Mock et return_value, side_effect, correctifs où un nom est utilisé, spec et autospec, dates moqueus…

Lire l'article →
Tests logiciels

Couverture du code expliquée : couverture des lignes par rapport aux branches et ce que signifie réellement 100 %

Couverture du code expliquée avec une véritable exécution de cover.py : couverture des lignes, des branches et des conditions, lecture d'un rapport,…

Lire l'article →
Bases de données et SQL

DELETE vs TRUNCATE vs DROP dans SQL : différences, restauration et quand les utiliser

DELETE vs TRUNCATE vs DROP expliqué avec SQL testé : ce que chacun supprime, restauration, déclencheurs, réinitialisation d'identité, vitesse et en …

Lire l'article →
Bases de données et SQL

Vues SQL expliquées : créez, utilisez et évitez les pièges, avec des exemples

Vues SQL expliquées avec les requêtes que nous avons exécutées : création d'une vue, résultats en direct, masquage des colonnes, performances, vues …

Lire l'article →
Développement logiciel

Interface TypeScript vs Type : différences réelles, testées avec le compilateur

Interface TypeScript vs type, vérifiée avec le vrai compilateur : ce que les deux peuvent faire, ce qu'un seul peut faire, la fusion des déclaration…

Lire l'article →
Développement logiciel

Python *args et **kwargs expliqués : fonctions flexibles avec des exemples clairs

Python *args et **kwargs expliqués avec le code que nous avons exécuté : emballage et déballage, ordre des paramètres, arguments de mot-clé uniqueme…

Lire l'article →
Développement logiciel

Fonctions Python Lambda : syntaxe, utilisations réelles et quand ne pas les utiliser

Fonctions Python lambda expliquées avec le code que nous avons exécuté : syntaxe, tri avec clé, carte et filtre, fermetures, piège de liaison tardiv…

Lire l'article →
Intelligence artificielle

Que sont les agents IA ? Comment ils fonctionnent, avec une simple boucle d'agent que vous pouvez exécuter

Que sont les agents IA ? Un guide simple sur la boucle d'agent, les outils, la mémoire et les garde-fous, avec une petite boucle Python que nous avo…

Lire l'article →
DevOps

Surveillance vs observabilité : la vraie différence, avec les journaux, les métriques et les traces

Surveillance et observabilité expliquées : échecs connus et inconnus, journaux, métriques et traces, présentation pas à pas des incidents de paiemen…

Lire l'article →
DevOps

Volumes Docker vs montages Bind : conserver les données du conteneur de la bonne manière

Volumes Docker et montages de liaison expliqués : pourquoi les données du conteneur disparaissent, volumes nommés, montages de liaison, tmpfs, exemp…

Lire l'article →
Automatisation des tests

TDD vs BDD : principales différences, une fonctionnalité conçue dans les deux sens et quand les utiliser

TDD vs BDD expliqué avec une fonctionnalité de remise construite dans les deux sens : refactor rouge-vert avec le code que nous avons exécuté, scéna…

Lire l'article →
Tests logiciels

Tests d'acceptation utilisateur (UAT) : processus, liste de contrôle et exemples réels

Les tests d'acceptation des utilisateurs sont expliqués : qui les exécute, en quoi ils diffèrent du contrôle qualité, un processus en sept étapes, u…

Lire l'article →
Bases de données et SQL

Explication des valeurs SQL NULL : IS NULL, COALESCE, NULLIF et les pièges à éviter

Les valeurs SQL NULL expliquées avec les requêtes que nous avons exécutées : logique à trois valeurs, IS NULL, COALESCE, NULLIF, comment les agrégat…

Lire l'article →
Bases de données et SQL

Instruction SQL CASE WHEN : syntaxe, exemples réels et erreurs courantes

SQL CASE WHEN expliqué avec les requêtes que nous avons exécutées : formulaires simples et recherchés, ordre des conditions, pivots avec SUM, astuce…

Lire l'article →
Développement logiciel

Qu'est-ce que JWT ? Les jetons Web JSON expliqués avec un exemple fonctionnel

Qu’est-ce que JWT ? JSON Web Tokens expliqué : les trois parties, un jeton construit et falsifié dans le code que nous avons exécuté, JWT vs session…

Lire l'article →
Développement logiciel

Boucle d'événements JavaScript expliquée : pile d'appels, microtâches et minuteries avec des exemples

La boucle d'événements JavaScript expliquée avec le code que nous avons exécuté : pile d'appels, files d'attente de tâches et de microtâches, pourqu…

Lire l'article →
Développement logiciel

Générateurs Python et rendement expliqués : économisez de la mémoire avec des exemples réels

Les générateurs Python et le rendement expliqués avec le code que nous avons exécuté : comment ils s'arrêtent et reprennent, les économies de mémoir…

Lire l'article →
Intelligence artificielle

Que sont les intégrations ? Vecteurs et similarité cosinus expliqués simplement

Que sont les intégrations ? Un guide en langage simple sur les vecteurs, la similarité cosinus et la recherche sémantique, avec un petit exemple que…

Lire l'article →
DevOps

Déploiement Bleu-Vert vs Canary : différences, compromis et comment choisir

Explication du déploiement bleu-vert ou canari : comment chacun fonctionne, coût, risque et restauration, regroupement d'utilisateurs stable que nou…

Lire l'article →
Automatisation des tests

Tests instables : quelles sont leurs causes et comment les corriger définitivement

Des tests irréguliers expliqués avec des démos que nous avons exécutées : les principales causes, comment en confirmer et en diagnostiquer une, les …

Lire l'article →
Tests logiciels

Tests de charge vs tests de contrainte : différences, métriques et exemples k6

Explication des tests de charge et des tests de stress : ce que chacun prouve, les tests de pointe et de trempage, les métriques qui comptent, pourq…

Lire l'article →
Tests logiciels

Scénario de test et scénario de test : principales différences, exemples et quand les utiliser

Scénario de test et scénario de test expliqués : des définitions claires, un tableau côte à côte, une fonctionnalité de réinitialisation de mot de p…

Lire l'article →
Bases de données et SQL

Optimisation des requêtes SQL : lire les plans d'exécution et corriger les requêtes lentes, avec des délais

Optimisation des requêtes SQL testée sur un million de lignes : lire les plans d'exécution, ajouter les bons index, corriger les filtres non Sargabl…

Lire l'article →
Bases de données et SQL

SQL UNION vs UNION ALL : différences, exemples et performances testées

SQL UNION vs UNION ALL expliqué avec les requêtes que nous avons exécutées : des doublons, les règles suivent toutes les deux, un véritable bug de d…

Lire l'article →
Développement logiciel

Tutoriel API JavaScript Fetch : GET, POST, gestion des erreurs et délais d'attente

Un didacticiel de l'API JavaScript Fetch testé sur un serveur local : GET et POST, pourquoi 404 ne lance pas, un assistant réutilisable, des chaînes…

Lire l'article →
Développement logiciel

Gestion des fichiers Python : lecture, écriture, CSV, JSON et pathlib avec exemples

Gestion des fichiers Python expliquée avec le code que nous avons exécuté : modes ouverts, avec lecture de fichiers volumineux, CSV, JSON, pathlib, …

Lire l'article →
Développement logiciel

Classes et objets Python : didacticiel POO avec des exemples réels

Classes et objets Python expliqués avec le code que nous avons exécuté : __init__, méthodes, attributs de classe par rapport à l'instance, héritage,…

Lire l'article →
Intelligence artificielle

Qu'est-ce qu'un grand modèle de langage ? Comment fonctionnent les LLM, expliqués sans battage médiatique

Qu’est-ce qu’un grand modèle de langage ? Les LLM expliqués en langage simple : jetons, intégrations, attention, formation, fenêtres de température …

Lire l'article →
DevOps

Commandes Linux pour les débutants : le guide du terminal essentiel avec des exemples

Commandes Linux pour débutants, regroupées par tâche : navigation, fichiers, affichage des journaux, grep, tuyaux, autorisations, processus et archi…

Lire l'article →
Automatisation des tests

Selenium vs Playwright : principales différences, code comparé et lequel choisir

Comparatif Selenium vs Playwright : architecture, attente, support du navigateur et du langage, débogage, même test dans les deux outils, conseils d…

Lire l'article →
Tests logiciels

Partitionnement d'équivalence : technique de conception de tests expliquée avec des exemples concrets

Le partitionnement d'équivalence expliqué : comment trouver des partitions valides et invalides, des exemples concrets d'âges, de mots de passe et d…

Lire l'article →
Tests logiciels

Gravité vs priorité dans les tests logiciels : différences, matrice et exemples réels

Explication de la gravité et de la priorité dans les tests logiciels : des définitions claires, une matrice à quatre voies avec des exemples, des éc…

Lire l'article →
Bases de données et SQL

Tutoriel sur les sous-requêtes SQL : types, sous-requêtes corrélées et EXISTE avec des exemples

Un didacticiel sur les sous-requêtes SQL avec les requêtes que nous avons exécutées : les sous-requêtes scalaires, IN, FROM et SELECT, les sous-requ…

Lire l'article →
Bases de données et SQL

Transactions SQL et ACID expliquées : COMMIT, ROLLBACK et niveaux d'isolement

Transactions SQL et ACID expliquées avec un virement bancaire que nous avons effectué : COMMIT, ROLLBACK, points de sauvegarde, verrous, niveaux d'i…

Lire l'article →
Développement logiciel

Git merge vs rebase : différences, exemples et quand utiliser chacun

Git merge vs rebase expliqué avec de vraies sorties de log, un tableau comparatif, la règle d'or du rebase et un flux de travail sûr pour les équipes.

Lire l'article →
Développement logiciel

List comprehension Python : syntaxe, exemples et cas à éviter

La list comprehension Python expliquée : syntaxe, filtres, if-else, boucles imbriquées, temps mesurés et cas où une boucle for classique est préféra…

Lire l'article →
Bases de données et SQL

Jointures SQL expliquées avec exemples (Inner, Left, Right, Full)

Comprenez les jointures SQL pas à pas avec des tables et requêtes d'exemple : INNER, LEFT, RIGHT, FULL, CROSS et SELF, plus erreurs courantes et con…

Lire l'article →