docs(dotnet): guides (#6639)

This commit is contained in:
Anže Vodovnik 2021-05-20 04:53:12 +02:00 committed by GitHub
parent 0aa9e06370
commit c80e9fa58a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 309 additions and 4 deletions

View file

@ -583,7 +583,7 @@ var result = new TaskCompletionSource<string>();
var page = await Context.NewPageAsync(); var page = await Context.NewPageAsync();
await Context.ExposeBindingAsync("clicked", async (BindingSource _, IJSHandle t) => 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" + await page.SetContentAsync("<script>\n" +

View file

@ -305,7 +305,7 @@ element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_tran
```csharp ```csharp
var handle = await page.EvaluateHandleAsync("() => new DataTransfer()"); 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 } { "dataTransfer", dataTransfer }
}); });

View file

@ -1485,7 +1485,7 @@ page.set_content("""
var result = new TaskCompletionSource<string>(); var result = new TaskCompletionSource<string>();
await page.ExposeBindingAsync("clicked", async (BindingSource _, IJSHandle t) => 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" + await page.SetContentAsync("<script>\n" +

View file

@ -63,6 +63,20 @@ with sync_playwright() as p:
browser.close() 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 Launching a browser instance can be expensive, and Playwright is designed to
maximize what a single instance can do through multiple browser contexts. maximize what a single instance can do through multiple browser contexts.
@ -99,6 +113,11 @@ browser = playwright.chromium.launch()
context = browser.new_context() 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 Browser contexts can also be used to emulate multi-page scenarios involving
mobile devices, permissions, locale and color scheme. mobile devices, permissions, locale and color scheme.
@ -174,6 +193,30 @@ with sync_playwright() as p:
browser.close() 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 ### API reference
- [BrowserContext] - [BrowserContext]
@ -256,6 +299,24 @@ print(page.url)
# window.location.href = 'https://example.com' # 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). > Read more on [page navigation and loading](./navigations.md).
A page can have one or more [Frame] objects attached to 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') 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 ### API reference
- [Page] - [Page]
@ -365,6 +444,11 @@ await page.click('data-test-id=foo')
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 ```js
// CSS and XPath selector engines are automatically detected // CSS and XPath selector engines are automatically detected
await page.click('div'); await page.click('div');
@ -389,6 +473,12 @@ page.click('div')
page.click('//html/body/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 ```js
// Find node by text substring // Find node by text substring
await page.click('text=Hello w'); await page.click('text=Hello w');
@ -409,6 +499,11 @@ await page.click('text=Hello w')
page.click('text=Hello w') page.click('text=Hello w')
``` ```
```csharp
// Find node by text substring
await page.ClickAsync("text=Hello w");
```
```js ```js
// Explicit CSS and XPath notation // Explicit CSS and XPath notation
await page.click('css=div'); await page.click('css=div');
@ -433,6 +528,12 @@ page.click('css=div')
page.click('xpath=//html/body/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 ```js
// Only search light DOM, outside WebComponent shadow DOM: // Only search light DOM, outside WebComponent shadow DOM:
await page.click('css:light=div'); await page.click('css:light=div');
@ -453,6 +554,11 @@ await page.click('css:light=div')
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, Selectors using the same or different engines can be combined using the `>>` separator. For example,
```js ```js
@ -475,6 +581,11 @@ await page.click('#free-month-promo >> text=Sign Up')
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 ```js
// Capture textContent of a section that contains an element with text 'Selectors'. // Capture textContent of a section that contains an element with text 'Selectors'.
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent); 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') 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/> <br/>
## Auto-waiting ## Auto-waiting
@ -529,6 +645,11 @@ await page.fill('#search', 'query')
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 ```js
// Playwright waits for element to stop animating // Playwright waits for element to stop animating
// and accept clicks. // and accept clicks.
@ -553,6 +674,12 @@ await page.click('#search')
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: You can explicitly wait for an element to appear in the DOM or to become visible:
```js ```js
@ -584,6 +711,13 @@ page.wait_for_selector('#search', state='attached')
page.wait_for_selector('#promo') 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 ... or to become hidden or detached
```js ```js
@ -616,6 +750,13 @@ page.wait_for_selector('#details', state='hidden')
page.wait_for_selector('#promo', state='detached') 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 ### API reference
- [`method: Page.click`] - [`method: Page.click`]
@ -648,6 +789,10 @@ href = await page.evaluate('() => document.location.href')
href = 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: If the result is a Promise or if the function is asynchronous evaluate will automatically wait until it's resolved:
```js ```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 ## 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. 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 }) { '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: Right:
```js ```js
@ -897,6 +1084,12 @@ result = page.evaluate("""data => {
}""", 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: Wrong:
```js ```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 ### API reference
- [`method: Page.evaluate`] - [`method: Page.evaluate`]

View file

@ -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 ## Browser Developer Tools
You can use browser developer tools in Chromium, Firefox and WebKit while running You can use browser developer tools in Chromium, Firefox and WebKit while running
@ -75,6 +79,9 @@ await chromium.launch(devtools=True)
```python sync ```python sync
chromium.launch(devtools=True) chromium.launch(devtools=True)
``` ```
```csharp
await using var browser = await playwright.Chromium.LaunchAsync(devtools: true);
```
::: :::
## Run in Debug Mode ## Run in Debug Mode
@ -181,3 +188,9 @@ DEBUG=pw:api pytest -s
set DEBUG=pw:api set DEBUG=pw:api
pytest -s pytest -s
``` ```
```sh csharp
# Powershell (Win/macOS)
$env:DEBUG="pw:api"
dotnet run
```

View file

@ -50,6 +50,16 @@ download = download_info.value
path = download.path() 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 #### Variations
If you have no idea what initiates the download, you can still handle the event: 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())) 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 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. are downloading a file since your main control flow is not awaiting for this operation to resolve.

View file

@ -17,7 +17,7 @@ can be changed for individual pages.
<br/> <br/>
## Devices ## 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 Playwright comes with a registry of device parameters for selected mobile devices. It can be used to simulate browser
behavior on a mobile device: behavior on a mobile device:
@ -63,6 +63,23 @@ with sync_playwright() as playwright:
run(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. All pages created in the context above will share the same device parameters.
### API reference ### API reference
@ -98,6 +115,10 @@ context = browser.new_context(
) )
``` ```
```csharp
var context = await browser.NewContextAsync(userAgent: "My User Agent");
```
### API reference ### API reference
- [`method: Browser.newContext`] - [`method: Browser.newContext`]
@ -168,6 +189,20 @@ context = browser.new_context(
device_scale_factor=2, 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 ### API reference
- [`method: Browser.newContext`] - [`method: Browser.newContext`]
- [`method: Page.setViewportSize`] - [`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 ### API reference
- [`method: Browser.newContext`] - [`method: Browser.newContext`]
@ -257,6 +296,10 @@ await context.grant_permissions(['geolocation'])
context.grant_permissions(['geolocation']) context.grant_permissions(['geolocation'])
``` ```
```csharp
await context.GrantPermissionsAsync(new[] { "geolocation" });
```
Grant notifications access from a specific domain: Grant notifications access from a specific domain:
```js ```js
@ -276,6 +319,10 @@ await context.grant_permissions(['notifications'], origin='https://skype.com')
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: Revoke all permissions:
```js ```js
@ -294,6 +341,10 @@ await context.clear_permissions()
context.clear_permissions() context.clear_permissions()
``` ```
```csharp
await context.ClearPermissionsAsync();
```
### API reference ### API reference
- [`method: Browser.newContext`] - [`method: Browser.newContext`]
- [`method: BrowserContext.grantPermissions`] - [`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: Change the location later:
```js ```js
@ -350,6 +408,10 @@ await context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
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. **Note** you can only change geolocation for all pages in the context.
### API reference ### API reference
@ -432,6 +494,20 @@ page.emulate_media(color_scheme='dark')
page.emulate_media(media='print') 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 ### API reference
- [`method: Browser.newContext`] - [`method: Browser.newContext`]
- [`method: Page.emulateMedia`] - [`method: Page.emulateMedia`]