In this step-by-step guide, we will show you how to create your first successful e2e Playwright test for an Angular 14 project.

Step 0 (optional): Start Cloud Desktop – or use your own environment

If you need a development environment, you can connect to our Developer’s Cloud Desktop. Simply click on the image below and launch the environment by clicking on the WebStorm Cloud Desktop button (bring your own license or get a free 30-day trial from JetBrains).

Alternatively, you also can use the free VS Code Cloud Desktop. Or you use your own development environment and install NPM if needed.

Cloud Desktop - WebStorm New!

You can increase the resolution by clicking on the Display icon on the desktop:

If you are running your development environment on a Full HD screen, we recommend 1920×1056 and running your browser in full-screen mode. This will avoid the need for scrollbars.

Step 1: (Re-) Install Angular

A relatively old version of angular is installed in the Developer’s Cloud Desktop, currently. The easiest way to upgrade it is to re-install it. For that, open a terminal and issue the following two commands:

npm remove -g @angular/cli
npm install -g @angular/cli

We can check the version with the ng version command:

Angular CLI: output of the command "ng version"

Step 2: Create a Hello World Project

Let us now create a new hello world project

ng new playwright-hello-world

You are asked some questions. In my case, I have chosen Angular routing: Yes and stylesheet format: SCSS. However, in this Hello World program, we will not manipulate CSS anyway.

ng new playwright-hello-world

Let us enter the newly-created directory and start the server:

cd playwright-hello-world
ng serve

We optionally can connect to the server by opening http://localhost:4200 in a browser on the developer’s cloud desktop:

However, this is not needed for our first Playwright test.

Step 3: Install Playwright

We now choose to install Playwright as a dev-dependency in our project. In addition,

npm install @playwright/test --save-dev npx playwright install chromium

Playwright needs to know how to start a browser. By default, it will not find any installed browser on the system. The simplest way to circumvent that problem is to let Playwright install its own browser:

npx playwright install chromium

Step 4: Configure Playwright

We have seen that Playwright is confused if it finds any karma or jest spec files, and the test.js file. For details see the appendix chapter below.

In order to fix this behavior, we create a minimalistic Playwright configuration file on project root:

// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';

const config: PlaywrightTestConfig = {
  testDir: './e2e-playwright',
export default config;

Here, we have told Playwright that it should search for spec files in the e2e-playwright directory. With that, it will not be confused by karma files anymore.

Step 5: Create a first Playwright spec file

In the Playwright configuration file above, we have specified that all Playwright tests will be located in the e2e-playwright directory. Therefore, let us create that folder and place a simple Playwright test into that folder:

// create test folder
mkdir e2e-playwright

// create an example spec file:
cat <EOF > e2e-playwright/example.spec.ts
import { test, expect } from '@playwright/test';

test('basic test', async ({ page }) => {
  await page.goto('');
  const title = page.locator('.navbar__inner .navbar__title');
  await expect(title).toHaveText('Playwright');

Step 6: Run the Playwright Test

Now the test should be successful:

playwright test

We should see something like:

your first playwright test

Step 7 (optional): Run the Test in non-headless Mode

We have not seen that yet, but under the hood, the installed Chromium browser will be started. We will be able to verify this by configuring the tests to be performed in a non-headless mode:

// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';

const config: PlaywrightTestConfig = {
  testDir: './e2e-playwright',
  use: {
    headless: false
export default config;

If we now re-run the test, a browser will be started visibly:

playwright test

Plawright starting the Chromium Browser

Step 8: Test your own Application

You might have noticed that the „hello world“ Playwright test above did not test your own application. Instead, an external URL was tested.

Let us now create a first test that will test our own application. Once again, we start the application, if not already done:

npm run start # or ng serve

At the moment, our application consists of the default page provided by Angular 14, which can be seen, if we navigate to http://localhost:4200/:

Copy Selector of the title in debug mode of the chrome browser

With F12 in a Chrome browser, we can see, that the locator of the title playwright-hello-world is body > app-root > div.content > div.card.highlight-card.card-small > span. In order for the locator not to be too implementation-specific, let us choose div.card.highlight-card.card-small > span only.

With this information, we can create a Playwright test that tests our application. Let us create following file within the e2e-playwright directory:

// project-url-example.spec.ts
// Test your own Application
import pkg from '../package.json';
import { test, expect } from '@playwright/test';

test('Main page find title', async ({ page }) => {
  await page.goto('http://localhost:4200/');
  const title = page.locator('div.card.highlight-card.card-small > span');
  await expect(title).toHaveText(`${} app is running!`);

Note: if you want to get rid of the TS-Lint complaints your IDE might show, you should add the following two lines into the compilerOptions section of the tsconfig.json file located in the project root:

// tsconfig.json
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true,

Now let us run the playwright test.

playwright test

If all went well, the output will look like follows:

Playwright two successful tests

Step 9 (optional): Automatically spin up the Server (suitable for Continuous Integration)

Note that the application must be up and running for the test to succeed. That is, why we have manually run the command npm run start above. Can we automate this, e.g. for usage in a continuous integration pipeline?

Yes, we can:

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

const config: PlaywrightTestConfig = {
  testDir: './e2e-playwright',
  webServer: {
    command: 'npm run start',
    reuseExistingServer: true,
    url: 'http://localhost:4200/'
  use: {
    headless: true
export default config;

Here, we have added the webServer section that specifies the command to start the application server, if the server is not already running on port 4200.

Now let us stop the manually started server and run the Playwright tests again:

playwright test

If the web server was stopped before, th

Two successful Playwright Tests with automatic start of the Web Server

Notice the WebServer logs before the actual tests are started if the server is not already running.

Let us double-check the other case, where the server is running in the background continuously:

npm run start

In a second terminal, we run the tests again:

playwright test

In this case, the startup of the web server is skipped, which speeds up the setup time:

Playwright two successful tests

Since the setup time is optimized in the mode, this mode is best suitable for the local development of Playwright scripts.

Step 10: Debugging with Playwright Inspector

There is a simple method how to debug Playwright scripts step by step: just start the Playwright Inspector by using the --debug option:

playwright test --debug

This will spin up the Playwright Inspector and it will pause on the first Playwright command; the page.goto command in this case:

Starting the Playwright Inspector with the --debug Option

We now can debug the Playwright script step-by-step by clicking the „step over“ button:

Step over Button in the Playwright Inspector

In our case, our application will load and the located HTML element is highlighted in the browser:

Playwright Inspector is highlighting the located HTML Element

Step 11 (optional): Debugging using the „Playwright Test for VSCode“ Plugin

Playwright Inspector comes with Playwright and there was no need to install anything. It helped to test our Playwright scripts step-by-step. However, Inspector does not offer a convenient possibility to watch the values of the variables used.

A little Internet research has shown that there is a free plugin for Visual Studio Code that will help us here.

In a recent version of Visual Studio Code, install the plugin „Playwright Test for VSCode“:

Installation of the Plugin "Playwright Test for VSCode"

Now open the Folder, where our project is located and wait for 2 to 3 minutes until the indexing has finished. After that, you should see a green triangle left of the playwright test:

Green Triangle left of the test code

Here, you can either run that single test, or you can debug the test by setting a breakpoint left of the await line and by right-clicking on the triangle:

Start Debugging in VS Code

VS Code run Playwright, which will start the browser. The execution is paused at the previously set breakpoint:

VS Code waits for user input at the breakpoint

We now can step through the code as we are used to when using an integrated development environment:

Stepping through the Code

Moreover, the IDE allows us to watch the values of any object.

Step 12: Tracing after failed tests

In case of failed tests, Playwright offers extensive tracing capabilities. After a failed test, run the following command and select the zip file found on <playwright-dir>/reports/html/data

playwright show-trace

In the actions pane, navigate through the steps. In the middle main window, you will see the content of the browser for each step. The great thing about the tool is. that those are no screenshots, but they are snapshotted browser contents that can be browsed by right-click and choosing „Investigate“. Chrome will open the dynamic HTML content of the page.

Note: you might need to repeat the right-click a second time in order to be navigated to the correct position within the dynamic HTML content of the snapshot.

Appendix: Error message in case of a missing playwright.config.ts File


We have seen that Playwright is confused if it finds any karma or jest spec files, and the test.js file. In our case, we have seen error messages like follows, when we run playwright test without telling Playwright where to search for specification files:

// error messages seen on a fresh Angular project 
// when we run `playwright test` without playwright.config.ts file:
$ playwright test

Running 0 test using 0 worker

Error [ERR_REQUIRE_ESM]: require() of ES Module /headless/git/playwright-hello-world/node_modules/@angular/core/fesm2015/testing.mjs not supported.
Instead change the require of /headless/git/playwright-hello-world/node_modules/@angular/core/fesm2015/testing.mjs to a dynamic import() which is available in all CommonJS modules.

   at src/app/app.component.spec.ts:3

  1 | import { TestBed } from '@angular/core/testing';
  2 | import { RouterTestingModule } from '@angular/router/testing';
> 3 | import { AppComponent } from './app.component';
    |                ^
  4 |
  5 | describe('AppComponent', () => {
  6 |   beforeEach(async () => {

    at Object. (/headless/git/playwright-hello-world/src/app/app.component.spec.ts:3:16)
    at Module.A._compile (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/utilsBundleImpl.js:16:994)
    at Object.t..tu._extensions. (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/utilsBundleImpl.js:16:1010)
    at Loader._requireOrImport (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/loader.js:276:14)
    at Loader.loadTestFile (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/loader.js:163:18)
    at Runner._runFiles (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/runner.js:289:44)
    at Runner._run (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/runner.js:224:23)
    at async (/headless/git/playwright-hello-world/node_modules/playwright-core/lib/utils/timeoutRunner.js:53:14)
    at async raceAgainstTimeout (/headless/git/playwright-hello-world/node_modules/playwright-core/lib/utils/timeoutRunner.js:113:15)
    at async Runner.runAllTests (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/runner.js:182:20)
    at async runTests (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/cli.js:162:18)
    at async Ai. (/headless/git/playwright-hello-world/node_modules/@playwright/test/lib/cli.js:70:7)

ReferenceError: Zone is not defined

   at node_modules/zone.js/bundles/zone-testing.umd.js:101

   99 |         return Error.stackTraceLimit > 0;
  100 |     }
> 101 |     Zone['longStackTraceZoneSpec'] = {
      |     ^
  102 |         name: 'long-stack-trace',
  103 |         longStackTraceLimit: 10,
  104 |         // add a getLongStackTrace method in spec to

    at /headless/git/playwright-hello-world/node_modules/zone.js/bundles/zone-testing.umd.js:101:5
    at /headless/git/playwright-hello-world/node_modules/zone.js/bundles/zone-testing.umd.js:18:9
    at Object. (/headless/git/playwright-hello-world/node_modules/zone.js/bundles/zone-testing.umd.js:19:3)
    at Object. (/headless/git/playwright-hello-world/src/test.ts:3:1)

 no tests found.

Even if there are valid Playwright tests, Playwright will skip them due to those errors.


In order to fix this behavior, we create a minimalistic Playwright configuration file on project root:

// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';

const config: PlaywrightTestConfig = {
  testDir: './e2e-playwright',
export default config;

Here, we have told Playwright that it should search for spec files in the e2e-playwright directory. With that, it will not be confused by karma files anymore.



Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.