In this tutorial, we’ll dive into one of Playwright’s most powerful concepts: fixtures. We’ll explore both the built-in fixtures (like browser, context, page) and see how to create a custom fixture for signup. Fixtures allow you to avoid boilerplate, keep tests clean, and ensure a consistent test setup and teardown.
A fixture is a ready-made object that Playwright sets up before your test runs and cleans up after the test finishes. Think of it as “hidden setup code” that saves you from launching browsers or creating contexts manually.
Playwright automatically provides:
browser
→ launches Chrome, Firefox, WebKit, etc.context
→ gives you an isolated browser profile (storage, cookies).page
→ a single browser tab to interact with.import { test, expect } from "@playwright/test";
test("visit Google", async ({ page }) => {
await page.goto("https://www.google.com");
await expect(page).toHaveTitle(/Google/);
});
Notice how we didn’t explicitly create browser
or context
.
Playwright’s built-in fixtures handle that automatically:
Built-ins are great, but sometimes you need extra setup for every test: signing up, logging in, preloading data, or navigating to a specific page. Instead of repeating that in every test, you can define a custom fixture.
import { test as base, expect, Page } from "@playwright/test";
type MyFixtures = {
signedUpPage: Page;
};
const test = base.extend({
signedUpPage: async ({ page }, use) => {
await page.goto("https://faruk-hasan.com/automation/signup.html");
await page.locator("#username").fill("myUser");
await page.locator("#email").fill("test@example.com");
await page.locator("#password").fill("Password123!");
await page.locator("#confirmPassword").fill("Password123!");
await page.getByRole("button", { name: "Sign Up" }).click();
await use(page); // hands signed-up page to tests
},
});
export { test, expect };
base.extend
→ extends Playwright’s built-in test with our custom logic.use
→ passes the prepared page (signed up) to your tests.export
→ share test
and expect
so other test files can import them.import { test, expect } from "./fixtures";
test("login page loads correctly", async ({ signedUpPage }) => {
await signedUpPage.waitForTimeout(5000); // just to observe
await expect(signedUpPage).toHaveTitle("Login - Automation Practice");
});
Here, signedUpPage
is already prepared by the fixture — no need to repeat signup steps.
The test simply checks that the login page loads correctly after signup.
loggedInAdmin
) as needed.You can explore the full project and run it yourself:
View on GitHub: custom_fixture_playwrightgit clone https://github.com/faruklmu17/custom_fixture_playwright.git
Everything above is explained step-by-step in my video tutorial: Watch on YouTube