mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
docs(dotnet): guides (#6639)
This commit is contained in:
parent
0aa9e06370
commit
c80e9fa58a
@ -583,7 +583,7 @@ var result = new TaskCompletionSource<string>();
|
||||
var page = await Context.NewPageAsync();
|
||||
await Context.ExposeBindingAsync("clicked", async (BindingSource _, IJSHandle t) =>
|
||||
{
|
||||
return result.TrySetResult(await t.AsElement.TextContentAsync());
|
||||
return result.TrySetResult(await t.AsElement().TextContentAsync());
|
||||
});
|
||||
|
||||
await page.SetContentAsync("<script>\n" +
|
||||
|
@ -305,7 +305,7 @@ element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_tran
|
||||
|
||||
```csharp
|
||||
var handle = await page.EvaluateHandleAsync("() => new DataTransfer()");
|
||||
await handle.AsElement.DispatchEventAsync("dragstart", new Dictionary<string, object>
|
||||
await handle.AsElement().DispatchEventAsync("dragstart", new Dictionary<string, object>
|
||||
{
|
||||
{ "dataTransfer", dataTransfer }
|
||||
});
|
||||
|
@ -1485,7 +1485,7 @@ page.set_content("""
|
||||
var result = new TaskCompletionSource<string>();
|
||||
await page.ExposeBindingAsync("clicked", async (BindingSource _, IJSHandle t) =>
|
||||
{
|
||||
return result.TrySetResult(await t.AsElement.TextContentAsync());
|
||||
return result.TrySetResult(await t.AsElement().TextContentAsync());
|
||||
});
|
||||
|
||||
await page.SetContentAsync("<script>\n" +
|
||||
|
@ -63,6 +63,20 @@ with sync_playwright() as p:
|
||||
browser.close()
|
||||
```
|
||||
|
||||
```csharp
|
||||
using Microsoft.Playwright;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class BrowserExamples
|
||||
{
|
||||
public static async Task Main()
|
||||
{
|
||||
using var playwright = await Playwright.CreateAsync();
|
||||
await using var firefox = playwright.Firefox.LaunchAsync(headless: false);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Launching a browser instance can be expensive, and Playwright is designed to
|
||||
maximize what a single instance can do through multiple browser contexts.
|
||||
|
||||
@ -99,6 +113,11 @@ browser = playwright.chromium.launch()
|
||||
context = browser.new_context()
|
||||
```
|
||||
|
||||
```csharp
|
||||
await using var browser = playwright.Chromium.LaunchAsync();
|
||||
var context = await browser.NewContextAsync();
|
||||
```
|
||||
|
||||
Browser contexts can also be used to emulate multi-page scenarios involving
|
||||
mobile devices, permissions, locale and color scheme.
|
||||
|
||||
@ -174,6 +193,30 @@ with sync_playwright() as p:
|
||||
browser.close()
|
||||
```
|
||||
|
||||
```csharp
|
||||
using Microsoft.Playwright;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class PlaywrightExample
|
||||
{
|
||||
public static async Task Main()
|
||||
{
|
||||
using var playwright = await Playwright.CreateAsync();
|
||||
await using var browser = await playwright.Webkit.LaunchAsync();
|
||||
var options = new BrowserContextOptions(Playwright.Devices["iPhone 11 Pro"])
|
||||
{
|
||||
Geolocation = new Geolocation() { Longitude = 12.492507f, Latitude = 41.889938f },
|
||||
Permissions = new[] { "geolocation" },
|
||||
Locale = "de-DE"
|
||||
};
|
||||
|
||||
await using var context = await browser.NewContextAsync(options);
|
||||
// do work
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API reference
|
||||
|
||||
- [BrowserContext]
|
||||
@ -256,6 +299,24 @@ print(page.url)
|
||||
# window.location.href = 'https://example.com'
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Create a page.
|
||||
var page = await context.NewPageAsync();
|
||||
|
||||
// Navigate explicitly, similar to entering a URL in the browser.
|
||||
await page.GotoAsync("http://example.com");
|
||||
// Fill an input.
|
||||
await page.FillAsync("#search", "query");
|
||||
|
||||
// Navigate implicitly by clicking a link.
|
||||
await page.ClickAsync("#submit");
|
||||
// Expect a new url.
|
||||
Console.WriteLine(page.Url);
|
||||
|
||||
// Page can navigate from the script - this will be picked up by Playwright.
|
||||
// window.location.href = "https://example.com";
|
||||
```
|
||||
|
||||
> Read more on [page navigation and loading](./navigations.md).
|
||||
|
||||
A page can have one or more [Frame] objects attached to
|
||||
@ -325,6 +386,24 @@ frame = frame_element_handle.content_frame()
|
||||
frame.fill('#username-input', 'John')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Create a page.
|
||||
var page = await context.NewPageAsync();
|
||||
|
||||
// Get frame using the frame's name attribute
|
||||
var frame = page.Frame("frame-login");
|
||||
|
||||
// Get frame using frame's URL
|
||||
var frame = page.FrameByUrl("*domain.");
|
||||
|
||||
// Get frame using any other selector
|
||||
var frameElementHandle = await page.QuerySelectorAsync(".frame-class");
|
||||
var frame = await frameElementHandle.ContentFrameAsync();
|
||||
|
||||
// Interact with the frame
|
||||
await frame.FillAsync("#username-input", "John");
|
||||
```
|
||||
|
||||
### API reference
|
||||
|
||||
- [Page]
|
||||
@ -365,6 +444,11 @@ await page.click('data-test-id=foo')
|
||||
page.click('data-test-id=foo')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Using data-test-id= selector engine
|
||||
await page.ClickAsync("data-test-id=foo");
|
||||
```
|
||||
|
||||
```js
|
||||
// CSS and XPath selector engines are automatically detected
|
||||
await page.click('div');
|
||||
@ -389,6 +473,12 @@ page.click('div')
|
||||
page.click('//html/body/div')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// CSS and XPath selector engines are automatically detected
|
||||
await page.ClickAsync("div");
|
||||
await page.ClickAsync("//html/body/div");
|
||||
```
|
||||
|
||||
```js
|
||||
// Find node by text substring
|
||||
await page.click('text=Hello w');
|
||||
@ -409,6 +499,11 @@ await page.click('text=Hello w')
|
||||
page.click('text=Hello w')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Find node by text substring
|
||||
await page.ClickAsync("text=Hello w");
|
||||
```
|
||||
|
||||
```js
|
||||
// Explicit CSS and XPath notation
|
||||
await page.click('css=div');
|
||||
@ -433,6 +528,12 @@ page.click('css=div')
|
||||
page.click('xpath=//html/body/div')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Explicit CSS and XPath notation
|
||||
await page.ClickAsync("css=div");
|
||||
await page.ClickAsync("xpath=//html/body/div");
|
||||
```
|
||||
|
||||
```js
|
||||
// Only search light DOM, outside WebComponent shadow DOM:
|
||||
await page.click('css:light=div');
|
||||
@ -453,6 +554,11 @@ await page.click('css:light=div')
|
||||
page.click('css:light=div')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Only search light DOM, outside WebComponent shadow DOM:
|
||||
await page.ClickAsync("css:light=div");
|
||||
```
|
||||
|
||||
Selectors using the same or different engines can be combined using the `>>` separator. For example,
|
||||
|
||||
```js
|
||||
@ -475,6 +581,11 @@ await page.click('#free-month-promo >> text=Sign Up')
|
||||
page.click('#free-month-promo >> text=Sign Up')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Click an element with text "Sign Up" inside of a #free-month-promo.
|
||||
await page.Click("#free-month-promo >> text=Sign Up");
|
||||
```
|
||||
|
||||
```js
|
||||
// Capture textContent of a section that contains an element with text 'Selectors'.
|
||||
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent);
|
||||
@ -495,6 +606,11 @@ section_text = await page.eval_on_selector('*css=section >> text=Selectors', 'e
|
||||
section_text = page.eval_on_selector('*css=section >> text=Selectors', 'e => e.textContent')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Capture textContent of a section that contains an element with text "Selectors".
|
||||
var sectionText = await page.EvalOnSelectorAsync<string>("*css=section >> text=Selectors", "e => e.textContent");
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
## Auto-waiting
|
||||
@ -529,6 +645,11 @@ await page.fill('#search', 'query')
|
||||
page.fill('#search', 'query')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Playwright waits for #search element to be in the DOM
|
||||
await page.FillAsync("#search", "query");
|
||||
```
|
||||
|
||||
```js
|
||||
// Playwright waits for element to stop animating
|
||||
// and accept clicks.
|
||||
@ -553,6 +674,12 @@ await page.click('#search')
|
||||
page.click('#search')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Playwright waits for element to stop animating
|
||||
// and accept clicks.
|
||||
await page.ClickAsync("#search");
|
||||
```
|
||||
|
||||
You can explicitly wait for an element to appear in the DOM or to become visible:
|
||||
|
||||
```js
|
||||
@ -584,6 +711,13 @@ page.wait_for_selector('#search', state='attached')
|
||||
page.wait_for_selector('#promo')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Wait for #search to appear in the DOM.
|
||||
await page.WaitForSelectorAsync("#search", WaitForSelectorState.Attached);
|
||||
// Wait for #promo to become visible, for example with `visibility:visible`.
|
||||
await page.WaitForSelectorAsync("#promo");
|
||||
```
|
||||
|
||||
... or to become hidden or detached
|
||||
|
||||
```js
|
||||
@ -616,6 +750,13 @@ page.wait_for_selector('#details', state='hidden')
|
||||
page.wait_for_selector('#promo', state='detached')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Wait for #details to become hidden, for example with "display:none".
|
||||
await page.WaitForSelectorAsync("#details", WaitForSelectorState.Hidden);
|
||||
// Wait for #promo to be removed from the DOM.
|
||||
await page.WaitForSelectorAsync("#promo", WaitForSelectorState.Detached);
|
||||
```
|
||||
|
||||
### API reference
|
||||
|
||||
- [`method: Page.click`]
|
||||
@ -648,6 +789,10 @@ href = await page.evaluate('() => document.location.href')
|
||||
href = page.evaluate('() => document.location.href')
|
||||
```
|
||||
|
||||
```csharp
|
||||
var href = await page.EvaluateAsync<string>("document.location.href");
|
||||
```
|
||||
|
||||
If the result is a Promise or if the function is asynchronous evaluate will automatically wait until it's resolved:
|
||||
|
||||
```js
|
||||
@ -678,6 +823,13 @@ status = page.evaluate("""async () => {
|
||||
}""")
|
||||
```
|
||||
|
||||
```csharp
|
||||
int status = await page.EvaluateAsync<int>(@"async () => {
|
||||
const response = await fetch(location.href);
|
||||
return response.status;
|
||||
}");
|
||||
```
|
||||
|
||||
## Evaluation Argument
|
||||
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] or [ElementHandle] instances. Handles are automatically converted to the value they represent.
|
||||
@ -861,6 +1013,41 @@ page.evaluate("""
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
```
|
||||
|
||||
```csharp
|
||||
// A primitive value.
|
||||
await page.EvaluateAsync<int>("num => num", 42);
|
||||
|
||||
// An array.
|
||||
await page.EvaluateAsync<int[]>("array => array.length", new[] { 1, 2, 3 });
|
||||
|
||||
// An object.
|
||||
await page.EvaluateAsync<object>("object => object.foo", new { foo = "bar" });
|
||||
|
||||
// A single handle.
|
||||
var button = await page.QuerySelectorAsync("button");
|
||||
await page.EvaluateAsync<IJSHandle>("button => button.textContent", button);
|
||||
|
||||
// Alternative notation using elementHandle.EvaluateAsync.
|
||||
await button.EvaluateAsync<string>("(button, from) => button.textContent.substring(from)", 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
var button1 = await page.QuerySelectorAsync(".button1");
|
||||
var button2 = await page.QuerySelectorAsync(".button2");
|
||||
await page.EvaluateAsync("o => o.button1.textContent + o.button2.textContent", new { button1, button2 });
|
||||
|
||||
// Object destructuring works. Note that property names must match
|
||||
// between the destructured object and the argument.
|
||||
// Also note the required parenthesis.
|
||||
await page.EvaluateAsync("({ button1, button2 }) => button1.textContent + button2.textContent", new { button1, button2 });
|
||||
|
||||
// Array works as well. Arbitrary names can be used for destructuring.
|
||||
// Note the required parenthesis.
|
||||
await page.EvaluateAsync("([b1, b2]) => b1.textContent + b2.textContent", new[] { button1, button2 });
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
await page.EvaluateAsync("x => x.button1.textContent + x.list[0].textContent + String(x.foo)", new { button1, list = new[] { button2 }, foo = null as object });
|
||||
```
|
||||
|
||||
Right:
|
||||
|
||||
```js
|
||||
@ -897,6 +1084,12 @@ result = page.evaluate("""data => {
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
|
||||
```
|
||||
|
||||
Wrong:
|
||||
|
||||
```js
|
||||
@ -933,6 +1126,15 @@ result = page.evaluate("""() => {
|
||||
}""")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync(@"data => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data);
|
||||
}");
|
||||
```
|
||||
|
||||
### API reference
|
||||
|
||||
- [`method: Page.evaluate`]
|
||||
|
@ -42,6 +42,10 @@ chromium.launch(headless=False, slow_mo=100) # or firefox, webkit
|
||||
|
||||
```
|
||||
|
||||
```csharp
|
||||
await using var browser = await playwright.Chromium.LaunchAsync(headless: false, slowMo: 100); // or firefox, webkit
|
||||
```
|
||||
|
||||
## Browser Developer Tools
|
||||
|
||||
You can use browser developer tools in Chromium, Firefox and WebKit while running
|
||||
@ -75,6 +79,9 @@ await chromium.launch(devtools=True)
|
||||
```python sync
|
||||
chromium.launch(devtools=True)
|
||||
```
|
||||
```csharp
|
||||
await using var browser = await playwright.Chromium.LaunchAsync(devtools: true);
|
||||
```
|
||||
:::
|
||||
|
||||
## Run in Debug Mode
|
||||
@ -181,3 +188,9 @@ DEBUG=pw:api pytest -s
|
||||
set DEBUG=pw:api
|
||||
pytest -s
|
||||
```
|
||||
|
||||
```sh csharp
|
||||
# Powershell (Win/macOS)
|
||||
$env:DEBUG="pw:api"
|
||||
dotnet run
|
||||
```
|
@ -50,6 +50,16 @@ download = download_info.value
|
||||
path = download.path()
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Start the task of waiting for the download
|
||||
var waitForDownloadTask = page.WaitForDownloadAsync();
|
||||
// Perform the action that initiates download
|
||||
await page.ClickAsync("#downloadButton");
|
||||
// Wait for the download process to complete
|
||||
var download = await waitForDownloadTask;
|
||||
Console.WriteLine(await download.PathAsync());
|
||||
```
|
||||
|
||||
#### Variations
|
||||
|
||||
If you have no idea what initiates the download, you can still handle the event:
|
||||
@ -72,6 +82,10 @@ page.on("download", handle_download)
|
||||
page.on("download", lambda download: print(download.path()))
|
||||
```
|
||||
|
||||
```csharp
|
||||
page.Download += (sender, download) => Console.WriteLine(download.Url);
|
||||
```
|
||||
|
||||
Note that handling the event forks the control flow and makes script harder to follow. Your scenario might end while you
|
||||
are downloading a file since your main control flow is not awaiting for this operation to resolve.
|
||||
|
||||
|
@ -17,7 +17,7 @@ can be changed for individual pages.
|
||||
<br/>
|
||||
|
||||
## Devices
|
||||
* langs: js, python
|
||||
* langs: js, python, csharp
|
||||
|
||||
Playwright comes with a registry of device parameters for selected mobile devices. It can be used to simulate browser
|
||||
behavior on a mobile device:
|
||||
@ -63,6 +63,23 @@ with sync_playwright() as playwright:
|
||||
run(playwright)
|
||||
```
|
||||
|
||||
```csharp
|
||||
using Microsoft.Playwright;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class Guides
|
||||
{
|
||||
public async void Main()
|
||||
{
|
||||
using var playwright = await Playwright.CreateAsync();
|
||||
|
||||
await using var browser = await playwright.Chromium.LaunchAsync(devtools: true);
|
||||
var pixel2 = playwright.Devices["Pixel 2"];
|
||||
await using var context = await browser.NewContextAsync(pixel2);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All pages created in the context above will share the same device parameters.
|
||||
|
||||
### API reference
|
||||
@ -98,6 +115,10 @@ context = browser.new_context(
|
||||
)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var context = await browser.NewContextAsync(userAgent: "My User Agent");
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
@ -168,6 +189,20 @@ context = browser.new_context(
|
||||
device_scale_factor=2,
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Create context with given viewport
|
||||
await using var context = await browser.NewContextAsync(
|
||||
viewportSize: new ViewportSize() { Width = 1280, Height = 1024 });
|
||||
|
||||
// Resize viewport for individual page
|
||||
await page.SetViewportSizeAsync(1600, 1200);
|
||||
|
||||
// Emulate high-DPI
|
||||
await using var context = await browser.NewContextAsync(
|
||||
viewportSize: new ViewportSize() { Width = 2560, Height = 1440 },
|
||||
deviceScaleFactor: 2);
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Page.setViewportSize`]
|
||||
@ -207,6 +242,10 @@ context = browser.new_context(
|
||||
)
|
||||
```
|
||||
|
||||
```csharp
|
||||
await using var context = await browser.NewContextAsync(locale: "de-DE", timezoneId: "Europe/Berlin");
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
@ -257,6 +296,10 @@ await context.grant_permissions(['geolocation'])
|
||||
context.grant_permissions(['geolocation'])
|
||||
```
|
||||
|
||||
```csharp
|
||||
await context.GrantPermissionsAsync(new[] { "geolocation" });
|
||||
```
|
||||
|
||||
Grant notifications access from a specific domain:
|
||||
|
||||
```js
|
||||
@ -276,6 +319,10 @@ await context.grant_permissions(['notifications'], origin='https://skype.com')
|
||||
context.grant_permissions(['notifications'], origin='https://skype.com')
|
||||
```
|
||||
|
||||
```csharp
|
||||
await context.GrantPermissionsAsync(new[] { "notifications" },origin: "https://skype.com");
|
||||
```
|
||||
|
||||
Revoke all permissions:
|
||||
|
||||
```js
|
||||
@ -294,6 +341,10 @@ await context.clear_permissions()
|
||||
context.clear_permissions()
|
||||
```
|
||||
|
||||
```csharp
|
||||
await context.ClearPermissionsAsync();
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: BrowserContext.grantPermissions`]
|
||||
@ -332,6 +383,13 @@ context = browser.new_context(
|
||||
)
|
||||
```
|
||||
|
||||
```csharp
|
||||
await using var context = await browser.NewContextAsync(
|
||||
permissions: new[] { "geolocation" },
|
||||
geolocation: new Geolocation() { Longitude = 48.858455f, Latitude = 2.294474f }
|
||||
);
|
||||
```
|
||||
|
||||
Change the location later:
|
||||
|
||||
```js
|
||||
@ -350,6 +408,10 @@ await context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
|
||||
context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
|
||||
```
|
||||
|
||||
```csharp
|
||||
await context.SetGeolocationAsync(new Geolocation() { Longitude = 48.858455f, Latitude = 2.294474f });
|
||||
```
|
||||
|
||||
**Note** you can only change geolocation for all pages in the context.
|
||||
|
||||
### API reference
|
||||
@ -432,6 +494,20 @@ page.emulate_media(color_scheme='dark')
|
||||
page.emulate_media(media='print')
|
||||
```
|
||||
|
||||
```csharp
|
||||
// Create context with dark mode
|
||||
await using var context = await browser.NewContextAsync(colorScheme: ColorScheme.Dark);
|
||||
|
||||
// Create page with dark mode
|
||||
var page = await browser.NewPageAsync(colorScheme: ColorScheme.Dark);
|
||||
|
||||
// Change color scheme for the page
|
||||
await page.EmulateMediaAsync(ColorScheme.Dark);
|
||||
|
||||
// Change media for page
|
||||
await page.EmulateMediaAsync(Media.Print);
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Page.emulateMedia`]
|
Loading…
x
Reference in New Issue
Block a user