Playwright Tutorial: Experience Testing Browser Extensions

There are many frameworks for web application testing in the modern market. They all offer users different features and functionality, so each QA team can choose a tool depending on the characteristics of a particular project. However, today I want to talk about Playwright browser testing and my own experience using this open source framework.

My name is Oleksii Dolmatov, I am a middle QA automation engineer with experience working with Jmeter, Protractor, Jasmine.JS, and Playwright frameworks. I’ve been dealing with manual testing and test automation for 11 years, and today I want to tell you the story of how I started to use the Playwright framework for web testing.

In this article, we will go deeper into the features of Playwright testing and talk about a project on which I found it appropriate to use this testing framework for automation of manual testing.

Project Details

Project we are talking about was related to testing a password manager, which served as a browser extension. Later it became part of a larger product that included VPN, antivirus, transaction control, and much more. At that moment, I had the task of automating manual testing specifically for this extension.

In the process of choosing the most suitable solution, I considered several testing frameworks, including Selenium WebDriver, Cypress, and Playwright.

After studying all the advantages and disadvantages of these tools, I concluded that Selenium is somewhat outdated, and Cypress did not provide all the functions I needed. So I selected Microsoft Playwright. Starting with testing the extension, I later used this framework for testing full-fledged web apps, and I was also satisfied with its functionality.

Let’s move on to the possibilities of the Playwright framework that greatly simplify web application testing. I’ve been using this tool for two and a half years now.

Playwright Framework. Features and Purpose

Microsoft Playwright is a test automation library, which allows for effective end to end testing for all modern browsers: Safari, Microsoft Edge, Google Chrome, and Firefox.

This framework appeared not so long ago. It was created by Microsoft in 2020 and quickly managed to gather a fairly large audience. At the time of writing this material, Playwright has 62,6K stars on GitHub.

In terms of popularity among testers, the tool bypassed other frameworks that were previously leading in the field of automated testing of web applications. For example, Selenium WebDriver, which is not as good as the Playwright framework in functionality, performance, and speed.

To begin with, I think it is important to dwell on the basic concepts with which Playwright works:

  1. Browser. To start Playwright cross browser testing, you need to open an object of the Browser class, which is an instance of Chromium, Webkit, and Firefox.
  2. Browser context. It is an isolated session within the browser instance being used, which provides full test isolation and parallel execution.
  3. Page. These are separate tabs or pop-ups in the browser context on which all actions of test scenarios are performed.

To the main characteristics that turn Playwright the number one solution for testing modern web apps, I would attribute the following:

  • Support of cross-browser testing. As I mentioned earlier, the framework can run tests for different browsers: Chromium, Firefox, and WebKit.
  • Availability of cross-platform testing. In Playwright, test execution is possible in different operating systems: Windows, Linux, and macOS.
  • Ability to write test scripts in multiple languages. Playwright supports JavaScript, TypeScript, Python, .NET, C#, and Java. Thus, it does not limit automation engineers, allowing them to use their favorite technology stacks.
  • Wide integration possibilities. The framework supports integration with popular CI/CD tools, including GitHub Actions, Jenkins, GitLab, Azure Pipelines, etc. The tool can also integrate with various test runners, such as Jest/Jasmine, AVA, and Mocha. To launch large test suites and manage parallel test execution, you can take advantage of the integration of Playwright with Selenium Grid.
  • Ability to perform various types of testing. In addition to end-to-end testing, the framework allows you to perform API testing and run functional tests.
  • Support for working with multiple tabs. All browser contexts in Playwright may have several tabs (pages).

The last feature of the framework became decisive for me when I was choosing a tool for test automation. After all, the ability to work with multiple tabs was critical for my project, and other frameworks that I looked at (for example, Cypress) did not support this function.

Of course, this is not the only reason that makes the Playwright framework one of the best solutions for web application testing. It is also facilitated by its extensive functionality.

Key Features of Microsoft Playwright for Optimization of Web Automation

Now I want to focus on the main functions of Playwright, that allow the framework to easily integrate with existing workflows and development tools, as well as perform web application testing quickly and efficiently.

✅ Auto Wait

This is one of the advanced features of Playwright, which is not available in many other frameworks, for example, in Selenium. It lies in the fact that before any action, the framework performs a functionality check of the elements to ensure that the actions will be completed as expected.

This function allows you to fight one of the main problems of many testers – test flakiness.

✅ Codegen

This functionality greatly simplifies the creation of Playwright tests. It gives you the possibility to write tests and record each user interaction with a web application.

To start the generator of tests, you need to use the command

npx playwright codegen

and indicate the URL of the website for which you want to run tests. It can be done immediately or later by adding the window.

✅ Playwright Inspector

In parallel with starting the generator of tests, the Playwright inspector window opens, neseccary for recording and copying tests. Thanks to the Codegen function, the framework generates code based on user interaction with the website. This code appears in the window of the Playwright inspector. Once the code is completely generated, you can copy it and move it into the editor.

✅ Detailed Reports

Many tools for browser testing require the involvement of third-party services to create reporting. Playwright has no problem with that. It contains built-in List, Line, HTML, JSON, and JUnit reporters. To create reports on CI, the Dot reporter is used by default.

The framework also supports custom reports and integration with third-party tools, including Allure, Monocart, Tesults, ReportPortal, Currents, and Serenity/JS. And of course you can try Reports for your automated tests and sync them with your manual tests in one.

✅ Playwright Trace Viewer

If the report on test results is not enough for you, you can use Playwright Trace Viewer. You can use it to view all the tests and clearly see what happened during their execution. From the official Docs example of file playwright.config.ts

import { defineConfig } from '@playwright/test';
export default defineConfig({
  retries: 1,
  use: {
    trace: 'on-first-retry',

Typically, traces are run in the CI environment, but if necessary, you can also run a trace locally by forcing it.

✅ Test Retries

This function allows you to automatically launch all failed Playwright tests again. The convenient thing is that all tests in Playwright are provided as independent working processes, and each of them runs separate browsers. It ensures that failed tests will not affect successful ones.

Consider the following snippet from Plawright Docs:

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

test.describe('suite', () => {
  test.beforeAll(async () => { /* ... */ });
  test('first good', async ({ page }) => { /* ... */ });
  test('second flaky', async ({ page }) => { /* ... */ });
  test('third good', async ({ page }) => { /* ... */ });
  test.afterAll(async () => { /* ... */ });

✅ Record Videos and Screenshots

Video and photographic recording of automated testing results is a great addition to the advanced reporting available in Microsoft Playwright. It clearly demonstrates to testers and developers all failures that occur.

This feature opens up many possibilities. You can take a screenshot of the full scrollable page, a separate element, and change the image format and quality. As for video, video recording is disabled by default. However, this setting can be controlled in the Playwright configuration. If you enable this option, the video file will be available after closing the browser context.

✅ Testing in Headless Browser

By default, the Playwright framework launches tests in headless browsers, that is, in browsers that do not display UI elements in a graphical environment. This approach allows you to run tests quickly by saving the time required for display elements in the browser.

However, it is worth noting that Playwright also supports testing in full Microsoft Edge.

✅ Device Emulation

Using Playwright, you can emulate real devices to run Playwright tests – for example, tablet or mobile phone. After making all the necessary settings, the tool will simulate the behavior of a specific browser on the right device.

✅ Launch of a Browser With Extensions

For me, this function became another argument in favor of Playwright. The framework supports launching Chrome Browser with extensions. Please note that the headless browser Chrome does not support extensions by default. However, this problem can be easily solved. You just need to run persistent context in the new headless mode using the code of fixtures.ts file:

// ...

const pathToExtension = path.join(__dirname, 'my-extension');
const context = await chromium.launchPersistentContext('', {
  headless: false,
  args: [
// ...

Sometimes I need to enable headed mode, which makes the tests run slower. To achieve this, I use theisHeadedand isSlowMo fixtures:

isHeaded: async ({}, use) => {
    const isHeaded = false;
    await use(isHeaded);

  isSlowMo: async ({}, use) => {
    const isSlowMo = false;
    await use(isSlowMo);

The following spec file:

test.use({isHeaded: true, isSlowMo: true});
test.describe('Some suite', () => {
  test('Some test name', async ({extPage: page, account, helper}) => {...

When I start the browser with my extension, the extension’s welcome page opens. Thus, the fixture includes the welcome page. As a result, the basic fixture for starting the extension looks like this in my case”:

export const test = base.extend<Fixtures>({
  persistentContext: [
    async ({isHeaded, isSlowMo}, use, workerInfo) => {
      const useHeaded = isHeaded ? '' : `--headless=new`;
      const slowMoValue = isSlowMo ? 100 : 0;
      const contextName = textRandom(7);
      const pathToExtension = path.join(__dirname, `../dist/${getFolder()}/${}`);
      const userDataDir = path.join(__dirname, './testdata/tmp/' + contextName);
    context = await chromium.launchPersistentContext(userDataDir, {
          headless: false,
          viewport: {width: 1280, height: 800},
          args: [useHeaded, `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}`],
          permissions: ['notifications', 'geolocation', 'clipboard-read', 'clipboard-write', 'accessibility-events'],
          slowMo: slowMoValue,
    await use(context);
    await context.browser()?.close();
    {scope: 'test'},

  extPage: [
    async ({persistentContext: context}, use, workerInfo) => {
    const pageList = context.pages();
    if (pageList && pageList.length > 1) {
      const extensionPage = pageList.filter(page => page.url().includes('extension')) || [];
        if (extensionPage[0]) {
          await extensionPage[0].waitForLoadState();
          await use(extensionPage[0]);
    } else {
        const page = await context.waitForEvent('page');
        await page.waitForLoadState();
        if (page.url().includes('extension')) {
          await use(page);
    {scope: 'test'},

export {expect, Page} from '@playwright/test';
export default test;

Support and Updates of the Playwright Framework

I want to talk about Playwright support and its releases, because these points play a central role in organizing effective work with the framework.

You can check all the updates that have been implemented in Microsoft Playwright for the entire period of its existence on the official resource PLAYWRIGHT.DEV. I want to focus on the release of Version 1.18, which happened to coincide with my work testing the password manager.

At the time of the release of the updated version of Playwright, our team was just working on the implementation of the Drag-and-drop feature for convenient filling of the “Login/Password” fields. When there were only a few days left before the end of development, Playwright version 1.18 was released, in which the dragTo API was implemented, allowing you to drag the source element to the target one:

const source = page.locator('#source');
const target = page.locator('#target');

await source.dragTo(target);
// or specify exact positions relative to the top-left corners of the elements:
await source.dragTo(target, {
  sourcePosition: { x: 34, y: 7 },
  targetPosition: { x: 10, y: 20 },

Thanks to such timely updates, automated testing of the new feature became much easier.

Regarding support, Playwright cannot boast of an extensive community. Due to the fact that the framework appeared not so long ago, support is still in the development stage. However, this minor drawback is fully compensated by detailed documentation on the official website and on github.

Some Disadvantages of the Playwright Framework

I already said that I’ve been doing Playwright testing for several years now. This experience allows me to highlight for myself some of the imperfections of this tool, which, however, are insignificant in comparison with all its capabilities.

Framework does not support some browsers. I am talking about outdated versions of Microsoft Edge and Internet Explorer 11. In my opinion, the problem is insignificant. For modern teams, it is important that the tool supports modern browsers.
Playwright does not allow use for testing real devices. The inconveniences associated with this fact can be easily eliminated thanks to the ability to emulate devices.

What about community support, the Playwright community is actively developing, I recommend studying the detailed documentation on the framework – you can find answers to all your questions there.

Comparison with Competitors

Before you choose Playwright as the main framework for web application testing, I made a detailed comparison of this tool with a framework, which, in my opinion, is its main competitor. I am talking about Cypress. In the table below, you will find the key differences between these testing frameworks:


Screenshots ✔️ ✔️
Parallel Testing out of the box For Cypress should enable Cypress Cloud Integration ✔️
Easy debug ✔️ ✔️
Sending native keyboard/mouse events ✔️ ✔️
Fast tests execution ✔️ ✔️
CI: good compatibility ✔️ ✔️
Cross-browser testing ✔️ ✔️
Iframes support the Test Runner does not support selecting or accessing elements from within an iframe ✔️
Easy base-install for test execution ✔️ ✔️
Detailed documentation ✔️ ✔️
Files: uploading/downloading ✔️ ✔️
Access to browser console ✔️ ✔️
Time Travel ✔️ ✔️
Automatic Waiting ✔️ ✔️
Network Traffic Control ✔️ ✔️
Videos ✔️ ✔️
Visual Testing ✔️ ✔️
Retries: scenario or step ✔️ ✔️
Multiple tabs ❌ ✔️
Multiple windows ❌ ✔️
Possibility to intercept requests ✔️ ✔️
Possibility to mock responses ✔️ ✔️
Bundled with Chromium ✔️ ✔️
Reporters: good compatibility ✔️ ✔️
Special features
browser: Safari for Mac Experimental Support ✔️
browser: Safari for iOS ❌ ✔️
browser: Firefox ✔️ ✔️
Data-driven test support ✔️ ✔️
PageObject model support ✔️ ✔️
Element hover Need to be able to hover in/out of DOM elements ✔️
Develop without GUI ❌ ✔️
Less domain-specific knowledge ❌ ✔️
Elements matching one of the conditions. (PW example: await page.locator(‘button:has-text(“Log in”), button:has-text(“Sign in”)’).click(); ) ❌ ✔️
VS Code integration ❌ ✔️
native Promises ❌ ✔️
Work with browser extension page ❌ ✔️
Consistent set of assertions Cypress bundles nine different third-party libraries, which creates a mishmash ✔️
try-catch handler support ❌ ✔️
Soft Assertion support ❌ ✔️
No third-party plugins needed ❌ ✔️

Let’s Summarize

Playwright is a promising framework, which in the short time of its existence has managed to win a wide audience thanks to advanced features, ensuring high testing speed and advanced capabilities.

I hope this article was helpful to you and that you can use my successful experience in web application testing with Playwright on your own project.

Playwright extent report 📊
Simultaneously output manual and automated tests with the single test management tool
Follow us