This fixes an issue with APIs that use the underlying frame.waitForSelector. It does this by reusing frame.waitFor which contains a fix to retry on certain errors which can occur when a navigation is taking place while also waiting for the selector.
Why?
This makes several APIs more robust when called during or after a navigation to a new page. I believe the list covers most of the APIs that this fix applies to:
frame.WaitForSelector
locator.IsChecked
locator.DispatchEvent
locator.Fill
locator.Focus
locator.GetAttribute
locator.InnerHTML
locator.InnerText
locator.InputValue
locator.IsEditable
locator.IsEnabled
locator.IsDisabled
locator.Press
locator.SelectOption
frame.SetInputFiles
page.TextContent
locator.Type
locator.Click
locator.Check
locator.SetChecked
locator.Uncheck
locator.DblClick
locator.Hover
locator.Tap
Tests that works with fix (but not without)
Test that used to fail on reading the `textContent` of the `h2` header.
```js
import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}
export default async function() {
const context = await browser.newContext();
const page = await context.newPage();
try {
await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });
const wait1 = page.locator('input[name="login"]').waitFor();
await page.locator('a[href="/my_messages.php"]').click()
await wait1;
await page.locator('input[name="login"]').type('admin');
await page.locator('input[name="password"]').type("123");
const wait2 = page.locator('h2').waitFor();
await page.locator('input[type="submit"]').click();
await wait2;
await check(page.locator('h2'), {
'header': async lo => {
return await lo.textContent() == 'Welcome, admin!'
}
});
} finally {
await page.close();
}
}
```
Test that used to fail when working with `waitForSelector`.
```js
import { browser } from 'k6/browser';
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}
export default async function() {
const context = await browser.newContext();
const page = await context.newPage();
try {
await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });
const wait1 = page.waitForSelector('input[name="login"]');
await page.locator('a[href="/my_messages.php"]').click()
await wait1;
await page.locator('input[name="login"]').type('admin');
await page.locator('input[name="password"]').type("123");
const wait2 = page.waitForSelector('h2');
await page.locator('input[type="submit"]').click();
await wait2;
await check(page.locator('h2'), {
'header': async lo => {
return await lo.textContent() == 'Welcome, admin!'
}
});
} finally {
await page.close();
}
}
```
Checklist
[x] I have performed a self-review of my code
[ ] I have added tests for my changes
[x] I have commented on my code, particularly in hard-to-understand areas
What?
This fixes an issue with APIs that use the underlying
frame.waitForSelector
. It does this by reusingframe.waitFor
which contains a fix to retry on certain errors which can occur when a navigation is taking place while also waiting for the selector.Why?
This makes several APIs more robust when called during or after a navigation to a new page. I believe the list covers most of the APIs that this fix applies to:
frame.WaitForSelector
locator.IsChecked
locator.DispatchEvent
locator.Fill
locator.Focus
locator.GetAttribute
locator.InnerHTML
locator.InnerText
locator.InputValue
locator.IsEditable
locator.IsEnabled
locator.IsDisabled
locator.Press
locator.SelectOption
frame.SetInputFiles
page.TextContent
locator.Type
locator.Click
locator.Check
locator.SetChecked
locator.Uncheck
locator.DblClick
locator.Hover
locator.Tap
Tests that works with fix (but not without)
Test that used to fail on reading the `textContent` of the `h2` header. ```js import { browser } from 'k6/browser'; import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js'; export const options = { scenarios: { ui: { executor: 'shared-iterations', options: { browser: { type: 'chromium', }, }, }, }, thresholds: { checks: ["rate==1.0"] } } export default async function() { const context = await browser.newContext(); const page = await context.newPage(); try { await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' }); const wait1 = page.locator('input[name="login"]').waitFor(); await page.locator('a[href="/my_messages.php"]').click() await wait1; await page.locator('input[name="login"]').type('admin'); await page.locator('input[name="password"]').type("123"); const wait2 = page.locator('h2').waitFor(); await page.locator('input[type="submit"]').click(); await wait2; await check(page.locator('h2'), { 'header': async lo => { return await lo.textContent() == 'Welcome, admin!' } }); } finally { await page.close(); } } ``` Test that used to fail when working with `waitForSelector`. ```js import { browser } from 'k6/browser'; import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js'; export const options = { scenarios: { ui: { executor: 'shared-iterations', options: { browser: { type: 'chromium', }, }, }, }, thresholds: { checks: ["rate==1.0"] } } export default async function() { const context = await browser.newContext(); const page = await context.newPage(); try { await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' }); const wait1 = page.waitForSelector('input[name="login"]'); await page.locator('a[href="/my_messages.php"]').click() await wait1; await page.locator('input[name="login"]').type('admin'); await page.locator('input[name="password"]').type("123"); const wait2 = page.waitForSelector('h2'); await page.locator('input[type="submit"]').click(); await wait2; await check(page.locator('h2'), { 'header': async lo => { return await lo.textContent() == 'Welcome, admin!' } }); } finally { await page.close(); } } ```Checklist
Related PR(s)/Issue(s)
Related: https://github.com/grafana/xk6-browser/pull/1469 Fixes: https://github.com/grafana/k6/issues/4048