github grafana/xk6-browser v0.4.0

latest releases: v1.6.0, v2.0.0, v1.5.1...
24 months ago

xk6-browser v0.4.0 is here! 🎉

In this minor release, we implemented a large portion of a new API that will help you find elements on a page in a more robust way, fixed critical bugs, and made some improvements and code refactoring!

The team is aware that the extension is currently unstable for many users. This stems from the complexity in how CDP events from the browser and from our own internal event-based system are currently handled, as well as our lack of async support in JavaScript APIs, which introduces race conditions and can lead to intermittent failures. We've been delaying tackling these issues since it requires a substantial rearchitecture of core systems, but rest assured, it's currently our top priority and these issues will be addressed by, hopefully, the next release. If you want to follow along the progress, subscribe to issues #427 and #428.

New features

Locator API (#100)

The Locator API makes it easier to work with dynamically changing elements. Some of the benefits of using it over existing ways to locate an element (e.g. Page.$()) include:

  • Helps with writing robust tests by finding an element even if the underlying frame navigates.
  • Makes it easier to work with dynamic web pages and SPAs built with Svelte, React, Vue, etc.
  • Enables the use of test abstractions like the Page Object Model (POM) pattern to simplify and organize tests. See this example.

We follow Playwright's API and now cover most ElementHandle methods. 🎉 This is the first version of the Locator API, which paves the way for us to develop additional features on top of it in the upcoming milestones. For example, we can support React or Vue selectors in the future on top of the current version.

Here's an example:

import launcher from "k6/x/browser";

export default function () {
  const browser = launcher.launch('chromium', {
    headless: false,
  });
  const context = browser.newContext();
  const page = context.newPage();
  page.goto("https://test.k6.io/flip_coin.php", {
    waitUntil: "networkidle",
  });

  /*
  In this example, we will use two locators, matching a
  different betting button on the page. If you were to query
  the buttons once and save them as below, you would see an
  error after the initial navigation.

    const heads = page.$("input[value='Bet on heads!']");
    const tails = page.$("input[value='Bet on tails!']");

  The Locator API allows you to get a fresh element handle each
  time you use one of the locator methods. And, you can carry a
  locator across frame navigations. Let's create two locators;
  each locates a button on the page.
  */
  const heads = page.locator("input[value='Bet on heads!']");
  const tails = page.locator("input[value='Bet on tails!']");
  const currentBet = page.locator("//p[starts-with(text(),'Your bet: ')]");

  // the tails locator clicks on the tails button by using the
  // locator's selector.
  tails.click();

  // Since clicking on each button causes page navigation,
  // waitForNavigation is needed. It's because the page
  // won't be ready until the navigation completes.
  page.waitForNavigation();
  console.log(currentBet.innerText());

  // the heads locator clicks on the heads button by using the
  // locator's selector.
  heads.click();
  page.waitForNavigation();
  console.log(currentBet.innerText());

  tails.click();
  page.waitForNavigation();
  console.log(currentBet.innerText());

  page.close();
  browser.close();
}

The implemented methods in this release are:

  • page.locator(selector) (#310)

    Creates and returns a new page locator given a selector with strict mode on. The strict mode only allows selecting a single matching element, and will throw an error if multiple matches are found.

  • locator.click([options]) (#318)

  • locator.dblclick([options]) (#332)

  • locator.check([options]) (#362)

  • locator.uncheck([options]) (#365)

  • locator.isChecked([options]) (#369)

  • locator.isEditable([options]) (#372)

  • locator.isEnabled([options]) (#373)

  • locator.isDisabled([options]) (#375)

  • locator.isVisible([options]) (#376)

  • locator.isHidden([options]) (#377)

  • locator.fill(value, [options]) (#380)

  • locator.focus([options]) (#388)

  • locator.getAttribute(name, [options]) (#390)

  • locator.innerHTML([options]) (#392)

  • locator.innerText([options]) (#393)

  • locator.textContent([options]) (#394)

  • locator.inputValue([options]) (#395)

  • locator.selectOption(values, [options]) (#397)

  • locator.press(key, [options]) (#398)

  • locator.type(text, [options]) (#399)

  • locator.hover([options]) (#400)

  • locator.tap([options]) (#401)

  • locator.dispatchEvent(type, eventInit, [options])(#405)

  • locator.waitFor([options]) (#406)

Bugs fixed

  • Fixed zombie browser processes. (#306)

    Before this fix, browser processes remained active even after the test or k6 test runs. This could sometimes saturate the machine and therefore could affect the tests.

  • Fixed cleanup of the browser's temporary directory. (#323, #409)

    The temporary directory is now properly removed when Browser.close() is called, or when the iteration or test run completes. This will help ensure that any private data that the browser caches in the temporary directory is deleted.

    NOTE: There is a small chance that the temporary directory will not be cleaned and a ticket has been opened to track the next step/fix. (#403)

  • Fixed keyboard press of modifier keys (e.g. Shift) in keyboard.down and keyboard.up. (#325)

  • Fixed page.content() so that it no longer panics. (#327)

  • Fixed ElementHandle.fill(). (#383)

    Before, it was not filling in the text in the selected input element.

  • Fixed ElementHandle.tap(). (#401)

    Before, it was performing the tap without respecting the vertical coordinate.

  • Fixed timeout detection. (#411)

    Before this fix, we couldn't detect the timeouts properly. For example if we write a test where we are retrieving the contents of an element that doesn't exist, it used to return an empty string, but now it will raise a timeout error correctly. The current system is still unstable because this fix re-surfaced a data race bug that happens from time to time (happens on frame navigation). Previously reported in #254

  • Fixed a premature crash due to occasional incorrect type conversions. (#425)

    This is still an issue caused by internal race conditions (#427), but the extension no longer crashes because of incorrect type conversions.

    See issue #417 for details.

Improvements

  • Permissions, such as microphone and camera, can now be granted to the browser. (#314)

    This grants the new browser window permissions that would allow tests to use those devices. You can test the change using the example in examples/grant_permission.js

  • We're also removing the slow-motion option for Frame.isChecked() since it doesn't make sense to slow down this sort of check (#376)

  • Our log messages are now more concise and user friendlier. (#429)

  • We're working on making xk6-browser available in the k6 Cloud! The feature is still in early testing stages, but we hope to make more announcements about it soon. Stay tuned!

Internals

Don't miss a new xk6-browser release

NewReleases is sending notifications on new releases.