From 499324961a4fe581478a685dcffd951260b69cf0 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 30 Nov 2022 12:36:35 -0800 Subject: [PATCH] docs: remove Promise.all from examples (#19154) Replaced with explicit `popupPromise` variable. --- docs/src/api/class-browsercontext.md | 26 ++- docs/src/api/class-consolemessage.md | 12 +- docs/src/api/class-download.md | 17 +- docs/src/api/class-electronapplication.md | 7 +- docs/src/api/class-filechooser.md | 20 +- docs/src/api/class-frame.md | 10 +- docs/src/api/class-page.md | 156 ++++++-------- docs/src/api/class-request.md | 7 +- docs/src/downloads.md | 24 +-- docs/src/events.md | 31 ++- docs/src/input.md | 19 +- docs/src/navigations.md | 55 ++--- docs/src/network.md | 27 ++- docs/src/pages.md | 46 ++-- ...-workers-experimental-network-events-js.md | 16 +- packages/playwright-core/types/types.d.ts | 201 +++++++----------- 16 files changed, 277 insertions(+), 397 deletions(-) diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 7f2cdf88b1..f42beedd42 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -106,30 +106,29 @@ popup with `window.open('http://example.com')`, this event will fire when the ne done and its response has started loading in the popup. ```js -const [newPage] = await Promise.all([ - context.waitForEvent('page'), - page.locator('a[target=_blank]').click(), -]); +const newPagePromise = context.waitForEvent('page'); +await page.getByText('open new page').click(); +const newPage = await newPagePromise; console.log(await newPage.evaluate('location.href')); ``` ```java Page newPage = context.waitForPage(() -> { - page.locator("a[target=_blank]").click(); + page.getByText("open new page").click(); }); System.out.println(newPage.evaluate("location.href")); ``` ```python async async with context.expect_page() as page_info: - await page.locator("a[target=_blank]").click(), + await page.get_by_text("open new page").click(), page = await page_info.value print(await page.evaluate("location.href")) ``` ```python sync with context.expect_page() as page_info: - page.locator("a[target=_blank]").click(), + page.get_by_text("open new page").click(), page = page_info.value print(page.evaluate("location.href")) ``` @@ -137,7 +136,7 @@ print(page.evaluate("location.href")) ```csharp var popup = await context.RunAndWaitForPageAsync(async => { - await page.Locator("a").ClickAsync(); + await page.GetByText("open new page").ClickAsync(); }); Console.WriteLine(await popup.EvaluateAsync("location.href")); ``` @@ -1311,14 +1310,13 @@ value. Will throw an error if the context closes before the event is fired. Retu **Usage** ```js -const [page, _] = await Promise.all([ - context.waitForEvent('page'), - page.getByRole('button').click() -]); +const pagePromise = context.waitForEvent('page'); +await page.getByRole('button').click(); +const page = await pagePromise; ``` ```java -Page newPage = context.waitForPage(() -> page.getByRole("button").click()); +Page newPage = context.waitForPage(() -> page.getByRole(AriaRole.BUTTON).click()); ``` ```python async @@ -1336,7 +1334,7 @@ page = event_info.value ```csharp var page = await context.RunAndWaitForPageAsync(async () => { - await page.GetByRole("button").ClickAsync(); + await page.GetByRole(AriaRole.Button).ClickAsync(); }); ``` diff --git a/docs/src/api/class-consolemessage.md b/docs/src/api/class-consolemessage.md index 784eef8748..c415332577 100644 --- a/docs/src/api/class-consolemessage.md +++ b/docs/src/api/class-consolemessage.md @@ -16,13 +16,11 @@ page.on('console', msg => { }); // Get the next console log -const [msg] = await Promise.all([ - page.waitForEvent('console'), - // Issue console.log inside the page - page.evaluate(() => { - console.log('hello', 42, { foo: 'bar' }); - }), -]); +const msgPromise = page.waitForEvent('console'); +await page.evaluate(() => { + console.log('hello', 42, { foo: 'bar' }); // Issue console.log inside the page +}); +const msg = await msgPromise; // Deconstruct console log arguments await msg.args[0].jsonValue() // hello diff --git a/docs/src/api/class-download.md b/docs/src/api/class-download.md index db98634d94..de09ad8d33 100644 --- a/docs/src/api/class-download.md +++ b/docs/src/api/class-download.md @@ -9,16 +9,13 @@ browser context is closed. Download event is emitted once the download starts. Download path becomes available once download completes: ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the download. -const [ download ] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('download'), - // Triggers the download. - page.getByText('Download file').click(), -]); -// wait for download to complete -const path = await download.path(); +// Start waiting for download before clicking. Note no await. +const downloadPromise = page.waitForEvent('download'); +await page.getByText('Download file').click(); +const download = await downloadPromise; + +// Wait for the download process to complete. +console.log(await download.path()); ``` ```java diff --git a/docs/src/api/class-electronapplication.md b/docs/src/api/class-electronapplication.md index a672697506..c6f3ad38a0 100644 --- a/docs/src/api/class-electronapplication.md +++ b/docs/src/api/class-electronapplication.md @@ -144,10 +144,9 @@ Waits for event to fire and passes its value into the predicate function. Return **Usage** ```js -const [window] = await Promise.all([ - electronApp.waitForEvent('window'), - mainWindow.click('button') -]); +const windowPromise = electronApp.waitForEvent('window'); +await mainWindow.click('button'); +const window = await windowPromise; ``` ### param: ElectronApplication.waitForEvent.event = %%-wait-for-event-event-%% diff --git a/docs/src/api/class-filechooser.md b/docs/src/api/class-filechooser.md index d7e8c31799..c4890dff1a 100644 --- a/docs/src/api/class-filechooser.md +++ b/docs/src/api/class-filechooser.md @@ -4,32 +4,28 @@ [FileChooser] objects are dispatched by the page in the [`event: Page.fileChooser`] event. ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the file chooser. -const [fileChooser] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('filechooser'), - // Opens the file chooser. - page.getByText('Upload').click(), -]); +// Start waiting for file chooser before clicking. Note no await. +const fileChooserPromise = page.waitForEvent('filechooser'); +await page.getByText('Upload file').click(); +const fileChooser = await fileChooserPromise; await fileChooser.setFiles('myfile.pdf'); ``` ```java -FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload").click()); +FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload file").click()); fileChooser.setFiles(Paths.get("myfile.pdf")); ``` ```python async async with page.expect_file_chooser() as fc_info: - await page.get_by_text("Upload").click() + await page.get_by_text("Upload file").click() file_chooser = await fc_info.value await file_chooser.set_files("myfile.pdf") ``` ```python sync with page.expect_file_chooser() as fc_info: - page.get_by_text("Upload").click() + page.get_by_text("Upload file").click() file_chooser = fc_info.value file_chooser.set_files("myfile.pdf") ``` @@ -37,7 +33,7 @@ file_chooser.set_files("myfile.pdf") ```csharp var fileChooser = await page.RunAndWaitForFileChooserAsync(async () => { - await page.GetByText("Upload").ClickAsync(); + await page.GetByText("Upload file").ClickAsync(); }); await fileChooser.SetFilesAsync("temp.txt"); ``` diff --git a/docs/src/api/class-frame.md b/docs/src/api/class-frame.md index cbd4d1c2de..5f38257e53 100644 --- a/docs/src/api/class-frame.md +++ b/docs/src/api/class-frame.md @@ -1928,15 +1928,15 @@ This method waits for the frame to navigate to a new URL. It is useful for when the frame to navigate. Consider this example: ```js -const [response] = await Promise.all([ - frame.waitForNavigation(), // The promise resolves after navigation has finished - frame.click('a.delayed-navigation'), // Clicking the link will indirectly cause a navigation -]); +// Start waiting for navigation before clicking. Note no await. +const navigationPromise = page.waitForNavigation(); +await page.getByText('Navigate after timeout').click(); +await navigationPromise; ``` ```java // The method returns after navigation has finished -Response response = frame.waitForNavigation(() -> { +frame.waitForNavigation(() -> { // Clicking the link will indirectly cause a navigation frame.click("a.delayed-navigation"); }); diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 782ab716d1..425e7cbbb7 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -448,34 +448,30 @@ popup with `window.open('http://example.com')`, this event will fire when the ne done and its response has started loading in the popup. ```js -// Note that Promise.all prevents a race condition -// between evaluating and waiting for the popup. -const [popup] = await Promise.all([ - // It is important to call waitForEvent first. - page.waitForEvent('popup'), - // Opens the popup. - page.evaluate(() => window.open('https://example.com')), -]); +// Start waiting for popup before clicking. Note no await. +const popupPromise = page.waitForEvent('popup'); +await page.getByText('open the popup').click(); +const popup = await popupPromise; console.log(await popup.evaluate('location.href')); ``` ```java Page popup = page.waitForPopup(() -> { - page.evaluate("() => window.open('https://example.com')"); + page.getByText("open the popup").click(); }); System.out.println(popup.evaluate("location.href")); ``` ```python async async with page.expect_event("popup") as page_info: - page.evaluate("window.open('https://example.com')") + await page.get_by_text("open the popup").click() popup = await page_info.value print(await popup.evaluate("location.href")) ``` ```python sync with page.expect_event("popup") as page_info: - page.evaluate("window.open('https://example.com')") + page.get_by_text("open the popup").click() popup = page_info.value print(popup.evaluate("location.href")) ``` @@ -483,7 +479,7 @@ print(popup.evaluate("location.href")) ```csharp var popup = await page.RunAndWaitForPopupAsync(async () => { - await page.EvaluateAsync("() => window.open('https://microsoft.com')"); + await page.GetByText("open the popup").ClickAsync(); }); Console.WriteLine(await popup.EvaluateAsync("location.href")); ``` @@ -3761,14 +3757,10 @@ value. Will throw an error if the page is closed before the event is fired. Retu **Usage** ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the event. -const [frame, _] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('framenavigated'), - // Triggers the navigation. - page.getByRole('button').click(), -]); +// Start waiting for download before clicking. Note no await. +const downloadPromise = page.waitForEvent('download'); +await page.getByText('Download file').click(); +const download = await downloadPromise; ``` ```python async @@ -3987,20 +3979,18 @@ await page.WaitForLoadStateAsync(); // The promise resolves after 'load' event. ``` ```js -const [popup] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('popup'), - // Click triggers a popup. - page.getByRole('button').click(), -]) -await popup.waitForLoadState('domcontentloaded'); // The promise resolves after 'domcontentloaded' event. +const popupPromise = page.waitForEvent('popup'); +await page.getByRole('button').click(); // Click triggers a popup. +const popup = await popupPromise; +await popup.waitForLoadState('domcontentloaded'); // Wait for the 'DOMContentLoaded' event. console.log(await popup.title()); // Popup is ready to use. ``` ```java Page popup = page.waitForPopup(() -> { - page.getByRole("button").click(); // Click triggers a popup. + page.getByRole(AriaRole.BUTTON).click(); // Click triggers a popup. }); +// Wait for the "DOMContentLoaded" event popup.waitForLoadState(LoadState.DOMCONTENTLOADED); System.out.println(popup.title()); // Popup is ready to use. ``` @@ -4009,7 +3999,7 @@ System.out.println(popup.title()); // Popup is ready to use. async with page.expect_popup() as page_info: await page.get_by_role("button").click() # click triggers a popup. popup = await page_info.value - # Following resolves after "domcontentloaded" event. +# Wait for the "DOMContentLoaded" event. await popup.wait_for_load_state("domcontentloaded") print(await popup.title()) # popup is ready to use. ``` @@ -4018,7 +4008,7 @@ print(await popup.title()) # popup is ready to use. with page.expect_popup() as page_info: page.get_by_role("button").click() # click triggers a popup. popup = page_info.value - # Following resolves after "domcontentloaded" event. +# Wait for the "DOMContentLoaded" event. popup.wait_for_load_state("domcontentloaded") print(popup.title()) # popup is ready to use. ``` @@ -4026,8 +4016,9 @@ print(popup.title()) # popup is ready to use. ```csharp var popup = await page.RunAndWaitForPopupAsync(async () => { - await page.GetByRole("button").ClickAsync(); // click triggers the popup/ + await page.GetByRole(AriaRole.Button).ClickAsync(); // click triggers the popup }); +// Wait for the "DOMContentLoaded" event. await popup.WaitForLoadStateAsync(LoadState.DOMContentLoaded); Console.WriteLine(await popup.TitleAsync()); // popup is ready to use. ``` @@ -4056,40 +4047,39 @@ cause the page to navigate. e.g. The click target has an `onclick` handler that Consider this example: ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the navigation. -const [response] = await Promise.all([ - // It is important to call waitForNavigation before click to set up waiting. - page.waitForNavigation(), - // Clicking the link will indirectly cause a navigation. - page.locator('a.delayed-navigation').click(), -]); +// Start waiting for navigation before clicking. Note no await. +const navigationPromise = page.waitForNavigation(); +await page.getByText('Navigate after timeout').click(); +await navigationPromise; ``` ```java // The method returns after navigation has finished Response response = page.waitForNavigation(() -> { - page.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation + // This action triggers the navigation after a timeout. + page.getByText("Navigate after timeout").click(); }); ``` ```python async async with page.expect_navigation(): - await page.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation + # This action triggers the navigation after a timeout. + await page.get_by_text("Navigate after timeout").click() # Resolves after navigation has finished ``` ```python sync with page.expect_navigation(): - page.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation + # This action triggers the navigation after a timeout. + page.get_by_text("Navigate after timeout").click() # Resolves after navigation has finished ``` ```csharp await page.RunAndWaitForNavigationAsync(async () => { - // Clicking the link will indirectly cause a navigation. - await page.ClickAsync("a.delayed-navigation"); + // This action triggers the navigation after a timeout. + await page.GetByText("Navigate after timeout").ClickAsync(); }); // The method continues after navigation has finished @@ -4141,57 +4131,50 @@ Waits for the matching request and returns it. See [waiting for event](../events **Usage** ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the request. -const [request] = await Promise.all([ - // Waits for the next request with the specified url - page.waitForRequest('https://example.com/resource'), - // Triggers the request - page.click('button.triggers-request'), -]); +// Start waiting for request before clicking. Note no await. +const requestPromise = page.waitForRequest('https://example.com/resource'); +await page.getByText('trigger request').click(); +const request = await requestPromise; -// Alternative way with a predicate. -const [request] = await Promise.all([ - // Waits for the next request matching some conditions - page.waitForRequest(request => request.url() === 'https://example.com' && request.method() === 'GET'), - // Triggers the request - page.click('button.triggers-request'), -]); +// Alternative way with a predicate. Note no await. +const requestPromise = page.waitForRequest(request => request.url() === 'https://example.com' && request.method() === 'GET'); +await page.getByText('trigger request').click(); +const request = await requestPromise; ``` ```java // Waits for the next request with the specified url Request request = page.waitForRequest("https://example.com/resource", () -> { // Triggers the request - page.click("button.triggers-request"); + page.getByText("trigger request").click(); }); // Waits for the next request matching some conditions Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> { // Triggers the request - page.click("button.triggers-request"); + page.getByText("trigger request").click(); }); ``` ```python async async with page.expect_request("http://example.com/resource") as first: - await page.click('button') + await page.get_by_text("trigger request").click() first_request = await first.value # or with a lambda async with page.expect_request(lambda request: request.url == "http://example.com" and request.method == "get") as second: - await page.click('img') + await page.get_by_text("trigger request").click() second_request = await second.value ``` ```python sync with page.expect_request("http://example.com/resource") as first: - page.click('button') + page.get_by_text("trigger request").click() first_request = first.value # or with a lambda with page.expect_request(lambda request: request.url == "http://example.com" and request.method == "get") as second: - page.click('img') + page.get_by_text("trigger request").click() second_request = second.value ``` @@ -4199,13 +4182,13 @@ second_request = second.value // Waits for the next request with the specified url. await page.RunAndWaitForRequestAsync(async () => { - await page.ClickAsync("button"); + await page.GetByText("trigger request").ClickAsync(); }, "http://example.com/resource"); // Alternative way with a predicate. await page.RunAndWaitForRequestAsync(async () => { - await page.ClickAsync("button"); + await page.GetByText("trigger request").ClickAsync(); }, request => request.Url == "https://example.com" && request.Method == "GET"); ``` @@ -4266,60 +4249,53 @@ Returns the matched response. See [waiting for event](../events.md#waiting-for-e **Usage** ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the response. -const [response] = await Promise.all([ - // Waits for the next response with the specified url - page.waitForResponse('https://example.com/resource'), - // Triggers the response - page.click('button.triggers-response'), -]); +// Start waiting for response before clicking. Note no await. +const responsePromise = page.waitForRequest('https://example.com/resource'); +await page.getByText('trigger response').click(); +const response = await responsePromise; -// Alternative way with a predicate. -const [response] = await Promise.all([ - // Waits for the next response matching some conditions - page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200), - // Triggers the response - page.click('button.triggers-response'), -]); +// Alternative way with a predicate. Note no await. +const responsePromise = page.waitForRequest(response => response.url() === 'https://example.com' && response.status() === 200); +await page.getByText('trigger response').click(); +const response = await responsePromise; ``` ```java // Waits for the next response with the specified url Response response = page.waitForResponse("https://example.com/resource", () -> { // Triggers the response - page.click("button.triggers-response"); + page.getByText("trigger response").click(); }); // Waits for the next response matching some conditions Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> { // Triggers the response - page.click("button.triggers-response"); + page.getByText("trigger response").click(); }); ``` ```python async async with page.expect_response("https://example.com/resource") as response_info: - await page.click("input") + await page.get_by_text("trigger response").click() response = await response_info.value return response.ok # or with a lambda async with page.expect_response(lambda response: response.url == "https://example.com" and response.status == 200) as response_info: - await page.click("input") + await page.get_by_text("trigger response").click() response = await response_info.value return response.ok ``` ```python sync with page.expect_response("https://example.com/resource") as response_info: - page.click("input") + page.get_by_text("trigger response").click() response = response_info.value return response.ok # or with a lambda with page.expect_response(lambda response: response.url == "https://example.com" and response.status == 200) as response_info: - page.click("input") + page.get_by_text("trigger response").click() response = response_info.value return response.ok ``` @@ -4328,13 +4304,13 @@ return response.ok // Waits for the next response with the specified url. await page.RunAndWaitForResponseAsync(async () => { - await page.ClickAsync("button.triggers-response"); + await page.GetByText("trigger response").ClickAsync(); }, "http://example.com/resource"); // Alternative way with a predicate. await page.RunAndWaitForResponseAsync(async () => { - await page.ClickAsync("button"); + await page.GetByText("trigger response").ClickAsync(); }, response => response.Url == "https://example.com" && response.Status == 200); ``` diff --git a/docs/src/api/class-request.md b/docs/src/api/class-request.md index 2c8793ce7b..b55b6e014c 100644 --- a/docs/src/api/class-request.md +++ b/docs/src/api/class-request.md @@ -281,10 +281,9 @@ Returns resource timing information for given request. Most of the timing values **Usage** ```js -const [request] = await Promise.all([ - page.waitForEvent('requestfinished'), - page.goto('http://example.com') -]); +const requestFinishedPromise = page.waitForEvent('requestfinished'); +await page.goto('http://example.com'); +const request = await requestFinishedPromise; console.log(request.timing()); ``` diff --git a/docs/src/downloads.md b/docs/src/downloads.md index 9031b8816e..4da69a6777 100644 --- a/docs/src/downloads.md +++ b/docs/src/downloads.md @@ -16,12 +16,10 @@ Downloaded files are deleted when the browser context that produced them is clos Here is the simplest way to handle the file download: ```js -const [ download ] = await Promise.all([ - // Start waiting for the download - page.waitForEvent('download'), - // Perform the action that initiates download - page.locator('button#delayed-download').click(), -]); +// Start waiting for download before clicking. Note no await. +const downloadPromise = page.waitForEvent('download'); +await page.getByText('Download file').click(); +const download = await downloadPromise; // Wait for the download process to complete console.log(await download.path()); // Save downloaded file somewhere @@ -32,7 +30,7 @@ await download.saveAs('/path/to/save/download/at.txt'); // Wait for the download to start Download download = page.waitForDownload(() -> { // Perform the action that initiates download - page.locator("button#delayed-download").click(); + page.getByText("Download file").click(); }); // Wait for the download process to complete Path path = download.path(); @@ -45,7 +43,7 @@ download.saveAs(Paths.get("/path/to/save/download/at.txt")); # Start waiting for the download async with page.expect_download() as download_info: # Perform the action that initiates download - await page.locator("button#delayed-download").click() + await page.get_by_text("Download file").click() download = await download_info.value # Wait for the download process to complete print(await download.path()) @@ -57,7 +55,8 @@ download.save_as("/path/to/save/download/at.txt") # Start waiting for the download with page.expect_download() as download_info: # Perform the action that initiates download - page.locator("button#delayed-download").click() + page.get_by_text("Download file").click() +# Wait for the download to start download = download_info.value # Wait for the download process to complete print(download.path()) @@ -66,12 +65,11 @@ download.save_as("/path/to/save/download/at.txt") ``` ```csharp -// Start the task of waiting for the download +// Start the task of waiting for the download before clicking var waitForDownloadTask = page.WaitForDownloadAsync(); -// Perform the action that initiates download -await page.Locator("#downloadButton").ClickAsync(); -// Wait for the download process to complete +await page.GetByText("Download file").ClickAsync(); var download = await waitForDownloadTask; +// Wait for the download process to complete Console.WriteLine(await download.PathAsync()); // Save downloaded file somewhere await download.SaveAsAsync("/path/to/save/download/at.txt"); diff --git a/docs/src/events.md b/docs/src/events.md index f0f93581f7..24e6c68403 100644 --- a/docs/src/events.md +++ b/docs/src/events.md @@ -12,13 +12,10 @@ Most of the time, scripts will need to wait for a particular event to happen. Be Wait for a request with the specified url using [`method: Page.waitForRequest`]: ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the request. -const [request] = await Promise.all([ - page.waitForRequest('**/*logo*.png'), - // This action triggers the request - page.goto('https://wikipedia.org') -]); +// Start waiting for request before goto. Note no await. +const requestPromise = page.waitForRequest('**/*logo*.png'); +await page.goto('https://wikipedia.org'); +const request = await requestPromise; console.log(request.url()); ``` @@ -54,14 +51,10 @@ Console.WriteLine(request.Url); Wait for popup window: ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the popup. -const [popup] = await Promise.all([ - // It is important to call waitForEvent first. - page.waitForEvent('popup'), - // This action triggers the popup - page.evaluate('window.open()') -]); +// Start waiting for popup before clicking. Note no await. +const popupPromise = page.waitForEvent('popup'); +await page.getByText('open the popup').click(); +const popup = await popupPromise; await popup.goto('https://wikipedia.org'); ``` @@ -69,28 +62,28 @@ await popup.goto('https://wikipedia.org'); // The callback lambda defines scope of the code that is expected to // create popup window. Page popup = page.waitForPopup(() -> { - page.evaluate("window.open()"); + page.getByText("open the popup").click(); }); popup.navigate("https://wikipedia.org"); ``` ```python async async with page.expect_popup() as popup: - await page.evaluate("window.open()") + await page.get_by_text("open the popup").click() child_page = await popup.value await child_page.goto("https://wikipedia.org") ``` ```python sync with page.expect_popup() as popup: - page.evaluate("window.open()") + page.get_by_text("open the popup").click() popup.value.goto("https://wikipedia.org") ``` ```csharp var popup = await page.RunAndWaitForPopupAsync(async => { - await page.EvaluateAsync("window.open()"); + await page.GetByText("open the popup").ClickAsync(); }); await popup.GotoAsync("https://wikipedia.org"); ``` diff --git a/docs/src/input.md b/docs/src/input.md index a2b74023e0..371b3786b6 100644 --- a/docs/src/input.md +++ b/docs/src/input.md @@ -606,33 +606,30 @@ If you don't have input element in hand (it is created dynamically), you can han or use a corresponding waiting method upon your action: ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the file chooser. -const [fileChooser] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('filechooser'), - page.locator('upload').click(), -]); +// Start waiting for file chooser before clicking. Note no await. +const fileChooserPromise = page.waitForEvent('filechooser'); +await page.getByLabel('Upload file').click(); +const fileChooser = await fileChooserPromise; await fileChooser.setFiles('myfile.pdf'); ``` ```java FileChooser fileChooser = page.waitForFileChooser(() -> { - page.locator("upload").click(); + page.getByLabel("Upload file").click(); }); fileChooser.setFiles(Paths.get("myfile.pdf")); ``` ```python async async with page.expect_file_chooser() as fc_info: - await page.locator("upload").click() + await page.get_by_label("Upload file").click() file_chooser = await fc_info.value await file_chooser.set_files("myfile.pdf") ``` ```python sync with page.expect_file_chooser() as fc_info: - page.locator("upload").click() + page.get_by_label("Upload file").click() file_chooser = fc_info.value file_chooser.set_files("myfile.pdf") ``` @@ -640,7 +637,7 @@ file_chooser.set_files("myfile.pdf") ```csharp var fileChooser = page.RunAndWaitForFileChooserAsync(async () => { - await page.Locator("upload").ClickAsync(); + await page.GetByLabel("Upload file").ClickAsync(); }); await fileChooser.SetFilesAsync("myfile.pdf"); ``` diff --git a/docs/src/navigations.md b/docs/src/navigations.md index 6f7a66ab32..fcd3e54e1c 100644 --- a/docs/src/navigations.md +++ b/docs/src/navigations.md @@ -299,22 +299,17 @@ recommended to explicitly call [`method: Page.waitForNavigation`]. For example: * Page waits for network requests before navigation ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for a navigation. -await Promise.all([ - // Waits for the next navigation. - // It is important to call waitForNavigation before click to set up waiting. - page.waitForNavigation(), - // Triggers a navigation after a timeout. - page.locator('div.delayed-navigation').click(), -]); +// Start waiting for navigation before clicking. Note no await. +const navigationPromise = page.waitForNavigation(); +await page.getByText('Navigate after timeout').click(); +await navigationPromise; ``` ```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.locator("div.delayed-navigation").click(); // Triggers a navigation after a timeout + page.getByText("Navigate after timeout").click(); // Triggers a navigation after a timeout }); ``` @@ -323,7 +318,7 @@ page.waitForNavigation(() -> { // Waits for the next navigation # prevents a race condition between clicking and waiting for a navigation. async with page.expect_navigation(): # Triggers a navigation after a timeout - await page.locator("div.delayed-navigation").click() + await page.get_by_text("Navigate after timeout").click() ``` ```python sync @@ -331,7 +326,7 @@ async with page.expect_navigation(): # prevents a race condition between clicking and waiting for a navigation. with page.expect_navigation(): # Triggers a navigation after a timeout - page.locator("a").click() + page.get_by_text("Navigate after timeout").click() ``` ```csharp @@ -340,7 +335,7 @@ with page.expect_navigation(): await page.RunAndWaitForNavigationAsync(async () => { // Triggers a navigation after a timeout - await page.Locator("div.delayed-navigation").ClickAsync(); + await page.GetByText("Navigate after timeout").ClickAsync(); }); ``` @@ -352,14 +347,11 @@ Clicking an element could trigger multiple navigations. In these cases, it is re * Multiple pushes to history state ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for a navigation. -await Promise.all([ - // It is important to call waitForNavigation before click to set up waiting. - page.waitForNavigation({ url: '**/login' }), - // Triggers a navigation with a script redirect. - page.getByText('Click me').click(), -]); +// Start waiting for navigation before clicking. Note no await. +const navigationPromise = page.waitForNavigation({ url: '**/login' }); +// This action triggers the navigation with a script redirect. +await page.getByText('Click me').click(); +await navigationPromise; ``` ```java @@ -404,34 +396,31 @@ await page.RunAndWaitForNavigationAsync(async () => When popup is opened, explicitly calling [`method: Page.waitForLoadState`] ensures that popup is loaded to the desired state. ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the popup. -const [ popup ] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('popup'), - // Opens popup. - page.locator('a[target="_blank"]').click(), -]); +// Start waiting for popup before clicking. Note no await. +const popupPromise = page.waitForEvent('popup'); +await page.getByText('Open popup').click(); +const popup = await popupPromise; +// Wait for the popup to load. await popup.waitForLoadState('load'); ``` ```java Page popup = page.waitForPopup(() -> { - page.locator("a[target='_blank']").click(); // Opens popup + page.getByText("Open popup").click(); // Opens popup }); popup.waitForLoadState(LoadState.LOAD); ``` ```python async async with page.expect_popup() as popup_info: - await page.locator('a[target="_blank"]').click() # Opens popup + await page.get_by_text("Open popup").click() # Opens popup popup = await popup_info.value await popup.wait_for_load_state("load") ``` ```python sync with page.expect_popup() as popup_info: - page.locator('a[target="_blank"]').click() # Opens popup + page.get_by_text("Open popup").click() # Opens popup popup = popup_info.value popup.wait_for_load_state("load") ``` @@ -439,7 +428,7 @@ popup.wait_for_load_state("load") ```csharp var popup = await page.RunAndWaitForPopupAsync(async () => { - await page.Locator("a[target='_blank']").ClickAsync(); // Opens popup + await page.GetByText("Open popup").ClickAsync(); // Opens popup }); popup.WaitForLoadStateAsync(LoadState.Load); ``` diff --git a/docs/src/network.md b/docs/src/network.md index 4a8278d191..9ef45b7005 100644 --- a/docs/src/network.md +++ b/docs/src/network.md @@ -248,11 +248,10 @@ await page.GotoAsync("https://example.com"); Or wait for a network response after the button click with [`method: Page.waitForResponse`]: ```js -// Use a glob URL pattern -const [response] = await Promise.all([ - page.waitForResponse('**/api/fetch_data'), - page.getByText('Update').click(), -]); +// Use a glob URL pattern. Note no await. +const responsePromise = page.waitForResponse('**/api/fetch_data'); +await page.getByText('Update').click(); +const response = await responsePromise; ``` ```java @@ -288,17 +287,15 @@ var response = await waitForResponseTask; Wait for [Response]s with [`method: Page.waitForResponse`] ```js -// Use a RegExp -const [response] = await Promise.all([ - page.waitForResponse(/\.jpeg$/), - page.getByText('Update').click(), -]); +// Use a RegExp. Note no await. +const responsePromise = page.waitForResponse(/\.jpeg$/); +await page.getByText('Update').click(); +const response = await responsePromise; -// Use a predicate taking a Response object -const [response] = await Promise.all([ - page.waitForResponse(response => response.url().includes(token)), - page.getByText('Update').click(), -]); +// Use a predicate taking a Response object. Note no await. +const responsePromise = page.waitForResponse(response => response.url().includes(token)); +await page.getByText('Update').click(); +const response = await responsePromise; ``` ```java diff --git a/docs/src/pages.md b/docs/src/pages.md index 2dde6ca0c7..495d71f8ce 100644 --- a/docs/src/pages.md +++ b/docs/src/pages.md @@ -141,11 +141,10 @@ The `page` event on browser contexts can be used to get new pages that are creat handle new pages opened by `target="_blank"` links. ```js -// Get page after a specific action (e.g. clicking a link) -const [newPage] = await Promise.all([ - context.waitForEvent('page'), - page.locator('a[target="_blank"]').click() // Opens a new tab -]) +// Start waiting for new page before clicking. Note no await. +const pagePromise = context.waitForEvent('page'); +await page.getByText('open new tab').click(); +const newPage = await pagePromise; await newPage.waitForLoadState(); console.log(await newPage.title()); ``` @@ -153,7 +152,7 @@ console.log(await newPage.title()); ```java // Get page after a specific action (e.g. clicking a link) Page newPage = context.waitForPage(() -> { - page.locator("a[target='_blank']").click(); // Opens a new tab + page.getByText("open new tab").click(); // Opens a new tab }); newPage.waitForLoadState(); System.out.println(newPage.title()); @@ -162,7 +161,7 @@ System.out.println(newPage.title()); ```python async # Get page after a specific action (e.g. clicking a link) async with context.expect_page() as new_page_info: - await page.locator('a[target="_blank"]').click() # Opens a new tab + await page.get_by_text("open new tab").click() # Opens a new tab new_page = await new_page_info.value await new_page.wait_for_load_state() @@ -172,7 +171,7 @@ print(await new_page.title()) ```python sync # Get page after a specific action (e.g. clicking a link) with context.expect_page() as new_page_info: - page.locator('a[target="_blank"]').click() # Opens a new tab + page.get_by_text("open new tab").click() # Opens a new tab new_page = new_page_info.value new_page.wait_for_load_state() @@ -183,7 +182,7 @@ print(new_page.title()) // Get page after a specific action (e.g. clicking a link) var newPage = await context.RunAndWaitForPageAsync(async () => { - await page.Locator("a[target='_blank']").ClickAsync(); + await page.GetByText("open new tab").ClickAsync(); }); await newPage.WaitForLoadStateAsync(); Console.WriteLine(await newPage.TitleAsync()); @@ -241,14 +240,11 @@ If the page opens a pop-up (e.g. pages opened by `target="_blank"` links), you c This event is emitted in addition to the `browserContext.on('page')` event, but only for popups relevant to this page. ```js -// Note that Promise.all prevents a race condition -// between clicking and waiting for the popup. -const [popup] = await Promise.all([ - // It is important to call waitForEvent before click to set up waiting. - page.waitForEvent('popup'), - // Opens popup. - page.locator('#open').click(), -]); +// Start waiting for popup before clicking. Note no await. +const popupPromise = page.waitForEvent('popup'); +await page.getByText('open the popup').click(); +const popup = await popupPromise; +// Wait for the popup to load. await popup.waitForLoadState(); console.log(await popup.title()); ``` @@ -256,7 +252,7 @@ console.log(await popup.title()); ```java // Get popup after a specific action (e.g., click) Page popup = page.waitForPopup(() -> { - page.locator("#open").click(); + page.getByText("open the popup").click(); }); popup.waitForLoadState(); System.out.println(popup.title()); @@ -265,7 +261,7 @@ System.out.println(popup.title()); ```python async # Get popup after a specific action (e.g., click) async with page.expect_popup() as popup_info: - await page.locator("#open").click() + await page.get_by_text("open the popup").click() popup = await popup_info.value await popup.wait_for_load_state() @@ -275,7 +271,7 @@ print(await popup.title()) ```python sync # Get popup after a specific action (e.g., click) with page.expect_popup() as popup_info: - page.locator("#open").click() + page.get_by_text("open the popup").click() popup = popup_info.value popup.wait_for_load_state() @@ -284,12 +280,12 @@ print(popup.title()) ```csharp // Get popup after a specific action (e.g., click) -var newPage = await page.RunAndWaitForPopupAsync(async () => +var popup = await page.RunAndWaitForPopupAsync(async () => { - await page.Locator("#open").ClickAsync(); + await page.GetByText("open the popup").ClickAsync(); }); -await newPage.WaitForLoadStateAsync(); -Console.WriteLine(await newPage.TitleAsync()); +await popup.WaitForLoadStateAsync(); +Console.WriteLine(await popup.TitleAsync()); ``` If the action that triggers the popup is unknown, the following pattern can be used. @@ -298,7 +294,7 @@ If the action that triggers the popup is unknown, the following pattern can be u // Get all popups when they open page.on('popup', async popup => { await popup.waitForLoadState(); - await popup.title(); + console.log(await popup.title()); }) ``` diff --git a/docs/src/service-workers-experimental-network-events-js.md b/docs/src/service-workers-experimental-network-events-js.md index 2edd3409e2..35c1fdcb1a 100644 --- a/docs/src/service-workers-experimental-network-events-js.md +++ b/docs/src/service-workers-experimental-network-events-js.md @@ -28,17 +28,15 @@ If you're using (or are interested in using this this feature), please comment o You can use [`method: BrowserContext.serviceWorkers`] to list the Service [Worker]s, or specifically watch for the Service [Worker] if you anticipate a page will trigger its [registration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register): ```js tab=js-ts -const [ serviceworker ] = await Promise.all([ - context.waitForEvent('serviceworker'), - page.goto('/example-with-a-service-worker.html'), -]); +const serviceWorkerPromise = context.waitForEvent('serviceworker'); +await page.goto('/example-with-a-service-worker.html'); +const serviceworker = await serviceWorkerPromise; ``` ```js tab=js-js -const [ serviceworker ] = await Promise.all([ - context.waitForEvent('serviceworker'), - page.goto('/example-with-a-service-worker.html'), -]); +const serviceWorkerPromise = context.waitForEvent('serviceworker'); +await page.goto('/example-with-a-service-worker.html'); +const serviceworker = await serviceWorkerPromise; ``` ```python async @@ -148,7 +146,7 @@ Many Service Worker implementations simply execute the request from the page (po // filename: transparent-service-worker.js self.addEventListener("fetch", (event) => { // actually make the request - const responsePromise = fetch(event.request); + const responsePromise = fetch(event.request); // send it back to the page event.respondWith(responsePromise); }); diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 02d49c5bdc..70bb70c722 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -990,14 +990,10 @@ export interface Page { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * // Note that Promise.all prevents a race condition - * // between evaluating and waiting for the popup. - * const [popup] = await Promise.all([ - * // It is important to call waitForEvent first. - * page.waitForEvent('popup'), - * // Opens the popup. - * page.evaluate(() => window.open('https://example.com')), - * ]); + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; * console.log(await popup.evaluate('location.href')); * ``` * @@ -1287,14 +1283,10 @@ export interface Page { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * // Note that Promise.all prevents a race condition - * // between evaluating and waiting for the popup. - * const [popup] = await Promise.all([ - * // It is important to call waitForEvent first. - * page.waitForEvent('popup'), - * // Opens the popup. - * page.evaluate(() => window.open('https://example.com')), - * ]); + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; * console.log(await popup.evaluate('location.href')); * ``` * @@ -1679,14 +1671,10 @@ export interface Page { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * // Note that Promise.all prevents a race condition - * // between evaluating and waiting for the popup. - * const [popup] = await Promise.all([ - * // It is important to call waitForEvent first. - * page.waitForEvent('popup'), - * // Opens the popup. - * page.evaluate(() => window.open('https://example.com')), - * ]); + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; * console.log(await popup.evaluate('location.href')); * ``` * @@ -4214,14 +4202,10 @@ export interface Page { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * // Note that Promise.all prevents a race condition - * // between evaluating and waiting for the popup. - * const [popup] = await Promise.all([ - * // It is important to call waitForEvent first. - * page.waitForEvent('popup'), - * // Opens the popup. - * page.evaluate(() => window.open('https://example.com')), - * ]); + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; * console.log(await popup.evaluate('location.href')); * ``` * @@ -4295,13 +4279,10 @@ export interface Page { * ``` * * ```js - * const [popup] = await Promise.all([ - * // It is important to call waitForEvent before click to set up waiting. - * page.waitForEvent('popup'), - * // Click triggers a popup. - * page.getByRole('button').click(), - * ]) - * await popup.waitForLoadState('domcontentloaded'); // The promise resolves after 'domcontentloaded' event. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByRole('button').click(); // Click triggers a popup. + * const popup = await popupPromise; + * await popup.waitForLoadState('domcontentloaded'); // Wait for the 'DOMContentLoaded' event. * console.log(await popup.title()); // Popup is ready to use. * ``` * @@ -4336,14 +4317,10 @@ export interface Page { * a `setTimeout`. Consider this example: * * ```js - * // Note that Promise.all prevents a race condition - * // between clicking and waiting for the navigation. - * const [response] = await Promise.all([ - * // It is important to call waitForNavigation before click to set up waiting. - * page.waitForNavigation(), - * // Clicking the link will indirectly cause a navigation. - * page.locator('a.delayed-navigation').click(), - * ]); + * // Start waiting for navigation before clicking. Note no await. + * const navigationPromise = page.waitForNavigation(); + * await page.getByText('Navigate after timeout').click(); + * await navigationPromise; * ``` * * **NOTE** Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL @@ -4387,22 +4364,15 @@ export interface Page { * **Usage** * * ```js - * // Note that Promise.all prevents a race condition - * // between clicking and waiting for the request. - * const [request] = await Promise.all([ - * // Waits for the next request with the specified url - * page.waitForRequest('https://example.com/resource'), - * // Triggers the request - * page.click('button.triggers-request'), - * ]); + * // Start waiting for request before clicking. Note no await. + * const requestPromise = page.waitForRequest('https://example.com/resource'); + * await page.getByText('trigger request').click(); + * const request = await requestPromise; * - * // Alternative way with a predicate. - * const [request] = await Promise.all([ - * // Waits for the next request matching some conditions - * page.waitForRequest(request => request.url() === 'https://example.com' && request.method() === 'GET'), - * // Triggers the request - * page.click('button.triggers-request'), - * ]); + * // Alternative way with a predicate. Note no await. + * const requestPromise = page.waitForRequest(request => request.url() === 'https://example.com' && request.method() === 'GET'); + * await page.getByText('trigger request').click(); + * const request = await requestPromise; * ``` * * @param urlOrPredicate Request URL string, regex or predicate receiving [Request] object. @@ -4424,22 +4394,15 @@ export interface Page { * **Usage** * * ```js - * // Note that Promise.all prevents a race condition - * // between clicking and waiting for the response. - * const [response] = await Promise.all([ - * // Waits for the next response with the specified url - * page.waitForResponse('https://example.com/resource'), - * // Triggers the response - * page.click('button.triggers-response'), - * ]); + * // Start waiting for response before clicking. Note no await. + * const responsePromise = page.waitForRequest('https://example.com/resource'); + * await page.getByText('trigger response').click(); + * const response = await responsePromise; * - * // Alternative way with a predicate. - * const [response] = await Promise.all([ - * // Waits for the next response matching some conditions - * page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200), - * // Triggers the response - * page.click('button.triggers-response'), - * ]); + * // Alternative way with a predicate. Note no await. + * const responsePromise = page.waitForRequest(response => response.url() === 'https://example.com' && response.status() === 200); + * await page.getByText('trigger response').click(); + * const response = await responsePromise; * ``` * * @param urlOrPredicate Request URL string, regex or predicate receiving [Response] object. When a `baseURL` via the context options was @@ -6916,10 +6879,10 @@ export interface Frame { * cause the frame to navigate. Consider this example: * * ```js - * const [response] = await Promise.all([ - * frame.waitForNavigation(), // The promise resolves after navigation has finished - * frame.click('a.delayed-navigation'), // Clicking the link will indirectly cause a navigation - * ]); + * // Start waiting for navigation before clicking. Note no await. + * const navigationPromise = page.waitForNavigation(); + * await page.getByText('Navigate after timeout').click(); + * await navigationPromise; * ``` * * **NOTE** Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL @@ -7204,10 +7167,9 @@ export interface BrowserContext { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * const [newPage] = await Promise.all([ - * context.waitForEvent('page'), - * page.locator('a[target=_blank]').click(), - * ]); + * const newPagePromise = context.waitForEvent('page'); + * await page.getByText('open new page').click(); + * const newPage = await newPagePromise; * console.log(await newPage.evaluate('location.href')); * ``` * @@ -7333,10 +7295,9 @@ export interface BrowserContext { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * const [newPage] = await Promise.all([ - * context.waitForEvent('page'), - * page.locator('a[target=_blank]').click(), - * ]); + * const newPagePromise = context.waitForEvent('page'); + * await page.getByText('open new page').click(); + * const newPage = await newPagePromise; * console.log(await newPage.evaluate('location.href')); * ``` * @@ -7502,10 +7463,9 @@ export interface BrowserContext { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * const [newPage] = await Promise.all([ - * context.waitForEvent('page'), - * page.locator('a[target=_blank]').click(), - * ]); + * const newPagePromise = context.waitForEvent('page'); + * await page.getByText('open new page').click(); + * const newPage = await newPagePromise; * console.log(await newPage.evaluate('location.href')); * ``` * @@ -8036,10 +7996,9 @@ export interface BrowserContext { * "http://example.com" is done and its response has started loading in the popup. * * ```js - * const [newPage] = await Promise.all([ - * context.waitForEvent('page'), - * page.locator('a[target=_blank]').click(), - * ]); + * const newPagePromise = context.waitForEvent('page'); + * await page.getByText('open new page').click(); + * const newPage = await newPagePromise; * console.log(await newPage.evaluate('location.href')); * ``` * @@ -15289,13 +15248,11 @@ export interface BrowserServer { * }); * * // Get the next console log - * const [msg] = await Promise.all([ - * page.waitForEvent('console'), - * // Issue console.log inside the page - * page.evaluate(() => { - * console.log('hello', 42, { foo: 'bar' }); - * }), - * ]); + * const msgPromise = page.waitForEvent('console'); + * await page.evaluate(() => { + * console.log('hello', 42, { foo: 'bar' }); // Issue console.log inside the page + * }); + * const msg = await msgPromise; * * // Deconstruct console log arguments * await msg.args[0].jsonValue() // hello @@ -15539,16 +15496,13 @@ export interface Dialog { * Download event is emitted once the download starts. Download path becomes available once download completes: * * ```js - * // Note that Promise.all prevents a race condition - * // between clicking and waiting for the download. - * const [ download ] = await Promise.all([ - * // It is important to call waitForEvent before click to set up waiting. - * page.waitForEvent('download'), - * // Triggers the download. - * page.getByText('Download file').click(), - * ]); - * // wait for download to complete - * const path = await download.path(); + * // Start waiting for download before clicking. Note no await. + * const downloadPromise = page.waitForEvent('download'); + * await page.getByText('Download file').click(); + * const download = await downloadPromise; + * + * // Wait for the download process to complete. + * console.log(await download.path()); * ``` * */ @@ -15843,14 +15797,10 @@ export interface Electron { * [page.on('filechooser')](https://playwright.dev/docs/api/class-page#page-event-file-chooser) event. * * ```js - * // Note that Promise.all prevents a race condition - * // between clicking and waiting for the file chooser. - * const [fileChooser] = await Promise.all([ - * // It is important to call waitForEvent before click to set up waiting. - * page.waitForEvent('filechooser'), - * // Opens the file chooser. - * page.getByText('Upload').click(), - * ]); + * // Start waiting for file chooser before clicking. Note no await. + * const fileChooserPromise = page.waitForEvent('filechooser'); + * await page.getByText('Upload file').click(); + * const fileChooser = await fileChooserPromise; * await fileChooser.setFiles('myfile.pdf'); * ``` * @@ -16794,10 +16744,9 @@ export interface Request { * **Usage** * * ```js - * const [request] = await Promise.all([ - * page.waitForEvent('requestfinished'), - * page.goto('http://example.com') - * ]); + * const requestFinishedPromise = page.waitForEvent('requestfinished'); + * await page.goto('http://example.com'); + * const request = await requestFinishedPromise; * console.log(request.timing()); * ``` *