Test an ERP Checkout Flow with Playwright
Write end-to-end tests that catch real bugs in an ERP checkout flow.
Introduction
30 Second Summary
Every time you buy something online, dozens of invisible checks happen behind the scenes. A login has to work. Products need to appear. The cart has to hold your items. Checkout has to process. If any one of those steps breaks, the sale is lost.
In this project, you will build an automated test suite that validates an entire e-commerce checkout flow, from login to order confirmation. You will use Playwright to generate tests, catch real bugs, and debug failures visually.
What You'll Build
You will run a single command and watch a browser automatically log in, add products to a cart, and complete a checkout. Then you will switch to a "problem user" account and watch the same tests expose real application bugs, with a visual timeline showing exactly where things went wrong.
By the end of this project, you'll have:
- A Playwright test suite that logs in, browses inventory, adds items to a cart, and verifies a successful checkout with a single terminal command.
- A bug-detection workflow where your passing tests break against a problem user account, revealing real defects in the application.
- A Trace Viewer recording that shows a timeline of every action, screenshot, and network request for a failed test, so you can pinpoint exactly where the application misbehaved.
- An HTML report showing pass/fail results across your entire test suite.
- Secret Mission: Refactor your tests to use the Page Object Model pattern for maintainable, reusable test code.
Are there any prerequisites?
You should be comfortable with TypeScript or JavaScript basics, including types and async/await. You will also need Node.js installed on your machine (Step 1 will help you verify this).
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters.
Set Up Playwright
Playwright is a test framework that controls real browsers to verify your application works end-to-end. Before you can write or run any tests, you need the test runner, browser binaries, and editor tooling installed.
In this step, you'll scaffold a new Playwright project with TypeScript, configure it for the application you'll be testing, and confirm everything works by running the built-in example test.
In this step, get ready to:
- Initialize a Playwright project with TypeScript and Chromium.
- Configure Playwright to target the SauceDemo application.
- Run the scaffolded example test and view the HTML report.
Initialize a Playwright project
You need a dedicated folder for your test project. All Playwright files will live here.
- Open a terminal in Cursor by pressing Ctrl+` (backtick key, top-left of keyboard).
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir erp-checkout-tests
cd erp-checkout-tests
- Confirm the folder exists by running:
ls
The folder is empty for now. That changes next.
- Open this folder in Cursor's editor by clicking File in the top menu bar.
- Click Open Folder.
- Select the erp-checkout-tests folder on your Desktop, then click Open.
Why open the folder in Cursor?
Opening the folder gives Cursor full context of your project. The terminal, file explorer, and editor all anchor to this directory, so paths resolve correctly.
- Open a new terminal in Cursor by pressing Ctrl+`. It now starts inside erp-checkout-tests.
- Scaffold your Playwright project by running this command:
npm init playwright@latest
What prompts will I see?
The command is interactive. It will ask you four questions. Answer them exactly as follows:
- Language: choose TypeScript (the default).
- Tests folder name: accept the default tests by pressing Enter.
- Add a GitHub Actions workflow: type false or press Enter to decline.
- Install Playwright browsers: choose true (the default). This downloads Chromium, Firefox, and WebKit.
After answering the prompts, Playwright downloads browser binaries and creates your project files. You'll see output confirming the installation.
Seeing a permissions error or timeout?
If the browser download fails, check that you have a stable internet connection. On macOS, you may need to allow network access if prompted. On Windows, run your terminal as administrator.
help me troubleshoot the Playwright browser download failing during npm init playwright@latest
Your project now has playwright.config.ts, package.json, and a tests/ folder with an example test. Next, you'll tailor the config for this project.
- Open playwright.config.ts in Cursor's editor by clicking it in the Explorer sidebar on the left.
- Select all the existing content (Cmd+A on macOS or Ctrl+A on Windows) and delete it.
- Replace it with this configuration:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'https://www.saucedemo.com/',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
What does this configuration do?
- testDir: './tests' tells Playwright where to find your test files.
- baseURL: 'https://www.saucedemo.com/' sets the target application so your tests can use relative paths.
- trace: 'on-first-retry' captures a full trace when a test fails and retries. You'll use this for debugging later.
- The projects array contains only Chromium. The default scaffold includes Firefox and WebKit too, but you'll scope to one browser to keep test runs fast and focused.
- Save playwright.config.ts (Cmd+S on macOS or Ctrl+S on Windows).
Why only Chromium?
Running tests across three browsers triples execution time. For learning, Chromium alone gives you fast feedback. You can always add Firefox and WebKit back to the projects array later.
✔️ Awesome, I've got everything!
Great. Double check you've saved playwright.config.ts and move on to installing the extension.
ⓧ I'd like to double check the full code
Your playwright.config.ts should look exactly like this:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'https://www.saucedemo.com/',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
Install the Playwright extension in Cursor
The Playwright extension adds a test explorer, inline run buttons, and Codegen integration directly in your editor. Cursor uses the Open VSX Registry, so the extension may not appear in the built-in search.
- Open the Extensions panel by pressing Ctrl+Shift+X (macOS) or Ctrl+Shift+X (Windows).
- Type Playwright in the search bar and look for Playwright Test for VS Code by Microsoft.
✔️ I found it in the marketplace
- Click Install next to the extension.
The extension is now active. You'll see a flask icon in the left sidebar for the Test Explorer.
ⓧ I can't find it in Cursor's marketplace
Cursor's Open VSX Registry sometimes does not index all VS Code extensions. You can install it manually using a VSIX file.
- Open this link in your browser: VS Code Marketplace - Playwright.
- Click the Download Extension button on the right side of the page. This downloads a .vsix file.
- Back in Cursor, open the Command Palette by pressing Ctrl+Shift+P (macOS) or Ctrl+Shift+P (Windows).
- Type Extensions: Install from VSIX... and select it.
- Navigate to your Downloads folder, select the .vsix file, and click Open.
The extension installs. You'll see a flask icon appear in the left sidebar for the Test Explorer.
Run the scaffolded example test
Playwright scaffolded an example test file at tests/example.spec.ts. Running it proves your entire toolchain works: test runner, browser, and reporter.
Before you run the next command, what do you expect to see? Think about whether the example test will pass or fail with your new config.
- Run the example test by executing this command in your terminal:
npx playwright test
You should see output confirming that 1 test passed on the Chromium project. The example test hits the Playwright docs site, not SauceDemo, so it passes regardless of your baseURL setting.
Seeing test failures or 'no tests found'?
- Make sure you saved playwright.config.ts with testDir: './tests'. If the path is wrong, Playwright cannot find the test file.
- Confirm tests/example.spec.ts exists in your Explorer sidebar. If it is missing, re-run npm init playwright@latest and accept the defaults again.
- If you see a network error, the test needs internet access to reach the Playwright docs page.
help me debug why npx playwright test shows no tests found or a test failure
- Open the HTML report by running this command:
npx playwright show-report
A browser tab opens showing the Playwright HTML report. You should see your passed test listed with a green checkmark and the time it took to run.
What is the HTML report?
The HTML report is an interactive dashboard Playwright generates after every test run. You can filter by browser, test status (passed, failed, flaky), and click into any test to see its timeline. You'll use this heavily when debugging failures in later steps.
Your test environment is fully operational. Next up, you'll use Playwright's Codegen tool to record a login flow and generate test code automatically.
Generate Your First Test with Codegen
Your Playwright project is scaffolded and the example test passes. Now it is time to write a test that targets a real web application.
Writing test selectors by hand is slow and error-prone. You have to inspect the page, find the right element, copy the selector, and hope it does not break when the UI changes. Codegen solves this by recording your browser actions and generating working test code instantly.
In this step, get ready to:
- Launch Codegen to record a login flow on SauceDemo.
- Create a test file from the generated code.
- Run the test and confirm it passes.
Launch Codegen against SauceDemo
SauceDemo is a purpose-built e-commerce demo site by Sauce Labs. Its login credentials are displayed right on the page, making it a safe and predictable target for test automation practice.
- Launch the Codegen recorder by running this command in your terminal:
npx playwright codegen https://www.saucedemo.com/
What happens when you run this?
Two windows open side by side. A Chromium browser navigates to SauceDemo, and the Playwright Inspector window appears showing a live code editor. Every action you take in the browser is instantly recorded as TypeScript code in the Inspector.
You should see the SauceDemo login page in the browser, with username and password fields. The Playwright Inspector window sits alongside it, ready to record.
- Click the Username field in the browser and type standard_user.
- Click the Password field and type secret_sauce.
- Click the Login button.
Watch the Inspector window as you interact. You should see code lines appearing for each action: a fill call for each text field and a click call for the login button.
- Click the red Record button in the Inspector toolbar to stop recording.
- Click the Copy button to copy the generated code to your clipboard.
- Close the Playwright Inspector window to end the session.
Browser did not open?
If you see an error about missing browsers, run npx playwright install chromium to download the Chromium binary. Then try the codegen command again.
help me debug why Playwright Codegen is not opening a browser
Create your login test file
The generated code shows you the locators Playwright found, but it needs to live in a proper test file with an assertion that proves the login actually worked.
- In Cursor, create a new file called tests/saucedemo-login.spec.ts inside your tests folder.
- Replace any pasted content with the following complete test:
import { test, expect } from '@playwright/test';
test('login with standard user', async ({ page }) => {
// Navigate to the SauceDemo login page
await page.goto('https://www.saucedemo.com/');
// Fill in username and password
await page.locator('[data-test="username"]').fill('standard_user');
await page.locator('[data-test="password"]').fill('secret_sauce');
// Click the login button
await page.locator('[data-test="login-button"]').click();
// Assert that we landed on the Products page
await expect(page.locator('[data-test="title"]')).toHaveText('Products');
});
What does this code do?
This test does the same thing you just did by hand in the browser, but automatically. It navigates to SauceDemo, fills in the login credentials, clicks the button, and then checks that the page heading says "Products".
The [data-test="..."] locators target stable test-ID attributes that SauceDemo provides on every element. These are more reliable than CSS classes or XPath because they survive UI redesigns.
- Save tests/saucedemo-login.spec.ts.
Seeing red squiggly lines in Cursor?
If TypeScript shows import errors, make sure you saved the file with the .spec.ts extension (not .spec.js). Also confirm the file is inside the tests folder at the project root.
help me fix TypeScript import errors in my Playwright test file
✔️ Awesome, I've got everything!
Great. Double check you have saved tests/saucedemo-login.spec.ts and it matches the code above.
ⓧ I'd like to double check the full code
Here is the complete tests/saucedemo-login.spec.ts file:
import { test, expect } from '@playwright/test';
test('login with standard user', async ({ page }) => {
await page.goto('https://www.saucedemo.com/');
await page.locator('[data-test="username"]').fill('standard_user');
await page.locator('[data-test="password"]').fill('secret_sauce');
await page.locator('[data-test="login-button"]').click();
await expect(page.locator('[data-test="title"]')).toHaveText('Products');
});
Run the test and confirm it passes
You have a test file with a login flow and an assertion. Time to see if it works.
- Before you run this, predict: do you think the test will pass or fail? The code navigates to SauceDemo, fills in valid credentials, clicks Login, and checks for a "Products" heading.
- Run the login test by executing this command:
npx playwright test tests/saucedemo-login.spec.ts
You should see output indicating 1 passed in the terminal. Playwright launched a headless Chromium browser, ran through the login flow, and confirmed the Products heading appeared.
Why did it run so fast?
By default, Playwright runs tests in headless mode. The browser launches without a visible window, which makes execution much faster. You will use the --headed flag in a later step to watch the browser in action.
Test failed or timed out?
Make sure you have an internet connection. The test navigates to a live website. If you see a timeout error, SauceDemo may be temporarily down. Try refreshing https://www.saucedemo.com/ in your own browser to confirm the site loads.
If you see a locator error, double-check that the data-test attribute values in your code match exactly: username, password, login-button, title.
help me debug my failing Playwright login test for SauceDemo
You just went from zero to a passing end-to-end test in minutes. Codegen did the heavy lifting of finding locators, and you added the assertion that proves the login worked. Next up, you will extend this into a full checkout flow that exercises the entire application.
Write a Checkout Flow Test
Your login test proves the front door works, but a real e-commerce application needs to handle inventory, cart state, and order processing in sequence.
The checkout flow is where ERP systems fail most often. In this step, you'll write a test that walks through the entire purchase journey and asserts the order completes successfully.
In this step, get ready to:
- Create a checkout test that walks through the full purchase flow.
- Use data-test locators for reliable, resilient element selection.
- Run the test in headed mode and watch the browser execute the checkout.
Create the checkout test file
The checkout flow touches multiple pages: inventory, cart, checkout form, and order confirmation. Your test will walk through each page in sequence, just like a real customer would.
- Create a new file called tests/checkout.spec.ts in Cursor.
- Add the test structure with login and cart operations by pasting this code:
import { test, expect } from '@playwright/test';
const users = [
{ username: 'standard_user', shouldPass: true },
{ username: 'problem_user', shouldPass: false },
];
for (const user of users) {
test(`checkout flow for ${user.username}`, async ({ page }) => {
// Login
await page.goto('https://www.saucedemo.com/');
await page.locator('[data-test="username"]').fill(user.username);
await page.locator('[data-test="password"]').fill('secret_sauce');
await page.locator('[data-test="login-button"]').click();
await expect(page.locator('[data-test="title"]')).toHaveText('Products');
// Add two products to cart
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await page.locator('[data-test="add-to-cart-sauce-labs-bike-light"]').click();
// Verify cart badge shows 2 items
await expect(page.locator('[data-test="shopping-cart-badge"]')).toHaveText('2');
});
}
What does this code do?
The users array defines two test accounts. The for loop creates a separate test for each user, so the same checkout flow runs against both.
The shouldPass property is metadata for you to read. standard_user is the normal account. problem_user has intentional application bugs that will surface later.
Each test logs in, adds two specific products (Sauce Labs Backpack and Bike Light), then asserts the cart badge shows 2.
- Save tests/checkout.spec.ts.
- Run the test to confirm the login and cart section works by running:
npx playwright test tests/checkout.spec.ts
You should see at least 1 test pass (for standard_user). The problem_user test may also pass at this stage since the cart operations can succeed for that account.
Seeing a syntax error?
- Check for matching backticks in the template literal: test(`checkout flow for ${user.username}`. The string uses backticks, not single quotes.
- Make sure the closing }); and } are both present at the end of the file.
Having trouble? Why is my Playwright checkout test failing with a syntax error?
Complete the checkout flow
The test currently proves items land in the cart. Now you need to walk through checkout: navigate to the cart, fill the shipping form, and confirm the order.
- In tests/checkout.spec.ts, find this line inside your test:
// Verify cart badge shows 2 items
await expect(page.locator('[data-test="shopping-cart-badge"]')).toHaveText('2');
- Add the following checkout code directly below that line (before the closing });):
// Go to cart
await page.locator('[data-test="shopping-cart-link"]').click();
// Proceed to checkout
await page.locator('[data-test="checkout"]').click();
// Fill checkout information
await page.locator('[data-test="firstName"]').fill('John');
await page.locator('[data-test="lastName"]').fill('Doe');
await page.locator('[data-test="postalCode"]').fill('12345');
await page.locator('[data-test="continue"]').click();
// Finish checkout
await page.locator('[data-test="finish"]').click();
// Verify order complete
await expect(page.locator('[data-test="complete-header"]')).toHaveText('Thank you for your order!');
Why data-test locators?
SauceDemo was built with data-test attributes on every interactive element specifically for automated testing. These attributes never change when designers restyle the page or developers rename CSS classes.
This is the same strategy production teams use: a dedicated test attribute that decouples your tests from visual design. It makes selectors stable across deployments.
- Save tests/checkout.spec.ts.
Not sure where to paste?
The new code goes after the cart badge assertion but before the }); that closes the test function. Your file should end with }); (closing the test) followed by } (closing the for loop).
Need help? Where exactly should I place the checkout code in my test file?
Run the test and watch it execute
Before you run this, think about what you expect to happen. You have two users running through the same checkout flow. Do you think both will succeed?
- Run the full checkout test in headed mode so you can watch the browser by running:
npx playwright test tests/checkout.spec.ts --headed
You'll see standard_user complete the entire checkout flow and pass with the confirmation message. The problem_user test will fail. Its checkout form has an intentional bug where the Last Name field does not work correctly.
Why does problem_user fail?
SauceDemo's problem_user account has intentional defects baked into the application. The checkout form fields misbehave, preventing the order from completing. Your test just caught a real bug.
In the next step, you'll use Playwright's Trace Viewer to see exactly what went wrong, screenshot by screenshot.
Neither test is running?
- Make sure you saved the file before running the command. Playwright reads from disk, not from your editor buffer.
- Confirm the file is at tests/checkout.spec.ts (not test/checkout.spec.ts without the 's').
- Check for unmatched braces. The file should have exactly one }); closing the test and one } closing the for loop at the end.
Still stuck? Help me debug why my Playwright checkout test is not running at all.
✔️ Awesome, I've got everything!
Great. Double check you've saved tests/checkout.spec.ts and your standard_user test shows as passed.
ⓧ I'd like to double check the full code
Here is the complete tests/checkout.spec.ts file. Compare yours against it line by line:
import { test, expect } from '@playwright/test';
const users = [
{ username: 'standard_user', shouldPass: true },
{ username: 'problem_user', shouldPass: false },
];
for (const user of users) {
test(`checkout flow for ${user.username}`, async ({ page }) => {
// Login
await page.goto('https://www.saucedemo.com/');
await page.locator('[data-test="username"]').fill(user.username);
await page.locator('[data-test="password"]').fill('secret_sauce');
await page.locator('[data-test="login-button"]').click();
await expect(page.locator('[data-test="title"]')).toHaveText('Products');
// Add two products to cart
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await page.locator('[data-test="add-to-cart-sauce-labs-bike-light"]').click();
// Verify cart badge shows 2 items
await expect(page.locator('[data-test="shopping-cart-badge"]')).toHaveText('2');
// Go to cart
await page.locator('[data-test="shopping-cart-link"]').click();
// Proceed to checkout
await page.locator('[data-test="checkout"]').click();
// Fill checkout information
await page.locator('[data-test="firstName"]').fill('John');
await page.locator('[data-test="lastName"]').fill('Doe');
await page.locator('[data-test="postalCode"]').fill('12345');
await page.locator('[data-test="continue"]').click();
// Finish checkout
await page.locator('[data-test="finish"]').click();
// Verify order complete
await expect(page.locator('[data-test="complete-header"]')).toHaveText('Thank you for your order!');
});
}
You now have a test that proves the entire checkout flow works for a standard user and reveals a real bug for the problem user. Next up, you'll dig deeper into that failure with Playwright's debugging tools.
Break Your Tests with the Problem User
Your checkout test passes perfectly for standard_user. That proves the flow works under ideal conditions.
Tests that only pass are not useful. Real QA work means discovering bugs. SauceDemo includes a problem_user account with intentional defects that simulate the kind of application bugs ERP systems encounter in production. Your checkout test already iterates over both users. Time to see what happens when it hits the broken one.
In this step, get ready to:
- Run your checkout test against both user accounts.
- Observe how the problem user causes test failures.
- Document the failure for investigation with Trace Viewer.
Run the checkout tests against both users
Your checkout.spec.ts already has a users array with both standard_user and problem_user. The for loop creates a separate test for each. In the previous step you only verified that the standard user passes. Now you will run both variants.
Before you run this, what do you think will happen? Will both users complete checkout successfully, or will one break somewhere along the way?
- Run the checkout test file by executing this command:
npx playwright test tests/checkout.spec.ts
The standard_user test passes. The problem_user test fails. You will see a red failure message in your terminal indicating that an expected element was not found or had unexpected content.
Why does the problem user fail?
SauceDemo's problem_user account has intentional application bugs. The checkout form fields misbehave, product images are broken, and cart operations do not work reliably. These are real defects baked into the demo by Sauce Labs to simulate buggy production software.
Your test ran the exact same steps for both users. The only difference was the username. That is the power of parameterized testing. One test file, two accounts, and an instant signal showing which account is broken.
Both tests failed?
If both the standard_user and problem_user tests fail, check your internet connection. SauceDemo is a live website and requires network access.
If only the standard_user test fails, open checkout.spec.ts and confirm the credentials are standard_user with password secret_sauce.
help me figure out why both my Playwright tests are failing
Read the failure output
Look at the terminal output for the failed problem_user test. Playwright tells you exactly which assertion timed out or which locator could not be resolved.
- Find the line in the terminal output that starts with the test name checkout flow for problem_user and read the error below it.
- Note whether the failure happened at the cart badge check, the form submission step, or the final order confirmation.
What does this tell you?
The error message tells you WHAT failed but not WHY the application misbehaved. You know the assertion that broke, but you do not know what the browser was showing at that moment. Was the page blank? Did the form field reject input? Was the button unresponsive?
Terminal output alone is not enough for root-cause analysis. In the next step, you will use Playwright's Trace Viewer to see a full visual timeline of every action, with screenshots and DOM snapshots at each moment.
Do not fix anything yet. The test has revealed a real bug in the application, and the failure is your evidence. Leave checkout.spec.ts exactly as it is.
✔️ Awesome, I've got everything!
Great. Confirm you have saved checkout.spec.ts with no changes from the previous step.
ⓧ I'd like to double check the full code
Your tests/checkout.spec.ts should look exactly like this:
import { test, expect } from '@playwright/test';
const users = [
{ username: 'standard_user', shouldPass: true },
{ username: 'problem_user', shouldPass: false },
];
for (const user of users) {
test(`checkout flow for ${user.username}`, async ({ page }) => {
// Login
await page.goto('https://www.saucedemo.com/');
await page.locator('[data-test="username"]').fill(user.username);
await page.locator('[data-test="password"]').fill('secret_sauce');
await page.locator('[data-test="login-button"]').click();
await expect(page.locator('[data-test="title"]')).toHaveText('Products');
// Add two products to cart
await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();
await page.locator('[data-test="add-to-cart-sauce-labs-bike-light"]').click();
// Verify cart badge shows 2 items
await expect(page.locator('[data-test="shopping-cart-badge"]')).toHaveText('2');
// Go to cart
await page.locator('[data-test="shopping-cart-link"]').click();
// Proceed to checkout
await page.locator('[data-test="checkout"]').click();
// Fill checkout information
await page.locator('[data-test="firstName"]').fill('John');
await page.locator('[data-test="lastName"]').fill('Doe');
await page.locator('[data-test="postalCode"]').fill('12345');
await page.locator('[data-test="continue"]').click();
// Finish checkout
await page.locator('[data-test="finish"]').click();
// Verify order complete
await expect(page.locator('[data-test="complete-header"]')).toHaveText('Thank you for your order!');
});
}
Your test just caught a real application bug automatically. But the terminal error only tells you what assertion failed, not what was happening on screen. Next up, you will use Playwright's Trace Viewer to see a visual timeline of every action and pinpoint exactly where the application broke.
Debug with Trace Viewer
Your problem_user test failed in the previous step, and the terminal told you what went wrong. But the error message alone does not tell you why the application misbehaved.
Playwright's Trace Viewer shows a visual timeline of every action your test performed, complete with screenshots and DOM snapshots at each step. You will use it to pinpoint the exact moment the problem_user checkout diverges from the working flow.
In this step, get ready to:
- Re-run your tests with full tracing enabled.
- Open the Trace Viewer and inspect the failed test visually.
- Identify the root cause of the problem_user failure and document it.
Re-run with tracing enabled
By default, your playwright.config.ts only captures traces on the first retry. To get a trace for the failing test right now, you need to force tracing on for every test run.
- Re-run the checkout tests with tracing enabled by running this command:
npx playwright test tests/checkout.spec.ts --trace on
What does --trace on do?
The --trace on flag tells Playwright to record a zip archive for every test. Each archive contains screenshots, DOM snapshots, network logs, and the action timeline.
Without this flag, your config only traces on the first retry, which means you would not get a trace for a test that fails on its first attempt with zero retries configured.
You will see the standard_user test pass and the problem_user test fail again. This time, Playwright also saved trace files alongside the results.
Tests timed out or hung?
Make sure you are not running a headed browser from the previous step at the same time. Close any lingering Chromium windows and try the command again.
Help me debug a timeout when running Playwright tests with --trace on.
Open the trace for the failed test
The trace files are bundled into the HTML report. You do not need to find them manually.
- Open the HTML report by running:
npx playwright show-report
Your browser opens with the Playwright HTML report. You should see two test entries: one passed (green) for standard_user and one failed (red) for problem_user.
- Click the failed test entry (the red one for problem_user) to expand its details.
- Find the Traces section at the bottom of the test detail view.
- Click the trace attachment link to open the Trace Viewer.
The Trace Viewer opens in a new tab. You should see a timeline of actions on the left, a large screenshot preview in the center, and DOM/network details on the right.
What am I looking at?
The Trace Viewer is like a flight recorder for your test. Each row in the left panel represents one Playwright action (a click, a fill, an assertion). Clicking any row shows the exact screenshot and DOM state at that moment.
The red row is the action that failed. Everything above it succeeded. This lets you see exactly how far the test got before the application broke.
Don't see a Traces section?
Make sure you ran the tests with --trace on in the previous substep. Without that flag, no trace archive is generated. Re-run the command and then open the report again.
Help me find the trace attachment in my Playwright report.
Identify the root cause
Now you have the full visual history of the failed test. Your job is to find the exact moment where the problem_user checkout diverges from what your test expected.
- In the Trace Viewer timeline, click the first action (the page navigation to SauceDemo).
- Step forward through each action one by one. Watch the screenshot preview change as you move through the login, add-to-cart clicks, and cart navigation.
- Find the red (failed) action row. Click it and examine the screenshot. Compare what the page shows against what the assertion expected.
Before you read on, what do you think went wrong? Look at the screenshots leading up to the failure and form a hypothesis about why the problem_user cannot complete checkout.
What you should find
The problem_user account has broken add-to-cart behavior. Items are not correctly added to the cart, which causes the cart badge assertion and subsequent checkout steps to fail.
You can see this in the Trace Viewer: the screenshots show the add-to-cart buttons being clicked, but the cart badge never updates to show the expected item count. This is an intentional bug in SauceDemo designed to simulate real-world application defects.
Now document your finding directly in the test file so future developers understand what this test catches.
- In Cursor, open tests/checkout.spec.ts.
- Find this line at the top of the file:
import { test, expect } from '@playwright/test';
- Add the following comment block directly below the import statement, above the const users line:
// Bug found via Trace Viewer: problem_user has broken add-to-cart behavior —
// items are not correctly added to the cart, causing the cart badge and
// checkout flow assertions to fail.
Why document bugs in the test file?
In professional QA work, test files are living documentation. When a test intentionally catches a known bug, a comment explains why the failure is expected. This prevents other team members from wasting time investigating a known issue.
- Save tests/checkout.spec.ts.
- Confirm the comment is in place by running your tests one more time:
npx playwright test tests/checkout.spec.ts
The results should be the same as before: standard_user passes and problem_user fails. The comment does not change behavior. It documents the bug you just diagnosed.
Getting a syntax error after adding the comment?
Make sure each comment line starts with // followed by a space. Also check that you placed the comment between the import line and the const users line, not inside any code block.
Help me fix a syntax error in my checkout test file.
✔️ Awesome, I've got everything!
Great. Double check you have saved tests/checkout.spec.ts with the comment at the top.
ⓧ I'd like to double check the full code
Here is the complete tests/checkout.spec.ts file. Confirm your version matches:
import { test, expect } from '@playwright/test';
// Bug found via Trace Viewer: problem_user has broken add-to-cart behavior —
// items are not correctly added to the cart, causing the cart badge and
// checkout flow assertions to fail.
const users = [
{ username: 'standard_user', shouldPass: true },
{ username: 'problem_user', shouldPass: false },
];
The rest of the file (the for loop with the test body) is unchanged from what you wrote in the previous step. Scroll up through your file and confirm the login, add-to-cart, cart verification, checkout, and order-complete sections are all still present.
You just used Playwright's Trace Viewer to turn a cryptic terminal error into a clear visual diagnosis. This is the same workflow professional QA engineers use to investigate failures in production test suites. Ready for a bonus challenge? The Secret Mission will teach you how to organize your growing test code using the Page Object Model pattern.
Secret mission
Refactor to Page Object Model
Your tests work, but look at the login code duplicated across files. The locators are scattered everywhere. What happens when a selector changes? You would have to update every test file. Professional QA teams solve this with the Page Object Model pattern. Can you refactor your tests to use reusable page classes?
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.
Resources you used:
- Local Playwright project folder with test files, page objects, and configuration.
- Downloaded browser binaries (Chromium, Firefox, WebKit) stored locally by Playwright, taking up approximately 500MB of disk space.
Keep everything running
No action needed. Choose this if you're still actively building or plan to extend your test suite further.
- Your project folder stays on your Desktop, ready for you to add more tests.
- Playwright's browser binaries remain installed for instant test runs.
Pause - I'll come back to this later
Free up disk space from browser binaries while keeping your project files intact.
- Remove the browser binaries (reclaims ~500MB) by running:
npx playwright uninstall
- Your test files, page objects, and config remain untouched.
- When you return, run npx playwright install to re-download the browsers.
Delete - I don't want to use this again
Remove all project resources and start fresh.
- Remove the Playwright browser binaries by running:
npx playwright uninstall
- Delete your project folder. On macOS/Linux, run:
cd ~/Desktop
rm -rf playwright-tests
- On Windows, run:
cd ~\Desktop
rmdir /s /q playwright-tests
- If your project folder has a different name, replace playwright-tests with your actual folder name.
That's a Wrap!
That's a Wrap!
Nice work! You've built a professional end-to-end test suite that catches real bugs in an ERP checkout flow.
You've learned how to:
- Set up a Playwright testing project from scratch and used Codegen to auto-generate test code by recording browser interactions.
- Written a full end-to-end checkout flow test with data-test locators, then discovered real application bugs by running the same tests against a problem user account.
- Diagnosed test failures visually using Playwright's Trace Viewer and HTML report, pinpointing the exact moment the application misbehaved.
- Secret Mission: Refactored your tests to use the Page Object Model pattern for maintainable, scalable test architecture.
Ready to quiz yourself?