mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-26 12:42:39 +03:00
docs: add java snippets to the examples in guides (#5638)
This commit is contained in:
parent
aeb2b2f605
commit
6c9e806672
@ -8,7 +8,6 @@ text content of an element. These APIs can be used in your test assertions.
|
|||||||
|
|
||||||
<!-- TOC -->
|
<!-- TOC -->
|
||||||
|
|
||||||
|
|
||||||
## Text content
|
## Text content
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -16,6 +15,11 @@ const content = await page.textContent('nav:first-child');
|
|||||||
expect(content).toBe('home');
|
expect(content).toBe('home');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
String content = page.textContent("nav:first-child");
|
||||||
|
assertEquals("home", content);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
content = await page.text_content("nav:first-child")
|
content = await page.text_content("nav:first-child")
|
||||||
assert content == "home"
|
assert content == "home"
|
||||||
@ -37,6 +41,11 @@ const text = await page.innerText('.selected');
|
|||||||
expect(text).toBe('value');
|
expect(text).toBe('value');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
String text = page.innerText(".selected");
|
||||||
|
assertEquals("value", text);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
text = await page.inner_text(".selected")
|
text = await page.inner_text(".selected")
|
||||||
assert text == "value"
|
assert text == "value"
|
||||||
@ -58,6 +67,11 @@ const alt = await page.getAttribute('input', 'alt');
|
|||||||
expect(alt).toBe('Text');
|
expect(alt).toBe('Text');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
String alt = page.getAttribute("input", "alt");
|
||||||
|
assertEquals("Text", alt);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
checked = await page.get_attribute("input", "alt")
|
checked = await page.get_attribute("input", "alt")
|
||||||
assert alt == "Text"
|
assert alt == "Text"
|
||||||
@ -75,6 +89,11 @@ const checked = await page.isChecked('input');
|
|||||||
expect(checked).toBeTruthy();
|
expect(checked).toBeTruthy();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
boolean checked = page.isChecked("input");
|
||||||
|
assertTrue(checked);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
checked = await page.is_checked("input")
|
checked = await page.is_checked("input")
|
||||||
assert checked
|
assert checked
|
||||||
@ -96,6 +115,11 @@ const content = await page.$eval('nav:first-child', e => e.textContent);
|
|||||||
expect(content).toBe('home');
|
expect(content).toBe('home');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Object content = page.evalOnSelector("nav:first-child", "e => e.textContent");
|
||||||
|
assertEquals("home", content);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
content = await page.eval_on_selector("nav:first-child", "e => e.textContent")
|
content = await page.eval_on_selector("nav:first-child", "e => e.textContent")
|
||||||
assert content == "home"
|
assert content == "home"
|
||||||
@ -117,6 +141,11 @@ const html = await page.innerHTML('div.result');
|
|||||||
expect(html).toBe('<p>Result</p>');
|
expect(html).toBe('<p>Result</p>');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
String html = page.innerHTML("div.result");
|
||||||
|
assertEquals("<p>Result</p>", html);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
html = await page.inner_html("div.result")
|
html = await page.inner_html("div.result")
|
||||||
assert html == "<p>Result</p>"
|
assert html == "<p>Result</p>"
|
||||||
@ -138,6 +167,11 @@ const visible = await page.isVisible('input');
|
|||||||
expect(visible).toBeTruthy();
|
expect(visible).toBeTruthy();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
boolean visible = page.isVisible("input");
|
||||||
|
assertTrue(visible);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
visible = await page.is_visible("input")
|
visible = await page.is_visible("input")
|
||||||
assert visible
|
assert visible
|
||||||
@ -156,7 +190,12 @@ assert visible
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const enabled = await page.isEnabled('input');
|
const enabled = await page.isEnabled('input');
|
||||||
expect(visible).toBeTruthy();
|
expect(enabled).toBeTruthy();
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
boolean enabled = page.isEnabled("input");
|
||||||
|
assertTrue(enabled);
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
@ -198,6 +237,25 @@ const length = await page.$$eval('li.selected', (items) => items.length);
|
|||||||
expect(length === 3).toBeTruthy();
|
expect(length === 3).toBeTruthy();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Assert local storage value
|
||||||
|
Object userId = page.evaluate("() => window.localStorage.getItem('userId')");
|
||||||
|
assertNotNull(userId);
|
||||||
|
|
||||||
|
// Assert value for input element
|
||||||
|
page.waitForSelector("#search");
|
||||||
|
Object value = page.evalOnSelector("#search", "el => el.value");
|
||||||
|
assertEquals("query", value);
|
||||||
|
|
||||||
|
// Assert computed style
|
||||||
|
Object fontSize = page.evalOnSelector("div", "el => window.getComputedStyle(el).fontSize");
|
||||||
|
assertEquals("16px", fontSize);
|
||||||
|
|
||||||
|
// Assert list length
|
||||||
|
Object length = page.evalOnSelectorAll("li.selected", "items => items.length");
|
||||||
|
assertEquals(3, length);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Assert local storage value
|
# Assert local storage value
|
||||||
user_id = page.evaluate("() => window.localStorage.getItem('user_id')")
|
user_id = page.evaluate("() => window.localStorage.getItem('user_id')")
|
||||||
|
@ -36,6 +36,17 @@ await page.click('text=Submit');
|
|||||||
// Verify app is logged in
|
// Verify app is logged in
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Page page = context.newPage();
|
||||||
|
page.navigate("https://github.com/login");
|
||||||
|
// Interact with login form
|
||||||
|
page.click("text=Login");
|
||||||
|
page.fill("input[name='login']", USERNAME);
|
||||||
|
page.fill("input[name='password']", PASSWORD);
|
||||||
|
page.click("text=Submit");
|
||||||
|
// Verify app is logged in
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
page = await context.new_page()
|
page = await context.new_page()
|
||||||
await page.goto('https://github.com/login')
|
await page.goto('https://github.com/login')
|
||||||
@ -88,6 +99,16 @@ const storageState = JSON.parse(process.env.STORAGE);
|
|||||||
const context = await browser.newContext({ storageState });
|
const context = await browser.newContext({ storageState });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Save storage state and store as an env variable
|
||||||
|
String storage = context.storageState();
|
||||||
|
System.getenv().put("STORAGE", storage);
|
||||||
|
|
||||||
|
// Create a new context with the saved storage state
|
||||||
|
BrowserContext context = browser.newContext(
|
||||||
|
new Browser.NewContextOptions().withStorageState(storage));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -150,6 +171,23 @@ await context.addInitScript(storage => {
|
|||||||
}, sessionStorage);
|
}, sessionStorage);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get session storage and store as env variable
|
||||||
|
String sessionStorage = (String) page.evaluate("() => JSON.stringify(sessionStorage");
|
||||||
|
System.getenv().put("SESSION_STORAGE", sessionStorage);
|
||||||
|
|
||||||
|
// Set session storage in a new context
|
||||||
|
String sessionStorage = System.getenv("SESSION_STORAGE");
|
||||||
|
context.addInitScript("(storage => {\n" +
|
||||||
|
" if (window.location.hostname === 'example.com') {\n" +
|
||||||
|
" const entries = JSON.parse(storage);\n" +
|
||||||
|
" Object.keys(entries).forEach(key => {\n" +
|
||||||
|
" window.sessionStorage.setItem(key, entries[key]);\n" +
|
||||||
|
" });\n" +
|
||||||
|
" }\n" +
|
||||||
|
"})(" + sessionStorage + ")");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import os
|
import os
|
||||||
# Get session storage and store as env variable
|
# Get session storage and store as env variable
|
||||||
@ -199,8 +237,6 @@ manual intervention. Persistent authentication can be used to partially automate
|
|||||||
MFA scenarios.
|
MFA scenarios.
|
||||||
|
|
||||||
### Persistent authentication
|
### Persistent authentication
|
||||||
Web browsers use a directory on disk to store user history, cookies, IndexedDB
|
|
||||||
and other local state. This disk location is called the [User data directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md).
|
|
||||||
|
|
||||||
Note that persistent authentication is not suited for CI environments since it
|
Note that persistent authentication is not suited for CI environments since it
|
||||||
relies on a disk location. User data directories are specific to browser types
|
relies on a disk location. User data directories are specific to browser types
|
||||||
@ -216,6 +252,22 @@ const context = await chromium.launchPersistentContext(userDataDir, { headless:
|
|||||||
// Execute login steps manually in the browser window
|
// Execute login steps manually in the browser window
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
Path userDataDir = Paths.get("/path/to/directory");
|
||||||
|
BrowserContext context = chromium.launchPersistentContext(userDataDir,
|
||||||
|
new BrowserType.LaunchPersistentContextOptions().withHeadless(false));
|
||||||
|
// Execute login steps manually in the browser window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
@ -83,6 +83,11 @@ Suggested configuration
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
|
||||||
|
.withArgs(Arrays.asList("--disable-dev-shm-usage")));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
browser = await playwright.chromium.launch(
|
browser = await playwright.chromium.launch(
|
||||||
args=['--disable-dev-shm-usage']
|
args=['--disable-dev-shm-usage']
|
||||||
@ -233,6 +238,19 @@ const { chromium } = require('playwright');
|
|||||||
const browser = await chromium.launch({ chromiumSandbox: false });
|
const browser = await chromium.launch({ chromiumSandbox: false });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
Browser browser = chromium.launch(new BrowserType.LaunchOptions().withChromiumSandbox(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
browser = await playwright.chromium.launch(chromiumSandbox=False)
|
browser = await playwright.chromium.launch(chromiumSandbox=False)
|
||||||
```
|
```
|
||||||
@ -319,6 +337,20 @@ const { chromium } = require('playwright');
|
|||||||
const browser = await chromium.launch({ headless: false });
|
const browser = await chromium.launch({ headless: false });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Works across chromium, firefox and webkit
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
Browser browser = chromium.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
@ -91,6 +91,27 @@ const { chromium } = require('playwright');
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// FIXME
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
// Make sure to run headed.
|
||||||
|
Browser browser = chromium.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||||
|
// Setup context however you like.
|
||||||
|
BrowserContext context = browser.newContext(/* pass any options */);
|
||||||
|
context.route("**/*", route -> route.resume());
|
||||||
|
// Pause the page, and start recording manually.
|
||||||
|
Page page = context.newPage();
|
||||||
|
page.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
@ -29,6 +29,20 @@ const browser = await chromium.launch({ headless: false });
|
|||||||
await browser.close();
|
await browser.close();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
Browser browser = chromium.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||||
|
browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
@ -69,6 +83,11 @@ const browser = await chromium.launch();
|
|||||||
const context = await browser.newContext();
|
const context = await browser.newContext();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Browser browser = chromium.launch();
|
||||||
|
BrowserContext context = browser.newContext();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
browser = await playwright.chromium.launch()
|
browser = await playwright.chromium.launch()
|
||||||
context = await browser.new_context()
|
context = await browser.new_context()
|
||||||
@ -95,6 +114,29 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// FIXME
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType devices = playwright.devices();
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1")
|
||||||
|
.withViewportSize(375, 812)
|
||||||
|
.withDeviceScaleFactor(3)
|
||||||
|
.withIsMobile(true)
|
||||||
|
.withHasTouch(true)
|
||||||
|
.withPermissions(Arrays.asList("geolocation"))
|
||||||
|
.withGeolocation(52.52, 13.39)
|
||||||
|
.withColorScheme(ColorScheme.DARK)
|
||||||
|
.withLocale("de-DE"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
@ -161,6 +203,24 @@ console.log(page.url());
|
|||||||
window.location.href = 'https://example.com';
|
window.location.href = 'https://example.com';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Create a page.
|
||||||
|
Page page = context.newPage();
|
||||||
|
|
||||||
|
// Navigate explicitly, similar to entering a URL in the browser.
|
||||||
|
page.navigate("http://example.com");
|
||||||
|
// Fill an input.
|
||||||
|
page.fill("#search", "query");
|
||||||
|
|
||||||
|
// Navigate implicitly by clicking a link.
|
||||||
|
page.click("#submit");
|
||||||
|
// Expect a new url.
|
||||||
|
System.out.println(page.url());
|
||||||
|
|
||||||
|
// Page can navigate from the script - this will be picked up by Playwright.
|
||||||
|
// window.location.href = "https://example.com";
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
page = await context.new_page()
|
page = await context.new_page()
|
||||||
|
|
||||||
@ -219,6 +279,21 @@ const frame = await frameElementHandle.contentFrame();
|
|||||||
await frame.fill('#username-input', 'John');
|
await frame.fill('#username-input', 'John');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get frame using the frame"s name attribute
|
||||||
|
Frame frame = page.frame("frame-login");
|
||||||
|
|
||||||
|
// Get frame using frame"s URL
|
||||||
|
Frame frame = page.frameByUrl(Pattern.compile(".*domain.*"));
|
||||||
|
|
||||||
|
// Get frame using any other selector
|
||||||
|
ElementHandle frameElementHandle = page.querySelector(".frame-class");
|
||||||
|
Frame frame = frameElementHandle.contentFrame();
|
||||||
|
|
||||||
|
// Interact with the frame
|
||||||
|
frame.fill("#username-input", "John");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get frame using the frame's name attribute
|
# Get frame using the frame's name attribute
|
||||||
frame = page.frame('frame-login')
|
frame = page.frame('frame-login')
|
||||||
@ -274,6 +349,11 @@ Some examples below:
|
|||||||
await page.click('data-test-id=foo');
|
await page.click('data-test-id=foo');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Using data-test-id= selector engine
|
||||||
|
page.click("data-test-id=foo");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Using data-test-id= selector engine
|
# Using data-test-id= selector engine
|
||||||
await page.click('data-test-id=foo')
|
await page.click('data-test-id=foo')
|
||||||
@ -290,6 +370,12 @@ await page.click('div');
|
|||||||
await page.click('//html/body/div');
|
await page.click('//html/body/div');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// CSS and XPath selector engines are automatically detected
|
||||||
|
page.click("div");
|
||||||
|
page.click("//html/body/div");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# CSS and XPath selector engines are automatically detected
|
# CSS and XPath selector engines are automatically detected
|
||||||
await page.click('div')
|
await page.click('div')
|
||||||
@ -307,6 +393,11 @@ page.click('//html/body/div')
|
|||||||
await page.click('text=Hello w');
|
await page.click('text=Hello w');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Find node by text substring
|
||||||
|
page.click("text=Hello w");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Find node by text substring
|
# Find node by text substring
|
||||||
await page.click('text=Hello w')
|
await page.click('text=Hello w')
|
||||||
@ -323,6 +414,12 @@ await page.click('css=div');
|
|||||||
await page.click('xpath=//html/body/div');
|
await page.click('xpath=//html/body/div');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Explicit CSS and XPath notation
|
||||||
|
page.click("css=div");
|
||||||
|
page.click("xpath=//html/body/div");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Explicit CSS and XPath notation
|
# Explicit CSS and XPath notation
|
||||||
await page.click('css=div')
|
await page.click('css=div')
|
||||||
@ -340,6 +437,11 @@ page.click('xpath=//html/body/div')
|
|||||||
await page.click('css:light=div');
|
await page.click('css:light=div');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Only search light DOM, outside WebComponent shadow DOM:
|
||||||
|
page.click("css:light=div");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# 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')
|
||||||
@ -357,6 +459,11 @@ Selectors using the same or different engines can be combined using the `>>` sep
|
|||||||
await page.click('#free-month-promo >> text=Sign Up');
|
await page.click('#free-month-promo >> text=Sign Up');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Click an element with text "Sign Up" inside of a #free-month-promo.
|
||||||
|
page.click("#free-month-promo >> text=Sign Up");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Click an element with text 'Sign Up' inside of a #free-month-promo.
|
# Click an element with text 'Sign Up' inside of a #free-month-promo.
|
||||||
await page.click('#free-month-promo >> text=Sign Up')
|
await page.click('#free-month-promo >> text=Sign Up')
|
||||||
@ -372,6 +479,11 @@ page.click('#free-month-promo >> text=Sign Up')
|
|||||||
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent);
|
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Capture textContent of a section that contains an element with text "Selectors".
|
||||||
|
String sectionText = (String) page.evalOnSelector("*css=section >> text=Selectors", "e => e.textContent");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Capture textContent of a section that contains an element with text 'Selectors'.
|
# Capture textContent of a section that contains an element with text 'Selectors'.
|
||||||
section_text = await page.eval_on_selector('*css=section >> text=Selectors', 'e => e.textContent')
|
section_text = await page.eval_on_selector('*css=section >> text=Selectors', 'e => e.textContent')
|
||||||
@ -401,6 +513,11 @@ and [actionable](./actionability.md). For example, click will:
|
|||||||
await page.fill('#search', 'query');
|
await page.fill('#search', 'query');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Playwright waits for #search element to be in the DOM
|
||||||
|
page.fill("#search", "query");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Playwright waits for #search element to be in the DOM
|
# Playwright waits for #search element to be in the DOM
|
||||||
await page.fill('#search', 'query')
|
await page.fill('#search', 'query')
|
||||||
@ -417,6 +534,12 @@ page.fill('#search', 'query')
|
|||||||
await page.click('#search');
|
await page.click('#search');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Playwright waits for element to stop animating
|
||||||
|
// and accept clicks.
|
||||||
|
page.click("#search");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Playwright waits for element to stop animating
|
# Playwright waits for element to stop animating
|
||||||
# and accept clicks.
|
# and accept clicks.
|
||||||
@ -438,6 +561,14 @@ await page.waitForSelector('#search', { state: 'attached' });
|
|||||||
await page.waitForSelector('#promo');
|
await page.waitForSelector('#promo');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Wait for #search to appear in the DOM.
|
||||||
|
page.waitForSelector("#search", new Page.WaitForSelectorOptions()
|
||||||
|
.withState(WaitForSelectorState.ATTACHED));
|
||||||
|
// Wait for #promo to become visible, for example with "visibility:visible".
|
||||||
|
page.waitForSelector("#promo");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Wait for #search to appear in the DOM.
|
# Wait for #search to appear in the DOM.
|
||||||
await page.wait_for_selector('#search', state='attached')
|
await page.wait_for_selector('#search', state='attached')
|
||||||
@ -461,6 +592,15 @@ await page.waitForSelector('#details', { state: 'hidden' });
|
|||||||
await page.waitForSelector('#promo', { state: 'detached' });
|
await page.waitForSelector('#promo', { state: 'detached' });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Wait for #details to become hidden, for example with "display:none".
|
||||||
|
page.waitForSelector("#details", new Page.WaitForSelectorOptions()
|
||||||
|
.withState(WaitForSelectorState.HIDDEN));
|
||||||
|
// Wait for #promo to be removed from the DOM.
|
||||||
|
page.waitForSelector("#promo", new Page.WaitForSelectorOptions()
|
||||||
|
.withState(WaitForSelectorState.DETACHED));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Wait for #details to become hidden, for example with `display:none`.
|
# Wait for #details to become hidden, for example with `display:none`.
|
||||||
await page.wait_for_selector('#details', state='hidden')
|
await page.wait_for_selector('#details', state='hidden')
|
||||||
@ -495,6 +635,10 @@ of the web page and bring results back to the Playwright environment. Browser gl
|
|||||||
const href = await page.evaluate(() => document.location.href);
|
const href = await page.evaluate(() => document.location.href);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
String href = (String) page.evaluate("document.location.href");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
href = await page.evaluate('() => document.location.href')
|
href = await page.evaluate('() => document.location.href')
|
||||||
```
|
```
|
||||||
@ -512,6 +656,13 @@ const status = await page.evaluate(async () => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
int status = (int) page.evaluate("async () => {\n" +
|
||||||
|
" const response = await fetch(location.href);\n" +
|
||||||
|
" return response.status;\n" +
|
||||||
|
"}");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
status = await page.evaluate("""async () => {
|
status = await page.evaluate("""async () => {
|
||||||
response = await fetch(location.href)
|
response = await fetch(location.href)
|
||||||
@ -573,6 +724,57 @@ await page.evaluate(
|
|||||||
{ button1, list: [button2], foo: null });
|
{ button1, list: [button2], foo: null });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// A primitive value.
|
||||||
|
page.evaluate("num => num", 42);
|
||||||
|
|
||||||
|
// An array.
|
||||||
|
page.evaluate("array => array.length", Arrays.asList(1, 2, 3));
|
||||||
|
|
||||||
|
// An object.
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("foo", "bar");
|
||||||
|
page.evaluate("object => object.foo", obj);
|
||||||
|
|
||||||
|
// A single handle.
|
||||||
|
ElementHandle button = page.querySelector("button");
|
||||||
|
page.evaluate("button => button.textContent", button);
|
||||||
|
|
||||||
|
// Alternative notation using elementHandle.evaluate.
|
||||||
|
button.evaluate("(button, from) => button.textContent.substring(from)", 5);
|
||||||
|
|
||||||
|
// Object with multiple handles.
|
||||||
|
ElementHandle button1 = page.querySelector(".button1");
|
||||||
|
ElementHandle button2 = page.querySelector(".button2");
|
||||||
|
Map<String, ElementHandle> arg = new HashMap<>();
|
||||||
|
arg.put("button1", button1);
|
||||||
|
arg.put("button2", button2);
|
||||||
|
page.evaluate("o => o.button1.textContent + o.button2.textContent", arg);
|
||||||
|
|
||||||
|
// Object destructuring works. Note that property names must match
|
||||||
|
// between the destructured object and the argument.
|
||||||
|
// Also note the required parenthesis.
|
||||||
|
Map<String, ElementHandle> arg = new HashMap<>();
|
||||||
|
arg.put("button1", button1);
|
||||||
|
arg.put("button2", button2);
|
||||||
|
page.evaluate("({ button1, button2 }) => button1.textContent + button2.textContent", arg);
|
||||||
|
|
||||||
|
// Array works as well. Arbitrary names can be used for destructuring.
|
||||||
|
// Note the required parenthesis.
|
||||||
|
page.evaluate(
|
||||||
|
"([b1, b2]) => b1.textContent + b2.textContent",
|
||||||
|
Arrays.asList(button1, button2));
|
||||||
|
|
||||||
|
// Any non-cyclic mix of serializables and handles works.
|
||||||
|
Map<String, Object> arg = new HashMap<>();
|
||||||
|
arg.put("button1", button1);
|
||||||
|
arg.put("list", Arrays.asList(button2));
|
||||||
|
arg.put("foo", 0);
|
||||||
|
page.evaluate(
|
||||||
|
"x => x.button1.textContent + x.list[0].textContent + String(x.foo)",
|
||||||
|
arg);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# A primitive value.
|
# A primitive value.
|
||||||
await page.evaluate('num => num', 42)
|
await page.evaluate('num => num', 42)
|
||||||
@ -668,6 +870,16 @@ const result = await page.evaluate(data => {
|
|||||||
}, data);
|
}, data);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
data.put("text", "some data");
|
||||||
|
data.put("value", 1);
|
||||||
|
// Pass |data| as a parameter.
|
||||||
|
Object result = page.evaluate("data => {\n" +
|
||||||
|
" window.myApp.use(data);\n" +
|
||||||
|
"}", data);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
data = { 'text': 'some data', 'value': 1 }
|
data = { 'text': 'some data', 'value': 1 }
|
||||||
# Pass |data| as a parameter.
|
# Pass |data| as a parameter.
|
||||||
@ -694,6 +906,16 @@ const result = await page.evaluate(() => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
data.put("text", "some data");
|
||||||
|
data.put("value", 1);
|
||||||
|
Object result = page.evaluate("() => {\n" +
|
||||||
|
" // There is no |data| in the web page.\n" +
|
||||||
|
" window.myApp.use(data);\n" +
|
||||||
|
"}");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
data = { 'text': 'some data', 'value': 1 }
|
data = { 'text': 'some data', 'value': 1 }
|
||||||
result = await page.evaluate("""() => {
|
result = await page.evaluate("""() => {
|
||||||
|
@ -26,6 +26,12 @@ to slow down execution and follow along while debugging.
|
|||||||
await chromium.launch({ headless: false, slowMo: 100 }); // or firefox, webkit
|
await chromium.launch({ headless: false, slowMo: 100 }); // or firefox, webkit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
chromium.launch(new BrowserType.LaunchOptions() // or firefox, webkit
|
||||||
|
.withHeadless(false)
|
||||||
|
.withSlowMo(100));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await chromium.launch(headless=False, slow_mo=100) # or firefox, webkit
|
await chromium.launch(headless=False, slow_mo=100) # or firefox, webkit
|
||||||
|
|
||||||
@ -75,6 +81,10 @@ In Chromium, you can also open developer tools through a launch option.
|
|||||||
await chromium.launch({ devtools: true });
|
await chromium.launch({ devtools: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
chromium.launch(new BrowserType.LaunchOptions().withDevtools(true));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await chromium.launch(devtools=True)
|
await chromium.launch(devtools=True)
|
||||||
|
|
||||||
@ -98,6 +108,15 @@ $ set PWDEBUG=1
|
|||||||
$ npm run test
|
$ npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```sh java
|
||||||
|
# Linux/macOS
|
||||||
|
$ PWDEBUG=1 mvn test
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
$ set PWDEBUG=1
|
||||||
|
$ mvn test
|
||||||
|
```
|
||||||
|
|
||||||
```sh python
|
```sh python
|
||||||
# Linux/macOS
|
# Linux/macOS
|
||||||
$ PWDEBUG=1 pytest -s
|
$ PWDEBUG=1 pytest -s
|
||||||
@ -152,6 +171,15 @@ $ set DEBUG=pw:api
|
|||||||
$ npm run test
|
$ npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```sh java
|
||||||
|
# Linux/macOS
|
||||||
|
$ DEBUG=pw:api mvn test
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
$ set DEBUG=pw:api
|
||||||
|
$ mvn test
|
||||||
|
```
|
||||||
|
|
||||||
```sh python
|
```sh python
|
||||||
# Linux/macOS
|
# Linux/macOS
|
||||||
$ DEBUG=pw:api pytest -s
|
$ DEBUG=pw:api pytest -s
|
||||||
|
@ -16,6 +16,11 @@ page.on('dialog', dialog => dialog.accept());
|
|||||||
await page.click('button');
|
await page.click('button');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onDialog(dialog -> dialog.accept());
|
||||||
|
page.click("button");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
page.on("dialog", lambda dialog: dialog.accept())
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
await page.click("button")
|
await page.click("button")
|
||||||
@ -41,6 +46,11 @@ page.on('dialog', dialog => console.log(dialog.message()));
|
|||||||
await page.click('button'); // Will hang here
|
await page.click('button'); // Will hang here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onDialog(dialog -> System.out.println(dialog.message()));
|
||||||
|
page.click("button"); // Will hang here
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
page.on("dialog", lambda dialog: print(dialog.message))
|
page.on("dialog", lambda dialog: print(dialog.message))
|
||||||
await page.click("button") # Will hang here
|
await page.click("button") # Will hang here
|
||||||
@ -75,6 +85,14 @@ page.on('dialog', async dialog => {
|
|||||||
await page.close({runBeforeUnload: true});
|
await page.close({runBeforeUnload: true});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onDialog(dialog -> {
|
||||||
|
assertEquals("beforeunload", dialog.type());
|
||||||
|
dialog.dismiss();
|
||||||
|
});
|
||||||
|
page.close(new Page.CloseOptions().withRunBeforeUnload(true));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
async def handle_dialog(dialog):
|
async def handle_dialog(dialog):
|
||||||
assert dialog.type == 'beforeunload'
|
assert dialog.type == 'beforeunload'
|
||||||
|
@ -58,6 +58,10 @@ If you have no idea what initiates the download, you can still handle the event:
|
|||||||
page.on('download', download => download.path().then(console.log));
|
page.on('download', download => download.path().then(console.log));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onDownload(download -> System.out.println(download.path()));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
async def handle_download(download):
|
async def handle_download(download):
|
||||||
print(await download.path())
|
print(await download.path())
|
||||||
|
@ -81,6 +81,11 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withUserAgent("My user agent"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
user_agent='My user agent'
|
user_agent='My user agent'
|
||||||
@ -118,6 +123,20 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Create context with given viewport
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withViewportSize(1280, 1024));
|
||||||
|
|
||||||
|
// Resize viewport for individual page
|
||||||
|
page.setViewportSize(1600, 1200);
|
||||||
|
|
||||||
|
// Emulate high-DPI
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withViewportSize(2560, 1440)
|
||||||
|
.withDeviceScaleFactor(2);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Create context with given viewport
|
# Create context with given viewport
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
@ -165,6 +184,13 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Emulate locale and time
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withLocale("de-DE")
|
||||||
|
.withTimezoneId("Europe/Berlin"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Emulate locale and time
|
# Emulate locale and time
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
@ -196,6 +222,11 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withPermissions(Arrays.asList("notifications"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
permissions=['notifications'],
|
permissions=['notifications'],
|
||||||
@ -214,6 +245,10 @@ Grant all pages in the existing context access to current location:
|
|||||||
await context.grantPermissions(['geolocation']);
|
await context.grantPermissions(['geolocation']);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
context.grantPermissions(Arrays.asList("geolocation"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await context.grant_permissions(['geolocation'])
|
await context.grant_permissions(['geolocation'])
|
||||||
```
|
```
|
||||||
@ -228,6 +263,11 @@ Grant notifications access from a specific domain:
|
|||||||
await context.grantPermissions(['notifications'], {origin: 'https://skype.com'} );
|
await context.grantPermissions(['notifications'], {origin: 'https://skype.com'} );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
context.grantPermissions(Arrays.asList("notifications"),
|
||||||
|
new BrowserContext.GrantPermissionsOptions().withOrigin("https://skype.com"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await context.grant_permissions(['notifications'], origin='https://skype.com')
|
await context.grant_permissions(['notifications'], origin='https://skype.com')
|
||||||
```
|
```
|
||||||
@ -242,6 +282,10 @@ Revoke all permissions:
|
|||||||
await context.clearPermissions();
|
await context.clearPermissions();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
context.clearPermissions();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await context.clear_permissions()
|
await context.clear_permissions()
|
||||||
```
|
```
|
||||||
@ -268,6 +312,12 @@ const context = await browser.newContext({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withGeolocation(48.858455, 2.294474)
|
||||||
|
.withPermissions(Arrays.asList("geolocation")));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
geolocation={"longitude": 48.858455, "latitude": 2.294474},
|
geolocation={"longitude": 48.858455, "latitude": 2.294474},
|
||||||
@ -288,6 +338,10 @@ Change the location later:
|
|||||||
await context.setGeolocation({ longitude: 29.979097, latitude: 31.134256 });
|
await context.setGeolocation({ longitude: 29.979097, latitude: 31.134256 });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
context.setGeolocation(new Geolocation(29.979097, 31.134256));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
|
await context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
|
||||||
```
|
```
|
||||||
@ -326,6 +380,22 @@ await page.emulateMedia({ colorScheme: 'dark' });
|
|||||||
await page.emulateMedia({ media: 'print' });
|
await page.emulateMedia({ media: 'print' });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Create context with dark mode
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withColorScheme(ColorScheme.DARK)); // or "light"
|
||||||
|
|
||||||
|
// Create page with dark mode
|
||||||
|
Page page = browser.newPage(new Browser.NewPageOptions()
|
||||||
|
.withColorScheme(ColorScheme.DARK)); // or "light"
|
||||||
|
|
||||||
|
// Change color scheme for the page
|
||||||
|
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(ColorScheme.DARK));
|
||||||
|
|
||||||
|
// Change media for page
|
||||||
|
page.emulateMedia(new Page.EmulateMediaOptions().withMedia(Media.PRINT));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Create context with dark mode
|
# Create context with dark mode
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
|
@ -51,6 +51,33 @@ await page.click('tag=div >> span >> "Click me"');
|
|||||||
const buttonCount = await page.$$eval('tag=button', buttons => buttons.length);
|
const buttonCount = await page.$$eval('tag=button', buttons => buttons.length);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Must be a script that evaluates to a selector engine instance.
|
||||||
|
String createTagNameEngine = "{\n" +
|
||||||
|
" // Returns the first element matching given selector in the root's subtree.\n" +
|
||||||
|
" query(root, selector) {\n" +
|
||||||
|
" return root.querySelector(selector);\n" +
|
||||||
|
" },\n" +
|
||||||
|
"\n" +
|
||||||
|
" // Returns all elements matching given selector in the root's subtree.\n" +
|
||||||
|
" queryAll(root, selector) {\n" +
|
||||||
|
" return Array.from(root.querySelectorAll(selector));\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// Register the engine. Selectors will be prefixed with "tag=".
|
||||||
|
playwright.selectors().register("tag", createTagNameEngine);
|
||||||
|
|
||||||
|
// Now we can use "tag=" selectors.
|
||||||
|
ElementHandle button = page.querySelector("tag=button");
|
||||||
|
|
||||||
|
// We can combine it with other selector engines using ">>" combinator.
|
||||||
|
page.click("tag=div >> span >> \"Click me\"");
|
||||||
|
|
||||||
|
// We can use it in any methods supporting selectors.
|
||||||
|
int buttonCount = (int) page.evalOnSelectorAll("tag=button", "buttons => buttons.length");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
tag_selector = """
|
tag_selector = """
|
||||||
// Must evaluate to a selector engine instance.
|
// Must evaluate to a selector engine instance.
|
||||||
|
@ -28,6 +28,11 @@ const jsHandle = await page.evaluateHandle('window');
|
|||||||
// Use jsHandle for evaluations.
|
// Use jsHandle for evaluations.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
JSHandle jsHandle = page.evaluateHandle("window");
|
||||||
|
// Use jsHandle for evaluations.
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
js_handle = await page.evaluate_handle('window')
|
js_handle = await page.evaluate_handle('window')
|
||||||
# Use jsHandle for evaluations.
|
# Use jsHandle for evaluations.
|
||||||
@ -43,6 +48,11 @@ const ulElementHandle = await page.waitForSelector('ul');
|
|||||||
// Use ulElementHandle for actions and evaluation.
|
// Use ulElementHandle for actions and evaluation.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
ElementHandle ulElementHandle = page.waitForSelector("ul");
|
||||||
|
// Use ulElementHandle for actions and evaluation.
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
ul_element_handle = await page.wait_for_selector('ul')
|
ul_element_handle = await page.wait_for_selector('ul')
|
||||||
# Use ul_element_handle for actions and evaluation.
|
# Use ul_element_handle for actions and evaluation.
|
||||||
@ -76,6 +86,20 @@ const classNames = await elementHandle.getAttribute('class');
|
|||||||
expect(classNames.includes('highlighted')).toBeTruthy();
|
expect(classNames.includes('highlighted')).toBeTruthy();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get the element handle
|
||||||
|
JSHandle jsHandle = page.waitForSelector("#box");
|
||||||
|
ElementHandle elementHandle = jsHandle.asElement();
|
||||||
|
|
||||||
|
// Assert bounding box for the element
|
||||||
|
BoundingBox boundingBox = elementHandle.boundingBox();
|
||||||
|
assertEquals(100, boundingBox.width);
|
||||||
|
|
||||||
|
// Assert attribute for the element
|
||||||
|
String classNames = elementHandle.getAttribute("class");
|
||||||
|
assertTrue(classNames.contains("highlighted"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get the element handle
|
# Get the element handle
|
||||||
element_handle = page.wait_for_selector('#box')
|
element_handle = page.wait_for_selector('#box')
|
||||||
@ -129,6 +153,26 @@ await page.evaluate(arg => arg.myArray.push(arg.newElement), {
|
|||||||
await myArrayHandle.dispose();
|
await myArrayHandle.dispose();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Create new array in page.
|
||||||
|
JSHandle myArrayHandle = page.evaluateHandle("() => {\n" +
|
||||||
|
" window.myArray = [1];\n" +
|
||||||
|
" return myArray;\n" +
|
||||||
|
"}");
|
||||||
|
|
||||||
|
// Get the length of the array.
|
||||||
|
int length = (int) page.evaluate("a => a.length", myArrayHandle);
|
||||||
|
|
||||||
|
// Add one more element to the array using the handle
|
||||||
|
Map<String, Object> arg = new HashMap<>();
|
||||||
|
arg.put("myArray", myArrayHandle);
|
||||||
|
arg.put("newElement", 2);
|
||||||
|
page.evaluate("arg => arg.myArray.add(arg.newElement)", arg);
|
||||||
|
|
||||||
|
// Release the object when it"s no longer needed.
|
||||||
|
myArrayHandle.dispose();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Create new array in page.
|
# Create new array in page.
|
||||||
my_array_handle = await page.evaluate_handle("""() => {
|
my_array_handle = await page.evaluate_handle("""() => {
|
||||||
|
@ -26,6 +26,23 @@ await page.fill('#local', '2020-03-02T05:15');
|
|||||||
await page.fill('text=First Name', 'Peter');
|
await page.fill('text=First Name', 'Peter');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Text input
|
||||||
|
page.fill("#name", "Peter");
|
||||||
|
|
||||||
|
// Date input
|
||||||
|
page.fill("#date", "2020-02-02");
|
||||||
|
|
||||||
|
// Time input
|
||||||
|
page.fill("#time", "13-15");
|
||||||
|
|
||||||
|
// Local datetime input
|
||||||
|
page.fill("#local", "2020-03-02T05:15");
|
||||||
|
|
||||||
|
// Input through label
|
||||||
|
page.fill("text=First Name", "Peter");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Text input
|
# Text input
|
||||||
await page.fill('#name', 'Peter')
|
await page.fill('#name', 'Peter')
|
||||||
@ -86,6 +103,20 @@ await page.uncheck('#subscribe-label');
|
|||||||
await page.check('text=XL');
|
await page.check('text=XL');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Check the checkbox
|
||||||
|
page.check("#agree");
|
||||||
|
|
||||||
|
// Assert the checked state
|
||||||
|
assertTrue(page.isChecked("#agree"));
|
||||||
|
|
||||||
|
// Uncheck by input <label>.
|
||||||
|
page.uncheck("#subscribe-label");
|
||||||
|
|
||||||
|
// Select the radio button
|
||||||
|
page.check("text=XL");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Check the checkbox
|
# Check the checkbox
|
||||||
await page.check('#agree')
|
await page.check('#agree')
|
||||||
@ -145,6 +176,21 @@ const option = await page.$('#best-option');
|
|||||||
await page.selectOption('select#colors', option);
|
await page.selectOption('select#colors', option);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Single selection matching the value
|
||||||
|
page.selectOption("select#colors", "blue");
|
||||||
|
|
||||||
|
// Single selection matching the label
|
||||||
|
page.selectOption("select#colors", new SelectOption().withLabel("Blue"));
|
||||||
|
|
||||||
|
// Multiple selected items
|
||||||
|
page.selectOption("select#colors", new String[] {"red", "green", "blue"});
|
||||||
|
|
||||||
|
// Select the option via element handle
|
||||||
|
ElementHandle option = page.querySelector("#best-option");
|
||||||
|
page.selectOption("select#colors", option);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Single selection matching the value
|
# Single selection matching the value
|
||||||
await page.select_option('select#colors', 'blue')
|
await page.select_option('select#colors', 'blue')
|
||||||
@ -207,6 +253,26 @@ await page.hover('#item');
|
|||||||
await page.click('#item', { position: { x: 0, y: 0} });
|
await page.click('#item', { position: { x: 0, y: 0} });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Generic click
|
||||||
|
page.click("button#submit");
|
||||||
|
|
||||||
|
// Double click
|
||||||
|
page.dblclick("#item");
|
||||||
|
|
||||||
|
// Right click
|
||||||
|
page.click("#item", new Page.ClickOptions().withButton(MouseButton.RIGHT));
|
||||||
|
|
||||||
|
// Shift + click
|
||||||
|
page.click("#item", new Page.ClickOptions().withModifiers(Arrays.asList(KeyboardModifier.SHIFT)));
|
||||||
|
|
||||||
|
// Hover over element
|
||||||
|
page.hover("#item");
|
||||||
|
|
||||||
|
// Click the top left corner
|
||||||
|
page.click("#item", new Page.ClickOptions().withPosition(0, 0));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Generic click
|
# Generic click
|
||||||
await page.click('button#submit')
|
await page.click('button#submit')
|
||||||
@ -264,6 +330,10 @@ Sometimes, apps use non-trivial logic where hovering the element overlays it wit
|
|||||||
await page.click('button#submit', { force: true });
|
await page.click('button#submit', { force: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.click("button#submit", new Page.ClickOptions().withForce(true));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.click('button#submit', force=True)
|
await page.click('button#submit', force=True)
|
||||||
```
|
```
|
||||||
@ -280,6 +350,10 @@ If you are not interested in testing your app under the real conditions and want
|
|||||||
await page.dispatchEvent('button#submit', 'click');
|
await page.dispatchEvent('button#submit', 'click');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.dispatchEvent("button#submit", "click");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.dispatch_event('button#submit', 'click')
|
await page.dispatch_event('button#submit', 'click')
|
||||||
```
|
```
|
||||||
@ -314,6 +388,11 @@ Type into the field character by character, as if it was a user with a real keyb
|
|||||||
await page.type('#area', 'Hello World!');
|
await page.type('#area', 'Hello World!');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Type character by character
|
||||||
|
page.type("#area", "Hello World!");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Type character by character
|
# Type character by character
|
||||||
await page.type('#area', 'Hello World!')
|
await page.type('#area', 'Hello World!')
|
||||||
@ -352,6 +431,17 @@ await page.press('#name', 'Control+ArrowRight');
|
|||||||
await page.press('#value', '$');
|
await page.press('#value', '$');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Hit Enter
|
||||||
|
page.press("#submit", "Enter");
|
||||||
|
|
||||||
|
// Dispatch Control+Right
|
||||||
|
page.press("#name", "Control+ArrowRight");
|
||||||
|
|
||||||
|
// Press $ sign on keyboard
|
||||||
|
page.press("#value", "$");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Hit Enter
|
# Hit Enter
|
||||||
await page.press('#submit', 'Enter')
|
await page.press('#submit', 'Enter')
|
||||||
@ -397,6 +487,14 @@ await page.press('#name', 'Shift+A');
|
|||||||
await page.press('#name', 'Shift+ArrowLeft');
|
await page.press('#name', 'Shift+ArrowLeft');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// <input id=name>
|
||||||
|
page.press("#name", "Shift+A");
|
||||||
|
|
||||||
|
// <input id=name>
|
||||||
|
page.press("#name", "Shift+ArrowLeft");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# <input id=name>
|
# <input id=name>
|
||||||
await page.press('#name', 'Shift+A')
|
await page.press('#name', 'Shift+A')
|
||||||
@ -449,6 +547,21 @@ await page.setInputFiles('input#upload', {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Select one file
|
||||||
|
page.setInputFiles("input#upload", Paths.get("myfile.pdf"));
|
||||||
|
|
||||||
|
// Select multiple files
|
||||||
|
page.setInputFiles("input#upload", new Path[] {Paths.get("file1.txt"), Paths.get("file2.txt")});
|
||||||
|
|
||||||
|
// Remove all the selected files
|
||||||
|
page.setInputFiles("input#upload", new Path[0]);
|
||||||
|
|
||||||
|
// Upload buffer from memory
|
||||||
|
page.setInputFiles("input#upload", new FilePayload(
|
||||||
|
"file.txt", "text/plain", "this is test".getBytes(StandardCharsets.UTF_8)));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Select one file
|
# Select one file
|
||||||
await page.set_input_files('input#upload', 'myfile.pdf')
|
await page.set_input_files('input#upload', 'myfile.pdf')
|
||||||
@ -498,6 +611,13 @@ const [fileChooser] = await Promise.all([
|
|||||||
await fileChooser.setFiles('myfile.pdf');
|
await fileChooser.setFiles('myfile.pdf');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
FileChooser fileChooser = page.waitForFileChooser(() -> {
|
||||||
|
page.click("upload");
|
||||||
|
});
|
||||||
|
fileChooser.setFiles(Paths.get("myfile.pdf"));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
async with page.expect_file_chooser() as fc_info:
|
async with page.expect_file_chooser() as fc_info:
|
||||||
await page.click("upload")
|
await page.click("upload")
|
||||||
@ -528,6 +648,10 @@ For the dynamic pages that handle focus events, you can focus the given element.
|
|||||||
await page.focus('input#name');
|
await page.focus('input#name');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.focus("input#name");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.focus('input#name')
|
await page.focus('input#name')
|
||||||
```
|
```
|
||||||
|
@ -44,6 +44,11 @@ configures Playwright for debugging and opens the inspector.
|
|||||||
await page.pause();
|
await page.pause();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Pause on the following line.
|
||||||
|
page.pause();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Pause on the following line.
|
# Pause on the following line.
|
||||||
await page.pause()
|
await page.pause()
|
||||||
|
@ -28,6 +28,27 @@ await userContext.addCookies(userCookies);
|
|||||||
await adminContext.addCookies(adminCookies);
|
await adminContext.addCookies(adminCookies);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// FIXME
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
// Create a Chromium browser instance
|
||||||
|
Browser browser = chromium.launch();
|
||||||
|
// Create two isolated browser contexts
|
||||||
|
BrowserContext userContext = browser.newContext();
|
||||||
|
BrowserContext adminContext = browser.newContext();
|
||||||
|
// Load user and admin cookies
|
||||||
|
userContext.addCookies(userCookies);
|
||||||
|
adminContext.addCookies(adminCookies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
@ -92,6 +113,15 @@ const pageTwo = await context.newPage();
|
|||||||
const allPages = context.pages();
|
const allPages = context.pages();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Create two pages
|
||||||
|
Page pageOne = context.newPage();
|
||||||
|
Page pageTwo = context.newPage();
|
||||||
|
|
||||||
|
// Get pages of a brower context
|
||||||
|
List<Page> allPages = context.pages();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# create two pages
|
# create two pages
|
||||||
page_one = await context.new_page()
|
page_one = await context.new_page()
|
||||||
@ -130,6 +160,15 @@ await newPage.waitForLoadState();
|
|||||||
console.log(await newPage.title());
|
console.log(await newPage.title());
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get page after a specific action (e.g. clicking a link)
|
||||||
|
Page newPage = context.waitForPage(() -> {
|
||||||
|
page.click("a[target='_blank']"); // Opens a new tab
|
||||||
|
});
|
||||||
|
newPage.waitForLoadState();
|
||||||
|
System.out.println(newPage.title());
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get page after a specific action (e.g. clicking a link)
|
# Get page after a specific action (e.g. clicking a link)
|
||||||
async with context.expect_page() as new_page_info:
|
async with context.expect_page() as new_page_info:
|
||||||
@ -160,6 +199,14 @@ context.on('page', async page => {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get all new pages (including popups) in the context
|
||||||
|
context.onPage(page -> {
|
||||||
|
page.waitForLoadState();
|
||||||
|
System.out.println(page.title());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get all new pages (including popups) in the context
|
# Get all new pages (including popups) in the context
|
||||||
async def handle_page(page):
|
async def handle_page(page):
|
||||||
@ -197,6 +244,15 @@ await popup.waitForLoadState();
|
|||||||
console.log(await popup.title());
|
console.log(await popup.title());
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get popup after a specific action (e.g., click)
|
||||||
|
Page popup = page.waitForPopup(() -> {
|
||||||
|
page.click("#open");
|
||||||
|
});
|
||||||
|
popup.waitForLoadState();
|
||||||
|
System.out.println(popup.title());
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get popup after a specific action (e.g., click)
|
# Get popup after a specific action (e.g., click)
|
||||||
async with page.expect_popup() as popup_info:
|
async with page.expect_popup() as popup_info:
|
||||||
@ -227,6 +283,14 @@ page.on('popup', async popup => {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Get all popups when they open
|
||||||
|
page.onPopup(popup -> {
|
||||||
|
popup.waitForLoadState();
|
||||||
|
System.out.println(popup.title());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Get all popups when they open
|
# Get all popups when they open
|
||||||
async def handle_popup(popup):
|
async def handle_popup(popup):
|
||||||
|
@ -41,6 +41,11 @@ Navigating to a URL auto-waits for the page to fire the `load` event. If the pag
|
|||||||
await page.goto('https://example.com');
|
await page.goto('https://example.com');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Navigate the page
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Navigate the page
|
# Navigate the page
|
||||||
await page.goto("https://example.com")
|
await page.goto("https://example.com")
|
||||||
@ -60,6 +65,12 @@ Override the default behavior to wait until a specific event, like `networkidle`
|
|||||||
await page.goto('https://example.com', { waitUntil: 'networkidle' });
|
await page.goto('https://example.com', { waitUntil: 'networkidle' });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Navigate and wait until network is idle
|
||||||
|
page.navigate("https://example.com", new Page.NavigateOptions()
|
||||||
|
.withWaitUntil(WaitUntilState.NETWORKIDLE));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Navigate and wait until network is idle
|
# Navigate and wait until network is idle
|
||||||
await page.goto("https://example.com", wait_until="networkidle")
|
await page.goto("https://example.com", wait_until="networkidle")
|
||||||
@ -86,6 +97,17 @@ await page.goto('https://example.com');
|
|||||||
await page.click('text=Example Domain');
|
await page.click('text=Example Domain');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Navigate and wait for element
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
page.waitForSelector("text=Example Domain");
|
||||||
|
|
||||||
|
// Navigate and click element
|
||||||
|
// Click will auto-wait for the element
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
page.click("text=Example Domain");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Navigate and wait for element
|
# Navigate and wait for element
|
||||||
await page.goto("https://example.com")
|
await page.goto("https://example.com")
|
||||||
@ -126,10 +148,19 @@ the navigated page which would auto-wait for an element.
|
|||||||
```js
|
```js
|
||||||
// Click will auto-wait for navigation to complete
|
// Click will auto-wait for navigation to complete
|
||||||
await page.click('text=Login');
|
await page.click('text=Login');
|
||||||
|
|
||||||
// Fill will auto-wait for element on navigated page
|
// Fill will auto-wait for element on navigated page
|
||||||
await page.fill('#username', 'John Doe');
|
await page.fill('#username', 'John Doe');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Click will auto-wait for navigation to complete
|
||||||
|
page.click("text=Login");
|
||||||
|
|
||||||
|
// Fill will auto-wait for element on navigated page
|
||||||
|
page.fill("#username", "John Doe");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Click will auto-wait for navigation to complete
|
# Click will auto-wait for navigation to complete
|
||||||
await page.click("text=Login")
|
await page.click("text=Login")
|
||||||
@ -155,6 +186,11 @@ await page.click('button'); // Click triggers navigation
|
|||||||
await page.waitForLoadState('networkidle'); // This resolves after 'networkidle'
|
await page.waitForLoadState('networkidle'); // This resolves after 'networkidle'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.click("button"); // Click triggers navigation
|
||||||
|
page.waitForLoadState(LoadState.NETWORKIDLE); // This resolves after "networkidle"
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.click("button"); # Click triggers navigation
|
await page.click("button"); # Click triggers navigation
|
||||||
await page.wait_for_load_state("networkidle"); # This waits for the "networkidle"
|
await page.wait_for_load_state("networkidle"); # This waits for the "networkidle"
|
||||||
@ -171,10 +207,10 @@ In lazy-loaded pages, it can be useful to wait until an element is visible with
|
|||||||
Alternatively, page interactions like [`method: Page.click`] auto-wait for elements.
|
Alternatively, page interactions like [`method: Page.click`] auto-wait for elements.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Click triggers navigation
|
// Click will auto-wait for the element and trigger navigation
|
||||||
await page.click('text=Login');
|
await page.click('text=Login');
|
||||||
// Click will auto-wait for the element
|
// Wait for the element
|
||||||
await page.waitForSelector('#username', 'John Doe');
|
await page.waitForSelector('#username');
|
||||||
|
|
||||||
// Click triggers navigation
|
// Click triggers navigation
|
||||||
await page.click('text=Login');
|
await page.click('text=Login');
|
||||||
@ -182,11 +218,23 @@ await page.click('text=Login');
|
|||||||
await page.fill('#username', 'John Doe');
|
await page.fill('#username', 'John Doe');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Click will auto-wait for the element and trigger navigation
|
||||||
|
page.click("text=Login");
|
||||||
|
// Wait for the element
|
||||||
|
page.waitForSelector("#username");
|
||||||
|
|
||||||
|
// Click triggers navigation
|
||||||
|
page.click("text=Login");
|
||||||
|
// Fill will auto-wait for element
|
||||||
|
page.fill("#username", "John Doe");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Click triggers navigation
|
# Click will auto-wait for the element and trigger navigation
|
||||||
await page.click("text=Login")
|
await page.click("text=Login")
|
||||||
# Click will auto-wait for the element
|
# Wait for the element
|
||||||
await page.wait_for_selector("#username", "John Doe")
|
await page.wait_for_selector("#username")
|
||||||
|
|
||||||
# Click triggers navigation
|
# Click triggers navigation
|
||||||
await page.click("text=Login")
|
await page.click("text=Login")
|
||||||
@ -222,6 +270,14 @@ await Promise.all([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Using waitForNavigation with a callback prevents a race condition
|
||||||
|
// between clicking and waiting for a navigation.
|
||||||
|
page.waitForNavigation(() -> { // Waits for the next navigation
|
||||||
|
page.click("a"); // Triggers a navigation after a timeout
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Waits for the next navigation. Using Python context manager
|
# Waits for the next navigation. Using Python context manager
|
||||||
# prevents a race condition between clicking and waiting for a navigation.
|
# prevents a race condition between clicking and waiting for a navigation.
|
||||||
@ -254,6 +310,14 @@ await Promise.all([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Running action in the callback of waitForNavigation prevents a race
|
||||||
|
// condition between clicking and waiting for a navigation.
|
||||||
|
page.waitForNavigation(new Page.WaitForNavigationOptions().withUrl("**/login"), () -> {
|
||||||
|
page.click("a"); // Triggers a navigation with a script redirect
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Using Python context manager prevents a race condition
|
# Using Python context manager prevents a race condition
|
||||||
# between clicking and waiting for a navigation.
|
# between clicking and waiting for a navigation.
|
||||||
@ -283,6 +347,13 @@ const [ popup ] = await Promise.all([
|
|||||||
await popup.waitForLoadState('load');
|
await popup.waitForLoadState('load');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Page popup = page.waitForPopup(() -> {
|
||||||
|
page.click("a[target='_blank']"); // Opens popup
|
||||||
|
});
|
||||||
|
popup.waitForLoadState(LoadState.LOAD);
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
async with page.expect_popup() as popup_info:
|
async with page.expect_popup() as popup_info:
|
||||||
await page.click('a[target="_blank"]') # Opens popup
|
await page.click('a[target="_blank"]') # Opens popup
|
||||||
@ -316,6 +387,13 @@ await page.waitForFunction(() => window.amILoadedYet());
|
|||||||
await page.screenshot();
|
await page.screenshot();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.navigate("http://example.com");
|
||||||
|
page.waitForFunction("() => window.amILoadedYet()");
|
||||||
|
// Ready to take a screenshot, according to the page itself.
|
||||||
|
page.screenshot();
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.goto("http://example.com")
|
await page.goto("http://example.com")
|
||||||
await page.wait_for_function("() => window.amILoadedYet()")
|
await page.wait_for_function("() => window.amILoadedYet()")
|
||||||
|
@ -24,6 +24,13 @@ const page = await context.newPage();
|
|||||||
await page.goto('https://example.com');
|
await page.goto('https://example.com');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withHttpCredentials("bill", "pa55w0rd"));
|
||||||
|
Page page = context.newPage();
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
http_credentials={"username": "bill", "password": "pa55w0rd"}
|
http_credentials={"username": "bill", "password": "pa55w0rd"}
|
||||||
@ -65,6 +72,24 @@ const { chromium, webkit, firefox } = require('playwright');
|
|||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try (Playwright playwright = Playwright.create()) {
|
||||||
|
BrowserType chromium = playwright.chromium();
|
||||||
|
Browser browser = chromium.launch();
|
||||||
|
Page page = browser.newPage();
|
||||||
|
page.onRequest(request -> System.out.println(">> " + request.method() + " " + request.url()));
|
||||||
|
page.onResponse(response -> System.out.println("<<" + response.status() + " " + response.url()));
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
import asyncio
|
import asyncio
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
@ -112,6 +137,13 @@ const [response] = await Promise.all([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Use a glob URL pattern
|
||||||
|
Response response = page.waitForResponse("**/api/fetch_data", () -> {
|
||||||
|
page.click("button#update");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Use a glob url pattern
|
# Use a glob url pattern
|
||||||
async with page.expect_response("**/api/fetch_data") as response_info:
|
async with page.expect_response("**/api/fetch_data") as response_info:
|
||||||
@ -142,6 +174,18 @@ const [response] = await Promise.all([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Use a RegExp
|
||||||
|
Response response = page.waitForResponse(Pattern.compile("\\.jpeg$"), () -> {
|
||||||
|
page.click("button#update");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use a predicate taking a Response object
|
||||||
|
Response response = page.waitForResponse(r -> r.url().contains(token), () -> {
|
||||||
|
page.click("button#update");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Use a regular expression
|
# Use a regular expression
|
||||||
async with page.expect_response(re.compile(r"\.jpeg$")) as response_info:
|
async with page.expect_response(re.compile(r"\.jpeg$")) as response_info:
|
||||||
@ -186,6 +230,13 @@ await page.route('**/api/fetch_data', route => route.fulfill({
|
|||||||
await page.goto('https://example.com');
|
await page.goto('https://example.com');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.route("**/api/fetch_data", route -> route.fulfill(new Route.FulfillOptions()
|
||||||
|
.withStatus(200)
|
||||||
|
.withBody(testData)));
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.route(
|
await page.route(
|
||||||
"**/api/fetch_data",
|
"**/api/fetch_data",
|
||||||
@ -215,6 +266,13 @@ await browserContext.route('**/api/login', route => route.fulfill({
|
|||||||
await page.goto('https://example.com');
|
await page.goto('https://example.com');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
browserContext.route("**/api/login", route -> route.fulfill(new Route.FulfillOptions()
|
||||||
|
.withStatus(200)
|
||||||
|
.withBody("accept")));
|
||||||
|
page.navigate("https://example.com");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Set up route on the entire browser context.
|
# Set up route on the entire browser context.
|
||||||
# It will apply to popup windows and opened links.
|
# It will apply to popup windows and opened links.
|
||||||
@ -256,6 +314,18 @@ await page.route('**/*', route => {
|
|||||||
await page.route('**/*', route => route.continue({method: 'POST'}));
|
await page.route('**/*', route => route.continue({method: 'POST'}));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Delete header
|
||||||
|
page.route("**/*", route -> {
|
||||||
|
Map<String, String> headers = new HashMap<>(route.request().headers());
|
||||||
|
headers.remove("X-Secret");
|
||||||
|
route.resume(new Route.ResumeOptions().withHeaders(headers));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Continue requests as POST.
|
||||||
|
page.route("**/*", route -> route.resume(new Route.ResumeOptions().withMethod("POST")));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Delete header
|
# Delete header
|
||||||
async def handle_route(route):
|
async def handle_route(route):
|
||||||
@ -294,6 +364,18 @@ await page.route('**/*', route => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.route("**/*.{png,jpg,jpeg}", route -> route.abort());
|
||||||
|
|
||||||
|
// Abort based on the request type
|
||||||
|
page.route("**/*", route -> {
|
||||||
|
if ("image".equals(route.request().resourceType()))
|
||||||
|
route.abort();
|
||||||
|
else
|
||||||
|
route.resume();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())
|
await page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())
|
||||||
|
|
||||||
|
@ -39,6 +39,30 @@ class SearchPage {
|
|||||||
module.exports = { SearchPage };
|
module.exports = { SearchPage };
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// models/SearchPage.java
|
||||||
|
package models;
|
||||||
|
|
||||||
|
import com.microsoft.playwright;
|
||||||
|
|
||||||
|
public class SearchPage {
|
||||||
|
private final Page page;
|
||||||
|
|
||||||
|
public SearchPage(Page page) {
|
||||||
|
this.page = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void navigate() {
|
||||||
|
page.navigate("https://bing.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void search(String text) {
|
||||||
|
page.fill("[aria-label='Enter your search term']", text);
|
||||||
|
page.press("[aria-label='Enter your search term']", "Enter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# models/search.py
|
# models/search.py
|
||||||
class SearchPage:
|
class SearchPage:
|
||||||
@ -80,6 +104,18 @@ await searchPage.navigate();
|
|||||||
await searchPage.search('search query');
|
await searchPage.search('search query');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import models.SearchPage;
|
||||||
|
import com.microsoft.playwright.*;
|
||||||
|
...
|
||||||
|
|
||||||
|
// In the test
|
||||||
|
Page page = browser.newPage();
|
||||||
|
SearchPage searchPage = new SearchPage(page);
|
||||||
|
searchPage.navigate();
|
||||||
|
searchPage.search("search query");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# test_search.py
|
# test_search.py
|
||||||
from models.search import SearchPage
|
from models.search import SearchPage
|
||||||
|
@ -30,6 +30,12 @@ tall screen and the page could fit it entirely.
|
|||||||
await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.screenshot(new Page.ScreenshotOptions()
|
||||||
|
.withPath(Paths.get("screenshot.png"))
|
||||||
|
.withFullPage(true));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.screenshot(path="screenshot.png", full_page=True)
|
await page.screenshot(path="screenshot.png", full_page=True)
|
||||||
```
|
```
|
||||||
@ -47,6 +53,11 @@ const buffer = await page.screenshot();
|
|||||||
console.log(buffer.toString('base64'));
|
console.log(buffer.toString('base64'));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
byte[] buffer = page.screenshot();
|
||||||
|
System.out.println(Base64.getEncoder().encode(buffer));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Capture into Image
|
# Capture into Image
|
||||||
screenshot_bytes = await page.screenshot()
|
screenshot_bytes = await page.screenshot()
|
||||||
@ -67,6 +78,11 @@ const elementHandle = await page.$('.header');
|
|||||||
await elementHandle.screenshot({ path: 'screenshot.png' });
|
await elementHandle.screenshot({ path: 'screenshot.png' });
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
ElementHandle elementHandle = page.querySelector(".header");
|
||||||
|
elementHandle.screenshot(new ElementHandle.ScreenshotOptions().withPath(Paths.get("screenshot.png")));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
element_handle = await page.query_selector(".header")
|
element_handle = await page.query_selector(".header")
|
||||||
await element_handle.screenshot(path="screenshot.png")
|
await element_handle.screenshot(path="screenshot.png")
|
||||||
|
@ -15,6 +15,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click('text=Log in');
|
await page.click('text=Log in');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("text=Log in");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("text=Log in")
|
await page.click("text=Log in")
|
||||||
```
|
```
|
||||||
@ -27,6 +30,10 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
await page.click('button');
|
await page.click('button');
|
||||||
await page.click('#nav-bar .contact-us-item');
|
await page.click('#nav-bar .contact-us-item');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("button");
|
||||||
|
page.click("#nav-bar .contact-us-item");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("button")
|
await page.click("button")
|
||||||
await page.click("#nav-bar .contact-us-item")
|
await page.click("#nav-bar .contact-us-item")
|
||||||
@ -41,6 +48,10 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
await page.click('[data-test=login-button]');
|
await page.click('[data-test=login-button]');
|
||||||
await page.click('[aria-label="Sign in"]');
|
await page.click('[aria-label="Sign in"]');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("[data-test=login-button]");
|
||||||
|
page.click("[aria-label='Sign in']");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("[data-test=login-button]")
|
await page.click("[data-test=login-button]")
|
||||||
await page.click("[aria-label='Sign in']")
|
await page.click("[aria-label='Sign in']")
|
||||||
@ -55,6 +66,10 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
await page.click('article:has-text("Playwright")');
|
await page.click('article:has-text("Playwright")');
|
||||||
await page.click('#nav-bar :text("Contact us")');
|
await page.click('#nav-bar :text("Contact us")');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("article:has-text(\"Playwright\")");
|
||||||
|
page.click("#nav-bar :text(\"Contact us\")");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("article:has-text('Playwright')")
|
await page.click("article:has-text('Playwright')")
|
||||||
await page.click("#nav-bar :text('Contact us')")
|
await page.click("#nav-bar :text('Contact us')")
|
||||||
@ -68,6 +83,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click('.item-description:has(.item-promo-banner)');
|
await page.click('.item-description:has(.item-promo-banner)');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click(".item-description:has(.item-promo-banner)");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click(".item-description:has(.item-promo-banner)")
|
await page.click(".item-description:has(.item-promo-banner)")
|
||||||
```
|
```
|
||||||
@ -79,6 +97,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click('input:right-of(:text("Username"))');
|
await page.click('input:right-of(:text("Username"))');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("input:right-of(:text(\"Username\"))");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("input:right-of(:text('Username'))")
|
await page.click("input:right-of(:text('Username'))")
|
||||||
```
|
```
|
||||||
@ -90,6 +111,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click('.login-button:visible');
|
await page.click('.login-button:visible');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click(".login-button:visible");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click(".login-button:visible")
|
await page.click(".login-button:visible")
|
||||||
```
|
```
|
||||||
@ -101,6 +125,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click(':nth-match(:text("Buy"), 3)');
|
await page.click(':nth-match(:text("Buy"), 3)');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click(":nth-match(:text('Buy'), 3)");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click(":nth-match(:text('Buy'), 3)"
|
await page.click(":nth-match(:text('Buy'), 3)"
|
||||||
```
|
```
|
||||||
@ -112,6 +139,9 @@ methods accept [`param: selector`] as their first argument.
|
|||||||
```js
|
```js
|
||||||
await page.click('xpath=//button');
|
await page.click('xpath=//button');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("xpath=//button");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("xpath=//button")
|
await page.click("xpath=//button")
|
||||||
```
|
```
|
||||||
@ -127,6 +157,9 @@ Text selector locates elements that contain passed text.
|
|||||||
```js
|
```js
|
||||||
await page.click('text=Log in');
|
await page.click('text=Log in');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("text=Log in");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("text=Log in")
|
await page.click("text=Log in")
|
||||||
```
|
```
|
||||||
@ -141,6 +174,9 @@ Text selector has a few variations:
|
|||||||
```js
|
```js
|
||||||
await page.click('text=Log in');
|
await page.click('text=Log in');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("text=Log in");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("text=Log in")
|
await page.click("text=Log in")
|
||||||
```
|
```
|
||||||
@ -155,6 +191,9 @@ Text selector has a few variations:
|
|||||||
```js
|
```js
|
||||||
await page.click('text="Log in"');
|
await page.click('text="Log in"');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("text='Log in'");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("text='Log in'")
|
await page.click("text='Log in'")
|
||||||
```
|
```
|
||||||
@ -167,6 +206,9 @@ Text selector has a few variations:
|
|||||||
```js
|
```js
|
||||||
await page.click('"Log in"');
|
await page.click('"Log in"');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("'Log in'");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("'Log in'")
|
await page.click("'Log in'")
|
||||||
```
|
```
|
||||||
@ -179,6 +221,9 @@ Text selector has a few variations:
|
|||||||
```js
|
```js
|
||||||
await page.click('text=/Log\\s*in/i');
|
await page.click('text=/Log\\s*in/i');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("text=/Log\\s*in/i");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("text=/Log\s*in/i")
|
await page.click("text=/Log\s*in/i")
|
||||||
```
|
```
|
||||||
@ -195,6 +240,14 @@ Text selector has a few variations:
|
|||||||
// Correct, only matches the <article> element
|
// Correct, only matches the <article> element
|
||||||
await page.click('article:has-text("Playwright")');
|
await page.click('article:has-text("Playwright")');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Wrong, will match many elements including <body>
|
||||||
|
page.click(":has-text(\"Playwright\")");
|
||||||
|
// Correct, only matches the <article> element
|
||||||
|
page.click("article:has-text(\"Playwright\")");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Wrong, will match many elements including <body>
|
# Wrong, will match many elements including <body>
|
||||||
await page.click(':has-text("Playwright")')
|
await page.click(':has-text("Playwright")')
|
||||||
@ -213,6 +266,9 @@ Text selector has a few variations:
|
|||||||
```js
|
```js
|
||||||
await page.click('#nav-bar :text("Home")');
|
await page.click('#nav-bar :text("Home")');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("#nav-bar :text('Home')");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("#nav-bar :text('Home')")
|
await page.click("#nav-bar :text('Home')")
|
||||||
```
|
```
|
||||||
@ -242,6 +298,10 @@ Playwright augments standard CSS selectors in two ways:
|
|||||||
await page.click('button');
|
await page.click('button');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.click("button");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.click("button")
|
await page.click("button")
|
||||||
```
|
```
|
||||||
@ -275,6 +335,10 @@ Consider a page with two buttons, first invisible and second visible.
|
|||||||
await page.click('button');
|
await page.click('button');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.click("button");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.click("button")
|
await page.click("button")
|
||||||
```
|
```
|
||||||
@ -288,6 +352,9 @@ Consider a page with two buttons, first invisible and second visible.
|
|||||||
```js
|
```js
|
||||||
await page.click('button:visible');
|
await page.click('button:visible');
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
page.click("button:visible");
|
||||||
|
```
|
||||||
```python async
|
```python async
|
||||||
await page.click("button:visible")
|
await page.click("button:visible")
|
||||||
```
|
```
|
||||||
@ -310,6 +377,10 @@ Following snippet returns text content of an `<article>` element that has a `<di
|
|||||||
await page.textContent('article:has(div.promo)');
|
await page.textContent('article:has(div.promo)');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.textContent("article:has(div.promo)");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.textContent("article:has(div.promo)")
|
await page.textContent("article:has(div.promo)")
|
||||||
```
|
```
|
||||||
@ -330,6 +401,11 @@ selectors in a more compact form.
|
|||||||
await page.click(':is(button:has-text("Log in"), button:has-text("Sign in"))');
|
await page.click(':is(button:has-text("Log in"), button:has-text("Sign in"))');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Clicks a <button> that has either a "Log in" or "Sign in" text.
|
||||||
|
page.click(":is(button:has-text(\"Log in\"), button:has-text(\"Sign in\"))");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Clicks a <button> that has either a "Log in" or "Sign in" text.
|
# Clicks a <button> that has either a "Log in" or "Sign in" text.
|
||||||
await page.click(':is(button:has-text("Log in"), button:has-text("Sign in"))')
|
await page.click(':is(button:has-text("Log in"), button:has-text("Sign in"))')
|
||||||
@ -357,6 +433,10 @@ If you'd like to opt-out of this behavior, you can use `:light` CSS extension or
|
|||||||
await page.click(':light(.article > .header)');
|
await page.click(':light(.article > .header)');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.click(":light(.article > .header)");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
await page.click(":light(.article > .header)")
|
await page.click(":light(.article > .header)")
|
||||||
```
|
```
|
||||||
@ -419,6 +499,14 @@ await page.fill('input:right-of(:text("Username"))', 'value');
|
|||||||
await page.click('button:near(.promo-card)');
|
await page.click('button:near(.promo-card)');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Fill an input to the right of "Username".
|
||||||
|
page.fill("input:right-of(:text(\"Username\"))", "value");
|
||||||
|
|
||||||
|
// Click a button near the promo card.
|
||||||
|
page.click("button:near(.promo-card)");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Fill an input to the right of "Username".
|
# Fill an input to the right of "Username".
|
||||||
await page.fill('input:right-of(:text("Username"))', 'value')
|
await page.fill('input:right-of(:text("Username"))', 'value')
|
||||||
@ -465,6 +553,14 @@ await page.fill('id=username', 'value');
|
|||||||
await page.click('data-test-id=submit');
|
await page.click('data-test-id=submit');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Fill an input with the id "username"
|
||||||
|
page.fill("id=username", "value");
|
||||||
|
|
||||||
|
// Click an element with data-test-id "submit"
|
||||||
|
page.click("data-test-id=submit");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Fill an input with the id "username"
|
# Fill an input with the id "username"
|
||||||
await page.fill('id=username', 'value')
|
await page.fill('id=username', 'value')
|
||||||
@ -503,6 +599,11 @@ In this case, `:nth-match(:text("Buy"), 3)` will select the third button from th
|
|||||||
await page.click(':nth-match(:text("Buy"), 3)');
|
await page.click(':nth-match(:text("Buy"), 3)');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Click the third "Buy" button
|
||||||
|
page.click(":nth-match(:text('Buy'), 3)");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Click the third "Buy" button
|
# Click the third "Buy" button
|
||||||
await page.click(":nth-match(:text('Buy'), 3)"
|
await page.click(":nth-match(:text('Buy'), 3)"
|
||||||
@ -520,6 +621,11 @@ page.click(":nth-match(:text('Buy'), 3)"
|
|||||||
await page.waitForSelector(':nth-match(:text("Buy"), 3)');
|
await page.waitForSelector(':nth-match(:text("Buy"), 3)');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Wait until all three buttons are visible
|
||||||
|
page.waitForSelector(":nth-match(:text('Buy'), 3)");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Wait until all three buttons are visible
|
# Wait until all three buttons are visible
|
||||||
await page.wait_for_selector(":nth-match(:text('Buy'), 3)")
|
await page.wait_for_selector(":nth-match(:text('Buy'), 3)")
|
||||||
@ -578,8 +684,8 @@ await page.click('text="Login"');
|
|||||||
await page.click('"Login"'); // short-form
|
await page.click('"Login"'); // short-form
|
||||||
|
|
||||||
// queries "Search GitHub" placeholder attribute
|
// queries "Search GitHub" placeholder attribute
|
||||||
await page.fill('css=[placeholder="Search GitHub"]');
|
await page.fill('css=[placeholder="Search GitHub"]', 'query');
|
||||||
await page.fill('[placeholder="Search GitHub"]'); // short-form
|
await page.fill('[placeholder="Search GitHub"]', 'query'); // short-form
|
||||||
|
|
||||||
// queries "Close" accessibility label
|
// queries "Close" accessibility label
|
||||||
await page.click('css=[aria-label="Close"]');
|
await page.click('css=[aria-label="Close"]');
|
||||||
@ -589,14 +695,31 @@ await page.click('[aria-label="Close"]'); // short-form
|
|||||||
await page.click('css=nav >> text=Login');
|
await page.click('css=nav >> text=Login');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// queries "Login" text selector
|
||||||
|
page.click("text=\"Login\"");
|
||||||
|
page.click("\"Login\""); // short-form
|
||||||
|
|
||||||
|
// queries "Search GitHub" placeholder attribute
|
||||||
|
page.fill("css=[placeholder='Search GitHub']", "query");
|
||||||
|
page.fill("[placeholder='Search GitHub']", "query"); // short-form
|
||||||
|
|
||||||
|
// queries "Close" accessibility label
|
||||||
|
page.click("css=[aria-label='Close']");
|
||||||
|
page.click("[aria-label='Close']"); // short-form
|
||||||
|
|
||||||
|
// combine role and text queries
|
||||||
|
page.click("css=nav >> text=Login");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# queries "Login" text selector
|
# queries "Login" text selector
|
||||||
await page.click('text="Login"')
|
await page.click('text="Login"')
|
||||||
await page.click('"Login"') # short-form
|
await page.click('"Login"') # short-form
|
||||||
|
|
||||||
# queries "Search GitHub" placeholder attribute
|
# queries "Search GitHub" placeholder attribute
|
||||||
await page.fill('css=[placeholder="Search GitHub"]')
|
await page.fill('css=[placeholder="Search GitHub"]', 'query')
|
||||||
await page.fill('[placeholder="Search GitHub"]') # short-form
|
await page.fill('[placeholder="Search GitHub"]', 'query') # short-form
|
||||||
|
|
||||||
# queries "Close" accessibility label
|
# queries "Close" accessibility label
|
||||||
await page.click('css=[aria-label="Close"]')
|
await page.click('css=[aria-label="Close"]')
|
||||||
@ -640,6 +763,15 @@ await page.click('[data-test-id=directions]'); // short-form
|
|||||||
await page.click('data-test-id=directions');
|
await page.click('data-test-id=directions');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// queries data-test-id attribute with css
|
||||||
|
page.click("css=[data-test-id=directions]");
|
||||||
|
page.click("[data-test-id=directions]"); // short-form
|
||||||
|
|
||||||
|
// queries data-test-id with id
|
||||||
|
page.click("data-test-id=directions");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# queries data-test-id attribute with css
|
# queries data-test-id attribute with css
|
||||||
await page.click('css=[data-test-id=directions]')
|
await page.click('css=[data-test-id=directions]')
|
||||||
@ -669,6 +801,12 @@ await page.click('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.
|
|||||||
await page.click('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input');
|
await page.click('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// avoid long css or xpath chains
|
||||||
|
page.click("#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input");
|
||||||
|
page.click("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# avoid long css or xpath chains
|
# avoid long css or xpath chains
|
||||||
await page.click('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input')
|
await page.click('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input')
|
||||||
|
@ -33,6 +33,27 @@ await msg.args[0].jsonValue() // hello
|
|||||||
await msg.args[1].jsonValue() // 42
|
await msg.args[1].jsonValue() // 42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Listen for all System.out.printlns
|
||||||
|
page.onConsole(msg -> System.out.println(msg.text()));
|
||||||
|
|
||||||
|
// Listen for all console events and handle errors
|
||||||
|
page.onConsole(msg -> {
|
||||||
|
if ("error".equals(msg.type()))
|
||||||
|
System.out.println("Error text: " + msg.text());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the next System.out.println
|
||||||
|
ConsoleMessage msg = page.waitForConsoleMessage(() -> {
|
||||||
|
// Issue console.log inside the page
|
||||||
|
page.evaluate("console.log('hello', 42, { foo: 'bar' });");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Deconstruct console.log arguments
|
||||||
|
msg.args().get(0).jsonValue() // hello
|
||||||
|
msg.args().get(1).jsonValue() // 42
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Listen for all console logs
|
# Listen for all console logs
|
||||||
page.on("console", msg => print(msg.text))
|
page.on("console", msg => print(msg.text))
|
||||||
@ -90,6 +111,16 @@ page.on('pageerror', exception => {
|
|||||||
await page.goto('data:text/html,<script>throw new Error("Test")</script>');
|
await page.goto('data:text/html,<script>throw new Error("Test")</script>');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Log all uncaught errors to the terminal
|
||||||
|
page.onPageError(exception -> {
|
||||||
|
System.out.println("Uncaught exception: " + exception);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Navigate to a page with an exception.
|
||||||
|
page.navigate("data:text/html,<script>throw new Error('Test')</script>");
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# Log all uncaught errors to the terminal
|
# Log all uncaught errors to the terminal
|
||||||
page.on("pageerror", lambda exc: print(f"uncaught exception: {exc}"))
|
page.on("pageerror", lambda exc: print(f"uncaught exception: {exc}"))
|
||||||
@ -122,6 +153,12 @@ page.on('requestfailed', request => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onRequestFailed(request -> {
|
||||||
|
System.out.println(request.url() + " " + request.failure());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
page.on("requestfailed", lambda request: print(request.url + " " + request.failure.error_text))
|
page.on("requestfailed", lambda request: print(request.url + " " + request.failure.error_text))
|
||||||
```
|
```
|
||||||
@ -134,6 +171,12 @@ page.on('dialog', dialog => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
page.onDialog(dialog -> {
|
||||||
|
dialog.accept();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
page.on("dialog", lambda dialog: dialog.accept())
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
```
|
```
|
||||||
@ -147,6 +190,12 @@ const [popup] = await Promise.all([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
Page popup = page.waitForPopup(() -> {
|
||||||
|
page.click("#open");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
async with page.expect_popup() as popup_info:
|
async with page.expect_popup() as popup_info:
|
||||||
await page.click("#open")
|
await page.click("#open")
|
||||||
|
@ -19,15 +19,32 @@ const page = await browser.newPage({ recordVideo: { dir: 'videos/' } });
|
|||||||
// Make sure to await close, so that videos are saved.
|
// Make sure to await close, so that videos are saved.
|
||||||
await page.close();
|
await page.close();
|
||||||
|
|
||||||
// [Optional] Specify video size; defaults to viewport size
|
// [Optional] Specify video size; defaults to viewport size scaled down to fit 800x800
|
||||||
const context = await browser.newContext({
|
const context = await browser.newContext({
|
||||||
recordVideo: {
|
recordVideo: {
|
||||||
dir: 'videos/',
|
dir: 'videos/',
|
||||||
size: { width: 800, height: 600 },
|
size: { width: 1024, height: 768 },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// With browser.newContext()
|
||||||
|
context = browser.newContext(new Browser.NewContextOptions().withRecordVideoDir(Paths.get("videos/")));
|
||||||
|
// Make sure to close, so that videos are saved.
|
||||||
|
context.close();
|
||||||
|
|
||||||
|
// With browser.newPage()
|
||||||
|
Page page = browser.newPage(new Browser.NewPageOptions().withRecordVideoDir(Paths.get("videos/")));
|
||||||
|
// Make sure to close, so that videos are saved.
|
||||||
|
page.close();
|
||||||
|
|
||||||
|
// [Optional] Specify video size; defaults to viewport size scaled down to fit 800x800
|
||||||
|
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
|
.withRecordVideoDir(Paths.get("videos/"))
|
||||||
|
.withRecordVideoSize(1024, 768));
|
||||||
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# With browser.new_context()
|
# With browser.new_context()
|
||||||
context = await browser.new_context(record_video_dir="videos/")
|
context = await browser.new_context(record_video_dir="videos/")
|
||||||
@ -39,10 +56,10 @@ page = await browser.new_page(record_video_dir="videos/")
|
|||||||
# Make sure to await close, so that videos are saved.
|
# Make sure to await close, so that videos are saved.
|
||||||
await page.close()
|
await page.close()
|
||||||
|
|
||||||
# [Optional] specify video size; defaults to viewport size
|
# [Optional] specify video size; defaults to viewport size scaled down to fit 800x800
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
record_video_dir="videos/",
|
record_video_dir="videos/",
|
||||||
record_video_size={"width": 800, "height": 600}
|
record_video_size={"width": 1024, "height": 768}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -57,10 +74,10 @@ page = browser.new_page(record_video_dir="videos/")
|
|||||||
# Make sure to close, so that videos are saved.
|
# Make sure to close, so that videos are saved.
|
||||||
page.close()
|
page.close()
|
||||||
|
|
||||||
# [Optional] specify video size; defaults to viewport size
|
# [Optional] specify video size; defaults to viewport size scaled down to fit 800x800
|
||||||
context = browser.new_context(
|
context = browser.new_context(
|
||||||
record_video_dir="videos/",
|
record_video_dir="videos/",
|
||||||
record_video_size={"width": 800, "height": 600}
|
record_video_size={"width": 1024, "height": 768}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -135,12 +135,12 @@ function multiplyComment(spec) {
|
|||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const name of fs.readdirSync("docs/src/api")) {
|
for (const name of fs.readdirSync("docs/src")) {
|
||||||
if (!name.endsWith(".md"))
|
if (!name.endsWith(".md"))
|
||||||
continue;
|
continue;
|
||||||
if (name.includes('android'))
|
if (name.includes('android'))
|
||||||
continue;
|
continue;
|
||||||
const inputFile = `docs/src/api/${name}`;
|
const inputFile = `docs/src/${name}`;
|
||||||
const fileline = fs.readFileSync(inputFile).toString();
|
const fileline = fs.readFileSync(inputFile).toString();
|
||||||
const nodes = md.parse(fileline);
|
const nodes = md.parse(fileline);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user