What approach should I adopt when beginning to use Playwright for NET?

Falanga, Rod, DOH 1,150 Reputation points
2026-07-29T20:24:28.4466667+00:00

Over the years I've written several unit tests, first using MSTest, and the last 5 years using xUnit. I'm used to the AAA pattern (Arrange/Act/Assert).

Now I am trying to learn how to use Playwright. I know that initially it was probably written to work with Node, npm, etc. I'm familiar with Node and npm, but more from reputation as I haven't used them much. So, I was pleased to learn that Playwright has a Playwright for NET. I've been using this link to get some experience with it: https://playwright.dev/dotnet/docs/intro

However, I've run into a few problems. One is I've been wanting to read the values of a couple of dropdowns on a page. I used two links to help me with that: https://playwright.dev/dotnet/docs/locators#locate-by-label which when it came to the dropdown wasn't much good, so I checked out this link: https://playwright.dev/dotnet/docs/locators#locate-by-role

The first problem is that although the LocateByRole was more helpful, it still didn't give me an example of using it to read the values displayed. Nor how to assign a different value to the dropdown. Both are things I will want to do.

The second problem is I now realize that I'll have to adopt a pattern that doesn't strictly speaking, in my mind at least, follow the AAA pattern I've used for years. Here's a method from my Playwright for NET class which initially I thought would have an Assert.Equal() call, but now I realize should only be a helpful function.


    [Fact]
    public async Task HomePageHasJobTitleAndSite()
    {
        await Page.GotoAsync("https://FPTimetrack");
        await Task.Delay(1000); // Wait for the page to load

        // Position the cursor to the job title dropdown from the page
        var titleId = await Page.GetByLabel("Select the title that best describes your job position:").InputValueAsync();
        //Assert.Equal("Family Planning Time Tracker", titleId);

        string? titleText = null;
        if (titleId != "")
        {
            titleText = await Page.GetByRole(AriaRole.Combobox).Locator("option:checked").TextContentAsync();
        }
        else
        {
            titleText = string.Empty;
        }

        // Position the cursor to the site dropdown
        var siteId = await Page.GetByLabel("Select the site at which you work:").InputValueAsync();   // This returns the value of the input field, not the text displayed on the page
        //Assert.Equal("Family Planning Time Tracker", siteId);

        var siteLocation = await Page.GetByRole(AriaRole.Combobox).Locator("option:checked").TextContentAsync();
        Assert.Equal("Family Planning Time Tracker", siteLocation);
    }

So, how does one structure their Playwright code so that you can call something, store some values intermittently, then restore them? For example, either of the two dropdowns may not have any value in them, and that is not a problem. If they do have a value, then I would want to store that value, so that I can restore it later. I'm sure I could create class-level variables, but I'm not sure how to order the execution of the methods so they'll run in the correct order.

Developer technologies | .NET | Other

Answer accepted by question author
Taki Ly (WICLOUD CORPORATION) 3,700 Reputation points Microsoft External Staff Moderator
2026-07-30T04:25:56.85+00:00

Hello @Falanga, Rod, DOH ,

To be completely transparent, I have actually never used Playwright for .NET myself, so I did some research into their documentation and common practices. From what I’ve found, I have a few suggestions that might address the challenges you are running into.

Regarding dropdowns (the <select> elements), based on my understanding of the docs, it seems Playwright provides dedicated methods for them, so you don't necessarily have to rely on explicit locators like option:checked.

To solve your issue of assigning a different value based on the text displayed to the user (rather than the underlying value), you can do this:

await Page.GetByLabel("Select the title that best describes your job position:")
          .SelectOptionAsync(new SelectOptionValue { Label = "Family Planning Time Tracker" });

As you noticed, InputValueAsync() only returns the underlying programmatic value (the ID). To read the actual text displayed on the screen, the community approach seems to use a quick JavaScript evaluation:

var displayedText = await Page.EvaluateAsync<string>(@"() => {
    // Replace with your actual dropdown ID
    var d = document.getElementById('yourDropdownId'); 
    return d.options[d.selectedIndex].text;
}");

Regarding the AAA Pattern, it seems that mixing UI commands (like await Page...) with assertions is what breaks the clean structure you are used to.

From my findings, the standard practice in the E2E testing world is to adopt the Page Object Model (POM). The idea is to push all those locator queries, Task.Delay calls, and dropdown logic into a separate helper class (e.g., TimeTrackPageObj). That way, your actual xUnit test method remains a pure Arrange, Act, and Assert sequence.

Regarding execution order to store initial values and restore them at the end, since xUnit doesn't use [TestInitialize] and [TestCleanup], the framework uses the IAsyncLifetime interface instead.

  • InitializeAsync() runs before the test (where you can store values).
  • DisposeAsync() runs after the test (where you can restore values).

However, the documentation suggests against manually restoring UI states (like forcing dropdowns back to their original values). If a test throws an exception midway, the page won't be restored, which can break the next tests.

Instead, they recommend relying on Playwright's Browser Contexts. A Context acts like opening a completely fresh "Incognito Window" for each test. This means you don't have to worry about cleaning up the page state, the framework just disposes of the entire browser instance after the test finishes and spins up a pristine new one.

If you're interested in reading more about the specifics, below are the resources I referenced to put this together:

I hope these findings provide some helpful pointers for your project! If you found my response helpful or informative, I would greatly appreciate it if you could follow this guide for your confirmation.

Thank you.

Was this answer helpful?

2 people found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.