# Capstone: Test the Practice Shop

Course: [Playwright](https://www.devtutorials.ai/learn/playwright) · Section: Advanced Playwright and AI
Source: https://www.devtutorials.ai/learn/playwright/advanced/capstone-test-the-practice-shop

> Build a complete Playwright suite for the Practice Shop step by step: risk-based planning, a CI-ready config with a setup project, a saved login, page objects, fixtures with option data, end-to-end journeys with unhappy paths, API-powered test data, mocked failure states, an accessibility gate, investigating a failure with a trace, and shipping the suite to CI.

## Capstone: Test the Practice Shop

- You have learned Playwright one feature at a time. Real projects use them all together.
- In this capstone, you build a complete test suite for the Practice Shop, the way a team would: config, login, page objects, fixtures, end-to-end tests, API tests, mocks and an accessibility gate.
- Seven graded steps take you from an empty config to a suite you could run on CI.

**Simple lesson:** a good suite is small pieces that fit together. Each piece does one job.

### A Real-World Example

- This is the finished project. Open the **Explorer** to see every file, then run it.
- The setup project logs in once. The checkout tests use page objects through fixtures and read like the shopper's journey.

- Look at the output. `[setup]` runs first, then the checkout tests, without typing the password again.

### What You Will Build

1. A CI-ready config with a setup project.
2. A login that runs once and is saved.
3. Page objects for products, cart and checkout.
4. Fixtures that hand out page objects and test data.
5. End-to-end tests that read like user stories.
6. API tests and API-powered test data.
7. Network failure tests and an accessibility gate.

## Planning the Suite

### Start from Risks, Not Pages

- Before writing code, list what would hurt the business most if it broke:
  - A shopper cannot pay. (**Critical**: end-to-end tests.)
  - Prices or totals are wrong. (**Critical**: UI and API checks.)
  - Login breaks. (**High**: setup project fails loudly.)
  - Extras like recommendations fail. (**Medium**: mocked failure tests.)
  - Some shoppers cannot use the site with a screen reader. (**High**: accessibility gate.)
- Each risk gets the cheapest test that catches it. Not everything needs a browser.

<figure className="plw-fig">
<svg viewBox="0 0 640 230" role="img" aria-labelledby="fig-plw-pyramid" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-plw-pyramid">Animation: a test pyramid builds from the bottom. Many fast API tests at the base, fewer mocked UI tests in the middle, and a few end-to-end journeys at the top, with an accessibility gate beside it</title>
  <g style={{ fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>
    <g opacity="0"><animate attributeName="opacity" values="0;1;1;0" keyTimes="0;0.08;0.95;1" dur="9s" repeatCount="indefinite" />
      <polygon points="80,200 460,200 410,150 130,150" style={{ fill: "var(--plw-green-soft)", stroke: "var(--plw-green)" }} />
      <text x="270" y="181" textAnchor="middle" style={{ fill: "var(--plw-green)" }}>API tests: many, milliseconds each</text>
    </g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.25;0.33;0.95;1" dur="9s" repeatCount="indefinite" />
      <polygon points="135,145 405,145 360,95 180,95" style={{ fill: "var(--plw-blue-soft)", stroke: "var(--plw-blue)" }} />
      <text x="270" y="126" textAnchor="middle" style={{ fill: "var(--plw-blue)" }}>Mocked UI states</text>
    </g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.5;0.58;0.95;1" dur="9s" repeatCount="indefinite" />
      <polygon points="185,90 355,90 270,25" style={{ fill: "var(--plw-purple-soft)", stroke: "var(--plw-purple)" }} />
      <text x="270" y="75" textAnchor="middle" style={{ fill: "var(--plw-purple)", fontSize: 12 }}>E2E journeys</text>
    </g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.72;0.8;0.95;1" dur="9s" repeatCount="indefinite" />
      <rect x="490" y="80" width="135" height="80" rx="10" style={{ fill: "var(--plw-orange-soft)", stroke: "var(--plw-orange)" }} />
      <text x="557" y="115" textAnchor="middle" style={{ fill: "var(--plw-orange)" }}>Accessibility</text>
      <text x="557" y="135" textAnchor="middle" style={{ fill: "var(--plw-orange)" }}>gate</text>
    </g>
  </g>
</svg>
<figcaption>Many cheap API checks, some mocked UI states, a few full journeys, and an accessibility gate on key pages.</figcaption>
</figure>

### The Project Layout

- `pages/` holds page objects. `tests/` holds specs, fixtures and the setup file. `.gitignore` lists `playwright/.auth` and `test-results`.

Write the test names first, as a plan: "a shopper buys two products by UPI", "checkout refuses a missing address". Clear names make failures easy to understand in reports.

**Simple lesson:** test the biggest risks with the cheapest checks. Plan names before code.

## Building the Foundation

### Config and Login

- The config sets `baseURL`, traces on retry, CI retries and two projects: `setup` and `chromium`.
- `tests/auth.setup.ts` logs in once and saves `playwright/.auth/asha.json`. **Authentication and Storage State** explains the pattern.
- Steps 1 and 2 of the exercises build these two files.

### Page Objects and Fixtures

- `ProductsPage`, `CartPage` and `CheckoutPage` each own their page's locators and actions. Navigation methods return the next page object.
- `tests/fixtures.ts` provides `productsPage` (already open) and `shopper` (test data as an **option fixture**, so a file can override it with `test.use()`).
- Steps 3 and 4 build these. **Page Object Model** and **Fixtures** cover the details.

**Simple lesson:** config and login first, then page objects, then fixtures. Specs come last and stay short.

## Writing the Tests

### End-to-End Journeys

- The checkout spec in the first box is the core journey. `test.step()` names the phases, so the report shows where a failure happened.
- The second test checks an **unhappy path**: a missing address. Teams often forget these, and they catch real bugs.
- Step 5 asks you to write a journey of your own.

### API Tests and Test Data

- Creating an order through the UI takes many clicks. Through the API, it takes one call.
- Here, `page.request` creates an order with Asha's saved cookie, and the UI check proves the orders page shows it.

### When the Network Goes Wrong

- Mocks test the states you cannot produce on demand: server errors, empty data and offline mode.

### An Accessibility Gate

- One loop scans the key pages with axe. If a change adds a missing label or low-contrast text, the build fails.

In a real team, these four spec files run on every pull request. The suite above finishes in seconds in the lab and in well under a minute on CI.

**Simple lesson:** journeys for the main flows, API for data, mocks for failures, axe for accessibility.

## Investigating a Failure

### A Planted Bug

- A teammate changed the expected cart total by mistake. Run this box with tracing on, then open the **Trace** tab.
- Follow the actions to `toHaveText`, look at the page snapshot, and compare the real total with the expected one.

- The trace shows the page was right: the cart really holds ₹1,248 of products. The test was wrong. Fix the expected text and run again.

### A Debugging Routine

1. Read the error line, expected and received, and the call log.
2. Open the trace at the failing step. Check the snapshot, network and console.
3. Decide: is the **app** wrong, or the **test**? Fix the right one.
4. Run it with `--repeat-each=5` to be sure it is stable.

Never "fix" a failing test by changing the expected value until you know the app is right. A wrong total in a real shop costs money.

**Simple lesson:** error, trace, decide, fix, repeat. In that order.

## Shipping the Suite

### Ready for CI

- Add the GitHub Actions workflow from **CI/CD and Scaling**: `npm ci`, `npx playwright install --with-deps`, `npx playwright test`, upload `playwright-report`.
- Tag the two most important journeys `@smoke` and run them on every pull request. Run everything before merging.
- Keep secrets like the test password in CI secrets, read with `process.env`.

### Keeping It Healthy

- Review flaky tests weekly. Each one has a cause: find it in the trace.
- When the UI changes, fix page objects, not specs.
- Delete tests that no longer protect anything. A smaller, trusted suite beats a big, ignored one.

**Simple lesson:** run it on every change, keep it green, and keep it small.

## Try It in Your Project

- These steps take the lesson from the lab to your own app.
- Repeat the capstone for your own app: list risks, then build config, login, page objects and fixtures.
- Start with two journeys and one API test, then grow the suite.
- Put it on CI in the first week, so it stays green from the start.

**Simple lesson:** use one idea from this lesson on your own app this week.

## TL;DR

- Plan from risks. Use the cheapest test that catches each one.
- Config and a setup project log in once. Page objects and fixtures keep specs short.
- Journeys for main flows, unhappy paths too. API for test data, mocks for failures, axe for accessibility.
- Traces explain failures. Decide whether the app or the test is wrong.
- Run on CI with smoke tags, secrets and uploaded reports.

## Common mistakes

| Mistake | What happens | Fix |
|---|---|---|
| Only happy-path tests | Validation and error bugs ship | Add one unhappy path per journey |
| Building all data through the UI | Slow, fragile suites | Create data with the API |
| Raw locators spread across specs | One UI change breaks many files | Page objects and fixtures |
| Changing expected values to make tests pass | Real bugs become "expected" | Check the trace and the app first |
| One giant test for the whole shop | Hard to tell what broke | Small tests with clear names and steps |

## Check Yourself

## Exercises

- Each step adds one piece of the project. The files from earlier steps are already in the Explorer, so you can focus on the new part.

## What to Remember

- Plan from risks, then pick the cheapest test for each.
- Config, login once, page objects, fixtures, then short specs.
- Cover happy and unhappy paths, API data, failures and accessibility.
- Traces tell you whether the app or the test is wrong.
- Ship it on CI, keep it green, keep it small.

Next: **Playwright Cheat Sheet**
