Playwright: Launching Cross-Browser Automation to the Stars

Hey,

Hope you and your family are doing well.

Several months have passed since our last article about efficient browser automation. If you missed some of them — the entire list can be found here. Today we are going to dive into an attractive Playwright browser automation world.

What is Playwright?

Even if you have very limited experience with web application testing you should have heard about Selenium. Selenium exists since 2004 and nowadays is a de-facto worldwide standard for running automated tests in various browsers and platforms. Being mature and widely used technology, Selenium was created in times when the majority of web sites consisted of static HTML pages with forms and asynchronous (AJAX) requests to the backend were more of an exception than a rule. We were living in the world where almost all the work was being done on the backend side. In this world simply opening pages in browsers, doing the clicks, entering some text in the fields and checking page element attributes was sufficient for testing.

Web application architecture has evolved a lot during the last years. Now client-side part of a web application (frontend) can be as complex as the backend. From dozens of large static HTML pages with Javascript inclusions the world now moved to a single HTML page with thousands of lines of complex Javascript logic. Such fundamental change in web applications certainly requires a lot of changes in testing. It would be great to have full control over a running single-page application code with an ability to catch any page lifecycle events, log messages and exceptions being thrown. We certainly would like to inspect and optionally mock all network requests between client and server side. Sometimes we would need to manipulate and mock page layout including DOM tree and CSS styles. Unfortunately such important features are simply not available in Selenium and that is the first reason to create new generation of browser automation tools.

The second reason is that in the majority of cases the only thing that matters when opening a web page in browser is the rendering engine used in this browser. If we don’t need to test in old-school browsers like Internet Explorer and Opera 12.16, all other browsers are nowadays using one of three popular engines:

  • Blink — used in Chromium-based browsers like Google Chrome, modern Opera and Microsoft Edge
  • Gecko — used in Firefox and other Mozilla projects
  • Webkit — nowadays used by Safari browser for desktop and mobile platforms

So being able to run automated tests in these 3 browser engines we cover browser automation in the majority of modern browsers. These considerations (more powerful API and limited set of supported browser engines) gave life to the new generation of browser automation tools like Puppeteer and its successor — Playwright.

So what is Playwright nowadays? Basically it is a Node.js library able to launch Blink, Gecko and WebKit engines, giving everything Selenium can do and additionally providing all important features not available in Selenium and described above. A typical Playwright test working with Firefox is very similar to Selenium one and looks like the following:

const { firefox } = require('playwright');

(async () => {
var browser = await firefox.launch();
const page = await browser.newPage();
await page.goto('http://internet.yandex.ru/');
await page.screenshot({ path: `screenshot.png` });
await browser.close();
})();

To use another browser, e.g. Chromium you just need to replace firefox with chromium:

var browser = await chromium.launch();

Execute your Playwright tests in parallel

We in Aerokube team are not the first talking about Playwright. There is a lot of hype about Playwright during last months in conferences and blogs. Everybody is showing powerful features and how easy is to start automating things. However sooner or later every experienced test automation engineer is asking an important question — is it possible to run Playwright tests remotely and in parallel? One test can finish in seconds but thousands of tests accompanying every mature web application require a remote infrastructure to run them in parallel, otherwise you will retire waiting for your tests to complete. This problem was not solved until the last weeks, when we added parallel Playwright tests execution support to Moon — a browser automation solution running everything in Kubernetes cluster and compatible with Selenium and Playwright. We have already been talking about it in our previous articles (one, two, three), so today I would like to show how to start running as many parallel Playwright tests as you wish.

To understand how to run Playwright tests in parallel we need to dive a bit into its internals. Both Selenium and Playwright are sending all browser automation commands and receiving responses in JSON format. Selenium for historical reasons is doing this using separate HTTP requests for every command like launching the browser, opening the page, taking screenshots and so forth. Sending a new HTTP request for every command requires to send and receive a lot of redundant information such as HTTP headers. Such approach tends to be slower than using one permanent communication channel for all commands which is alive while browser is running. Knowing this Playwright is using the second approach and communicates with browser using one long-living web-socket connection. In the code above this web-socket connection is being established inside launch() method implementation which also automatically starts browser process for you. If you wish to start Playwright test working with remote browser, you have to explicitly configure this test to connect to remote web-socket endpoint as follows:

var browser = await chromium.connect({ wsEndpoint: 'ws://remote-host/some-endpoint' });

Every time you run this line of code — a completely new browser with clean cache will be started in remote Kubernetes cluster in seconds. Now let’s apply this knowledge to Moon. In Selenium world a standard port to execute tests remotely is 4444, so having Moon running on some host moon.example.com a working connection string will be:

var browser = await chromium.connect({ wsEndpoint: 'ws://moon.example.com:4444/playwright/chromium' });

In addition to host and port this connection URL contains playwright/chromium which tells Moon browser type to be launched. If you need to change browser type and enable additional features like video recording - you just add more parameters to the same URL as follows:

var browser = await firefox.connect({ wsEndpoint: 'ws://moon.example.com:4444/playwright/firefox?headless=false&enableVideo=true&screenResolution=1280x1024' });

To run multiple browsers in parallel — you just have to enable running tests in parallel in your test framework. This is how running tests in parallel looks like in action:

What about debugging my tests?

We have now seen how easy is to start running Playwright tests in parallel. But what about debugging such tests on workstation? This is an important question because sooner or later a web-application changes and automated tests also need to be adapted to these changes. While changing tests source code it should be easy to run this code many times on your development machine ideally on the similar testing infrastructure that your are using in CI\CD pipeline. Moon allows to deploy local Playwright infrastructure without installing a browser in minutes. Let’s do this.

  • First of all we quickly install a small Kubernetes cluster on workstation. The best way to do this is using minikube — a one-command Kubernetes installation tool. Simply get this tool as shown in the docs and run one command to start Kubernetes:
$ minikube start
  • Now let’s deploy Moon for local tests development. To do this we clone and apply ready-to-use YAML manifests where Moon automated installation instructions are stored.
$ git clone https://github.com/aerokube/moon-deploy.git
$ cd moon-deploy
$ minikube kubectl -- create -f moon-local.yaml # This command will actually start Moon
$ minikube kubectl -- patch svc moon -n moon --patch "{\"spec\":{\"externalIPs\":[\"$(minikube ip)\"]}}" # This is needed for network connectivity
  • Now let’s get Playwright connection IP:
$ minikube ip
192.168.99.100

Having this IP— simply use it in your tests as follows:

var browser = await chromium.connect({ wsEndpoint: 'ws://192.168.99.100:4444/playwright/chromium' });
  • For debugging your tests you can optionally use Moon UI allowing to interact with running browser sessions. To open UI simply use this address and open in browser:
http://192.168.99.100:8080

Here is a video demonstrating how it looks like in real life:

Conclusion

In this article we learned what are the new generation of browser automation tools: Puppeteer and Playwright and how to use them to run automated tests remotely and in parallel. More details about this feature can be found in documentation. If you have any suggestions about improving parallel Playwright execution — don’t hesitate to contact us by email: support[at]aerokube.com or in Telegram channel.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store