Playwright

Lesson 9 of 17

Lesson · 22 min

Groups and hooks

Repeated setup

Look at the two tests in the starter. Both begin with await page.goto('/login'). In a real project, many tests begin the same way. When the address changes, you must change it in every test.

Playwright has two tools for this: groups and hooks.

Groups with describe

test.describe puts tests in a group with a name. The group has no effect on how the tests run. It shows in the report, so a person can see which tests belong together, and it lets you share a hook.

test.describe('sign in', () => {
  test('shows the heading', async ({ page }) => { /* ... */ });
  test('rejects a wrong password', async ({ page }) => { /* ... */ });
});

In the report, the title of each test starts with the name of the group: sign in › shows the heading.

Hooks

A hook is a function that Playwright runs for you at a set time.

Hook Runs
test.beforeEach Before every test in the file, or in the group.
test.afterEach After every test, also when the test failed.
test.beforeAll One time, before the first test.
test.afterAll One time, after the last test.

beforeEach and afterEach receive the same things as a test, so you can use page in them. Every test still has its own new page. The hook prepares that page before the test starts.

test.beforeEach(async ({ page }) => {
  await page.goto('/login');
});

A hook in a describe runs only for the tests in that group. A hook outside a group runs for every test in the file.

Use beforeEach for steps that every test needs, such as opening a page. Do not hide the interesting part of a test in a hook. A person who reads a test must see what the test does.

Steps

test.step gives a name to a part of a long test. The report of a real Playwright project shows the steps, so a failure says which part broke.

await test.step('fill in the form', async () => {
  await page.getByLabel('Email').fill('ada@example.com');
});

Skip and focus

test.skip('title', ...) keeps a test in the file but does not run it. test.only('title', ...) runs this test and no other. Never save a test.only in a shared project. In a real project, the setting forbidOnly: true makes the run fail when someone does.

Your turn

First tidy up the two tests that you have. Then add three tests, each for a rule of the form. The checker runs each one on an app that breaks the rule.

Tasks

4 to do

  1. Task 1, not checked yet. Put both tests inside test.describe('sign in', () => { ... }). Move the two repeated page.goto('/login') lines into one test.beforeEach. The file must still have two passing tests.

  2. Task 2, not checked yet. Add a test named rejects a wrong password, inside the group. Sign in as ada@example.com with the password not-the-password. Check that the alert has the text Wrong email or password. and that the address is still /login.

  3. Task 3, not checked yet. Add a test named checks the email address, inside the group. Fill the email field with nope and a good password. Click Sign in. Check that the page shows Enter a valid email address.

  4. Task 4, not checked yet. Add a test named checks the length of the password, inside the group. Fill the email field with ada@example.com and the password abc. Click Sign in. Check that the page shows Use at least 8 characters.

Task 1 of 4

Put both tests inside test.describe('sign in', () => { ... }). Move the two repeated page.goto('/login') lines into one test.beforeEach. The file must still have two passing tests.

All tasks

example.spec.js

Ctrl+Enter runs your tests. Ctrl+Shift+Enter checks it. Press Esc, then Tab, to leave the editor.

Practice browser

The sample app is ready

The results of your tests show here. Press Run tests to watch them run in the practice browser.