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
Task 1, not checked yet. Put both tests inside
test.describe('sign in', () => { ... }). Move the two repeatedpage.goto('/login')lines into onetest.beforeEach. The file must still have two passing tests.Task 2, not checked yet. Add a test named
rejects a wrong password, inside the group. Sign in asada@example.comwith the passwordnot-the-password. Check that the alert has the textWrong email or password.and that the address is still/login.Task 3, not checked yet. Add a test named
checks the email address, inside the group. Fill the email field withnopeand a good password. ClickSign in. Check that the page showsEnter a valid email address.Task 4, not checked yet. Add a test named
checks the length of the password, inside the group. Fill the email field withada@example.comand the passwordabc. ClickSign in. Check that the page showsUse 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.