diff --git a/docs/sources/k6/next/javascript-api/k6-browser/frame/_index.md b/docs/sources/k6/next/javascript-api/k6-browser/frame/_index.md index cf97196bf7..c3dc0a5e3b 100644 --- a/docs/sources/k6/next/javascript-api/k6-browser/frame/_index.md +++ b/docs/sources/k6/next/javascript-api/k6-browser/frame/_index.md @@ -56,3 +56,4 @@ Frame represents a single frame in a browser window. It can be a top-level frame | [waitForNavigation([options])](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitfornavigation/) | Waits for the given navigation lifecycle event to occur and returns the main resource response. | | [waitForSelector(selector[, options])](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitforselector/) | Returns when element specified by selector satisfies `state` option. | | [waitForTimeout(timeout)](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitfortimeout) | Waits for the given `timeout` in milliseconds. | +| [waitForURL(url[, options])](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitforurl/) | Waits for the frame to navigate to the specified URL. | diff --git a/docs/sources/k6/next/javascript-api/k6-browser/frame/waitfornavigation.md b/docs/sources/k6/next/javascript-api/k6-browser/frame/waitfornavigation.md index 5fda14139e..8bc0414834 100644 --- a/docs/sources/k6/next/javascript-api/k6-browser/frame/waitfornavigation.md +++ b/docs/sources/k6/next/javascript-api/k6-browser/frame/waitfornavigation.md @@ -9,14 +9,19 @@ Waits for the given navigation lifecycle event to occur and returns the main res -| Parameter | Type | Default | Description | -| ----------------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| options | object | `null` | | -| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | -| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | +| Parameter | Type | Default | Description | +| ----------------- | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | +| options.url | string\|RegExp | `null` | URL or URL pattern to match the navigation URL against. Useful when frame navigation performs multiple redirects and you need to wait until a final destination within the frame is reached. | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | +### When to use the url option + +Use `options.url` when frame navigation passes through several intermediate pages (e.g., third‑party authentication or consent flows) before settling on a final URL. Matching the final URL or a regex pattern helps you reliably wait for the intended destination inside the frame. However, opt to work with [waitForURL](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitforurl) instead since it mitigates the risk of race conditions better than `waitForNavigation`. + ### Events {{< admonition type="caution" >}} @@ -36,3 +41,54 @@ Events can be either: | Type | Description | | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | Promise/javascript-api/k6-browser/response/)> | The `Response` instance associated with the frame. Else, it returns `null` | + +### Examples + + + +```javascript +import { browser } from 'k6/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +}; + +export default async function () { + const page = await browser.newPage(); + + try { + await page.setContent(` + + `); + + // Retreive the frame of the iframe + const iframeElement = await page.$('iframe'); + const frame = await iframeElement.contentFrame(); + + // Wait for navigation to a specific URL + await Promise.all([ + frame.click('a[href="/my_messages.php"]'), + frame.waitForNavigation({ url: 'https://quickpizza.grafana.com/my_messages.php' }), + ]); + + await frame.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation using URL pattern with RegExp + await Promise.all([ + frame.click('a[href="/browser.php"]'), + frame.waitForNavigation({ url: /\/browser\.php$/ }), + ]); + } finally { + await page.close(); + } +} +``` diff --git a/docs/sources/k6/next/javascript-api/k6-browser/frame/waitforurl.md b/docs/sources/k6/next/javascript-api/k6-browser/frame/waitforurl.md new file mode 100644 index 0000000000..d7c87499a1 --- /dev/null +++ b/docs/sources/k6/next/javascript-api/k6-browser/frame/waitforurl.md @@ -0,0 +1,146 @@ +--- +title: 'waitForURL(url[, options])' +description: 'Browser module: frame.waitForURL(url[, options]) method' +--- + +# waitForURL(url[, options]) + +Waits for the frame to navigate to the specified URL. This method is useful for ensuring that navigation within a specific frame (such as an iframe) to a particular URL has completed before proceeding with the test. This is especially useful if there are multiple redirects before hitting the end destination. + + + +| Parameter | Type | Default | Description | +| ----------------- | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| url | string\|RegExp | - | Required. URL or URL pattern to match against. The method will wait until the frame navigates to a URL that matches this parameter. | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | + + + +### Events + +{{< admonition type="caution" >}} + +`networkidle` is DISCOURAGED. Don't use this method for testing especially with chatty websites where the event may never fire, rely on web assertions to assess readiness instead. + +{{< /admonition >}} + +Events can be either: + +- `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. +- `'load'` - consider operation to be finished when the `load` event is fired. +- `'networkidle'` - Consider operation to be finished when there are no network connections for at least `500` ms. + +### Returns + +| Type | Description | +| ------- | ------------------------------------------------------------------------------------------------------------------------ | +| Promise | A Promise that resolves when the frame has navigated to the specified URL and the specified load state has been reached. | + +### Examples + + + +```javascript +import { browser } from 'k6/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +}; + +export default async function () { + const page = await browser.newPage(); + + try { + await page.setContent(` + + `); + + const iframeElement = await page.$('iframe'); + const iframeContent = await iframeElement.contentFrame(); + + // Wait for navigation to a specific URL + await Promise.all([ + iframeContent.click('a[href="/my_messages.php"]'), + iframeContent.waitForURL('https://quickpizza.grafana.com/my_messages.php'), + ]); + + await iframeContent.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation using URL pattern with RegExp + await Promise.all([ + iframeContent.click('a[href="/browser.php"]'), + iframeContent.waitForURL(/\/browser\.php$/), + ]); + } finally { + await page.close(); + } +} +``` + +### Valid usage patterns for waitForURL + +Use one of the following patterns to coordinate the action that triggers navigation with waiting for the final URL. + + + +```js +await Promise.all([ + frame.waitForURL('https://quickpizza.grafana.com/my_messages.php'), + frame.locator('a[href="/my_messages.php"]').click(), +]); +``` + +or + + + +```js +const navPromise = frame.waitForURL('https://quickpizza.grafana.com/my_messages.php'); +await frame.locator('a[href="/my_messages.php"]').click(); +await navPromise; +``` + +Unlike [waitForNavigation](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitfornavigation), `waitForURL` will first check whether it is already on the page with the given URL before proceeding to wait. If it is already there and the `waitUntil` condition has also been met, it will return straight away. This means that it is safe to do this: + + + +```js +await frame.locator('a[href="/my_messages.php"]').click(); +await frame.waitForURL('https://quickpizza.grafana.com/my_messages.php'); +``` + +### Best practices + +1. **Verify frame existence**: Frames can be created, destroyed, or replaced during page navigation. Always verify frame existence before calling `waitForURL()`. + +2. **Use appropriate selectors**: Use frame selectors that are stable and unique. + +3. **Handle cross-origin scenarios**: Be aware of limitations when working with cross-origin iframes. + +4. **Combine with content verification**: After URL change, verify that the expected content is present. + +5. **Consider frame timing**: Frame navigation may happen after page navigation, so allow appropriate time. + +### Common use cases + +- **Payment processing**: Waiting for payment iframe redirects +- **Social media embeds**: Handling navigation in embedded social content +- **OAuth flows**: Managing authentication within iframes +- **Multi-frame applications**: Coordinating navigation across multiple frames +- **Embedded widgets**: Testing third-party widget navigation + +### Related + +- [frame.waitForNavigation()](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitfornavigation/) - Wait for frame navigation events +- [frame.waitForLoadState()](https://grafana.com/docs/k6//javascript-api/k6-browser/frame/waitforloadstate/) - Wait for load states diff --git a/docs/sources/k6/next/javascript-api/k6-browser/page/_index.md b/docs/sources/k6/next/javascript-api/k6-browser/page/_index.md index 3b54fddda1..7c6c865428 100644 --- a/docs/sources/k6/next/javascript-api/k6-browser/page/_index.md +++ b/docs/sources/k6/next/javascript-api/k6-browser/page/_index.md @@ -72,4 +72,5 @@ Page provides methods to interact with a single tab in a running web browser. A | [waitForNavigation([options])](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitfornavigation/) | Waits for the given navigation lifecycle event to occur and returns the main resource response. | | [waitForSelector(selector[, options])](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitforselector/) | Returns when element specified by selector satisfies `state` option. | | [waitForTimeout(timeout)](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitfortimeout) | Waits for the given `timeout` in milliseconds. | +| [waitForURL(url[, options])](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitforurl/) | Waits for the page to navigate to the specified URL. | | [workers()](https://grafana.com/docs/k6//javascript-api/k6-browser/page/workers) | Returns an array of the dedicated [WebWorkers](https://grafana.com/docs/k6//javascript-api/k6-browser/worker) associated with the page. | diff --git a/docs/sources/k6/next/javascript-api/k6-browser/page/waitfornavigation.md b/docs/sources/k6/next/javascript-api/k6-browser/page/waitfornavigation.md index d1702915ec..da332a6fbe 100644 --- a/docs/sources/k6/next/javascript-api/k6-browser/page/waitfornavigation.md +++ b/docs/sources/k6/next/javascript-api/k6-browser/page/waitfornavigation.md @@ -9,14 +9,19 @@ Waits for the given navigation lifecycle event to occur and returns the main res -| Parameter | Type | Default | Description | -| ----------------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| options | object | `null` | | -| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | -| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | +| Parameter | Type | Default | Description | +| ----------------- | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | +| options.url | string\|RegExp | `null` | URL or URL pattern to match the navigation URL against. When provided, the method will wait for navigation to a URL that matches this parameter. | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | +## When to use the url option + +Use `options.url` when frame navigation passes through several intermediate pages (e.g., third‑party authentication or consent flows) before settling on a final URL. Matching the final URL or a regex pattern helps you reliably wait for the intended destination. However, opt to work with [waitForURL](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitforurl) instead since it mitigates the risk of race conditions better than `waitForNavigation`. + ### Events {{< admonition type="caution" >}} @@ -37,9 +42,9 @@ Events can be either: | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | Promise/javascript-api/k6-browser/response/)> | The `Response` instance associated with the page. Else, it returns `null` | -### Example +### Examples -{{< code >}} +#### Basic navigation waiting ```javascript import { browser } from 'k6/browser'; @@ -69,13 +74,10 @@ export default async function () { const submitButton = page.locator('input[type="submit"]'); - await Promise.all([ - submitButton.click(), - page.waitForNavigation(), - ]); + await Promise.all([submitButton.click(), page.waitForNavigation()]); await check(page.locator('h2'), { - header: async h2 => await h2.textContent() == 'Welcome, admin!' + header: async (h2) => (await h2.textContent()) == 'Welcome, admin!', }); } finally { await page.close(); @@ -83,4 +85,47 @@ export default async function () { } ``` -{{< /code >}} +#### Wait for navigation to specific URL + + + +```javascript +import { browser } from 'k6/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +}; + +export default async function () { + const page = await browser.newPage(); + + try { + await page.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation to a specific URL + await Promise.all([ + page.click('a[href="/my_messages.php"]'), + page.waitForNavigation({ url: 'https://quickpizza.grafana.com/my_messages.php' }), + ]); + + await page.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation using URL pattern with RegExp + await Promise.all([ + page.click('a[href="/browser.php"]'), + page.waitForNavigation({ url: /\/browser\.php$/ }), + ]); + } finally { + await page.close(); + } +} +``` diff --git a/docs/sources/k6/next/javascript-api/k6-browser/page/waitforurl.md b/docs/sources/k6/next/javascript-api/k6-browser/page/waitforurl.md new file mode 100644 index 0000000000..d320a621cd --- /dev/null +++ b/docs/sources/k6/next/javascript-api/k6-browser/page/waitforurl.md @@ -0,0 +1,139 @@ +--- +title: 'waitForURL(url[, options])' +description: 'Browser module: page.waitForURL(url[, options]) method' +--- + +# waitForURL(url[, options]) + +Waits for the page to navigate to the specified URL. This method is useful for ensuring that navigation to a particular URL has completed before proceeding with the test. This is especially useful if there are multiple redirects before hitting the end destination. + + + +| Parameter | Type | Default | Description | +| ----------------- | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| url | string\|RegExp | - | Required. URL or URL pattern to match against. The method will wait until the page navigates to a URL that matches this parameter. | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](https://grafana.com/docs/k6//javascript-api/k6-browser/browsercontext/) or [Page](https://grafana.com/docs/k6//javascript-api/k6-browser/page/). | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | + + + +### Events + +{{< admonition type="caution" >}} + +`networkidle` is DISCOURAGED. Don't use this method for testing especially with chatty websites where the event may never fire, rely on web assertions to assess readiness instead. + +{{< /admonition >}} + +Events can be either: + +- `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. +- `'load'` - consider operation to be finished when the `load` event is fired. +- `'networkidle'` - Consider operation to be finished when there are no network connections for at least `500` ms. + +### Returns + +| Type | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------- | +| Promise | A Promise that resolves when the page has navigated to the specified URL and the specified load state has been reached. | + +### Examples + + + +```javascript +import { browser } from 'k6/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +}; + +export default async function () { + const page = await browser.newPage(); + + try { + await page.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation to a specific URL + await Promise.all([ + page.click('a[href="/my_messages.php"]'), + page.waitForURL('https://quickpizza.grafana.com/my_messages.php'), + ]); + + await page.goto('https://quickpizza.grafana.com/test.k6.io/'); + + // Wait for navigation using URL pattern with RegExp + await Promise.all([page.click('a[href="/browser.php"]'), page.waitForURL(/\/browser\.php$/)]); + } finally { + await page.close(); + } +} +``` + +### Valid usage patterns for waitForURL + +Use one of the following patterns to coordinate the action that triggers navigation with waiting for the final URL. + + + +```js +await Promise.all([ + page.waitForURL('https://quickpizza.grafana.com/my_messages.php'), + page.locator('a[href="/my_messages.php"]').click(), +]); +``` + +or + + + +```js +const navPromise = page.waitForURL('https://quickpizza.grafana.com/my_messages.php'); +await page.locator('a[href="/my_messages.php"]').click(); +await navPromise; +``` + +Unlike [waitForNavigation](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitfornavigation), `waitForURL` will first check whether it is already on the page with the given URL before proceeding to wait. If it is already there and the `waitUntil` condition has also been met, it will return straight away. This means that it is safe to do this: + + + +```js +await page.locator('a[href="/my_messages.php"]').click(); +await page.waitForURL('https://quickpizza.grafana.com/my_messages.php'); +``` + +### Best practices + +1. **Use appropriate matching**: Choose the right matching method based on your needs: + + - Exact strings for known, static URLs + - RegExp for pattern-based matching and complex URL validation + +2. **Handle dynamic content**: For URLs with dynamic parts (IDs, timestamps), use regular expression patterns instead of exact matches. + +3. **Set appropriate timeouts**: Adjust timeouts based on expected navigation time and network conditions. + +4. **Verify final state**: After waiting for URL, verify that the page content matches your expectations. + +### Common use cases + +- **Form submissions**: Verify redirects after successful form submission +- **Authentication flows**: Wait for login/logout redirects +- **E-commerce**: Track progression through shopping and checkout flows +- **SPAs**: Handle client-side routing changes +- **API redirects**: Wait for server-side redirects after API calls + +### Related + +- [page.waitForNavigation()](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitfornavigation/) - Wait for navigation events +- [page.waitForLoadState()](https://grafana.com/docs/k6//javascript-api/k6-browser/page/waitforloadstate/) - Wait for load states