Best features in Playwright 1.42 – with practical examples!

Posted in

πŸ‘‹ Introduction

Lets look at Playwright 1.42πŸŽ‰

In addition to lots of bug fixes and browser updates, it also includes a few new features: πŸ”— https://playwright.dev/docs/release-notes#version-142

Let’s discuss and test the most important ones. I will perform the tests using our special 🦎GAD application, which you can download here: πŸ”— https://github.com/jaktestowac/gad-gui-api-demo.

We will do this with the example of crazy tests that will play a game of catching the bug: πŸ”— http://localhost:3000/whacker.html

πŸ’‘

The 🦎GAD (πŸ”— https://playwrightmaster.com/about-gad/) application has many interesting features and bugs that we use when teach how to develop professional automated test framework with Playwright πŸ”— https://jaktestowac.pl/playwright/

Before you start testing, don’t forget to update Playwright via:

npm install @playwright/test

and install new browsers using:

npx playwright install

πŸ”– Tags now have a native implementation – they no longer need to clutter test names

Previously, we added tags after the @ sign:

import { test, expect } from '@playwright/test';

test('should catch a 3 bugs @release_1_42 @game', async () => {
  expect(true).toBeTruthy();
});

Now in Playwright 1.42 we can use a new way:

test(
  'should catch a 3 bugs',
  { tag: ['@release_1_42', '@game'] },
  async () => {

    expect(true).toBeTruthy();

  },
);

The difference is significant – the first test has old-style tags and the second one has new-style tags πŸ‘:

tags in Playwright 1.42


More about tags: πŸ”— https://playwright.dev/docs/test-annotations#tag-tests

πŸ€– LocatorHandler – an automatic clicker in the test

This function will be useful when we want some action to be performed automatically, and we do not know when it will happen during the flow test…

Let’s assume that we have, for example, a pop-up window with a subscription subscription. We want it to be closed automatically whenever it appears.

Boooring. We’ve got πŸ› to catch!

What will classic catching look like?

test(
  'should catch a 3 bugs',
  { tag: ['@release_1_42', '@game'] },
  async ({page}) => {
  
  // Arrange
  await page.goto('http://localhost:3000/whacker.html');
  
  // Act
  await page.getByRole('button', { name: 'Start Game' }).click();
  await page.getByText('πŸ›').click();
  await page.getByText('πŸ›').click();
  await page.getByText('πŸ›').click();
  
  // Assert
  const actualScore = await page.locator('#score').innerText().then(Number);
  expect(actualScore).toBe(3);

  },
);

This can be done automaticallyπŸ€– using the new handler introduced in Playwright 1.42.

Before our test actions, we create a handler that will handle this:

page.addLocatorHandler(locator, function after identifying the tenant)

test(
  'should catch a 3 bugs handler',
  { tag: ['@release_1_42', '@game'] },
  async ({ page }) => {
    // Handler 
    await page.addLocatorHandler(page.getByText('πŸ›'), async () => {
      await page.getByText('πŸ›').click();
    });

    // Arrange
    await page.goto('http://localhost:3000/whacker.html');

    // Act
    await page.getByRole('button', { name: 'Start Game' }).click();

    const scoreLocatorWaitFor3 =  page.locator('#score').filter({hasText: '3'});
    await scoreLocatorWaitFor3.focus();

    // Assert
    await expect(scoreLocatorWaitFor3).toBeVisible();
  },
);

After running the tests, you will see the handler clicking when it sees a nasty bugπŸ’₯

Sounds a bit scary?
Playwright, during our test, can start clicking on its own as soon as the condition of the prepared handler is met.

You must be aware that this may disturb your test flow (the creators also warn about this in the documentation)
πŸ”— https://playwright.dev/docs/api/class-page#page-add-locator-handler

🚧

Attention! The handler will only work when executing the action:

await page.getByRole('button', { name: 'Start Game' }).click();

If the action is very fast (a few ms), e.g.:

await page.getByRole('button', { name: 'Start Game' }).innerText();

It is very possible that the handler will not execute. And tests can be susceptible to this behavior. You can learn more by analyzing our submission to the developers: πŸ”— https://github.com/microsoft/playwright/issues/29701

βŒ› Set a global timeout for assertions waiting for a given state

For assertions that execute a function in a loop waiting for a given state (polling), we can set a global timeout. If you don’t know what such assertions are – see how we can wait for our result in another way:

test('should catch a 3 bugs with polling', async ({ page }) => {
  // Arrange
  const expectScore = 3;
  let actualScore = 0;

  // Act
  await page.goto('http://localhost:3000/whacker.html');
  await page.getByRole('button', { name: 'Start Game' }).click();

  // Assert
  await expect
    .poll(async () => {
      await page.getByText('πŸ›').click();
      actualScore = await page.locator('#score').innerText().then(Number);
      // don't forget to return the value
      return actualScore;
    })
    .toBe(expectScore);
});

This is how we can set this timeout in playwright.config.ts expect:

{ toPass: { timeout: 1000 } },

Thanks to this, we no longer have to add timeout directly in expect or look for the default value in the documentationπŸ’ͺ

πŸ”— https://playwright.dev/docs/api/class-testproject#test-project-expect

πŸ“‘ Adding multiple annotations

In Playwright 1.42 new annotation mechanism was introduced (i.e. adding such additional information to tests and visible in reports, e.g. for links to bugs).

They look like this:

And we implement them like this:

test(
  'should catch a 3 bugs with one annotation',
  {
    annotation: {
      type: 'issue',
      description:
        'This will be implemented in blog post https://playwright.info',
    },
  },
  async () => {
    expect(true).toBeTruthy();
  },
);

Now you can add multiple annotations at once as annotation: []

test(
  'should catch a 3 bugs with multiple annotations @release_1_42 @game',
  {
    annotation: [
      {
        type: 'issue',
        description:
          'This will be implemented in blog post https://playwright.info',
      },
      {
        type: 'linked-post',
        description: 'https://playwright.info/co-nowego-w-playwright-1.42',
      },
      {
        type: 'documentation',
        description:
          'https://playwright.dev/docs/test-annotations#annotate-tests',
      },
    ],
  },
  async () => {
    expect(true).toBeTruthy();
  },
);

Effect:

annotations in Playwright 1.42

I think we will ask you to catch links in the annotation text because currently only independent links work πŸ€”

πŸ’‘

You can read more about annotations in the official documentation: πŸ”— https://playwright.dev/docs/test-annotations#annotate-tests

Summary for Playwright 1.42

These are not all the news, but certainly the most important ones!

Of course, you can find more in the official release notes for Playwright 1.42: πŸ”— https://playwright.dev/docs/release-notes#version-142

See you in the next Playwright code games!😎