Skip to content

Commit 629b772

Browse files
committed
docs(loading): nits and fixes
1 parent 04ed683 commit 629b772

File tree

1 file changed

+56
-46
lines changed

1 file changed

+56
-46
lines changed

docs/loading.md

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,74 @@
22

33
Playwright logically splits the process of showing a new document in the page into **navigation** and **loading**.
44

5-
**Navigation** starts with an intent, for example:
6-
- loading a url with [`page.goto('http://example.com')`](api.md#pagegotourl-options);
7-
- clicking a link with [`page.click('text="Continue"')`](api.md#pageclickselector-options);
8-
- reloading with [`page.reload()`](api.md#pagereloadoptions);
9-
- assiging to [location](https://developer.mozilla.org/en-US/docs/Web/API/Location) in the script like `location.href = 'http://example.com'`;
10-
- using [history api](https://developer.mozilla.org/en-US/docs/Web/API/History) in the script like `history.pushState({}, 'title', '#deep-link')`.
11-
12-
This navigation intent may result in a navigation or get canceled, for example transformed into a download. When navigation succeeds, page starts **loading** the document.
13-
14-
**Loading** usually takes time, retrieving the response over the network, parsing, executing scripts and firing events. The typical loading scenario is:
15-
- [`page.url()`](api.md#pageurl) is set to the loading url;
16-
- document content is loaded over network and parsed;
17-
- [`domcontentloaded`](api.md#event-domcontentloaded) event is fired;
18-
- page executes some scripts and loads resources like stylesheets and images;
19-
- `networkidle2` is triggered (no more than two network connections for at least `500` ms),
20-
- [`load`](api.md#event-load) event is fired;
21-
- page executes some more scripts;
22-
- `networkidle0` is triggered (no network connections for at least `500` ms).
5+
### Navigation
236

24-
### Common scenarios
7+
Page navigation can be either initiated by the Playwright call:
8+
9+
```js
10+
// Load a page
11+
await page.goto('https://example.com')
12+
13+
// Reload a page
14+
await page.reload()
15+
16+
// Click a link
17+
await page.click('text="Continue"')
18+
```
19+
20+
or by the page itself:
21+
22+
```js
23+
// Programmatic navigation
24+
window.location.href = 'https://example.com'
25+
26+
// Single page app navigation
27+
history.pushState({}, 'title', '#deep-link')
28+
```
29+
30+
Navigation intent may result in being canceled, for example transformed into a download or hitting an unresolved DNS address. Only when the navigation succeeds, page starts **loading** the document.
2531

26-
Playwright tries its best to handle **navigations** seamlessly, so that script does not have to worry about it:
27-
- `page.goto()` waits for the navigation to happen;
28-
- `page.click('a')` waits for synchronously triggered navigation to happen;
29-
- history api calls are treated as navigations to make automating single-page applications easy.
32+
### Loading
3033

31-
Playwright reasonably handles **loading** by default - it waits for the `load` event in explicit navigations like `page.goto()`; and for the `domcontentloaded` event in the implicit navigations triggered by clicks, evaluations and popups.
34+
Page load takes time retrieving the response body over the network, parsing, executing the scripts and firing the events. Typical load scenario goes through the following load states:
35+
- [`page.url()`](api.md#pageurl) is set to the new url
36+
- document content is loaded over network and parsed
37+
- [`domcontentloaded`](api.md#event-domcontentloaded) event is fired
38+
- page executes some scripts and loads resources like stylesheets and images
39+
- [`load`](api.md#event-load) event is fired
40+
- page executes dynamically loaded scripts
41+
- `networkidle0` is fired - no new network requests made for at least `500` ms
3242

33-
In the typical scenario where navigation is followed by performing some action, the action will wait for the target element to appear. There is no need to explicitly wait for loading to finish.
43+
### Common scenarios
3444

35-
Consider the following scenario, where everything is handled by Playwright behind the scenes:
45+
By default, Playwright handles navigations seamlessly so that you did not need to think about them. Consider the following scenario, where everything is handled by Playwright behind the scenes:
3646

3747
```js
38-
// The page does a client-side redirect to 'http://example.com/login'.
39-
// Playwright automatically waits for the login page to load.
4048
await page.goto('http://example.com');
49+
// If the page does a client-side redirect to 'http://example.com/login'.
50+
// Playwright will automatically wait for the login page to load.
4151

4252
// Playwright waits for the lazy loaded #username and #password inputs
4353
// to appear before filling the values.
4454
await page.fill('#username', 'John Doe');
4555
await page.fill('#password', '********');
4656

4757
// Playwright waits for the login button to become enabled and clicks it.
58+
await page.click('text=Login');
4859
// Clicking the button navigates to the logged-in page and Playwright
4960
// automatically waits for that.
50-
await page.click('text=Login');
5161
```
5262

53-
However, depending on the page, an explicit loading handling may be required.
54-
55-
### Lazy loading, for example client side hydration
56-
57-
When the page loads essential content lazily (e.g. from the `onload`), loading stages like `networkidle0` or `networkidle2` can help.
58-
```js
59-
await page.goto('http://example.com', { waitUntil: 'networkidle0' });
60-
// Hydration is done, all the lazy resources have been loaded, ready to take a screenshot.
61-
await page.screenshot();
62-
```
63+
Explicit loading handling may be required for more complicated scenarios though.
6364

6465
### Loading a popup
6566

66-
When popup is opened, explicitly calling [`page.waitForLoadState()`](#pagewaitforloadstatestate-options) ensures that popup is ready for evaluation.
67+
When popup is opened, explicitly calling [`page.waitForLoadState()`](#pagewaitforloadstatestate-options) ensures that popup is loaded to the desired state.
6768
```js
68-
const {popup} = await page.click('a[target="_blank"]'); // Opens a popup.
69+
const { popup } = await Promise.all([
70+
page.waitForEvent('popup'),
71+
page.click('a[target="_blank"]') // <-- opens popup
72+
]);
6973
await popup.waitForLoadState('load');
7074
await popup.evaluate(() => window.globalVariableInitializedByOnLoadHandler);
7175
```
@@ -75,22 +79,24 @@ await popup.evaluate(() => window.globalVariableInitializedByOnLoadHandler);
7579
Usually, the client-side redirect happens before the `load` event, and `page.goto()` method automatically waits for the redirect. However, when redirecting from a link click or after the `load` event, it would be easier to explicitly [`waitForNavigation()`](#pagewaitfornavigationoptions) to a specific url.
7680
```js
7781
await Promise.all([
78-
page.click('a'), // Triggers a navigation with a script redirect.
7982
page.waitForNavigation({ url: '**/login' }),
83+
page.click('a'), // Triggers a navigation with a script redirect.
8084
]);
8185
```
82-
Note the `Promise.all` to click and wait for navigation at the same time. Awaiting these methods one after the other is racy, because navigation could happen too fast.
86+
87+
Notice the `Promise.all` to click and wait for navigation. Awaiting these methods one after the other is racy, because navigation could happen too fast.
8388

8489
### Click triggers navigation after a timeout
8590

8691
When `onclick` handler triggers a navigation from a `setTimeout`, use an explicit [`waitForNavigation()`](#pagewaitfornavigationoptions) call as a last resort.
8792
```js
8893
await Promise.all([
89-
page.click('a'), // Triggers a navigation after a timeout.
9094
page.waitForNavigation(), // Waits for the next navigation.
95+
page.click('a'), // Triggers a navigation after a timeout.
9196
]);
9297
```
93-
Note the `Promise.all` to click and wait for navigation at the same time. Awaiting these methods one after the other is racy, because navigation could happen too fast.
98+
99+
Notice the `Promise.all` to click and wait for navigation. Awaiting these methods one after the other is racy, because navigation could happen too fast.
94100

95101
### Unpredictable patterns
96102

@@ -105,7 +111,11 @@ await page.screenshot();
105111
When clicking on a button triggers some asynchronous processing, issues a couple GET requests and pushes a new history state multiple times, explicit [`waitForNavigation()`](#pagewaitfornavigationoptions) to a specific url is the most reliable option.
106112
```js
107113
await Promise.all([
108-
page.click('text=Process the invoice'), // Triggers some complex handling.
109114
page.waitForNavigation({ url: '**/invoice#processed' }),
115+
page.click('text=Process the invoice'), // Triggers some complex handling.
110116
]);
111117
```
118+
119+
### Lazy loading, hydration
120+
121+
TBD

0 commit comments

Comments
 (0)