Advanced Configuration & Projects — Suite Mastery
Stop maintaining multiple config files for Smoke, Regression, and Cross-Browser testing. Learn how Playwright's "Projects" feature handles complex execution matrices in a single, elegant config.
📖 The Story: The Config Monster
A growing QA team had a problem. They needed to run a fast "Smoke" suite on every Pull Request, but a massive "Regression" suite every night. They also needed to test Chrome, Firefox, and Safari.
To solve this, they created three config files: playwright.smoke.config.ts, playwright.regression.config.ts, and playwright.cross-browser.config.ts.
Within a year, the repo was a mess. A developer changing the base URL had to update three files. CI scripts were a tangled web of --config flags. They had created a Config Monster.
Then they discovered Playwright Projects. They consolidated everything into a single playwright.config.ts. They defined projects for Smoke, Regression, Chromium, and WebKit. The CI pipeline simply called --project=Smoke. The Config Monster was slain.
One config file to rule them all. Projects are the enterprise standard for test execution.
🎯 Why Use Projects?
Single Source of Truth
Maintain one config file instead of a dozen fragmented variations.
Flexible Execution
Run just the smoke tests, just the API tests, or just the mobile tests via a single CLI flag.
Dependencies
Guarantee that a "Setup" project (like logging in) runs before the main test projects.
Clean Reporting
The HTML report groups results by project, making it easy to see "Chrome passed but Firefox failed."
🌍 Real World Example
You want to test a desktop app on Chrome and a mobile app on Safari iOS. In your config, you define a Desktop Chrome project and an iPhone 14 project. When you run npx playwright test, it runs both. If you only want to test mobile today, you run npx playwright test --project="iPhone 14".
🧒 Explain Like I'm 10
Imagine a restaurant menu. Instead of having a "Breakfast Menu", "Lunch Menu", and "Dinner Menu" printed on separate pieces of paper, you have one big menu. The items are grouped into sections: "Breakfast", "Lunch", and "Dinner".
If you want breakfast, you just order from the Breakfast section. Playwright Projects are those sections. One menu (config file), multiple sections (projects).
🎓 Professional Explanation
The projects array in playwright.config.ts allows you to define multiple execution environments or test groupings. Each project can override top-level use properties (like browserName, viewport, or baseURL) and filter tests using testMatch or grep.
When Playwright runs without a --project flag, it executes all projects sequentially (or in parallel if configured). When a --project flag is passed, it runs only that specific project.
📊 Single Config vs Projects
Organizing Your Test Suite
The Bad Way (Multiple Files)
The Playwright Way (Projects)
💨 Smoke vs. Regression Projects
The most common use case is splitting tests by speed/importance. You can tag tests in your code, and filter them in the project.
import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', projects: [ { name: 'Smoke', testMatch: ['**/*.smoke.ts'], // OR use grep: /@smoke/ use: { ...devices['Desktop Chrome'] }, }, { name: 'Regression', testIgnore: ['**/*.smoke.ts'], // Run everything except smoke use: { ...devices['Desktop Chrome'] }, }, { name: 'Mobile Safari', testMatch: ['**/*.mobile.ts'], use: { ...devices['iPhone 14'] }, } ] });
Grep vs TestMatch: You can use testMatch to match file names (e.g., login.smoke.ts), or you can use grep: /@smoke/ to match test titles like test('login @smoke', ...). Both are valid; grep is often easier to maintain.
🔗 Project Dependencies (Setup Projects)
Sometimes Project B relies on Project A finishing first. For example, a "Setup" project logs in and saves the storageState. The "Chromium" project depends on that state.
projects: [ { name: 'Setup', testMatch: '/.*\.setup\.ts/', }, { name: 'Chromium', dependencies: ['Setup'], // Waits for Setup to finish first use: { storageState: 'auth-state.json', // Uses the file Setup created ...devices['Desktop Chrome'] }, } ]
⚙️ Running Projects via CLI
# Run everything (Smoke, Regression, Mobile) npx playwright test # Run ONLY the Smoke project npx playwright test --project=Smoke # Run both Smoke and Mobile Safari npx playwright test --project=Smoke --project="Mobile Safari"
⚠️ Common Mistakes
Mistake 1: Overlapping Test Files
If Project A uses testMatch: ['**/*.ts'] and Project B uses testMatch: ['**/*.spec.ts'], Project A will run all tests, including B's tests. Use testIgnore to keep them strictly separate.
Mistake 2: Forgetting Device Context
// ❌ BAD: This doesn't test mobile, it just names it mobile { name: 'Mobile', use: { browserName: 'chromium' } } // ✅ GOOD: Use Playwright's device descriptors { name: 'Mobile', use: { ...devices['Pixel 7'] } }
✅ Best Practices
- Name projects clearly. "Desktop Chrome" is better than "chromium". "Mobile Safari" is better than "webkit".
- Use dependencies for auth. It's cleaner than using
globalSetupfor multi-role authentication. - Keep Smoke tests under 3 minutes. A PR shouldn't wait 20 minutes for a smoke suite.
- Use tags (grep). Tagging tests with
@criticalor@flakyallows you to group them in projects without moving files around.
🏗️ Senior Engineer Deep Dive
Execution Order and Parallelism
By default, projects run sequentially. The "Smoke" project finishes entirely before "Regression" starts. However, within each project, tests run in parallel across workers. If you have dependencies, Playwright guarantees the dependency project completes all its tests (and workers) before spawning workers for the dependent project.
Environment Variables per Project
You can inject specific env vars per project using use: { env: { ADMIN_TOKEN: 'xyz' } }. This is incredibly powerful for testing multi-tenant architectures where Test A acts as Admin and Test B acts as a standard User, without them colliding on the same database row.
💼 Interview Questions
Show Answer
playwright.config.ts with a specific name and device configuration (e.g., iPhone 14). Then I run npx playwright test --project="iPhone 14".Show Answer
testMatch to match different file extensions (e.g., *.smoke.ts) or use the grep option to match test titles tagged with @smoke. Then I run the specific project via the CLI.Show Answer
storageState. The main test project lists "Setup" in its dependencies array, ensuring the auth state file exists before the tests try to use it.Show Answer
playwright.config.ts. The PR CI job runs npx playwright test --project=Smoke. The Main branch CI job runs npx playwright test (which executes all projects, including Regression).🏋️ Practical Exercise
Split Your Suite
- Open your
playwright.config.ts. - Create two projects: "Smoke" and "Regression".
- Tag a few of your tests with
@smokein their titles. - Configure the Smoke project to
grep: /@smoke/. - Run
npx playwright test --project=Smokeand verify only the tagged tests run.
🚀 Mini Project
🏗️ The Multi-Device Matrix
- Configure 3 projects in your config: "Desktop Chrome", "Desktop Firefox", and "Mobile Safari".
- Write a single test that navigates to a responsive website.
- Run the full suite (all 3 projects).
- Open the HTML report. Observe how Playwright groups the test results by project, showing how the test performed across all 3 environments.
📝 Quiz
Test your understanding. Click an option to check your answer.
package.json fileprojects array inside playwright.config.tstests/ directorynpx playwright test --grep=Smokenpx playwright test --project=Smokenpx playwright smokenpx playwright test --config=Smoke--project flag filters execution to the specified project name.dependencies property do in a project?viewport: { width: 390, height: 844 }use: { ...devices['iPhone 14'] } inside a projectpage.setMobile()devices['iPhone 14'] into use sets the correct viewport, userAgent, and touch events.npx playwright test without any flags, what happens?test('login', { tag: 'smoke' })login.smoke.ts and use testMatch@smoke in the test title and use grepuse settings?use block override the global ones.use properties take precedence over top-level use properties.storageState, which the dependent project then uses.❓ FAQ
Q: Can projects run in parallel with each other?
A: By default, projects run sequentially. However, there is a projects configuration in experimental phases (or you can use CI matrices) to run them simultaneously. Usually, sequential is fine because tests within the project are already running in parallel.
Q: Should I put Smoke and Regression tests in different folders?
A: It's up to you. Some prefer tests/smoke/ and tests/regression/. Others keep them in the same folder but use grep tags. Tags are often easier to maintain.
📦 Summary
🎯 Key Takeaways
- Projects allow multiple execution environments (browsers, devices, suites) in one config file.
- Use
--project=Nameto run specific suites via CLI. - Use
dependenciesto guarantee setup projects run first. - Use
devicesfor accurate mobile emulation. - Keep CI scripts clean by filtering at the project level, not the file level.
