Move setup into a custom fixture
advanced Fixtures Challenge 13 of 22
Two cart tests share a module-level cartPage variable that is set in beforeEach and cleaned up in afterEach. Refactor them to use a custom fixture named cartPage.
CartPage is provided in pages/cart-page.ts (shown below the requirements) with goto(), add(name), applyCoupon(code), clear() and the locators items and total. Your tests run against the demo cart, so the coupon SAVE10 really takes 10% off.
Requirements
- Extend Playwright’s
testwith acartPagefixture usingtest.extend. - In the fixture, create the
CartPage, callgoto(), pass it to the test withawait use(...), and callclear()afterwards. - Remove
beforeEach,afterEachand the module-level variable. - Each test receives the fixture as a parameter:
async ({ cartPage }) => { ... }.
Expected output
`test` is extended with a `cartPage` fixture that creates and opens the page object, hands it to the test with `await use(cartPage)`, and clears the cart afterwards. Tests receive it by destructuring `{ cartPage }`, with no hooks or module-level variables.
Scenarios (2)
Your tests run once against each version of the demo app. They must pass on the working app and fail on every version with a planted bug.
- ○Working app · must pass
- ○Bug: coupon ignored · must catch
Provided file · pages/cart-page.ts
import { expect, type Locator, type Page } from '@playwright/test';
export class CartPage {
readonly items: Locator;
readonly total: Locator;
constructor(private readonly page: Page) {
this.items = page.getByTestId('cart-item');
this.total = page.getByTestId('cart-total');
}
async goto() {
await this.page.goto('/cart');
}
async add(product: string) {
await this.page.getByLabel('Product').selectOption({ label: product });
await this.page.getByRole('button', { name: 'Add', exact: true }).click();
await expect(this.items.filter({ hasText: product })).toBeVisible();
}
async applyCoupon(code: string) {
await this.page.getByLabel('Coupon code').fill(code);
await this.page.getByRole('button', { name: 'Apply' }).click();
await expect(this.page.getByText('Coupon applied')).toBeVisible();
}
async clear() {
await this.page.getByRole('button', { name: 'Clear cart' }).click();
await expect(this.items).toHaveCount(0);
}
}
Checks (5)
- ○Defines a fixture with test.extend
- ○Hands the value to the test with await use(...)
- ○Runs teardown after use()
- ○No beforeEach/afterEach hooks
- ○Tests receive cartPage as a fixture parameter
Ctrl/⌘ + Enter to run tests · your code is saved in this browser
Results
Run the tests to see results here.
Demo app
The working app. You can click around it; your tests start from a fresh copy.