Playwright Describe Blocks
A library organizes books into sections labeled fiction, history, and science instead of piling every book onto one giant shelf. A describe block organizes tests the same way, grouping related tests under one clear label instead of leaving them scattered without structure.
Tests Grouped Under a Label
Login Feature (describe block) |-- test: shows error on wrong password |-- test: logs in with correct password |-- test: shows forgot password link
Writing a Basic Describe Block
test.describe('Login Feature', () => {
test('shows error on wrong password', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Password').fill('wrongpass');
await page.getByRole('button', { name: 'Log In' }).click();
await expect(page.getByText('Invalid credentials')).toBeVisible();
});
test('logs in with correct password', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Password').fill('correctpass');
await page.getByRole('button', { name: 'Log In' }).click();
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
});Both tests now appear grouped under "Login Feature" in every test report, making results far easier to scan at a glance.
Nesting Describe Blocks for Larger Features
test.describe('Checkout', () => {
test.describe('Payment', () => {
test('accepts a valid card', async ({ page }) => {
// test steps here
});
test('rejects an expired card', async ({ page }) => {
// test steps here
});
});
test.describe('Shipping', () => {
test('calculates standard shipping cost', async ({ page }) => {
// test steps here
});
});
});This structure mirrors a real feature breakdown, with "Payment" and "Shipping" sitting as clear sub-sections inside the larger "Checkout" area.
Adding Hooks Scoped to One Group
test.describe('Login Feature', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://example.com/login');
});
test('shows error on wrong password', async ({ page }) => {
// test steps here
});
});This hook only applies to tests inside the "Login Feature" group, leaving tests in other describe blocks completely unaffected.
Skipping an Entire Group Temporarily
test.describe.skip('Old Checkout Flow', () => {
test('legacy payment method still works', async ({ page }) => {
// test steps here
});
});This skips every test inside the group without deleting the code, useful when a feature is temporarily disabled or under active rebuilding.
A Real-World Example
A travel booking website organizes its two hundred tests into describe blocks named "Flight Search," "Hotel Booking," and "Payment." A manager reviewing a report instantly sees which entire feature area has failures, without reading through every individual test name.
Quick Practice Task
Take five unrelated tests from your project and organize them into two or three clearly labeled describe blocks based on the feature each test covers.
Key Takeaways
- Describe blocks group related tests under one clear label.
- Groups can nest to represent larger features with sub-sections.
- Hooks inside a describe block apply only to that specific group.
- Clear grouping makes large test reports far easier to scan and understand.
