User-Flow Checks

By Syncfusion®, Inc. · Last updated

See every unit test pass while checkout is broken. Write flow tests that act like a shopper, find things by role and label, cover happy and unhappy paths, choose the right test for each bug, and export your first verification pack.

When Every Part Works but the App Does Not

A user flow = the steps a person takes to get something done. For example:

  1. Open the checkout page.
  2. Type a coupon code.
  3. Click Apply.
  4. Click Place order.

Every function in that flow can pass its unit tests, and the flow can still be broken. The parts may be wired together wrongly.

AI agents often change many files at once. Wiring mistakes are common, and unit tests do not see them.

Simple lesson: test the journey, not just the parts.

A Real-World Example

Think about a new lift in a building.

  • The motor was tested. It works.
  • The buttons were tested. They light up.
  • The doors were tested. They open and close.
  • But the button for floor 3 was wired to floor 5.

Only one test finds this: get in, press 3, and see where you stop.

A flow test does that for your app.

What You Will Learn

In this lesson, you will learn:

  1. Why unit tests can all pass while a user flow is broken.
  2. How to write a flow test that acts like a person.
  3. How to find things on the page by role and label, not by code details.
  4. Why you test the unhappy path too.
  5. Which kind of test catches which kind of bug.
  6. How to export your first verification pack.

Green Units, Broken Checkout

The agent added coupons to checkout. Here are its unit tests.

Press ▶ Run tests. Green.

  • cartTotal: correct. ₹1000.
  • applyCoupon: correct. ₹900 with SAVE10.
  • But open src/app.ts: the Place order button uses subtotal(), not total().

Now run a flow test on the same code.

Press ▶ Run tests.

  • The Tests tab: red. "expected "Order placed. You paid ₹1000.00" to be "Order placed. You paid ₹900.00"".
  • Why: the shopper saw ₹900 on the screen but paid ₹1000.
  • Fix it: in src/app.ts, find the Place order button and change money(subtotal()) to money(total()). Run again.

Animation: a shopper moves through four steps: type SAVE10, click Apply, see To pay 900, click Place order. The last step shows You paid 1000 in red.

1. Type SAVE10 ✓

2. Click Apply ✓

3. To pay ₹900 ✓

4. Place order ✗ paid ₹1000

Each step on its own is fine. The journey as a whole is not.

A flow test walks the whole journey, like a shopper.

Simple lesson: unit tests check that each part is right. A flow test checks that the parts are joined right.

Writing a Flow Test

Find Things Like a Person Does

A person does not see your variable names. They see buttons, boxes and text.

So a flow test finds things the same way:

  • getByRole('button', { name: 'Apply' }): the button that says Apply.
  • getByLabelText('Coupon code'): the box labelled Coupon code.
  • getByText(/To pay/): the text that contains "To pay".

Role = what a thing on the page is: a button, a text box, a heading, an alert.

Then it acts like a person:

  • user.type(box, 'SAVE10'): types into the box.
  • user.click(button): clicks the button.

In the real world, flow tests run in a real browser with Playwright, or with Testing Library on a rendered page. In this lab, the page is a small model of a web page, so tests run in your browser's test worker. The queries map to Playwright like this:

  • getByRole('button', { name: 'Apply' }) → page.getByRole('button', { name: 'Apply' })
  • getByLabelText('Coupon code') → page.getByLabel('Coupon code')
  • user.click(x) → await x.click()

The Playwright course on this site teaches the real tool.

Your Turn

The test opens the page and checks the heading. Add the next steps:

  1. Change () => to async () => at the top of the test, so you can use await.
  2. Replace the comment with these lines:
await user.type(screen.getByLabelText('Coupon code'), 'SAVE10');
await user.click(screen.getByRole('button', { name: 'Apply' }));
expect(screen.getByText(/To pay/).text).toBe('To pay: ₹900.00');
  1. Press ▶ Run tests. Green. Then add a click on Place order and check the status text yourself.

Simple lesson: find by role and label, act like a person, check what the person sees.

The Unhappy Path

Happy path = everything goes right. Unhappy path = the user makes a mistake, or something fails.

Agents test the happy path well. Unhappy paths are often missed.

Press ▶ Run tests, then 🐞 Plant bugs.

  • This test: types a wrong coupon, then checks the error and the price.
  • The Bug check tab: it catches the "no error shown" bug, but not the others.
  • What it means: you need both paths. Happy path for the coupon. Unhappy path for the error.

Press ▶ Run tests. Green.

  • This test: an empty cart must not be ordered.
  • await expect(...).rejects.toThrow(): checks that clicking a disabled button fails.

Unhappy paths to try in every flow:

  • a wrong or empty input
  • an empty cart or list
  • a button clicked twice
  • a slow or failed network call

Simple lesson: one happy flow and one unhappy flow for every journey that matters.

Which Test Catches What?

Each kind of test has its job:

BugBest testWhy
Wrong maths in one functionUnit testFast, and points at the exact function.
Data shape changed between two partsContract testChecks the agreement between the parts.
Parts wired together wronglyFlow testOnly the whole journey shows it.

Flow tests are slower, so keep them for the journeys that matter most: sign-in, checkout, payment.

Simple lesson: many unit tests, some contract tests, and a few flow tests for key journeys.

Your First Verification Pack

You now have the first rungs of evidence: claims, diffs, fail-first tests, mutation, properties, contracts and flows.

Export them as a verification pack for your own project. It has:

  • Test policy lines for your rules file: fail first, no .skip, mock only the edges.
  • A review-checklist skill for your agent.
  • A test-diff guard hook that blocks .skip and deleted checks.
  • A Stryker config with the mutation score you choose.
  • A property-test starter and a CI workflow.

Check the hook settings against your tool's docs. Claude Code, Codex and Cursor change their hook formats from time to time. The pack follows their docs as of November 2026.

Simple lesson: the pack turns this course into rules your agent follows on every change.

Use It at Work

The page model in the labs works the same way as Playwright in a real project.

  • Set up once: npm init playwright@latest.
  • Record a first draft: npx playwright codegen http://localhost:5173.
  • Run the flows: npx playwright test. Add --ui to watch them.
  • Ask the agent for stable tests:
Write a Playwright test for the checkout flow.
Use getByRole and getByLabel, not CSS classes.
Do not use waitForTimeout. Check what the shopper sees at the end.

TL;DR

  1. User flow = the steps a person takes to get something done.
  2. Flow test = a test that walks that journey, like a person.
  3. Find by role and label: getByRole('button', { name: 'Apply' }), getByLabelText('Coupon code').
  4. Act like a person: user.type(...), user.click(...).
  5. Happy path = everything goes right. Unhappy path = mistakes and failures. Test both.
  6. Which test:

    • wrong maths → unit test
    • changed data shape → contract test
    • wrong wiring → flow test
  7. Verification pack = policy, checklist, hooks, gates and CI for your own repo.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
Only unit tests"Every function passes, so the app works."Add a flow test for key journeys.The shopper pays the wrong price.
Finding by code details"Find the button by its variable name."Find it by role and label, like a person.Tests break on every rename and miss real problems.
Happy path only"SAVE10 works, so coupons work."Also try a wrong code and an empty cart.Errors never show to users.
Flow tests for everything"Test every rule through the page."Use unit tests for rules, flows for journeys.The suite gets slow and flaky.
Checking the code, not the screen"total() returns 900."Check what the person sees on the screen.The screen shows something else.

Check Your Understanding

Exercises

What to Remember

  • Parts can all work while the journey is broken.
  • A flow test walks the journey like a person.
  • Find things by role and label. Check what the person sees.
  • Test the happy path and the unhappy path.
  • Unit tests for rules, contract tests for data shapes, flow tests for wiring.
  • Export your verification pack and check the hook settings.

Further Reading

Next: Verification Gates for Agents. You will turn the pack into gates. Then the agent cannot fake green by skipping or loosening a test.