How to get best from Playwright in automation

Rahul R
4 min readSep 16, 2024

--

Playwright is a powerful tool for web automation and testing across multiple browsers and platforms. To make the most of Playwright, you need to follow best practices that ensure your tests are easy to manage, reliable, and scalable. Here are some essential tips to help you improve your Playwright test automation.

1. Use Page Object Model (POM)

Page Object Model (POM) is a design pattern that helps keep your test code organised by separating the page interactions from the test logic. By using POM, you centralize the logic for interacting with a page, so if the UI changes, you only need to update the page object once instead of fixing multiple tests.

class LoginPage {
constructor(private page: Page) {}

async login(username: string, password: string) {
await this.page.fill('#username', username);
await this.page.fill('#password', password);
await this.page.click('#login-button');
}
}

2. Avoid Hard-Coding Values

Avoid hard-coding sensitive data or URLs in your tests. Use environment variables or configuration files to keep your tests flexible and easier to run in different environments. This practice makes tests portable and adaptable to changes in the test environment.

const config = {
use: {
baseURL: process.env.BASE_URL || <your app URL>,
}
};

export default config;

3. Leverage Test Fixtures

Test fixtures allow you to set up common states, like logged-in users or browser configurations, that can be reused across multiple tests. This reduces repetition and makes your tests cleaner and faster by reusing already-initialized states.

import { test as base } from '@playwright/test';

const test = base.extend({
loggedInPage: async ({ page }, use) => {
await page.goto('/login');
await page.fill('#username', 'demo');
await page.fill('#password', 'test123');
await page.click('#login-button');
await use(page);
}
});

test('Test with logged-in user', async ({ loggedInPage }) => {

// Write your login code here

});

4. Run Tests in Parallel

Running tests in parallel helps save time, especially when you have a large test suite. You can configure how many tests run at the same time using the workers setting.

const config = {
workers: 4, // This will run your 4 test cases in parallel
};

export default config;

5. Handle Flaky Tests with Retries

Sometimes tests fail due to unexpected factors like network issues or timing problems. You can configure your tests to automatically retry if they fail to prevent false failures and reduce flaky tests.

const config = {
retries: 2, // This will retry you failed case for 2 times
};

export default config;

6. Use Built-in Assertions

Playwright provides built-in assertions to help you verify conditions like text content or element visibility. Using Playwright’s assertions improves test performance and provides better error reporting.

await expect(page).toHaveURL('https://google.com');
await expect(page.locator('#header')).toHaveText('Google!');

7. Test Across Multiple Browsers

Playwright supports running tests across different browsers like Chromium, Firefox, and WebKit. Make sure to configure your test suite to run in all supported browsers to catch browser-specific issues.

const config = {
projects: [
{ name: 'chromium', use: { browserName: 'chromium' } },
{ name: 'firefox', use: { browserName: 'firefox' } },
{ name: 'webkit', use: { browserName: 'webkit' } },
],
};

export default config;

8. Avoid Test Dependencies

Tests should be independent and able to run in any order. Avoid writing tests that rely on the results or states of other tests. Independent tests are easier to maintain and more reliable.

9. Use Explicit Waits, Not Hard Waits

Instead of using fixed delays (page.waitForTimeout()), use explicit waits like page.waitForSelector() or Playwright’s built-in assertions. Explicit waits ensure that tests continue as soon as the required condition is met, making them faster and more reliable.

await page.waitForSelector('#element', { state: 'visible' });

10. Use Browser Contexts for Test Isolation

Browser contexts let you run tests in isolated environments within the same browser. This ensures that tests don’t interfere with each other’s cookies or sessions, making them more reliable and efficient.

const context = await browser.newContext();
const page = await context.newPage();

11. Optimise Your Locators

Use stable and unique locators for interacting with web elements. Avoid using fragile locators like class names or indexes, and instead, use more reliable options like text or data-testid attributes. Stable locators reduce the need to update tests when the UI changes.

await page.click('button:has-text("Submit")');
await page.click('[data-testid="login-button"]');

12. Configure Timeouts Properly

Adjust global or individual test timeouts based on your application’s performance. This helps avoid test failures due to timeouts and ensures that tests are flexible enough to handle slow environments, like CI pipelines.

const config = {
timeout: 30000, // timeout for th 30 * 1000 seconds
};

export default config;

Following these best practices will help you build a robust and scalable test automation suite with Playwright. By writing clean, reliable, and maintainable tests, you’ll improve the speed and quality of your testing, making your application more stable and your development process more efficient.

Don’t forget to follow! 😊

Also checkout articles about how you can leverage your test automation with the help of the AI tools! ⚒️

Need more help, feel free to contact me @ Topmate 🚀

--

--

Rahul R

🇮🇳 🇩🇪 Automation enthusiast mastering Selenium, Appium, Java, JavaScript, Cypress, and Playwright. DevOps advocate transforming testing into excellence. 🚀