CONTACT
arrow_left Back to blog

Testing Angular Applications With Playwright

Playwright is an excellent option for end-to-end (E2E) testing your Angular applications if you're looking to transition away from Protractor. According to this summary, it's the third most popular E2E tool in the Angular community—just after Cypress and Protractor.

What is Playwright

Playwright is developed by Microsoft—the company that brought us TypeScript. It has a large following on GitHub; with 40k stars, and almost 2k forks, it is one of the most popular open-source projects for E2E testing.

How Playwright works

Playwright runs tests and controls the browser from the outside. The test runner runs the test scripts, controls the browsers via API, and doesn't share the execution context with the application—the same approach as in Protractor or Selenium.

Strengths

Because Playwright tests run outside the browser, there is a bigger choice of languages in which you can write your tests: you’re not restricted to just JS or its flavors like in Protractor, Cypress, or Nightwatch.js. Currently, you can write your test in:

  • JavaScript
  • Python
  • Java
  • .Net

This provides the flexibility to adapt the tests to the project and pick the language to get the most out of the skills you have available within your team.

Playwright allows you to run your tests in major browsers:

  • Chromium (Chrome and Edge)
  • Firefox
  • WebKit (Safari)

Playwright emphasizes speed, and according to this article, they deliver on that.

Example tests

Let's take a look at an example test suite in Playwright.

Application

The application we will test is the final step from the official Angular tutorial Tour of Heroes. You can find the repository with the example code here.

Configuration updates

An easy way to initialize the Playwright tests in a project is to run:

npm init playwright@latest

For easy access to running the tests, let's update package.json:

package.json example

With this change, npm run e2e will run Playwright with the default configuration—running tests on three headless browsers: Chromium, Firefox, and WebKit. Headless runs are faster and happen in isolation from the user, but they make debugging tests more difficult. For this, we have npm run e2e:debug, starting with only one visible browser.

Tests

Example tests in tests/example.spec.ts:

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

test.describe('Tour of Heroes pages', () => {
  test('should load default route', async ({page}) => {
    await page.goto('http://localhost:4200');

    await expect(page).toHaveURL(/\/dashboard$/);
  });

  test('should allow edits', async ({page}) => {
    await page.goto('http://localhost:4200');

    await page.locator('[data-test="detail-link"]').first().click();

    await expect(page).toHaveURL(/\/detail\/\d+/);

    await page.locator('#hero-name').fill('lorem ipsum');

    await page.locator('[data-test="save-button"]').click();

    await expect(page.locator('[data-test="detail-link"]').first()).toContainText('lorem ipsum');
  });

  test('should search for heroes', async ({page}) => {
    await page.goto('http://localhost:4200');

    await page.locator('#search-box').fill('nice');

    await expect(page.locator('[data-test="search-result-link"]')).toHaveCount(1);

    await page.locator('[data-test="search-result-link"]').click();

    await expect(page).toHaveURL(/\/detail\/12/);
  });

  test('should delete heroes', async ({page}) => {
    await page.goto('http://localhost:4200/heroes');

    await expect(page.locator('.delete')).toHaveCount(9);

    await page.locator('.delete').first().click();

    await expect(page.locator('.delete')).toHaveCount(8);
  });

  test('should add heroes', async ({page}) => {
    await page.goto('http://localhost:4200/heroes');

    await page.locator('#new-hero').fill('Lorem Ipsum');

    await page.locator('.add-button').click();

    await expect(page.locator('.delete')).toHaveCount(10);
  });
});

The way of organizing tests in Playwright is similar to how it’s done in Protractor or Cypress. The API is returning promises, and we use await to ensure that each step is done executing before the next one is started.

Running tests

To run tests, we need to start the application server in the background:

$ npm run start

> angular.io-example@0.0.0 start
> ng serve

…

** Angular Live Development Server is listening on localhost:4200. Open your browser on http://localhost:4200/ **

…

✔ Compiled successfully.

With the server running, we can run all tests with:

npm run e2e

Summary

As you see, setting E2E tests with Playwright for Angular applications is pretty straightforward. Thanks to its broad language support, you can choose a language depending on what skills are available in your team. E2E tests are an essential tool to maintain a high quality of an application in fast-moving teams.

Looking for more support for your Angular projects?

Our team at DevIntent is highly experienced in Angular development, testing, and software quality. If you'd like to chat about how we can help you, please contact us at sales@devintent.com.