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();
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" +

View File

@ -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 }
});

View File

@ -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" +

View File

@ -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`]

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
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
```

View File

@ -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.

View File

@ -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`]