🗂️ Test Organization & Fixtures
Test Organization & Fixtures: Playwright fixtures are Java's @BeforeEach method upgraded with dependency injection: @BeforeEach runs the same setup for every test in a class but
Playwright fixtures are Java's @BeforeEach method upgraded with dependency injection: @BeforeEach runs the same setup for every test in a class but can't pass its result directly into a test from another class. A fixture works like a modular station in a factory pipeline — when you request "loggedInPage", Playwright opens the browser, performs login, sets the cookies, and hands you a ready page object; when the test ends, teardown runs automatically. Why prefer fixtures over beforeEach? When you need to share the same "logged in as admin" state across multiple test files, beforeEach gets copy-pasted into every file, and the day login steps change you have to update each file separately; a fixture is defined in one place and imported everywhere. The QA reality: in a 200-test suite where every test runs its own login step, the overall suite time inflates unnecessarily. Fixtures combined with storageState perform the login once and share the session across all parallel workers — a meaningful CI pipeline time optimization.
Test organization has two main pieces: (1) grouping tests into logical groups with test.describe() and writing shared setup/teardown code with hooks like beforeEach/afterEach, and (2) using fixtures to inject that setup code into tests automatically as "dependency injection". Together, they reduce repeated code across hundreds of tests to near zero.
test.describe() is like a JUnit @Nested test class. test.beforeEach() / afterEach() → JUnit @BeforeEach / @AfterEach. test.beforeAll() / afterAll() → @BeforeAll / @AfterAll (but these receive { browser }, not { page } — page is never shared between tests). Fixtures are similar to Spring's @Autowired dependency injection: you ask for what you need as a parameter, and the framework hands it to you ready-made — you don't manually do new LoginPage(driver).
The Anatomy of a Test — Arrange / Act / Assert
Micro Lab: Playwright — Fixture and Setup
Replace the TODO line with the critical line from the expected solution. This is not a real runtime; the goal is to reinforce writing the correct structure in a controlled way.
This Test Actually Runs in 3 Phases: Arrange → Act → Assert
Arrange phase: page.goto('/login')…
Arrange phase: page.goto('/login') doesn't just change the URL, it waits until the page fires its "load" event — that's why the next line can safely search for the form.
Act phase: fill() and click() run…
Act phase: fill() and click() run in order, each waiting on its own actionability check — the password field isn't touched before email is filled, and click WAITS if the button is disabled.
Assert phase: expect(page).toHaveURL('/dashboard')…
Assert phase: expect(page).toHaveURL('/dashboard') is NOT a one-shot check — it polls for up to 5 seconds by default (an auto-retrying assertion), replacing the manual WebDriverWait you'd write in Selenium.
If the URL never changes within 5 seconds…