Selenium C# → Playwright .NET
Migration
selenium-nunit
Bascule a réécrit cette suite Selenium en Playwright .NET. Ce rapport liste ce qui a été converti, ce qui mérite une relecture et ce qui reste à reprendre à la main, fichier par fichier.
Analyse locale : aucun code envoyé, aucun test exécuté
Une conversion de la suite
Assertion web-first : Playwright réessaie jusqu'à ce que la condition soit vraie (5 s par défaut), ce qui supprime une source d'instabilité. Tests/CatalogueTests.cs · ligne 15
Assert.That(catalogue.Resultats.Text, Is.EqualTo("8 pièce(s)"))await Expect(catalogue.Resultats).ToHaveTextAsync("8 pièce(s)")Par catégorie
| Catégorie | Automatique | À relire | À reprendre | Répartition |
|---|---|---|---|---|
| Cycle de vie du navigateur | 2 | · | · | |
| Navigation | 4 | · | · | |
| Sélecteurs | 43 | · | · | |
| Actions sur les éléments | 21 | 1 | · | |
| Lecture d'état | 23 | · | · | |
| Assertions | 11 | · | · | |
| Attentes | 6 | · | · | |
| Pauses fixes | 0 | 1 | · | |
| Listes déroulantes | 5 | · | · | |
| Clavier, souris, glisser-déposer | 2 | · | · | |
| JavaScript | 2 | · | · | |
| Captures d'écran | 1 | · | · | |
| Cadres (iframes) | 1 | · | · | |
| Alertes et dialogues | 4 | 1 | · | |
| Cookies et fenêtre | 1 | · | · | |
| Page objects | 4 | · | · | |
| Exceptions Selenium | 1 | · | · | |
| Passage en asynchrone | 34 | · | · | |
| Projet et dépendances | 5 | · | · | |
| Total | 170 | 3 | 0 |
automatique à relire à reprendre à la main
Travail restant estimé : 20 min par point à reprendre (5 min quand le même point se répète dans un fichier), 4 min par point à relire, 1 min par test pour l'exécuter et vérifier son résultat. C'est un ordre de grandeur pour planifier, pas un devis.
À reprendre (0)
Aucun point à reprendre : tout ce qui touche à Selenium a été converti.
À relire (3)
driver.FindElement(By.Id("bon")).SendKeys(chemin)Thread.Sleep(500)wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.AlertIsPresent())Conversions automatiques (170)
Le détail complet est dans bascule-rapport.json et dans le diff de votre dépôt. Voici les conversions regroupées par catégorie, cinq au plus par catégorie.
Cycle de vie du navigateur
| Selenium | Playwright |
|---|---|
protected IWebDriver driver;Infrastructure/TestBase.cs · L14 | protected IPage driver => Page;Le pilote devient la page Playwright du test. |
public abstract class TestBase { protected IWebDriver driver; protected WebDriverWait wait; protected static string BaseUrl => Environment.GetEnvironmentVariab…Infrastructure/TestBase.cs · L12 | class TestBase : PageTestLa classe hérite de PageTest (Microsoft.Playwright.NUnit) : Playwright crée un navigateur, un contexte et une page isolés pour chaque test. |
Navigation
| Selenium | Playwright |
|---|---|
driver.Navigate().GoToUrl(baseUrl + "/index.html")Pages/PageConnexion.cs · L30 | await driver.GotoAsync(baseUrl + "/index.html")Converti. |
d.UrlTests/ConnexionTests.cs · L15 | d.UrlUrl : propriété synchrone de la page. |
Sélecteurs
| Selenium | Playwright |
|---|---|
_driver.FindElement(_filtre)Pages/PageCatalogue.cs · L30 | _driver.Locator(_filtre).FirstFindElement devient un localisateur (attente automatique à chaque action). |
_driver.FindElements(_lignes)Pages/PageCatalogue.cs · L40 | (await BasculeOutils.TousAsync(_driver.Locator(_lignes), 2000))FindElements avec l'attente implicite du projet (2000 ms) : TousAsync attend qu'au moins un élément apparaisse, comme Selenium. |
_driver.FindElements(_lignes).CountPages/PageCatalogue.cs · L40 | await BasculeOutils.CompterAsync(_driver.Locator(_lignes), 2000)Nombre d'éléments : CountAsync(). |
_driver.FindElement(By.Id("bandeau-cookies"))Pages/PageCatalogue.cs · L70 | (await BasculeOutils.ExigerAsync(_driver.Locator("#bandeau-cookies")))Recherche dans un try / catch NoSuchElementException : échec immédiat si l'élément manque. |
driver.FindElements(By.CssSelector("#priorites li"))[0]Pages/PageCommande.cs · L54 | driver.Locator("#priorites li").Nth(0)Élément d'index n de FindElements : Nth(n). |
Actions sur les éléments
| Selenium | Playwright |
|---|---|
champ.Clear()Pages/PageCatalogue.cs · L31 | await champ.ClearAsync()Converti. |
champ.SendKeys(texte)Pages/PageCatalogue.cs · L32 | await champ.FillAsync(texte)SendKeys devient FillAsync (remplace le contenu du champ ; SendKeys l'ajoutait à la fin). |
champMotDePasse.SendKeys(motDePasse + Keys.Enter);Pages/PageConnexion.cs · L45 | { await champMotDePasse.FillAsync(motDePasse);
await champMotDePasse.PressAsync("Enter");
}Texte et touches : FillAsync puis PressAsync. |
Lecture d'état
| Selenium | Playwright |
|---|---|
e.TextPages/PageCatalogue.cs · L44 | await e.InnerTextAsync()Converti. |
_driver.FindElements(By.CssSelector("#pieces td.ref")).Select(e => e.Text)Pages/PageCatalogue.cs · L44 | (await _driver.Locator("#pieces td.ref").AllInnerTextsAsync())Textes d'une liste d'éléments : AllInnerTextsAsync(). |
Assertions
| Selenium | Playwright |
|---|---|
Assert.That(catalogue.Resultats.Text, Is.EqualTo("8 pièce(s)"))Tests/CatalogueTests.cs · L15 | await Expect(catalogue.Resultats).ToHaveTextAsync("8 pièce(s)")Assertion web-first : Playwright réessaie jusqu'à ce que la condition soit vraie (5 s par défaut), ce qui supprime une source d'instabilité. |
Attentes
| Selenium | Playwright |
|---|---|
wait.Until(ExpectedConditions.UrlContains("catalogue"))Infrastructure/TestBase.cs · L45 | await Expect(driver).ToHaveURLAsync(new Regex(Regex.Escape("catalogue")), new() { Timeout = 10_000 })Attente explicite convertie. |
var confirmation = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("confirmation")));Pages/PageCommande.cs · L47 | { var confirmation = driver.Locator("#confirmation");
await confirmation.WaitForAsync(new() { Timeout = 5_000 });
}Attente explicite d'un élément : localisateur puis WaitForAsync. |
wait.Until(d => d.Url.Contains("catalogue"))Tests/ConnexionTests.cs · L15 | await BasculeOutils.AttendreJusquaAsync(driver, d => d.Url.Contains("catalogue"), delaiMs: 10_000)Attente sur une condition libre : sondée par BasculeOutils.AttendreJusquaAsync avec le même délai. Une assertion Expect(…) serait plus idiomatique. |
Listes déroulantes
| Selenium | Playwright |
|---|---|
new SelectElement(_driver.FindElement(By.Id("categorie"))).SelectByText(libelle)Pages/PageCatalogue.cs · L37 | await _driver.Locator("#categorie").SelectOptionAsync(new SelectOptionValue { Label = libelle })Liste déroulante : SelectOptionAsync. |
Clavier, souris, glisser-déposer
| Selenium | Playwright |
|---|---|
new Actions(_driver).MoveToElement(menu).Perform();Pages/PageCatalogue.cs · L61 | await menu.HoverAsync();Chaîne Actions : appels Playwright équivalents, dans le même ordre. |
JavaScript
| Selenium | Playwright |
|---|---|
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", caseCgv)Pages/PageCommande.cs · L38 | await driver.EvaluateAsync("(args) => (function() { arguments[0].scrollIntoView(true); }).apply(null, args)", new object?[] { await caseCgv.ElementHandleAsync() })ExecuteScript devient EvaluateAsync ; le script garde son code (arguments[…] et return compris). |
Captures d'écran
| Selenium | Playwright |
|---|---|
((ITakesScreenshot)driver).GetScreenshot()Infrastructure/TestBase.cs · L36 | new BasculeCapture(await driver.ScreenshotAsync())Capture d'écran : ScreenshotAsync. |
Cadres (iframes)
| Selenium | Playwright |
|---|---|
_driver.SwitchTo().Frame("aide");Pages/PageCatalogue.cs · L82 | _driver.Locator("iframe[name=\"aide\"], iframe[id=\"aide\"], frame[name=\"aide\"], frame[id=\"aide\"]").ContentFrameCadre : les recherches suivantes passent par ce FrameLocator. |
Alertes et dialogues
| Selenium | Playwright |
|---|---|
_driver.SwitchTo().Alert().Accept();Pages/PageCatalogue.cs · L63 | BasculeOutils.PreparerDialogue(_driver, accepter: true);Le dialogue est traité par un gestionnaire posé avant l'action qui l'ouvre (Playwright ferme sinon les dialogues automatiquement). |
alerte.Accept()Tests/CommandeTests.cs · L74 | await alerte.AcceptAsync()Converti. |
Cookies et fenêtre
| Selenium | Playwright |
|---|---|
driver.Manage().Cookies.GetCookieNamed("bandeau")Tests/CatalogueTests.cs · L54 | (((await driver.Context.CookiesAsync())).FirstOrDefault(c => c.Name == "bandeau"))Converti. |
Page objects
| Selenium | Playwright |
|---|---|
[FindsBy(How = How.Id, Using = "utilisateur")] private IWebElement champUtilisateur;Pages/PageConnexion.cs · L10 | driver.Locator("#utilisateur")[FindsBy] devient une propriété ILocator (plus besoin de PageFactory). |
Projets analysés (1)
| Projet | Cadre de test | Fichiers | Avec Selenium | Tests | Dépendances |
|---|---|---|---|---|---|
| Atelier.Tests Atelier.Tests.csproj | NUnit | 8 | 8 | 17 | Retiré : Selenium.WebDriver 4.25.0 Retiré : Selenium.Support 4.25.0 Retiré : DotNetSeleniumExtras.WaitHelpers 3.11.0 Retiré : DotNetSeleniumExtras.PageObjects.Core 4.14.1 Ajouté : Microsoft.Playwright.NUnit 1.64.1 Ajouté : BasculeOutils.cs |
Compilation du résultat
« dotnet build » sur le dossier migré : réussie, 0 erreur(s), 2 avertissement(s).
Méthode et limites
- Le code est lu avec Roslyn, le compilateur C#, et chaque appel est identifié par son type réel (IWebDriver, IWebElement, By…), pas par son nom.
- Automatique : Bascule produit l'équivalent Playwright. À relire : converti, mais le comportement peut différer (pause fixe, dialogue, attribut calculé). À reprendre : sans équivalent automatique (fenêtres multiples, grille distante, DevTools…) ; le code est laissé tel quel et Selenium reste référencé tant qu'il sert.
- La migration ne compile ni n'exécute vos tests (sauf option --compiler). Lancez la suite après migration : c'est la seule preuve qui compte.
- Rien n'est envoyé sur le réseau : l'analyse se fait entièrement sur votre poste.