Back to blog

9 Playwright Best Practices: Reliable and Easy Tests

Maryia Stsiopkina

2025-02-204 min read
Share

Automated testing allows developers to programmatically verify application behavior by writing code that simulates user interactions and checks expected outcomes, saving countless hours of manual testing. Following the right practices with Playwright can significantly improve your development workflow and help you create scalable test scripts.  Poor testing practices, on the other hand, can lead to flaky tests, false positives, and countless hours spent debugging unreliable test suites. 

In this article, we'll explore nine essential Playwright best practices that will help you build more reliable and easier-to-maintain test suites.

If you're new to this tool, check out what Playwright is first to understand its testing and automation capabilities. 

9 Playwright best practices

To make the most of Playwright and ensure your tests are reliable, maintainable, and efficient, follow the nine best practices listed below.

1. Use stable selectors

Choosing the right way to identify elements on your page is crucial for creating reliable tests. The best approach is to use dedicated testing attributes like data-testid (e.g., data-testid="submit-button") instead of regular CSS classes or XPath. These special attributes won't change when you update your page's design or structure, making your tests more stable. You can also use role-based selectors that identify elements by their purpose (like buttons or text inputs) rather than their appearance. Keep all your selectors in one central file to make them easier to maintain and update.

Below is an example of bad practice.

await page.click('.btn-primary');

And here’s a code snippet of good practice. 

await page.click('[data-testid="submit-button"]');

2. Isolate tests

Each test should work independently without relying on other tests. This approach helps increase test reliability and makes troubleshooting easier. Before running a test, reset everything to its starting state – clear any test data, reset the database, and clean up any leftover information from previous tests. This way, when a test fails, you'll know exactly where to look for the problem.

Here's how to reset before each test:

beforeEach(async () => {
  await resetDatabase();
  await page.goto('http://example.com');
});

3. Focus on user interactions

Write tests that mimic real user behavior instead of testing technical details. Think about what users actually do: clicking buttons, filling out forms, and navigating between pages. This approach helps you catch real issues that users might encounter.

Here's an example of simulating natural user interaction:

// Bad practice - direct manipulation
await page.$eval('#hidden-input', el => el.value = 'test');

// Good practice - user-like interaction
await page.fill('[data-testid="username-input"]', 'test');

4. Automate and monitor tests

Set up your tests to run automatically in your CI/CD pipeline (like GitHub Actions, Jenkins, or GitLab CI). This means your tests will run whenever someone makes code changes, helping catch problems early. Keep track of how your tests are performing by monitoring things like how long they take to run and how often they fail. When tests start failing regularly, investigate the cause quickly rather than ignoring the problem. Regular monitoring in your CI/CD process helps ensure your application stays reliable as it grows.

5. Test across relevant browsers

Make sure your application works well in all the browsers your users might use. Playwright makes it easy to test in different browsers like Chrome, Firefox, and Safari. Focus on testing the most important features across all browsers while running detailed tests in your main target browser.

Here's a simple way to run tests in multiple browsers:

const browsers = ['chromium', 'firefox', 'webkit'];
for (const browserType of browsers) {
  const browser = await playwright[browserType].launch();
  // Run your tests
}

For more advanced scenarios, such as automated data collection, check out our Scrapy Playwright tutorial or learn how to bypass CAPTCHA with Playwright.

6. Define test coverage goals

Decide which parts of your application need the most testing by creating a clear testing strategy. Focus on the features that are most important to your users and your business, such as user authentication, payment processing, and data submission forms. You don't need to test everything – concentrate on the critical user journeys that could cause the biggest problems if they break. Additionally, pay special attention to areas of your application that change frequently or have a history of bugs.

7. Use Playwright's built-in tools

Take advantage of the helpful tools that come with Playwright to make your testing process more efficient. The Playwright test runner helps you execute and manage both your unit tests and end-to-end tests effectively. The Playwright Inspector lets you debug tests by stepping through each action, while the code generator helps you generate tests by watching your browser interactions. The built-in video recorder captures test runs automatically, making it easier to understand why a test failed. The code generator watches your browser interactions and converts them into test code, which is perfect for getting started with new test scenarios. These tools work together to save you time during both test creation and maintenance.

For more advanced use cases, learn about Playwright web scraping and Playwright proxy integration.

8. Write clear test names

Give your tests descriptive names that explain what they're checking. A good test name helps others understand what the test does without having to read the code. Think of test names as documentation that describes the feature being tested and the expected outcome.

For example:

// Bad practice
test('login test', async () => {});

// Good practice
test('user can log in with correct email and password', async () => {});

9. Handle waiting properly

Don't use fixed time delays in your tests, as they make tests either slow or unreliable. Instead, wait for specific things to happen, like an element appearing or a message being displayed. This approach not only makes your tests more reliable but also helps them run as fast as possible by moving forward as soon as the application is ready.

Here's the right way to handle waiting:

// Bad practice
await page.waitForTimeout(2000);

// Good practice
await page.waitForSelector('[data-testid="loaded-content"]');

Conclusion

Following these practices will help you create better, more reliable tests with Playwright. Each practice builds upon the others – stable selectors support reliable waiting strategies, clear test names make maintenance easier, and good test coverage ensures you're testing the right things. Start implementing these tips in your testing process today, and you'll spend less time fixing broken tests and more time ensuring your application works well for your users. Remember that good testing practices are an investment that pays off in the long run through improved reliability and easier maintenance.

Frequently Asked Questions

How to structure a Playwright test project?

A well-structured Playwright project should have a clear and logical organization. Start with a dedicated tests directory for your test files, and create a separate directory for page objects that represent the pages or components you're testing. Store your test data in a fixtures directory and keep your global configuration in a playwright.config.js file. For better maintainability, group related tests into logical test suites and place any reusable helper functions in a utils directory. This structure helps maintain clarity as your test suite grows and makes it easier for team members to navigate the project.

Is Playwright better than Selenium?

While both tools are capable of automated testing (Playwright vs Selenium, Playwright vs Puppeteer), Playwright offers several distinct advantages over Selenium. It provides better out-of-the-box performance with auto-waiting mechanisms and includes native support for modern web features like Shadow DOM. Playwright also offers built-in mobile device emulation and more reliable cross-browser testing capabilities. However, the choice between the two depends on your specific needs. Selenium might be preferable if you need broader browser support or have an existing test infrastructure built around it. Consider your project requirements and team expertise when making the decision.

What is the best language for Playwright?

TypeScript is generally considered the best language for Playwright testing due to its strong type checking that catches errors before runtime and excellent IDE support. It provides improved code maintainability and readability, along with built-in documentation through type definitions. However, Playwright works equally well with JavaScript, Python, and .NET, so you should choose the language that best aligns with your team's expertise and project requirements. The most important factor is selecting a language that your team is comfortable with and that fits into your existing development workflow.

What is the Playwright wait strategy?

Playwright implements a sophisticated auto-waiting strategy that automatically waits for elements to be actionable before performing any operations. When interacting with elements, Playwright automatically ensures they are visible, not covered by other elements, stable (not moving), and enabled for interaction. You can also use explicit wait commands when needed, such as waiting for specific elements to appear, network requests to complete, or responses to arrive. This intelligent waiting system eliminates the need for arbitrary timeouts and makes tests more reliable and efficient.

About the author

Maryia Stsiopkina avatar

Maryia Stsiopkina

Senior Content Manager

Maryia Stsiopkina is a Senior Content Manager at Oxylabs. As her passion for writing was developing, she was writing either creepy detective stories or fairy tales at different points in time. Eventually, she found herself in the tech wonderland with numerous hidden corners to explore. At leisure, she does birdwatching with binoculars (some people mistake it for stalking), makes flower jewelry, and eats pickles.

All information on Oxylabs Blog is provided on an "as is" basis and for informational purposes only. We make no representation and disclaim all liability with respect to your use of any information contained on Oxylabs Blog or any third-party websites that may be linked therein. Before engaging in scraping activities of any kind you should consult your legal advisors and carefully read the particular website's terms of service or receive a scraping license.

Related articles

Get the latest news from data gathering world

I’m interested