Understanding Playwright Test Fixtures
At their core, fixtures in Playwright are predefined components likepage
, context
, browser
, and browserName
that you can use across different test cases. They encapsulate functionality into modular blocks, simplifying test code.
When writing multiple tests for a single site or service, you’re likely to end up performing the same tasks over and over, so we’d like to add fixtures to our Playwright tests that developers can re-use, rather than copying and pasting big blocks of code. This helps us follow the DRY principle: don’t repeat yourself when writing code!
Why we need custom fixtures
In our web shop, we’ve got a login process that we want to simulate and test before doing further account actions:
Playwright and Fixtures
Playwright and its test runner Playwright Test, were designed with a broader testing scope and includes first-class support for fixtures. This design choice streamlines the setup and teardown process, making tests cleaner and reducing redundancy.Built-in Support
Playwright’s test runner provides a rich set of predefined fixtures, such asbrowser
, context
, page
, and request
, and allows for easy customization and extension of these fixtures. This built-in support enables more structured and maintainable tests, with less manual setup required.
Create a Custom Test Fixture in Playwright Test
Imagine testing a web application where multiple tests require logging in. Repeating login logic in every test is inefficient and violates the DRY (Don’t Repeat Yourself) principle. Let’s implement a fixture to reuse and share code across Playwright test cases.Step 1: Extend the Test Object
First, create a new test file or use an existing one. Here, we’re testing a web application with Playwright, accessing environment variables, and performing UI interactions. To create a custom fixture, extend thetest
object provided by Playwright:
fixture.js
test.extend
call. In this case, all tests using the extended test
method can rely on the webApp
fixture.
Step 2: Use the Custom Fixture
With thewebApp
fixture defined, you can use it in your tests. The fixture code will only run when a test “requests” to use it. For example, the custom webApp
fixture will only be executed if a test case uses it.
Replace page
with webApp
and use the fixture in your test cases:
webApp
fixture encapsulates the login logic, making it accessible to any test that requires it.
Step 3: Debugging and Validation
Debugging is crucial to ensure your fixture works as expected. Playwright’s inspector is invaluable here, allowing you to step through test execution and verify the setup and teardown processes.Step 4: Sharing Across Tests
To share your custom fixture across different test files, encapsulate it in a separate module:setup.js
test
and use the custom fixtures:
tests/your-test.spec.js
Replace beforeEach
/ afterEach
Hooks with Automatic Fixtures
As explained in the previous section, fixtures enable the sharing and distributing of code across Playwright tests. By default, fixture code is only executed when a test case accesses a fixture. But there are scenarios in which you always want to run your fixture code, like global beforeEach
and afterEach
hooks.
Let’s implement an automatic fixture to log the current time before and after every test case.
Define an Automatic Fixture
If you want to run code before and after each test case, you can reach for the commonly knownbeforeEach
and afterEach
hooks.
In the following example, we log the current time before and after every test to the console.
beforeEach
and afterEach
calls in every spec
file. Additionally, beforeEach
and afterEach
don’t share the same function scope. This behavior leads to unexpected errors in some scenarios.
A more convenient way to implement global test hooks is relying on automatic fixtures. Like the webApp
fixture defined in the previous section, you must extend the test
object to use automatic fixtures.
base.js
timeLogger
fixture will be executed for every running test.
Note that you’ll want to update your other test spec files to import test
from our base.js
, they probably have something like: