Microsoft Technologies based on the .NET software framework. Miscellaneous topics that do not fit into specific categories.
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.