.NET version of the Playwright testing and automation library.
Accessibility assertions
Expect(locator).ToHaveAccessibleNameAsync() checks if the element has the specified accessible name:
var locator = Page.GetByRole(AriaRole.Button);
await Expect(locator).ToHaveAccessibleNameAsync("Submit");
Expect(locator).ToHaveAccessibleDescriptionAsync() checks if the element has the specified accessible description:
var locator = Page.GetByRole(AriaRole.Button);
await Expect(locator).ToHaveAccessibleDescriptionAsync("Upload a photo");
Expect(locator).ToHaveRoleAsync() checks if the element has the specified ARIA role:
var locator = Page.GetByTestId("save-button");
await Expect(locator).ToHaveRoleAsync(AriaRole.Button);
Locator handler
NoWaitAfter
option.Times
option in page.AddLocatorHandlerAsync() to specify maximum number of times the handler should be run.var locator = Page.GetByText("This interstitial covers the button");
await Page.AddLocatorHandlerAsync(locator, async (overlay) =>
{
await overlay.Locator("#close").ClickAsync();
}, new() { Times = 3, NoWaitAfter = true });
// Run your tests that can be interrupted by the overlay.
// ...
await Page.RemoveLocatorHandlerAsync(locator);
Miscellaneous options
Multipart
option in APIRequestContext.FetchAsync()
supports now repeating fields with the same name using formData.append():
var formData = Context.APIRequest.CreateFormData();
formData.Append("file", new FilePayload()
{
Name = "f1.js",
MimeType = "text/javascript",
Buffer = System.Text.Encoding.UTF8.GetBytes("var x = 2024;")
});
formData.Append("file", new FilePayload()
{
Name = "f2.txt",
MimeType = "text/plain",
Buffer = System.Text.Encoding.UTF8.GetBytes("hello")
});
var response = await Context.APIRequest.PostAsync("https://example.com/uploadFiles", new() { Multipart = formData });
Expect(page).ToHaveURLAsync() now supports IgnoreCase
option.
This version was also tested against the following stable channels:
Method BrowserContext.ClearCookiesAsync() now supports filters to remove only some cookies.
// Clear all cookies.
await Context.ClearCookiesAsync();
// New: clear cookies with a particular name.
await Context.ClearCookiesAsync(new() { Name = "session-id" });
// New: clear cookies for a particular domain.
await Context.ClearCookiesAsync(new() { Domain = "my-origin.com" });
New property Locator.ContentFrame converts a Locator object to a FrameLocator. This can be useful when you have a Locator object obtained somewhere, and later on would like to interact with the content inside the frame.
var locator = Page.Locator("iframe[name='embedded']");
// ...
var frameLocator = locator.ContentFrame;
await frameLocator.GetByRole(AriaRole.Button).ClickAsync();
New property FrameLocator.Owner converts a FrameLocator object to a Locator. This can be useful when you have a FrameLocator object obtained somewhere, and later on would like to interact with the iframe
element.
var frameLocator = page.FrameLocator("iframe[name='embedded']");
// ...
var locator = frameLocator.Owner;
await Expect(locator).ToBeVisibleAsync();
This version was also tested against the following stable channels:
New method page.addLocatorHandler(locator, handler, handler, handler) registers a callback that will be invoked when specified element becomes visible and may block Playwright actions. The callback can get rid of the overlay. Here is an example that closes a cookie dialog when it appears.
// Setup the handler.
await Page.AddLocatorHandlerAsync(
Page.GetByRole(AriaRole.Heading, new() { Name = "Hej! You are in control of your cookies." }),
async () =>
{
await Page.GetByRole(AriaRole.Button, new() { Name = "Accept all" }).ClickAsync();
});
// Write the test as usual.
await Page.GotoAsync("https://www.ikea.com/");
await Page.GetByRole(AriaRole.Link, new() { Name = "Collection of blue and white" }).ClickAsync();
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Light and easy" })).ToBeVisibleAsync();
tagged
and outline
.This version was also tested against the following stable channels:
https://github.com/microsoft/playwright/issues/29067 - [REGRESSION] Codegen/Recorder: not all clicks are being actioned nor recorded https://github.com/microsoft/playwright/issues/29019 - [REGRESSION] trace.playwright.dev does not currently support the loading from URL
This version was also tested against the following stable channels:
This version was also tested against the following stable channels:
style
in page.ScreenshotAsync() and locator.ScreenshotAsync() to add custom CSS to the page before taking a screenshot.This version was also tested against the following stable channels:
New tools to generate assertions:
Here is an example of a generated test with assertions:
await Page.GotoAsync("https://playwright.dev/");
await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync();
await Expect(Page.GetByLabel("Breadcrumbs").GetByRole(AriaRole.List)).ToContainTextAsync("Installation");
await Expect(Page.GetByLabel("Search")).ToBeVisibleAsync();
await Page.GetByLabel("Search").ClickAsync();
await Page.GetByPlaceholder("Search docs").FillAsync("locator");
await Expect(Page.GetByPlaceholder("Search docs")).ToHaveValueAsync("locator");
Reason
in Page.CloseAsync([options]), BrowserContext.CloseAsync([options]) and Browser.CloseAsync([options]). Close reason is reported for all operations interrupted by the closure.FirefoxUserPrefs
in browserType.launchPersistentContext(userDataDir[, options]).When using Microsoft.Playwright.MSTest
or Microsoft.Playwright.NUnit
, Locale
and ColorScheme
were taken from the operating system as a default. After v1.40, its now aligned with Playwright for Node.js to en-US
and light
. In order to opt-in for the previous behaviour, the ContextOptions
method can be overidden.
using Microsoft.Playwright.NUnit;
namespace PlaywrightTests;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class MyTest : PageTest
{
public override BrowserNewContextOptions ContextOptions()
{
return new BrowserNewContextOptions()
{
Locale = "en-GB",
ColorScheme = ColorScheme.Light,
};
}
}
This version was also tested against the following stable channels:
Page.TypeAsync()
, Frame.TypeAsync()
, Locator.TypeAsync()
and ElementHandle.TypeAsync()
.
Please use Locator.FillAsync()
instead which is much faster. Use Locator.PressSequentiallyAsync()
only if there is a
special keyboard handling on the page, and you need to press keys one-by-one.This version was also tested against the following stable channels:
Fixes: