Playwright logo on yellow background and custom text

Integration testing with Playwright

In our last blog post, we compared the Playwright and Cypress end-to-end testing tools and concluded that Playwright is the best E2E testing tool for web applications as it’s powerful, feature-rich and universal.

Playwright also states ease of use as one of its benefits, claiming that the first creation should take just a couple of minutes. But is it really that simple? Continue reading to find out.

Adding a project

The first step is to install the dependencies. Playwright provides the test runner and test execution environment as a single dependency. You can install it as a development dependency:

npm i -D @playwright/test

Next, download the binaries of the browsers. This step has to be done in CI (Continuous Integration) every time you install dependencies, so don’t forget to add it as an npm (node package manager) pre-install step.

npx playwright install

The next step is then to add the configuration of the project. 

Minimal configuration

The very minimum you need to get the first test running is a surprisingly small amount of configuration. You only need to configure the tests directory, so that Playwright knows where to look for them, and a list of the browsers to test with. The rest is optional, but we do recommend adding a few more configuration options… 

One particularly nice feature is providing a screenshot of a failed test and recording a video when the test retries. Having a visual clue usually significantly reduces the time required to debug the tests, as often the issue is obvious.

This is how a minimal configuration like this looks:

import { PlaywrightTestConfig, devices } from '@playwright/test';
 
const config: PlaywrightTestConfig = {
  testDir: './tests',
  expect: {
    // Maximum time expect() should wait for the condition to be met.
    timeout: 5000
  },
  /* Fail the build on CI if you accidentally left test.only in the source code. */
  forbidOnly: !!process.env.CI,
  /* Retry on CI only */
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  use: {
    /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
    actionTimeout: 0,
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'on-first-retry',
  },
  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
      },
    },
    {
      name: 'firefox',
      use: {
        ...devices['Desktop Firefox'],
      },
    },
    {
      name: 'webkit',
      use: {
        ...devices['Desktop Safari'],
      },
    }
  ]
};
export default config;

Adding mobile devices

Playwright allows testing against mobile devices, which is another cool feature. Of course, mobile devices are only emulating the behavior, but that is enough for many use cases. If you need to test against real mobile phones, you can always integrate with services such as BrowserStack to run the test in their device grid.

With the new experimental API, you can even use real Android devices and test in Chrome for Android and Android WebView, or use a full-feature emulator. This process requires a bit of overhead connecting to the device using ADB daemon.

If you want to run all of the tests against specific mobile devices and browsers, you just need to extend the browsers list and include the new ones.

const config: PlaywrightTestConfig = {
  ...
  projects: [
      {
      name: 'Mobile Chrome',
      use: {
        ...devices['Pixel 5'],
      },
    },
    {
      name: 'Mobile Safari',
      use: {
        ...devices['iPhone 12'],
      },
    },
  ]
};

First test

And now we’re ready to write the first test case. That was easy, right? So now you just need to create a spec file in the previously defined tests folder. After that, you can either use a low-level Playwright instance, or use the test runner from the @playwright/test package. We went with the second option.

import { test, expect } from '@playwright/test';
 
test('basic test', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await page.locator('text=Get started').click();
  await expect(page).toHaveTitle(/Getting started/);
});

The elementary test opens the website, clicks the navigation button, and validates the title. Also worth noticing is the auto waiting. Every event or change is asynchronous, and there is no need for any explicit timeouts – it just waits the maximum allowed time for the update to propagate and proceed. If this time gets exceeded, the test is simply marked as failed. Well, first it tries to replay the test, if it is allowed to 🙂

Are you testing unique device behavior?

Playwright allows you to override the device or page configuration for every spec file, group of tests, or single test. 

import { test, expect } from '@playwright/test';
 
test.use({locale: 'fr-FR', timezoneId: 'Europe/Paris', geolocation: {latitude: 48.864716, longitude: 2.349014}});
 
test('title test', async ({ page }) => {
  ...
});
 
test('basic test', async ({ page }) => {
  test.use({colorScheme: 'dark'});
 
  await page.goto('https://playwright.dev/');
  const html = await page.locator('html');
  await expect(html).toHaveAttribute('data-theme', 'dark');
});

There is a comprehensive list of the options you can modify, such as viewport sizes, locales with timezones, permissions, and geolocation.

Reporters

Once the tests are up and running, you need to get the results out of Playwright. There is a dot reporter used for CI, and otherwise a list reporter is used by default. Both of these output into the console. However, if you plan to consume the reports with other tools, we recommend using a JSON or HTML reporter, which writes the result into the file.

Reporters can be added into the configuration: 

const config: PlaywrightTestConfig = {
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
  reporter: 'html',
…
}

Or passed via the command line:

npx playwright-test --reporter=html

You can combine multiple reporters, and show results in the console with dot reporter and also produce an HTML report. 

The entire list of the available reporters and their options are described in the Playwright documentation. If you need more options, you can also use a 3rd-party reporter such as an allure reporter, or create a custom one.

Conclusion

Setting up and running tests with Playwright is indeed a breeze. Minimal initial configuration allows each project to be started easily, and then extended later depending on the specific requirements.

about author

Jozef Radonak

Leader of the web tech stream at Hotovo. Passionate about hiking, web technologies and ...coffee ;)

READ MORE

Tech corner with orange background

Angular, Gatsby, Astro? Pretty hot, huh?

Hello readers! Just as we do every month, we’ve pulled …

Hotovo tech corner

The Latest Tips, News, and New Features in the World of Web Development

Hello readers! Just as we do every month, we’ve pulled …

Asynchronous programming Hotovo tech corner

Asynchronous Programming World (Part 1)

What will this multi-episode blog post be about? In short: …