Como celebración por el mejor dia del año (mi cumpleaños) puedes conseguir un 15% de descuento en todos los libros de la web:

Introduction to Playwright: E2E Tests in C#

Imagine you are building a web application that includes certain forms or features in the user interface, and of course, you need to ensure these functionalities are always available and work correctly.

 

 

1 - What is playwright?

 

So today we’re going to talk about playwright, a library or framework that helps us test web applications by automating end to end flows.

 

This automation framework is open source and was created by Microsoft, with the intention of reliably ensuring that our applications work correctly across all browsers.

Even though it’s by Microsoft, it has several official SDKs, including .NET (which is what we’ll see in this post), as well as Typescript, Java, and Python.

 

Many of you may have used Selenium in the past, and playwright is a direct competitor (I myself have used it quite a bit). The reality is, nowadays playwright is taking the lead, at least in my professional experience, as it brings improvements such as test isolation by context, or built-in traces, screenshots, and videos directly within the framework.

 

The first thing you need is a website to test; technically it can be any website, whether it’s yours or just something online. To avoid any issues, I quickly created a demo site using Codex and I have it running locally on my machine; in my case, it’s a simple reporting form.

Remember, whenever you’re automating, make sure you have permission for the websites you use, as you could be violating terms of service or even the law.

 

The same applies if you’re using these tools for scraping.

scraping de websites

 

 

2 - How to use playwright in C#

 

Using it is very simple. We need to create a C# test project; it works with MSTest, NUnit, or XUnit. Depending on which test runner you use, you’ll need to install a different package, but the code is practically the same for all of them.

Microsoft.Playwright.Nunit

Next, we build, and now we need to install playwright, or basically, the browsers it will use.

powershell -NoProfile -ExecutionPolicy Bypass -File .\bin\Debug\net8.0\playwright.ps1 install

NOTE: Notice this command includes net8, which means you need to update it according to your .NET version.

 

 

2.1 - Creating a test with Playwright in C#

Now we just need to create the end to end test to see how it works.

 

All the code from this post is available for free on Github and running on my machine. Of course, it also works against online websites.

 

For my use case, I created a simple form to report rat sightings (🐀), since this post is to show the tool and not to do a deep dive into its documentation.

 

The very first step is to navigate to a website, for which we’ll use the Page.GotoAsync command, which starts the browser and goes to the given URL.

await Page.GotoAsync("file:///C:/repos/playwright-example/frontend/index.html");

We can verify that we are in the right place using the Expect command along with the ToHaveTitleAsync method and a regex for the text:

await Page.GotoAsync("file:///C:/repos/playwright-example/frontend/index.html");

await Expect(Page).ToHaveTitleAsync(new Regex("Avistamientos de RATAS"));

Every time we use Expect in our code, we’re making an Assertion.

 

 

2.2 - Interacting with a website using Playwright in C#

Now we need to interact with the website, and that’s where all the End2End work comes in.

 

In our form, we have several fields to indicate where we saw the rats, so we need to locate each one. We use the Page.Locator command, which searches for the indicated element in the DOM. For our case, the first form field can be found and filled like this:

string cornerPub = "el bar de la esquina";
var localNameField = Page.Locator("input[name='form_fields[local__name]']");
await localNameField.FillAsync(cornerPub);
await Expect(localNameField).ToHaveValueAsync(cornerPub);

Alternatively, we can locate elements by ID, full DOM path, CSS, XPath, or even by placeholder.

 

Now we just need to fill in the rest of the form elements and submit it.

[Test]
public async Task ShowcasePlaywright()
{
    await Page.GotoAsync("file:///C:/repos/playwright-example/frontend/index.html");

    await Expect(Page).ToHaveTitleAsync(new Regex("Avistamientos de RATAS"));


    string cornerPub = "el bar de la esquina";
    var localNameField = Page.Locator("input[name='form_fields[local__name]']");
    await localNameField.FillAsync(cornerPub);
    await Expect(localNameField).ToHaveValueAsync(cornerPub);


    string street = "calle number 1";
    var localStreetField = Page.Locator("input[name='form_fields[local__street]']");
    await localStreetField.FillAsync(street);
    await Expect(localStreetField).ToHaveValueAsync(street);

    string postal = "calle number 1";
    var localPostalField = Page.Locator("input[name='form_fields[local__street]']");
    await localPostalField.FillAsync(postal);
    await Expect(localPostalField).ToHaveValueAsync(postal);


    string city = "Madriz";
    var localCityField = Page.Locator("input[name='form_fields[local__localy]']");
    await localCityField.FillAsync(city);
    await Expect(localCityField).ToHaveValueAsync(city);

    string activity = "madrid - barcelona";
    var eventField = Page.Locator("input[name='form_fields[field__evento]']");
    await eventField.FillAsync(activity);
    await Expect(eventField).ToHaveValueAsync(activity);

    string message = "muchas ratas por todas partes";
    var messageField = Page.Locator("textarea[name='form_fields[field__message]']");
    await messageField.FillAsync(message);
    await Expect(messageField).ToHaveValueAsync(message);

    string quantity = "100";
    var quantityField = Page.Locator("input[name='form_fields[rats_count]']");
    await quantityField.FillAsync(quantity);
    await Expect(quantityField).ToHaveValueAsync(quantity);

    var size = Page.GetByLabel("como de gordas");
    await size.SelectOptionAsync(new SelectOptionValue { Label = "tremendas" });


    var status = Page.Locator("id=form-status");
    await Expect(status).ToHaveTextAsync(string.Empty);
    await Expect(status).Not.ToHaveClassAsync(new Regex(@"\bshow\b"));

    await Page.GetByRole(AriaRole.Button, new() { NameRegex = new Regex("Enviar reporte") }).ClickAsync();

    await Expect(status).ToHaveTextAsync("Reporte enviado. Gracias por tu ayuda.");
    await Expect(status).ToHaveClassAsync(new Regex(@"\bshow\b"));
}

This is an example of a test for a form; as you can see, it’s straightforward, and you can even simplify the code further.

 

 

3 - Additional Features of Playwright

 

Playwright doesn’t stop there; it has tons of features, practically anything you can imagine that has to do with the web. This includes authentication, it has a module where you can assign authentication and each test authenticates, you can reuse tokens if necessary, etc.

If you want to mock an API response, you can do it directly from the framework. You can manage or check downloads or even interact with videos.

 

You can find all this and more in their documentation, but still, there are two features I’ll discuss.

 

 

3.1 - Screenshots with Playwright

 

The first is screenshots. When running end to end tests on a web app you don’t have direct access to, or most likely you’re executing tests from your CI/CD pipeline, it’s very important to have logs of everything that happens, and one of those is screenshots. You can take them at any time, whether something fails (inside a try-catch) or when everything goes well.

await Page.ScreenshotAsync(new()
{
    Path = "screenshot.png",
});

 

And here’s the result:

imagen resultado playwright

 

This is a really useful feature because you can even take screenshots of elements instead of the whole page.

 

 

3.2 - Traces in Playwright

 

Playwright can show you traces of all the actions it performs and the time they take.

 

To do this, you simply need to indicate it in the code; depending on the testing framework you use, the code might look different, but the idea is the same, setting up traces:

[SetUp]
public async Task Setup()
{
    await Context.Tracing.StartAsync(new()
    {
        Title = $"{TestContext.CurrentContext.Test.ClassName}.{TestContext.CurrentContext.Test.Name}",
        Screenshots = true,
        Snapshots = true,
        Sources = true
    });
}

[TearDown]
public async Task TearDown()
{
    // var failed = TestContext.CurrentContext.Result.Outcome == NUnit.Framework.Interfaces.ResultState.Error
    //              || TestContext.CurrentContext.Result.Outcome == NUnit.Framework.Interfaces.ResultState.Failure;
    // Ideally store traces only on failure


    await Context.Tracing.StopAsync(new()
    {
        Path = Path.Combine(
            TestContext.CurrentContext.WorkDirectory,
            "playwright-traces",
            $"{TestContext.CurrentContext.Test.ClassName}.{TestContext.CurrentContext.Test.Name}.zip"
        ),
    });
}

 

The result is a zip file that contains the information, and you can view it using the trace viewer tool with the command:

npx playwright show-trace path/to/trace.zip

traces with palywright

 

And in my personal opinion, that tool is awesome.

Of course, it’s not a good idea to add traces to every single test, just those that fail.

 

 

3.3 - UI Mode

 

Lastly, I want to mention it has an editor mode where you can see the tests and interact manually with them.

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café