Frontend Developer · Focus area 3: Build tools and testing

FE8: Unit and component tests

Goal: write automatic tests that catch frontend bugs before users do: choosing what to test, unit tests for logic, component tests that act like a user, faking the network and time, and keeping tests trustworthy rather than brittle.

You'll need: your Kirana Express project with TypeScript from FE7, Vitest (or Jest), React Testing Library with user-event, and Mock Service Worker (MSW). You met testing ideas in Module 39.

Where this is used: teams that release often depend on tests to change code without fear. A cart that miscalculates GST, or a checkout button that stops working after a refactor, costs money and trust. Tests catch these in seconds, every time code changes.

How it differs: backend tests check data in and data out. Frontend tests must also check what a person sees and does: text on screen, buttons, keyboard use, loading and error states, across many small interactions.

Time: reading about 2 hours · practice (the Try it tasks) about 4 hours · assignment about 4 to 5 hours.

Lessons

  1. 1What to test, and how muchReading 15–25 minutes, plus practice✓
  2. 2Unit tests for logicReading 15–25 minutes, plus practice✓
  3. 3Component tests that act like usersReading 15–25 minutes, plus practice✓
  4. 4Faking the network and timeReading 15–25 minutes, plus practice✓
  5. 5Trustworthy testsReading 15–25 minutes, plus practice✓

🛠️Assignment: A test suite for Kirana Express

This gives the multi-page app project the tests it needs.

  1. Write a test plan for the ten most important behaviours, choosing unit, component or E2E for each.
  2. Write unit tests for the cart total, delivery fee and offers, including thresholds and empty carts.
  3. Write component tests for the product card, cart, slot picker and address form, querying by role and label.
  4. Use MSW to test loading, success, empty, error and out-of-order states, and fake timers for an OTP countdown.
  5. Run the suite ten times, fix any flaky tests, and record runtime and coverage for key modules.

Self-check before you finish:

✅Module check

Explain in a few sentences, in your own words:

How do you build frontend tests that catch real bugs and stay trustworthy?

Show a good answer

A good answer mentions: mostly component tests, plus unit tests for tricky logic and a few E2E journeys, starting with money and the main journey; plain functions with arrange-act-assert, edge cases and reproduce-then-fix for bugs; component tests that query by role, label and text and use user-event, avoiding implementation details; MSW and fake timers to test loading, empty, error, slow and out-of-order states; and fixing flaky and brittle tests, using coverage to find gaps rather than as a goal, and never skipping failing tests to get green.

📚Official references

Official documentation and guidance for this module's topics, chosen on 2 November 2026. Tools, laws and standards change, so check the current version before you rely on a detail. If a link has moved, search the same site.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. A team has 300 large snapshot tests and no test of the checkout journey. A checkout bug ships. What's the best change?

Why each option is right or wrong

  • “Add 100 more snapshots of the checkout pages” (Incorrect): More snapshots would still be updated without review and not test the journey.
  • “Remove all tests to save time” (Incorrect): That removes the safety net entirely.
  • “Ask testers to check checkout by hand before each release” (Incorrect): Manual checks help, but they're slow and easy to skip under pressure.
  • “Focused component tests plus a checkout E2E test” is correct.

    Snapshots of large components get updated without reading. Testing what customers do on each part, and one full checkout journey, catches the bugs that matter.

    • Keep: small snapshots of stable output, if useful.
    • Start with: money and the main journey.

📖 Revise: Lesson 1: What to test, and how much

Question ID sp-frontend-08-q1 · Report a mistake in this question
2. A customer is charged a delivery fee on a ₹499 order, though delivery is free from ₹499. What should you do first?

Why each option is right or wrong

  • “Refund the customer and move on” (Incorrect): Refund, yes, but the bug would stay and return.
  • “Change the banner to say "over ₹499"” (Incorrect): That hides the bug by changing the promise.
  • “Add a manual check to the release list” (Incorrect): People forget manual checks; an automatic test runs every time.
  • “Write a failing test for ₹499” is correct.

    A test that reproduces the bug proves the cause (here > instead of >=), shows the fix works, and stays to stop the bug returning.

    • Add: tests just below and above the threshold.
    • Also test: the empty cart.

📖 Revise: Lesson 2: Unit tests for logic

Question ID sp-frontend-08-q2 · Report a mistake in this question
3. A cart calculation uses rupees as decimals and sometimes shows ₹0.30000000000000004. What's the better approach?

Why each option is right or wrong

  • “Round the display to two decimal places only” (Incorrect): The display looks right, but totals and comparisons can still be off.
  • “Use a faster computer for calculations” (Incorrect): Speed doesn't change how decimals are stored.
  • “Remove paise from prices entirely” (Incorrect): Many prices include paise; the business needs them.
  • “Calculate in whole paise” is correct.

    Decimals such as 0.1 can't be stored exactly in binary, so small errors creep in. Whole numbers in paise are exact; convert to rupees only to display.

    • Name fields: pricePaise.
    • Test: thresholds and many-item totals.

📖 Revise: Lesson 2: Unit tests for logic

Question ID sp-frontend-08-q3 · Report a mistake in this question
4. A component test finds the add button with container.querySelector('.btn-primary'). After a redesign, it fails though the app works. What's the better approach?

Why each option is right or wrong

  • “Keep the old class names forever” (Incorrect): That blocks design changes to protect tests.
  • “Add a test ID to every element” (Incorrect): Test IDs are a fallback; role and name also check accessibility.
  • “Use snapshots instead” (Incorrect): Snapshots break on every visual change.
  • “Find it by role and name” is correct.

    getByRole('button', { name: 'Add Tata salt to cart' }) finds the button the way people and screen readers do, and keeps working when class names change.

    • Bonus: checks the button has an accessible name.
    • Avoid: testing internal state too.

📖 Revise: Lesson 3: Component tests that act like users

Question ID sp-frontend-08-q4 · Report a mistake in this question
5. A test can't find the "Remove" button with getByRole('button', { name: /remove/i }), though it's visible on screen. What does that suggest?

Why each option is right or wrong

  • “The testing library is broken” (Incorrect): The library is reporting what's in the accessibility tree.
  • “The test should use a CSS selector instead” (Incorrect): That would hide a real accessibility problem.
  • “Buttons can't be found by role” (Incorrect): Buttons are among the easiest elements to find by role.
  • “The button may lack an accessible name” is correct.

    If the test can't find it by name, a screen reader may announce it as just "button". Adding an aria-label such as "Remove Tata salt from cart" fixes both the test and the accessibility gap.

    • Check: with a screen reader too.
    • Pattern: icon-only buttons need names.

📖 Revise: Lesson 3: Component tests that act like users

Question ID sp-frontend-08-q5 · Report a mistake in this question
6. In production, an API error leaves customers staring at a spinner forever. Tests all pass. What's missing?

Why each option is right or wrong

  • “More tests of the success state” (Incorrect): The success state works; the error state wasn't tested.
  • “A shorter spinner animation” (Incorrect): The spinner's style isn't the issue.
  • “Real API calls in tests” (Incorrect): Real calls make tests slow and flaky, and you can't easily force errors.
  • “A test with a fake error response” is correct.

    Using MSW to return a 500 and expecting a clear message and a retry button would have shown that the error wasn't handled. The fix then adds that state.

    • Test every state: loading, success, empty, error.
    • Also: slow and out-of-order responses.

📖 Revise: Lesson 4: Faking the network and time

Question ID sp-frontend-08-q6 · Report a mistake in this question
7. You need to test that "Resend OTP" becomes active after 30 seconds. What's the best way?

Why each option is right or wrong

  • “Make the test wait 30 real seconds” (Incorrect): Real waiting makes the suite slow and still timing-sensitive.
  • “Change the app to 1 second for tests” (Incorrect): Then the test doesn't check the real behaviour.
  • “Skip testing the timer” (Incorrect): It's part of a sign-in flow customers rely on.
  • “Use fake timers and jump ahead 30 s” is correct.

    Fake timers let the test move time forward instantly, checking the button is disabled before 30 seconds and enabled after, in milliseconds of real time.

    • Vitest: vi.useFakeTimers() and vi.advanceTimersByTime().
    • Reset: real timers after the test.

📖 Revise: Lesson 4: Faking the network and time

Question ID sp-frontend-08-q7 · Report a mistake in this question
8. A test for "today's slots" fails every night after 6:30 pm IST on the CI server. What's the cause?

Why each option is right or wrong

  • “The CI server is overloaded at night” (Incorrect): Load wouldn't fail the test at the same time every night.
  • “Slots really disappear at 6:30 pm” (Incorrect): The app works for customers; only the test fails.
  • “The test runs too fast” (Incorrect): Speed isn't related to the time of day.
  • “The test uses the real clock in UTC” is correct.

    After 6:30 pm IST it's already the next day in UTC, so "today" differs. Fixing the date and time zone in the test makes it reliable.

    • Rule: tests don't read the real clock.
    • Use: fake timers with an Asia/Kolkata date.

📖 Revise: Lesson 5: Trustworthy tests

Question ID sp-frontend-08-q8 · Report a mistake in this question
9. A flaky test fails about one run in ten. A teammate suggests rerunning CI until it passes. What should you do?

Why each option is right or wrong

  • “Rerun until green; it passes most of the time” (Incorrect): Rerunning hides the cause and teaches the team to ignore failures.
  • “Delete the test” (Incorrect): The behaviour it checks may still need checking.
  • “Mark it as skipped until someone has time” (Incorrect): Skipped tests are usually forgotten, and the behaviour goes unchecked.
  • “Find and fix the cause of the flakiness” is correct.

    Flaky tests usually come from timing, shared state, real network calls or dates. Fixing the cause keeps the check and makes failures meaningful again.

    • Try: running it many times in a row.
    • Check: for leaked mocks between tests.

📖 Revise: Lesson 5: Trustworthy tests

Question ID sp-frontend-08-q9 · Report a mistake in this question
10. A manager asks for 100% test coverage. What's the best response?

Why each option is right or wrong

  • “Agree, and add tests that run every line without assertions” (Incorrect): That reaches 100% while checking nothing.
  • “Refuse to measure coverage at all” (Incorrect): Coverage is a useful tool for spotting gaps.
  • “Remove code that's hard to test” (Incorrect): Hard-to-test code may still be needed; it may need restructuring instead.
  • “Target the risky code, not a number” is correct.

    Coverage shows which lines ran, not whether behaviour was checked. Focusing on money, the main journey and past bugs gives more protection than chasing a percentage.

    • Use coverage: to find untested important code.
    • Report: behaviours covered, not just a percentage.

📖 Revise: Lesson 5: Trustworthy tests

Question ID sp-frontend-08-q10 · Report a mistake in this question

ProLearners Assist