As a test suite grows, you need to run the right tests at the right time. In this lesson you will group tests with describe blocks, label them with tags, filter runs with grep, and make those filters permanent in the config and npm scripts.
๐ What You’ll Learn: test.describe and nested groups, the tag option and title tags, a practical tagging strategy, –grep and –grep-invert including AND and OR patterns, grep in config projects, npm scripts, describe.configure and serial mode, focus and skip, and reading tags at runtime.
๐๏ธ Why Organize Tests?
With ten tests, organization does not matter. With five hundred, it decides whether your team can answer questions like:
- “Run only the smoke tests before every deployment.”
- “Run the checkout tests after the payments team changed something.”
- “Skip the slow tests on pull requests, run them nightly.”
Playwright gives you three tools for this: describe blocks to group tests, tags to label them, and grep to filter what runs.
๐ฆ Group Tests with test.describe
test.describe groups related tests under a title. Groups can be nested, and the titles are combined in reports, for example Cart โบ Add items โบ add one product.
import { test, expect } from '@playwright/test';
test.describe('Cart', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://www.saucedemo.com/');
await page.getByPlaceholder('Username').fill('standard_user');
await page.getByPlaceholder('Password').fill('secret_sauce');
await page.getByRole('button', { name: 'Login' }).click();
});
test.describe('Add items', () => {
test('add one product', async ({ page }) => {
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await expect(page.locator('.shopping_cart_badge')).toHaveText('1');
});
test('add two products', async ({ page }) => {
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await page.locator('[data-test="add-to-cart-sauce-labs-bike-light"]').click();
await expect(page.locator('.shopping_cart_badge')).toHaveText('2');
});
});
test.describe('Remove items', () => {
test('remove a product', async ({ page }) => {
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await page.locator('[data-test="remove-sauce-labs-backpack"]').click();
await expect(page.locator('.shopping_cart_badge')).toHaveCount(0);
});
});
});
Describe blocks also scope hooks, so each group can have its own setup.
๐ท๏ธ Tag Tests
A tag is a label that starts with @. Add tags with the tag option (recommended) or directly in the title:
// Option 1: tag details (shown as tags in the HTML report)
test('user can log in', { tag: '@smoke' }, async ({ page }) => {
// ...
});
test('full checkout flow', { tag: ['@regression', '@checkout'] }, async ({ page }) => {
// ...
});
// Option 2: tag in the title
test('user can log out @smoke', async ({ page }) => {
// ...
});
// Tag a whole group
test.describe('Payments', { tag: '@payments' }, () => {
test('pay by card', async ({ page }) => { /* ... */ });
test('pay by UPI', async ({ page }) => { /* ... */ });
});
A practical tagging strategy
| Tag | Meaning | When it runs |
|---|---|---|
@smoke | Critical paths, fast | Every commit and deployment |
@regression | Full functional coverage | Nightly or before release |
@slow | Long tests | Nightly only |
@api / @ui | Test type | Separate CI jobs |
@checkout, @search | Feature area | When that feature changes |
@flaky | Known unstable test under investigation | Excluded from blocking runs |
๐ก Tip: Agree on a short, fixed list of tags with your team and document it. Fifty random tags are as confusing as none.
๐ Filter Tests with –grep
--grep (short: -g) runs only tests whose full title, including describe titles and tags, matches a regular expression:
npx playwright test --grep @smoke # tagged @smoke
npx playwright test -g "add two products" # by title text
npx playwright test --grep "Cart" # every test inside the Cart describe
npx playwright test --grep-invert @slow # everything except @slow
npx playwright test --grep "@smoke|@api" # @smoke OR @api
npx playwright test --grep "(?=.*@smoke)(?=.*@checkout)" # @smoke AND @checkout
npx playwright test --grep @regression --grep-invert @flaky
๐ Note: On Windows PowerShell, keep the quotes around patterns that contain |, otherwise the shell treats it as a pipe.
Check what would run without running it:
npx playwright test --grep @smoke --list
โ๏ธ Filters in the Config and npm Scripts
Make common filters permanent:
// playwright.config.ts
export default defineConfig({
grepInvert: /@flaky/, // never run @flaky tests by default
projects: [
{ name: 'smoke', grep: /@smoke/, use: { ...devices['Desktop Chrome'] } },
{ name: 'regression', grep: /@regression/, use: { ...devices['Desktop Chrome'] } },
],
});
{
"scripts": {
"test:smoke": "playwright test --grep @smoke",
"test:regression": "playwright test --grep @regression --grep-invert @flaky",
"test:api": "playwright test --grep @api"
}
}
Then npm run test:smoke or npx playwright test --project=smoke. More command options are in Playwright CLI commands.
๐งต Control How a Group Runs: describe.configure
// Run tests in this file in parallel, even if fullyParallel is false
test.describe.configure({ mode: 'parallel' });
// Run tests in order; if one fails, the rest are skipped
test.describe.serial('Checkout wizard', () => {
test('step 1: shipping', async ({ page }) => { /* ... */ });
test('step 2: payment', async ({ page }) => { /* ... */ });
});
// Retries and timeout for one group
test.describe('Reports', () => {
test.describe.configure({ retries: 2, timeout: 60_000 });
test('export PDF', async ({ page }) => { /* ... */ });
});
โ ๏ธ Common mistake: Serial mode makes tests depend on each other, which slows the suite and spreads one failure to many tests. Prefer independent tests; use serial only for genuinely step-by-step flows.
๐ฏ Focus and Skip Groups While Developing
test.describe.only('Cart', () => { /* only this group runs */ });
test.describe.skip('Wishlist', () => { /* this group is skipped */ });
test.only('debug this one test', async ({ page }) => { /* ... */ });
Never commit .only: set forbidOnly: !!process.env.CI in the config so CI fails if one slips through. Skipping with conditions, fixme and slow are covered in annotations.
๐ Read Tags at Runtime
test('tagged test', { tag: '@smoke' }, async ({ page }, testInfo) => {
console.log(testInfo.tags); // ['@smoke']
});
This is useful in reporters, hooks and integrations with test management tools.
๐ Assignment
- Organize your Sauce Demo tests into
describeblocks:Login,Cart(with nestedAdd itemsandRemove items) andSorting. - Tag two critical tests
@smoke, all tests@regression, and one test@slow. - Run only
@smoketests, then everything except@slow, and use--listto confirm each selection first. - Run tests that are both
@regressionand@smokeusing a lookahead pattern. - Add
test:smokeandtest:regressionscripts topackage.json. - Create a
smokeproject in the config withgrep: /@smoke/and run it with--project=smoke. - Bonus: print
testInfo.tagsin anafterEachhook for every test.
โ FAQ
๐ค How do I tag tests in Playwright?
Pass a tag option: test('title', { tag: '@smoke' }, async ({ page }) => {}), or add @smoke to the test title. Tags can also be applied to a whole test.describe block.
๐ค How do I run only smoke tests in Playwright?
Run npx playwright test --grep @smoke, or create a project with grep: /@smoke/ and run it with --project.
๐ค How do I exclude tests in Playwright?
Use --grep-invert @tag on the command line, or grepInvert in the config.
๐ค What does test.describe do in Playwright?
It groups tests under a shared title, scopes hooks and configuration to that group, and makes reports easier to read.
๐ค How do I run Playwright tests in a specific order?
Use test.describe.serial or test.describe.configure({ mode: 'serial' }). Tests then run one after another in declaration order, and the rest are skipped if one fails.
๐ฏ Next Steps
- ๐ญ Annotations: skip, only, fixme, slow
- ๐ญ Playwright Fixtures Step by Step
- ๐ญ Retries and Fixing Flaky Tests
- ๐ญ Playwright Tutorial with TypeScript
๐ฌ Watch the full Playwright tutorial series on YouTube!
Subscribe to SqaToolsByDY • Practice on sqatools.in
2 thoughts on “Group, Tag and Filter Playwright Tests (describe, Tags and grep)”