chore: add some Python language snippets (#4933)
This commit is contained in:
parent
07cb5f71e3
commit
77bfcd2c74
|
|
@ -35,6 +35,42 @@ const checked = await page.getAttribute('input', 'checked');
|
|||
assert(checked);
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Assert text content
|
||||
content = await page.text_content('nav:first-child')
|
||||
assert content == 'home'
|
||||
|
||||
# Assert inner text
|
||||
text = await page.inner_text('.selected')
|
||||
assert text == 'value'
|
||||
|
||||
# Assert inner HTML
|
||||
html = await page.inner_html('div.result')
|
||||
assert html == '<p>Result</p>'
|
||||
|
||||
# Assert `checked` attribute
|
||||
checked = await page.get_attribute('input', 'checked')
|
||||
assert checked
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Assert text content
|
||||
content = page.text_content('nav:first-child')
|
||||
assert content == 'home'
|
||||
|
||||
# Assert inner text
|
||||
text = page.inner_text('.selected')
|
||||
assert text == 'value'
|
||||
|
||||
# Assert inner HTML
|
||||
html = page.inner_html('div.result')
|
||||
assert html == '<p>Result</p>'
|
||||
|
||||
# Assert `checked` attribute
|
||||
checked = page.get_attribute('input', 'checked')
|
||||
assert checked
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.textContent`]
|
||||
|
|
@ -70,6 +106,32 @@ const classNames = await elementHandle.getAttribute('class');
|
|||
assert(classNames.includes('highlighted'));
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = await element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = await element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: ElementHandle.textContent`]
|
||||
|
|
@ -109,6 +171,44 @@ const length = await page.$$eval('li.selected', (items) => items.length);
|
|||
assert(length === 3);
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Assert local storage value
|
||||
user_id = page.evaluate("() => window.localStorage.getItem('user_id')")
|
||||
assert user_id
|
||||
|
||||
# Assert value for input element
|
||||
await page.wait_for_selector('#search')
|
||||
value = await page.eval_on_selector('#search', 'el => el.value')
|
||||
assert value == 'query'
|
||||
|
||||
# Assert computed style
|
||||
font_size = await page.eval_on_selector('div', 'el => window.getComputedStyle(el).fontSize')
|
||||
assert font_size == '16px'
|
||||
|
||||
# Assert list length
|
||||
length = await page.eval_on_selector_all('li.selected', '(items) => items.length')
|
||||
assert length == 3
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Assert local storage value
|
||||
user_id = page.evaluate("() => window.localStorage.getItem('user_id')")
|
||||
assert user_id
|
||||
|
||||
# Assert value for input element
|
||||
page.wait_for_selector('#search')
|
||||
value = page.eval_on_selector('#search', 'el => el.value')
|
||||
assert value == 'query'
|
||||
|
||||
# Assert computed style
|
||||
font_size = page.eval_on_selector('div', 'el => window.getComputedStyle(el).fontSize')
|
||||
assert font_size == '16px'
|
||||
|
||||
# Assert list length
|
||||
length = page.eval_on_selector_all('li.selected', '(items) => items.length')
|
||||
assert length == 3
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.evaluate`]
|
||||
|
|
|
|||
144
docs/src/auth.md
144
docs/src/auth.md
|
|
@ -36,6 +36,30 @@ await page.click('text=Submit');
|
|||
// Verify app is logged in
|
||||
```
|
||||
|
||||
```python-async
|
||||
page = await context.new_page()
|
||||
await page.goto('https://github.com/login')
|
||||
|
||||
# Interact with login form
|
||||
await page.click('text=Login')
|
||||
await page.fill('input[name="login"]', USERNAME)
|
||||
await page.fill('input[name="password"]', PASSWORD)
|
||||
await page.click('text=Submit')
|
||||
# Verify app is logged in
|
||||
```
|
||||
|
||||
```python-sync
|
||||
page = context.new_page()
|
||||
page.goto('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
|
||||
```
|
||||
|
||||
These steps can be executed for every browser context. However, redoing login
|
||||
for every test can slow down test execution. To prevent that, we will reuse
|
||||
existing authentication state in new browser contexts.
|
||||
|
|
@ -67,6 +91,30 @@ const deserializedCookies = JSON.parse(process.env.COOKIES)
|
|||
await context.addCookies(deserializedCookies);
|
||||
```
|
||||
|
||||
```python-async
|
||||
import json
|
||||
import os
|
||||
# Get cookies and store as an env variable
|
||||
cookies = await context.cookies()
|
||||
os.environ["COOKIES"] = json.dumps(cookies)
|
||||
|
||||
# Set cookies in a new context
|
||||
deserialized_cookies = json.loads(os.environ["COOKIES"])
|
||||
await context.add_cookies(deserialized_cookies)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
import json
|
||||
import os
|
||||
# Get cookies and store as an env variable
|
||||
cookies = context.cookies()
|
||||
os.environ["COOKIES"] = json.dumps(cookies)
|
||||
|
||||
# Set cookies in a new context
|
||||
deserialized_cookies = json.loads(os.environ["COOKIES"])
|
||||
context.add_cookies(deserialized_cookies)
|
||||
```
|
||||
|
||||
### Local storage
|
||||
Local storage ([`window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage))
|
||||
is specific to a particular domain.
|
||||
|
|
@ -88,6 +136,44 @@ await context.addInitScript(storage => {
|
|||
}, localStorage);
|
||||
```
|
||||
|
||||
```python-async
|
||||
import os
|
||||
import json
|
||||
# Get local storage and store as env variable
|
||||
local_storage = await page.evaluate("() => JSON.stringify(window.localStorage))
|
||||
os.environ["LOCAL_STORAGE"] = local_storage
|
||||
|
||||
# Set local storage in a new context
|
||||
local_storage = os.environ["LOCAL_STORAGE"]
|
||||
await context.add_init_script("""storage => {
|
||||
if (window.location.hostname == 'example.com') {
|
||||
entries = JSON.parse(storage)
|
||||
Object.keys(entries).forEach(key => {
|
||||
window.localStorage.setItem(key, entries[key])
|
||||
})
|
||||
}
|
||||
}""", local_storage)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
import os
|
||||
import json
|
||||
# Get local storage and store as env variable
|
||||
local_storage = page.evaluate("() => JSON.stringify(window.localStorage)")
|
||||
os.environ["LOCAL_STORAGE"] = local_storage
|
||||
|
||||
# Set local storage in a new context
|
||||
local_storage = os.environ["LOCAL_STORAGE"]
|
||||
context.add_init_script("""storage => {
|
||||
if (window.location.hostname == 'example.com') {
|
||||
entries = JSON.parse(storage)
|
||||
Object.keys(entries).forEach(key => {
|
||||
window.localStorage.setItem(key, entries[key])
|
||||
})
|
||||
}
|
||||
}""", local_storage)
|
||||
```
|
||||
|
||||
### Session storage
|
||||
Session storage ([`window.sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage))
|
||||
is specific to a particular domain.
|
||||
|
|
@ -109,6 +195,42 @@ await context.addInitScript(storage => {
|
|||
}, sessionStorage);
|
||||
```
|
||||
|
||||
```python-async
|
||||
import os
|
||||
# Get session storage and store as env variable
|
||||
session_storage = await page.evaluate("() => JSON.stringify(sessionStorage)")
|
||||
os.environ["SESSION_STORAGE"] = session_storage
|
||||
|
||||
# Set session storage in a new context
|
||||
session_storage = os.environ["SESSION_STORAGE"]
|
||||
await context.add_init_script(storage => {
|
||||
if (window.location.hostname == 'example.com') {
|
||||
entries = JSON.parse(storage)
|
||||
Object.keys(entries).forEach(key => {
|
||||
window.sessionStorage.setItem(key, entries[key])
|
||||
})
|
||||
}
|
||||
}, session_storage)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
import os
|
||||
# Get session storage and store as env variable
|
||||
session_storage = page.evaluate("() => JSON.stringify(sessionStorage)")
|
||||
os.environ["SESSION_STORAGE"] = session_storage
|
||||
|
||||
# Set session storage in a new context
|
||||
session_storage = os.environ["SESSION_STORAGE"]
|
||||
context.add_init_script(storage => {
|
||||
if (window.location.hostname == 'example.com') {
|
||||
entries = JSON.parse(storage)
|
||||
Object.keys(entries).forEach(key => {
|
||||
window.sessionStorage.setItem(key, entries[key])
|
||||
})
|
||||
}
|
||||
}, session_storage)
|
||||
```
|
||||
|
||||
### Lifecycle
|
||||
|
||||
Logging in via the UI and then reusing authentication state can be combined to
|
||||
|
|
@ -157,6 +279,28 @@ const context = await chromium.launchPersistentContext(userDataDir, { headless:
|
|||
// Execute login steps manually in the browser window
|
||||
```
|
||||
|
||||
```python-async
|
||||
import asyncio
|
||||
from playwright import async_playwright
|
||||
|
||||
async def main():
|
||||
async with async_playwright() as p:
|
||||
user_data_dir = '/path/to/directory'
|
||||
browser = await p.chromium.launch_persistent_context(userDataDir, headless=False)
|
||||
# Execute login steps manually in the browser window
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
user_data_dir = '/path/to/directory'
|
||||
browser = p.chromium.launch_persistent_context(user_data_dir, headless=False)
|
||||
# Execute login steps manually in the browser window
|
||||
```
|
||||
|
||||
### Lifecycle
|
||||
|
||||
1. Create a user data directory on disk
|
||||
|
|
|
|||
|
|
@ -50,6 +50,18 @@ Suggested configuration
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
browser = await playwright.chromium.launch(
|
||||
args=['--disable-dev-shm-usage']
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
browser = playwright.chromium.launch({
|
||||
args=['--disable-dev-shm-usage']
|
||||
})
|
||||
```
|
||||
|
||||
This will write shared memory files into `/tmp` instead of `/dev/shm`. See
|
||||
[crbug.com/736452](https://bugs.chromium.org/p/chromium/issues/detail?id=736452) for more details.
|
||||
1. Using `--ipc=host` is also recommended when using Chromium—without it Chromium can run out of memory
|
||||
|
|
@ -191,6 +203,14 @@ const { chromium } = require('playwright');
|
|||
const browser = await chromium.launch({ chromiumSandbox: false });
|
||||
```
|
||||
|
||||
```python-async
|
||||
browser = await playwright.chromium.launch(chromiumSandbox=False)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
browser = playwright.chromium.launch(chromiumSandbox=False)
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
||||
To run Playwright tests on GitLab, use our public Docker image ([see Dockerfile](./docker.md)).
|
||||
|
|
@ -267,6 +287,26 @@ const { chromium } = require('playwright');
|
|||
const browser = await chromium.launch({ headless: false });
|
||||
```
|
||||
|
||||
```python-async
|
||||
import asyncio
|
||||
from playwright import async_playwright
|
||||
|
||||
async def main():
|
||||
async with async_playwright() as p:
|
||||
# Works across chromium, firefox and webkit
|
||||
browser = await p.chromium.launch(headless=False)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
# Works across chromium, firefox and webkit
|
||||
browser = p.chromium.launch(headless=False)
|
||||
```
|
||||
|
||||
On Linux agents, headful execution requires [Xvfb](https://en.wikipedia.org/wiki/Xvfb) to be installed. Our [Docker image](./docker.md) and GitHub Action have Xvfb pre-installed. To run browsers in headful mode with Xvfb, add `xvfb-run` before the Node.js command.
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -29,6 +29,26 @@ const browser = await chromium.launch({ headless: false });
|
|||
await browser.close();
|
||||
```
|
||||
|
||||
```python-async
|
||||
import asyncio
|
||||
from playwright import async_playwright
|
||||
|
||||
async def main():
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=False)
|
||||
await browser.close()
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=False)
|
||||
browser.close()
|
||||
```
|
||||
|
||||
Launching a browser instance can be expensive, and Playwright is designed to
|
||||
maximize what a single instance can do through multiple browser contexts.
|
||||
|
||||
|
|
@ -49,6 +69,16 @@ const browser = await chromium.launch();
|
|||
const context = await browser.newContext();
|
||||
```
|
||||
|
||||
```python-async
|
||||
browser = await playwright.chromium.launch()
|
||||
context = await browser.new_context()
|
||||
```
|
||||
|
||||
```python-sync
|
||||
browser = playwright.chromium.launch()
|
||||
context = browser.new_context()
|
||||
```
|
||||
|
||||
Browser contexts can also be used to emulate multi-page scenarios involving
|
||||
mobile devices, permissions, locale and color scheme.
|
||||
|
||||
|
|
@ -65,6 +95,42 @@ const context = await browser.newContext({
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
import asyncio
|
||||
from playwright import async_playwright
|
||||
|
||||
async def main():
|
||||
async with async_playwright() as p:
|
||||
iphone_11 = p.devices['iPhone 11 Pro']
|
||||
browser = await p.chromium.launch()
|
||||
context = await browser.new_context(
|
||||
**iphone_11,
|
||||
locale='de-DE',
|
||||
geolocation={ 'longitude': 12.492507, 'latitude': 41.889938 },
|
||||
permissions=['geolocation'],
|
||||
color_scheme='dark',
|
||||
)
|
||||
page = await browser.newPage()
|
||||
await browser.close()
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
iphone_11 = p.devices['iPhone 11 Pro']
|
||||
browser = p.webkit.launch(headless=False)
|
||||
context = browser.new_context(
|
||||
**iphone_11,
|
||||
locale='de-DE',
|
||||
geolocation={ 'longitude': 12.492507, 'latitude': 41.889938 },
|
||||
permissions=['geolocation']
|
||||
)
|
||||
browser.close()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [BrowserContext]
|
||||
|
|
@ -95,6 +161,40 @@ console.log(page.url());
|
|||
window.location.href = 'https://example.com';
|
||||
```
|
||||
|
||||
```python-async
|
||||
page = await context.new_page()
|
||||
|
||||
# Navigate explicitly, similar to entering a URL in the browser.
|
||||
await page.goto('http://example.com')
|
||||
# Fill an input.
|
||||
await page.fill('#search', 'query')
|
||||
|
||||
# Navigate implicitly by clicking a link.
|
||||
await page.click('#submit')
|
||||
# Expect a new url.
|
||||
print(page.url)
|
||||
|
||||
# Page can navigate from the script - this will be picked up by Playwright.
|
||||
# window.location.href = 'https://example.com'
|
||||
```
|
||||
|
||||
```python-sync
|
||||
page = context.new_page()
|
||||
|
||||
# Navigate explicitly, similar to entering a URL in the browser.
|
||||
page.goto('http://example.com')
|
||||
# Fill an input.
|
||||
page.fill('#search', 'query')
|
||||
|
||||
# Navigate implicitly by clicking a link.
|
||||
page.click('#submit')
|
||||
# Expect a new url.
|
||||
print(page.url)
|
||||
|
||||
# Page can navigate from the script - this will be picked up by Playwright.
|
||||
# window.location.href = 'https://example.com'
|
||||
```
|
||||
|
||||
> Read more on [page navigation and loading](./navigations.md).
|
||||
|
||||
A page can have one or more [Frame] objects attached to
|
||||
|
|
@ -119,6 +219,36 @@ const frame = await frameElementHandle.contentFrame();
|
|||
await frame.fill('#username-input', 'John');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Get frame using the frame's name attribute
|
||||
frame = page.frame('frame-login')
|
||||
|
||||
# Get frame using frame's URL
|
||||
frame = page.frame(url=r'.*domain.*')
|
||||
|
||||
# Get frame using any other selector
|
||||
frame_element_handle = await page.query_selector('.frame-class')
|
||||
frame = await frame_element_handle.content_frame()
|
||||
|
||||
# Interact with the frame
|
||||
await frame.fill('#username-input', 'John')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Get frame using the frame's name attribute
|
||||
frame = page.frame('frame-login')
|
||||
|
||||
# Get frame using frame's URL
|
||||
frame = page.frame(url=r'.*domain.*')
|
||||
|
||||
# Get frame using any other selector
|
||||
frame_element_handle = page.query_selector('.frame-class')
|
||||
frame = frame_element_handle.content_frame()
|
||||
|
||||
# Interact with the frame
|
||||
frame.fill('#username-input', 'John')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [Page]
|
||||
|
|
@ -144,28 +274,82 @@ Some examples below:
|
|||
await page.click('data-test-id=foo');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Using data-test-id= selector engine
|
||||
await page.click('data-test-id=foo')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Using data-test-id= selector engine
|
||||
page.click('data-test-id=foo')
|
||||
```
|
||||
|
||||
```js
|
||||
// CSS and XPath selector engines are automatically detected
|
||||
await page.click('div');
|
||||
await page.click('//html/body/div');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# CSS and XPath selector engines are automatically detected
|
||||
await page.click('div')
|
||||
await page.click('//html/body/div')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# CSS and XPath selector engines are automatically detected
|
||||
page.click('div')
|
||||
page.click('//html/body/div')
|
||||
```
|
||||
|
||||
```js
|
||||
// Find node by text substring
|
||||
await page.click('text=Hello w');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Find node by text substring
|
||||
await page.click('text=Hello w')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Find node by text substring
|
||||
page.click('text=Hello w')
|
||||
```
|
||||
|
||||
```js
|
||||
// Explicit CSS and XPath notation
|
||||
await page.click('css=div');
|
||||
await page.click('xpath=//html/body/div');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Explicit CSS and XPath notation
|
||||
await page.click('css=div')
|
||||
await page.click('xpath=//html/body/div')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Explicit CSS and XPath notation
|
||||
page.click('css=div')
|
||||
page.click('xpath=//html/body/div')
|
||||
```
|
||||
|
||||
```js
|
||||
// Only search light DOM, outside WebComponent shadow DOM:
|
||||
await page.click('css:light=div');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Only search light DOM, outside WebComponent shadow DOM:
|
||||
await page.click('css:light=div')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Only search light DOM, outside WebComponent shadow DOM:
|
||||
page.click('css:light=div')
|
||||
```
|
||||
|
||||
Selectors using the same or different engines can be combined using the `>>` separator. For example,
|
||||
|
||||
```js
|
||||
|
|
@ -173,11 +357,31 @@ Selectors using the same or different engines can be combined using the `>>` sep
|
|||
await page.click('#free-month-promo >> text=Sign Up');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Click an element with text 'Sign Up' inside of a #free-month-promo.
|
||||
await page.click('#free-month-promo >> text=Sign Up')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Click an element with text 'Sign Up' inside of a #free-month-promo.
|
||||
page.click('#free-month-promo >> text=Sign Up')
|
||||
```
|
||||
|
||||
```js
|
||||
// Capture textContent of a section that contains an element with text 'Selectors'.
|
||||
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent);
|
||||
```
|
||||
|
||||
```python-async
|
||||
# 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')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Capture textContent of a section that contains an element with text 'Selectors'.
|
||||
section_text = page.eval_on_selector('*css=section >> text=Selectors', 'e => e.textContent')
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
## Auto-waiting
|
||||
|
|
@ -196,12 +400,35 @@ and [actionable](./actionability.md). For example, click will:
|
|||
// Playwright waits for #search element to be in the DOM
|
||||
await page.fill('#search', 'query');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Playwright waits for #search element to be in the DOM
|
||||
await page.fill('#search', 'query')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Playwright waits for #search element to be in the DOM
|
||||
page.fill('#search', 'query')
|
||||
```
|
||||
|
||||
```js
|
||||
// Playwright waits for element to stop animating
|
||||
// and accept clicks.
|
||||
await page.click('#search');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Playwright waits for element to stop animating
|
||||
# and accept clicks.
|
||||
await page.click('#search')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Playwright waits for element to stop animating
|
||||
# and accept clicks.
|
||||
page.click('#search')
|
||||
```
|
||||
|
||||
You can explicitly wait for an element to appear in the DOM or to become visible:
|
||||
|
||||
```js
|
||||
|
|
@ -211,6 +438,20 @@ await page.waitForSelector('#search', { state: 'attached' });
|
|||
await page.waitForSelector('#promo');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Wait for #search to appear in the DOM.
|
||||
await page.wait_for_selector('#search', state='attached')
|
||||
# Wait for #promo to become visible, for example with `visibility:visible`.
|
||||
await page.wait_for_selector('#promo')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Wait for #search to appear in the DOM.
|
||||
page.wait_for_selector('#search', state='attached')
|
||||
# Wait for #promo to become visible, for example with `visibility:visible`.
|
||||
page.wait_for_selector('#promo')
|
||||
```
|
||||
|
||||
... or to become hidden or detached
|
||||
|
||||
```js
|
||||
|
|
@ -220,6 +461,20 @@ await page.waitForSelector('#details', { state: 'hidden' });
|
|||
await page.waitForSelector('#promo', { state: 'detached' });
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Wait for #details to become hidden, for example with `display:none`.
|
||||
await page.wait_for_selector('#details', state='hidden')
|
||||
# Wait for #promo to be removed from the DOM.
|
||||
await page.wait_for_selector('#promo', state='detached')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Wait for #details to become hidden, for example with `display:none`.
|
||||
page.wait_for_selector('#details', state='hidden')
|
||||
# Wait for #promo to be removed from the DOM.
|
||||
page.wait_for_selector('#promo', state='detached')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.click`]
|
||||
|
|
@ -240,7 +495,16 @@ of the web page and bring results back to the Node.js environment. Browser globa
|
|||
const href = await page.evaluate(() => document.location.href);
|
||||
```
|
||||
|
||||
```python-async
|
||||
href = await page.evaluate('() => document.location.href')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
href = page.evaluate('() => document.location.href')
|
||||
```
|
||||
|
||||
If the result is a Promise or if the function is asynchronous evaluate will automatically wait until it's resolved:
|
||||
|
||||
```js
|
||||
const status = await page.evaluate(async () => {
|
||||
const response = await fetch(location.href);
|
||||
|
|
@ -248,6 +512,20 @@ const status = await page.evaluate(async () => {
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
status = await page.evaluate("""async () => {
|
||||
response = await fetch(location.href)
|
||||
return response.status
|
||||
}""")
|
||||
```
|
||||
|
||||
```python-sync
|
||||
status = page.evaluate("""async () => {
|
||||
response = fetch(location.href)
|
||||
return response.status
|
||||
}""")
|
||||
```
|
||||
|
||||
## Evaluation Argument
|
||||
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] or [ElementHandle] instances. Handles are automatically converted to the value they represent.
|
||||
|
|
@ -295,6 +573,90 @@ await page.evaluate(
|
|||
{ button1, list: [button2], foo: null });
|
||||
```
|
||||
|
||||
```python-async
|
||||
# A primitive value.
|
||||
await page.evaluate('num => num', 42)
|
||||
|
||||
# An array.
|
||||
await page.evaluate('array => array.length', [1, 2, 3])
|
||||
|
||||
# An object.
|
||||
await page.evaluate('object => object.foo', { 'foo': 'bar' })
|
||||
|
||||
# A single handle.
|
||||
button = await page.query_selctor('button')
|
||||
await page.evaluate('button => button.textContent', button)
|
||||
|
||||
# Alternative notation using elementHandle.evaluate.
|
||||
await button.evaluate('(button, from) => button.textContent.substring(from)', 5)
|
||||
|
||||
# Object with multiple handles.
|
||||
button1 = await page.query_selector('.button1')
|
||||
button2 = await page.query_selector('.button2')
|
||||
await page.evaluate("""
|
||||
o => o.button1.textContent + o.button2.textContent""",
|
||||
{ 'button1': button1, 'button2': button2 })
|
||||
|
||||
# Object destructuring works. Note that property names must match
|
||||
# between the destructured object and the argument.
|
||||
# Also note the required parenthesis.
|
||||
await page.evaluate("""
|
||||
({ button1, button2 }) => button1.textContent + button2.textContent""",
|
||||
{ 'button1': button1, 'button2': button2 })
|
||||
|
||||
# Array works as well. Arbitrary names can be used for destructuring.
|
||||
# Note the required parenthesis.
|
||||
await page.evaluate("""
|
||||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
await page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# A primitive value.
|
||||
page.evaluate('num => num', 42)
|
||||
|
||||
# An array.
|
||||
page.evaluate('array => array.length', [1, 2, 3])
|
||||
|
||||
# An object.
|
||||
page.evaluate('object => object.foo', { 'foo': 'bar' })
|
||||
|
||||
# A single handle.
|
||||
button = page.query_selector('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.
|
||||
button1 = page.query_selector('.button1')
|
||||
button2 = page.query_selector('.button2')
|
||||
page.evaluate("""o => o.button1.textContent + o.button2.textContent""",
|
||||
{ 'button1': button1, 'button2': button2 })
|
||||
|
||||
# Object destructuring works. Note that property names must match
|
||||
# between the destructured object and the argument.
|
||||
# Also note the required parenthesis.
|
||||
page.evaluate("""
|
||||
({ button1, button2 }) => button1.textContent + button2.textContent""",
|
||||
{ 'button1': button1, 'button2': button2 })
|
||||
|
||||
# Array works as well. Arbitrary names can be used for destructuring.
|
||||
# Note the required parenthesis.
|
||||
page.evaluate("""
|
||||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
```
|
||||
|
||||
Right:
|
||||
|
||||
|
|
@ -306,6 +668,22 @@ const result = await page.evaluate(data => {
|
|||
}, data);
|
||||
```
|
||||
|
||||
```python-async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = await page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
Wrong:
|
||||
|
||||
```js
|
||||
|
|
@ -316,6 +694,22 @@ const result = await page.evaluate(() => {
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = await page.evaluate("""() => {
|
||||
# There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
```python-sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = page.evaluate("""() => {
|
||||
# There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.evaluate`]
|
||||
|
|
@ -350,6 +744,18 @@ const ulElementHandle = await page.$('ul');
|
|||
await ulElementHandle.evaluate(ulElement => getComputedStyle(ulElement).getPropertyValue('display'));
|
||||
```
|
||||
|
||||
```python-async
|
||||
# The first parameter of the elementHandle.evaluate callback is the element handle points to.
|
||||
ul_element_handle = await page.query_selector('ul')
|
||||
await ul_element_handle.evaluate("ulElement => getComputedStyle(ulElement).getPropertyValue('display')")
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# The first parameter of the elementHandle.evaluate callback is the element handle points to.
|
||||
ul_element_handle = page.query_selector('ul')
|
||||
ul_element_handle.evaluate("ulElement => getComputedStyle(ulElement).getPropertyValue('display')")
|
||||
```
|
||||
|
||||
Handles can also be passed as arguments to [`method: Page.evaluate`] function:
|
||||
|
||||
```js
|
||||
|
|
@ -358,6 +764,16 @@ const ulElementHandle = await page.$('ul');
|
|||
await page.evaluate(uiElement => getComputedStyle(uiElement).getPropertyValue('display'), uiElement);
|
||||
```
|
||||
|
||||
```python-async
|
||||
ul_element_handle = await page.query_selector('ul')
|
||||
await page.evaluate("uiElement => getComputedStyle(uiElement).getPropertyValue('display')", uiElement)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
ul_element_handle = page.query_selector('ul')
|
||||
page.evaluate("uiElement => getComputedStyle(uiElement).getPropertyValue('display')", uiElement)
|
||||
```
|
||||
|
||||
### Example: JSHandle
|
||||
|
||||
```js
|
||||
|
|
@ -387,6 +803,60 @@ const newLength = await page.evaluate(() => window.myArray.length);
|
|||
await myArrayHandle.dispose();
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Create a new array in the page, write a reference to it in
|
||||
# window.myArray and get a handle to it.
|
||||
my_array_handle = await page.evaluate_handle("""() => {
|
||||
window.myArray = [1]
|
||||
return myArray
|
||||
}""")
|
||||
|
||||
# Get current length of the array using the handle.
|
||||
length = await page.evaluate("""
|
||||
(arg) => arg.myArray.length""",
|
||||
{ 'myArray': my_array_handle }
|
||||
)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
await page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Get current length of the array using window.myArray reference.
|
||||
new_length = await page.evaluate("() => window.myArray.length")
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
await my_array_handle.dispose()
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Create a new array in the page, write a reference to it in
|
||||
# window.myArray and get a handle to it.
|
||||
my_array_handle = page.evaluate_handle("""() => {
|
||||
window.myArray = [1]
|
||||
return myArray
|
||||
}""")
|
||||
|
||||
# Get current length of the array using the handle.
|
||||
length = page.evaluate("""
|
||||
(arg) => arg.myArray.length""",
|
||||
{ 'myArray': my_array_handle }
|
||||
)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Get current length of the array using window.myArray reference.
|
||||
new_length = page.evaluate("() => window.myArray.length")
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
my_array_handle.dispose()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
- [JSHandle]
|
||||
- [ElementHandle]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ to slow down execution and follow along while debugging.
|
|||
await chromium.launch({ headless: false, slowMo: 100 }); // or firefox, webkit
|
||||
```
|
||||
|
||||
```python-async
|
||||
await chromium.launch(headless=False, slow_mo=100) # or firefox, webkit
|
||||
|
||||
```
|
||||
|
||||
```python-sync
|
||||
chromium.launch(headless=False, slow_mo=100) # or firefox, webkit
|
||||
|
||||
```
|
||||
|
||||
## Visual Studio Code debugger
|
||||
|
||||
The VS Code debugger can be used to pause and resume execution of Playwright
|
||||
|
|
@ -66,6 +76,15 @@ In Chromium, you can also open developer tools through a launch option.
|
|||
await chromium.launch({ devtools: true });
|
||||
```
|
||||
|
||||
```python-async
|
||||
await chromium.launch(devtools=True)
|
||||
|
||||
```
|
||||
|
||||
```python-sync
|
||||
chromium.launch(devtools=True)
|
||||
```
|
||||
|
||||
## Run in Debug Mode
|
||||
|
||||
Set the `PWDEBUG` environment variable to run your scripts in debug mode. This
|
||||
|
|
|
|||
|
|
@ -29,6 +29,32 @@ const context = await browser.newContext({
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
import asyncio
|
||||
from playwright import async_playwright
|
||||
|
||||
async def main():
|
||||
async with async_playwright() as p:
|
||||
pixel_2 = p.devices['Pixel 2']
|
||||
browser = await p.webkit.launch(headless=False)
|
||||
context = await browser.new_context(
|
||||
**pixel_2,
|
||||
)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
pixel_2 = p.devices['Pixel 2']
|
||||
browser = p.webkit.launch(headless=False)
|
||||
context = browser.new_context(
|
||||
**pixel_2,
|
||||
)
|
||||
```
|
||||
|
||||
All pages created in the context above will share the same device parameters.
|
||||
|
||||
#### API reference
|
||||
|
|
@ -48,6 +74,18 @@ const context = await browser.newContext({
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
context = await browser.new_context(
|
||||
user_agent='My user agent'
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context = browser.new_context(
|
||||
user_agent='My user agent'
|
||||
)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
@ -74,6 +112,38 @@ const context = await browser.newContext({
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Create context with given viewport
|
||||
context = await browser.new_context(
|
||||
viewport={ 'width': 1280, 'height': 1024 }
|
||||
)
|
||||
|
||||
# Resize viewport for individual page
|
||||
await page.set_viewport_size(width=1600, height=1200)
|
||||
|
||||
# Emulate high-DPI
|
||||
context = await browser.new_context(
|
||||
viewport={ 'width': 2560, 'height': 1440 },
|
||||
device_scale_factor=2,
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Create context with given viewport
|
||||
context = browser.new_context(
|
||||
viewport={ 'width': 1280, 'height': 1024 }
|
||||
)
|
||||
|
||||
# Resize viewport for individual page
|
||||
page.set_viewport_size(width=1600, height=1200)
|
||||
|
||||
# Emulate high-DPI
|
||||
context = browser.new_context(
|
||||
viewport={ 'width': 2560, 'height': 1440 },
|
||||
device_scale_factor=2,
|
||||
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
@ -91,6 +161,22 @@ const context = await browser.newContext({
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Emulate locale and time
|
||||
context = await browser.new_context(
|
||||
locale='de-DE',
|
||||
timezone_id='Europe/Berlin',
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Emulate locale and time
|
||||
context = browser.new_context(
|
||||
locale='de-DE',
|
||||
timezone_id='Europe/Berlin',
|
||||
)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
@ -100,27 +186,67 @@ const context = await browser.newContext({
|
|||
## Permissions
|
||||
|
||||
Allow all pages in the context to show system notifications:
|
||||
|
||||
```js
|
||||
const context = await browser.newContext({
|
||||
permissions: ['notifications'],
|
||||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
context = await browser.new_context(
|
||||
permissions=['notifications'],
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context = browser.new_context(
|
||||
permissions=['notifications'],
|
||||
)
|
||||
```
|
||||
|
||||
Grant all pages in the existing context access to current location:
|
||||
|
||||
```js
|
||||
await context.grantPermissions(['geolocation']);
|
||||
```
|
||||
|
||||
```python-async
|
||||
await context.grant_permissions(['geolocation'])
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context.grant_permissions(['geolocation'])
|
||||
```
|
||||
|
||||
Grant notifications access from a specific domain:
|
||||
|
||||
```js
|
||||
await context.grantPermissions(['notifications'], {origin: 'https://skype.com'} );
|
||||
```
|
||||
|
||||
```python-async
|
||||
await context.grant_permissions(['notifications'], origin='https://skype.com')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context.grant_permissions(['notifications'], origin='https://skype.com')
|
||||
```
|
||||
|
||||
Revoke all permissions:
|
||||
|
||||
```js
|
||||
await context.clearPermissions();
|
||||
```
|
||||
|
||||
```python-async
|
||||
await context.clear_permissions()
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context.clear_permissions()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
@ -131,18 +257,42 @@ await context.clearPermissions();
|
|||
|
||||
## Geolocation
|
||||
Create a context with `"geolocation"` permissions granted:
|
||||
|
||||
```js
|
||||
const context = await browser.newContext({
|
||||
geolocation: { longitude: 48.858455, latitude: 2.294474 },
|
||||
permissions: ['geolocation']
|
||||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
context = await browser.new_context(
|
||||
geolocation={ 'longitude': 48.858455, 'latitude': 2.294474 },
|
||||
permissions=['geolocation']
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context = browser.new_context(
|
||||
geolocation={ 'longitude': 48.858455, 'latitude': 2.294474 },
|
||||
permissions=['geolocation']
|
||||
)
|
||||
```
|
||||
|
||||
Change the location later:
|
||||
|
||||
```js
|
||||
await context.setGeolocation({ longitude: 29.979097, latitude: 31.134256 });
|
||||
```
|
||||
|
||||
```python-async
|
||||
await context.set_geolocation(longitude=29.979097, latitude=31.134256)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
context.set_geolocation(longitude=29.979097, latitude=31.134256)
|
||||
```
|
||||
|
||||
**Note** you can only change geolocation for all pages in the context.
|
||||
|
||||
#### API reference
|
||||
|
|
@ -175,6 +325,42 @@ await page.emulateMedia({ colorScheme: 'dark' });
|
|||
await page.emulateMedia({ media: 'print' });
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Create context with dark mode
|
||||
context = await browser.new_context(
|
||||
color_scheme='dark' # or 'light'
|
||||
)
|
||||
|
||||
# Create page with dark mode
|
||||
page = await browser.new_page(
|
||||
color_scheme='dark' # or 'light'
|
||||
)
|
||||
|
||||
# Change color scheme for the page
|
||||
await page.emulate_media(color_scheme='dark')
|
||||
|
||||
# Change media for page
|
||||
await page.emulate_media(media='print')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Create context with dark mode
|
||||
context = browser.new_context(
|
||||
color_scheme='dark' # or 'light'
|
||||
)
|
||||
|
||||
# Create page with dark mode
|
||||
page = browser.new_page(
|
||||
color_scheme='dark' # or 'light'
|
||||
)
|
||||
|
||||
# Change color scheme for the page
|
||||
page.emulate_media(color_scheme='dark')
|
||||
|
||||
# Change media for page
|
||||
page.emulate_media(media='print')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
|
|||
|
|
@ -26,6 +26,40 @@ await page.fill('#local', '2020-03-02T05:15');
|
|||
await page.fill('text=First Name', 'Peter');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Text input
|
||||
await page.fill('#name', 'Peter')
|
||||
|
||||
# Date input
|
||||
await page.fill('#date', '2020-02-02')
|
||||
|
||||
# Time input
|
||||
await page.fill('#time', '13-15')
|
||||
|
||||
# Local datetime input
|
||||
await page.fill('#local', '2020-03-02T05:15')
|
||||
|
||||
# Input through label
|
||||
await page.fill('text=First Name', 'Peter')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# 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')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.fill`]
|
||||
|
|
@ -49,6 +83,28 @@ await page.uncheck('#subscribe-label');
|
|||
await page.check('text=XL');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Check the checkbox
|
||||
await page.check('#agree')
|
||||
|
||||
# Uncheck by input <label>.
|
||||
await page.uncheck('#subscribe-label')
|
||||
|
||||
# Select the radio button
|
||||
await page.check('text=XL')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Check the checkbox
|
||||
page.check('#agree')
|
||||
|
||||
# Uncheck by input <label>.
|
||||
page.uncheck('#subscribe-label')
|
||||
|
||||
# Select the radio button
|
||||
page.check('text=XL')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.check`]
|
||||
|
|
@ -80,6 +136,36 @@ const option = await page.$('#best-option');
|
|||
await page.selectOption('select#colors', option);
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Single selection matching the value
|
||||
await page.select_option('select#colors', 'blue')
|
||||
|
||||
# Single selection matching the label
|
||||
await page.select_option('select#colors', label='Blue')
|
||||
|
||||
# Multiple selected items
|
||||
await page.select_option('select#colors', ['red', 'green', 'blue'])
|
||||
|
||||
# Select the option via element handle
|
||||
option = await page.query_selector('#best-option')
|
||||
await page.select_option('select#colors', option)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Single selection matching the value
|
||||
page.select_option('select#colors', 'blue')
|
||||
|
||||
# Single selection matching the label
|
||||
page.select_option('select#colors', label='Blue')
|
||||
|
||||
# Multiple selected items
|
||||
page.select_option('select#colors', ['red', 'green', 'blue'])
|
||||
|
||||
# Select the option via element handle
|
||||
option = page.query_selector('#best-option')
|
||||
page.select_option('select#colors', option)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.selectOption`]
|
||||
|
|
@ -112,6 +198,46 @@ await page.hover('#item');
|
|||
await page.click('#item', { position: { x: 0, y: 0} });
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Generic click
|
||||
await page.click('button#submit')
|
||||
|
||||
# Double click
|
||||
await page.dblclick('#item')
|
||||
|
||||
# Right click
|
||||
await page.click('#item', button='right')
|
||||
|
||||
# Shift + click
|
||||
await page.click('#item', modifiers=['Shift'])
|
||||
|
||||
# Hover over element
|
||||
await page.hover('#item')
|
||||
|
||||
# Click the top left corner
|
||||
await page.click('#item', position={ 'x': 0, 'y': 0})
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Generic click
|
||||
page.click('button#submit')
|
||||
|
||||
# Double click
|
||||
page.dblclick('#item')
|
||||
|
||||
# Right click
|
||||
page.click('#item', button='right')
|
||||
|
||||
# Shift + click
|
||||
page.click('#item', modifiers=['Shift'])
|
||||
|
||||
# Hover over element
|
||||
page.hover('#item')
|
||||
|
||||
# Click the top left corner
|
||||
page.click('#item', position={ 'x': 0, 'y': 0})
|
||||
```
|
||||
|
||||
Under the hood, this and other pointer-related methods:
|
||||
|
||||
- wait for element with given selector to be in DOM
|
||||
|
|
@ -129,6 +255,14 @@ Sometimes, apps use non-trivial logic where hovering the element overlays it wit
|
|||
await page.click('button#submit', { force: true });
|
||||
```
|
||||
|
||||
```python-async
|
||||
await page.click('button#submit', force=True)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
page.click('button#submit', force=True)
|
||||
```
|
||||
|
||||
#### Programmatic click
|
||||
|
||||
If you are not interested in testing your app under the real conditions and want to simulate the click by any means possible, you can trigger the [`HTMLElement.click()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click) behavior via simply dispatching a click event on the element:
|
||||
|
|
@ -137,6 +271,13 @@ If you are not interested in testing your app under the real conditions and want
|
|||
await page.dispatchEvent('button#submit', 'click');
|
||||
```
|
||||
|
||||
```python-async
|
||||
await page.dispatch_event('button#submit', 'click')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
page.dispatch_event('button#submit', 'click')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
|
|
@ -164,6 +305,16 @@ Type into the field character by character, as if it was a user with a real keyb
|
|||
await page.type('#area', 'Hello World!');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Type character by character
|
||||
await page.type('#area', 'Hello World!')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Type character by character
|
||||
page.type('#area', 'Hello World!')
|
||||
```
|
||||
|
||||
This method will emit all the necessary keyboard events, with all the `keydown`, `keyup`, `keypress` events in place. You can even specify the optional `delay` between the key presses to simulate real user behavior.
|
||||
|
||||
> **NOTE** that most of the time, [`method: Page.fill`] will just work. You only need to type characters if there is special keyboard handling on the page.
|
||||
|
|
@ -190,6 +341,28 @@ await page.press('#name', 'Control+ArrowRight');
|
|||
await page.press('#value', '$');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# Hit Enter
|
||||
await page.press('#submit', 'Enter')
|
||||
|
||||
# Dispatch Control+Right
|
||||
await page.press('#name', 'Control+ArrowRight')
|
||||
|
||||
# Press $ sign on keyboard
|
||||
await page.press('#value', '$')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# Hit Enter
|
||||
page.press('#submit', 'Enter')
|
||||
|
||||
# Dispatch Control+Right
|
||||
page.press('#name', 'Control+ArrowRight')
|
||||
|
||||
# Press $ sign on keyboard
|
||||
page.press('#value', '$')
|
||||
```
|
||||
|
||||
This method focuses the selected element and produces a single keystroke. It accepts the logical key names that are emitted in the [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) property of the keyboard events:
|
||||
|
||||
```
|
||||
|
|
@ -213,6 +386,22 @@ await page.press('#name', 'Shift+A');
|
|||
await page.press('#name', 'Shift+ArrowLeft');
|
||||
```
|
||||
|
||||
```python-async
|
||||
# <input id=name>
|
||||
await page.press('#name', 'Shift+A')
|
||||
|
||||
# <input id=name>
|
||||
await page.press('#name', 'Shift+ArrowLeft')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
# <input id=name>
|
||||
page.press('#name', 'Shift+A')
|
||||
|
||||
# <input id=name>
|
||||
page.press('#name', 'Shift+ArrowLeft')
|
||||
```
|
||||
|
||||
Shortcuts such as `"Control+o"` or `"Control+Shift+T"` are supported as well. When specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed.
|
||||
|
||||
Note that you still need to specify the capital `A` in `Shift-A` to produce the capital character. `Shift-a` produces a lower-case one as if you had the `CapsLock` toggled.
|
||||
|
|
@ -247,6 +436,42 @@ await page.setInputFiles('input#upload', {
|
|||
});
|
||||
```
|
||||
|
||||
```python-async
|
||||
from playwright.async_api import FilePayload
|
||||
# Select one file
|
||||
await page.set_input_files('input#upload', 'myfile.pdf')
|
||||
|
||||
# Select multiple files
|
||||
await page.set_input_files('input#upload', ['file1.txt', 'file2.txt'])
|
||||
|
||||
# Remove all the selected files
|
||||
await page.set_input_files('input#upload', [])
|
||||
|
||||
# Upload buffer from memory
|
||||
await page.set_input_files(
|
||||
"input#upload",
|
||||
files=[FilePayload("test.txt", "text/plain", b"this is a test")],
|
||||
)
|
||||
```
|
||||
|
||||
```python-sync
|
||||
from playwright.sync_api import FilePayload
|
||||
# Select one file
|
||||
page.set_input_files('input#upload', 'myfile.pdf')
|
||||
|
||||
# Select multiple files
|
||||
page.set_input_files('input#upload', ['file1.txt', 'file2.txt'])
|
||||
|
||||
# Remove all the selected files
|
||||
page.set_input_files('input#upload', [])
|
||||
|
||||
# Upload buffer from memory
|
||||
page.set_input_files(
|
||||
"input#upload",
|
||||
files=[FilePayload("test.txt", "text/plain", b"this is a test")],
|
||||
)
|
||||
```
|
||||
|
||||
You can select input files for upload using the [`method: Page.setInputFiles`] method. It expects first argument to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) with the type `"file"`. Multiple files can be passed in the array. If some of the file paths are relative, they are resolved relative to the [current working directory](https://nodejs.org/api/process.html#process_process_cwd). Empty array clears the selected files.
|
||||
|
||||
#### Example
|
||||
|
|
@ -269,6 +494,14 @@ For the dynamic pages that handle focus events, you can focus the given element.
|
|||
await page.focus('input#name');
|
||||
```
|
||||
|
||||
```python-async
|
||||
await page.focus('input#name')
|
||||
```
|
||||
|
||||
```python-sync
|
||||
page.focus('input#name')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.focus`]
|
||||
|
|
|
|||
Loading…
Reference in a new issue