Skip to content

Commit c48e566

Browse files
authored
docs: update README.md (#154)
1 parent ef38e91 commit c48e566

File tree

1 file changed

+109
-35
lines changed

1 file changed

+109
-35
lines changed

README.md

Lines changed: 109 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,11 @@ Playwright is built to automate the broad and growing set of web browser capabil
4444

4545
### Pytest
4646

47-
For writing end-to-end tests we recommend to use the official [Pytest plugin](https://github.com/microsoft/playwright-pytest#readme) for Playwright. It contains utilities for running it on multiple browsers, having a new page instance on every test or base-url support via a command-line argument. This will in the end look like that:
47+
Playwright can be used as a library in your application or as a part of the testing solution. We recommend using our [Pytest plugin](https://github.com/microsoft/playwright-pytest#readme) for testing.
4848

49-
```py
50-
def test_playwright_is_visible_on_google(page):
51-
page.goto("https://www.google.com")
52-
page.type("input[name=q]", "Playwright GitHub")
53-
page.click("input[type=submit]")
54-
page.waitForSelector("text=microsoft/Playwright")
55-
```
56-
57-
For more information checkout the project on [GitHub](https://github.com/microsoft/playwright-pytest#readme).
58-
59-
### Standalone
49+
As a library, Playwright offers both blocking (synchronous) API and asyncio API (async/await). You can pick the one that works best for you. They are identical in terms of capabilities and only differ in a way one consumes the API.
6050

61-
For using Playwright standalone, you can either use the sync version or the async variant (async/await). In most cases the sync variant is the right choice to automate the web browsers e.g. for writing end-to-end tests. Both will get initialized with a context manager.
51+
Below are some of the examples on how these variations of the API can be used:
6252

6353
#### Sync variant
6454

@@ -82,33 +72,30 @@ from playwright import async_playwright
8272

8373
async def main():
8474
async with async_playwright() as p:
85-
browser = await p.webkit.launch()
86-
page = await browser.newPage()
87-
await page.goto('http://whatsmyuseragent.org/')
88-
await page.screenshot(path=f'example-{browser_type.name}.png')
89-
await browser.close()
75+
for browser_type in [p.chromium, p.firefox, p.webkit]:
76+
browser = await browser_type.launch()
77+
page = await browser.newPage()
78+
await page.goto('http://whatsmyuseragent.org/')
79+
await page.screenshot(path=f'example-{browser_type.name}.png')
80+
await browser.close()
9081

9182
asyncio.get_event_loop().run_until_complete(main())
9283
```
9384

94-
## Examples
95-
96-
#### Page screenshot
97-
98-
This code snippet navigates to whatsmyuseragent.org in Chromium, Firefox and WebKit, and saves 3 screenshots.
85+
#### Using pytest-playwright
9986

10087
```py
101-
from playwright import sync_playwright
102-
103-
with sync_playwright() as p:
104-
for browser_type in [p.chromium, p.firefox, p.webkit]:
105-
browser = browser_type.launch()
106-
page = browser.newPage()
107-
page.goto('http://whatsmyuseragent.org/')
108-
page.screenshot(path=f'example-{browser_type.name}.png')
109-
browser.close()
88+
def test_playwright_is_visible_on_google(page):
89+
page.goto("https://www.google.com")
90+
page.type("input[name=q]", "Playwright GitHub")
91+
page.click("input[type=submit]")
92+
page.waitForSelector("text=microsoft/Playwright")
11093
```
11194

95+
For more information on pytest-playwright, see [GitHub](https://github.com/microsoft/playwright-pytest#readme).
96+
97+
## More examples
98+
11299
#### Mobile and geolocation
113100

114101
This snippet emulates Mobile Safari on a device at a given geolocation, navigates to maps.google.com, performs action and takes a screenshot.
@@ -128,7 +115,6 @@ with sync_playwright() as p:
128115
page = context.newPage()
129116
page.goto('https://maps.google.com')
130117
page.click('text="Your location"')
131-
page.waitForRequest('*preview/pwa')
132118
page.screenshot(path='colosseum-iphone.png')
133119
browser.close()
134120
```
@@ -152,7 +138,6 @@ async def main():
152138
page = await context.newPage()
153139
await page.goto('https://maps.google.com')
154140
await page.click('text="Your location"')
155-
await page.waitForRequest('*preview/pwa')
156141
await page.screenshot(path='colosseum-iphone.png')
157142
await browser.close()
158143

@@ -251,9 +236,98 @@ async def main():
251236
asyncio.get_event_loop().run_until_complete(main())
252237
```
253238

239+
## Documentation
240+
241+
We are in the process of converting the [documentation](https://playwright.dev/) from the Node form to the Python one. But you can go ahead and use the Node's documentation because the API is pretty much the same. You might have noticed that Playwright uses non-Python naming conventions, `camelCase` instead of the `snake_case` for its methods. We recognize that this is not ideal, but it was done deliberately, so that you could rely upon the stack overflow answers and the documentation of the Playwright for Node.
242+
243+
### Understanding examples from the JavaScript documentation
244+
245+
You can use all the same methods and arguments as [documented](https://playwright.dev/), just remember that since Python allows named arguments, we didn't need to put `options` parameter into every call as we had to in the Node version:
246+
247+
So when you see example like this in JavaScript
248+
249+
```js
250+
await webkit.launch({ headless: false });
251+
```
252+
253+
It translates into Python like this:
254+
255+
```py
256+
webkit.launch(headless=False)
257+
```
258+
259+
If you are using an IDE, it'll suggest parameters that are available in every call.
260+
261+
### Evaluating functions
262+
263+
Another difference is that in the JavaScript version, `page.evaluate` accepts JavaScript functions, while this does not make any sense in the Python version.
264+
265+
In JavaScript it will be documented as:
266+
267+
```js
268+
const result = await page.evaluate(([x, y]) => {
269+
return Promise.resolve(x * y);
270+
}, [7, 8]);
271+
console.log(result); // prints "56"
272+
```
273+
274+
And in Python that would look like:
275+
276+
```py
277+
result = page.evaluate("""
278+
([x, y]) => {
279+
return Promise.resolve(x * y);
280+
}""",
281+
[7, 8])
282+
print(result) # prints "56"
283+
```
284+
285+
The library will detect that what are passing it is a function and will invoke it with the given parameters. You can opt out of this function detection and pass `force_expr=True` to all evaluate functions, but you probably will never need to do that.
286+
287+
### Using context managers
288+
289+
Python enabled us to do some of the things that were not possible in the Node version and we used the opportunity. Instead of using the `page.waitFor*` methods, we recommend using corresponding `page.expect_*` context manager.
290+
291+
In JavaScript it will be documented as:
292+
293+
```js
294+
const [ download ] = await Promise.all([
295+
page.waitForEvent('download'), // <-- start waiting for the download
296+
page.click('button#delayed-download') // <-- perform the action that directly or indirectly initiates it.
297+
]);
298+
const path = await download.path();
299+
```
300+
301+
And in Python that would look much simpler:
302+
303+
```py
304+
with page.expect_download() as download_info:
305+
page.click("button#delayed-download")
306+
download = download_info.value
307+
path = download.path()
308+
```
309+
310+
Similarly, for waiting for the network response:
311+
312+
```js
313+
const [response] = await Promise.all([
314+
page.waitForResponse('**/api/fetch_data'),
315+
page.click('button#update'),
316+
]);
317+
```
318+
319+
Becomes
320+
321+
```py
322+
with page.expect_response("**/api/fetch_data"):
323+
page.click("button#update")
324+
```
325+
254326
## Is Playwright for Python ready?
255327

256-
We are ready for your feedback, but we are still covering Playwright Python with the tests, so expect some API changes and don't use for production.
328+
Yes, Playwright for Python is ready. We are still not at the version v1.0, so minor breaking API changes could potentially happen. But a) this is unlikely and b) we will only do that if we know it improves your experience with the new library. We'd like to collect your feedback before we freeze the API for v1.0.
329+
330+
> Note: We don't yet support some of the edge-cases of the vendor-specific APIs such as collecting chromium trace, coverage report, etc.
257331
258332
## Resources
259333

0 commit comments

Comments
 (0)