Refining Test Automation Setup with Playwright Project Dependencies

Cerosh Jacob
4 min readSep 26, 2023

--

Photo by Brett Jordan on Unsplash

The setup phase prepares the test environment before test execution. It includes tasks like initializing test data, configuring the application under test (AUT), and establishing necessary preconditions for successful test scenario execution. This phase is crucial to ensure tests start from a predefined state, reducing variables that may lead to inconsistent or unreliable test outcomes.

The teardown phase cleans up the test environment by closing connections, releasing resources, and resetting the system to its initial state. It is crucial for maintaining the integrity of the test environment and ensuring that each test case is isolated from others. Without teardown, the changes or side effects of one test case might affect subsequent test cases.

Setup and teardown are important in test automation. They establish a controlled testing environment and are essential to popular testing frameworks. They improve the reliability, maintainability, and scalability of automated tests. Modern test automation frameworks have built-in features for defining setup and teardown methods. For instance, Playwright uses isolated Browser Contexts for independent tests, ensuring no interference and a fresh start for each test. Tests can also use storage state from other tests to simulate a logged-in state, which is especially useful for authentication or authorization scenarios.

While the traditional approach in test automation is to use setup and teardown for logging in and out of the application, Playwright also supports this. In March 2023, Playwright introduced changes that allow traces to be used in global setup or teardown and captured in the HTML report.

To set up and tear down tests, we will use project dependencies in Playwright. A Playwright project is a group of tests that run with the same configuration. We will create a separate project in Playwright’s config for these tasks. The project’s dependencies are a list of projects that must run before the tests in the current project. If any of the projects in the list fail, the current project will not run because it depends on their success.

The benefits of using project dependencies for setup and teardown are:

  • Global setup and teardown can be traced and recorded, which can be helpful for debugging and troubleshooting.
  • Fixtures can be used in global setup and teardown, allowing you to share data between the setup and teardown code and your tests.
  • Project dependencies are declarative, making it easy to see which projects depend on each other.

When setting up a project, use testDir to specify the test directory and testMatch to run only setup.ts tests. Configure baseURL in playwright.config.ts when working with shared URLs.

import { test as setup, expect } from '@playwright/test';
import { STORAGE_STATE } from '../playwright.config';
setup('Login to Saucedemo', async ({ page }) => {
await page.goto('/');
await page.locator('[data-test="username"]').click();
await page.locator('[data-test="username"]').fill('standard_user');
await page.locator('[data-test="password"]').click();
await page.locator('[data-test="password"]').fill('secret_sauce');
await page.locator('[data-test="login-button"]').click();
await page.context().storageState({ path: STORAGE_STATE });
});

In the setup script, we import test as setup to define a setup method that runs before each test method. In this method, we can create the necessary resources or objects required for the tests, or set up the necessary state. The setup project writes the storage state into a json file and exports a constant called STORAGE_STATE. This constant is used to share the location of the storage file between different projects. When configuring the setup project, we can specify the teardown project, which will automatically be called once all tests in the project have been executed.

Similarly, we can use teardown to define a method called after all the test method. Inside the teardown method, we can clean up any resources or objects created by the setup method, or reset any changed state.

export const STORAGE_STATE = path.join(__dirname, 'playwright/.auth/user.json');
export default defineConfig({
use: {
baseURL: '<https://www.saucedemo.com>',
},
projects: [
{
name: 'setup',
testDir: './',
testMatch: '*.setup.ts',
teardown: 'teardown'
},
{
name: 'teardown',
testDir: './',
testMatch: '*.teardown.ts',
use: {
storageState: STORAGE_STATE,
}
},
{
name: 'saucedemo',
testMatch: '*.e2e.spec.ts',
dependencies: ['setup'],
testIgnore: ['*.setup.ts'],
use: {
storageState: STORAGE_STATE,
},
},

Create a project called saucedemo that matches all tests with the file name e2e.spec.ts. Using the use option, we inform the test to use storageState as the STORAGE_STATE variable created in the setup script. The saucedemo project should depend on the setup project. The setup project will have a corresponding teardown project. During the first text execution, the JSON file will be created and stored. For faster testing during subsequent executions, use [testIgnore] to skip setup.

My recent publication compiled a comprehensive collection of 100 similar typescript programs. Each program not only elucidates essential Typescript concepts and expounds upon the significance of test automation but also provides practical guidance on its implementation using Playwright. This resource will undoubtedly be valuable if you look deeper into similar topics.

--

--

No responses yet