# Testing Terms, All in One Place — A Frontend Testing Glossary (Appendix)

> From unit tests to flaky, fixtures, and MCP — every term in the Frontend Testing, Done Right series, explained for beginners and ordered the way you'll meet them. Bookmark this page and come back whenever a word looks unfamiliar.

**Published:** 2026-07-04 | **Updated:** 2026-07-06

---

> This is the **appendix** to the "Frontend Testing, Done Right" series. Whenever you hit an unfamiliar term in the series, come back here. [Browse the full series](/en/series/frontend-testing-done-right/)

Learning frontend testing means getting buried in unfamiliar words. How is a mock different from a stub? When do getBy and queryBy part ways? Why shouldn't you take a coverage number at face value? This one page collects all of those terms — and each entry goes beyond "what it is" to "why it matters" and "when you'd use it."

There are two ways to use this page. Treat it as a **dictionary** when you hit an unfamiliar word — or simply **read it top to bottom**. The terms are ordered not alphabetically but in learning order (by chapter), so reading straight through sketches the whole map of frontend testing. Want to go deeper? Follow the link at the end of each term to the installment that covers it.

Jump straight to the questions people ask most:

- "mock, stub, spy — I mix them up" → **Test double** in [Unit-testing tools](#unit-testing-tools-ch-1)
- "When do I use getBy vs queryBy vs findBy?" → **Queries** in [Component testing](#component-testing-ch-2)
- "What does *flaky* even mean?" → **Flaky test** in [E2E & Playwright](#e2e--playwright-ch-3)

---

## The basics (Ch. 0)

The big-picture terms you meet first, whatever you're learning.

**Unit test**
A test that takes the smallest piece of a program — like a single function or module — and checks it in isolation: given this input, does it produce the expected output? Because it touches no network, database, or browser, it runs in milliseconds, and when it fails you know immediately which function is at fault. That's why it sits at the wide base of the testing pyramid, where you write the most tests. → more: {{< eplink "frontend-testing-unit-basics" "Part 4" >}}

**Integration / component test**
Where a unit test looks at one piece, an integration or component test checks whether several pieces work together. In frontend work the subject is usually a UI component, and the key idea is to verify it by *what the user sees and does* rather than by its internal wiring. For example: type into a search box and confirm the result list changes — just as a real user would. → more: {{< eplink "frontend-testing-testing-library" "Part 7" >}}

**E2E test (End-to-End)**
A test that reproduces a full user journey from start to finish, in a real browser: load the page → type a query → check the results. It exercises whole scenarios where multiple screens and network calls are tangled together. It's the slowest and most expensive to maintain, but the closest to real usage, so it gives the highest confidence that things actually work. That's why you keep them few but meaningful, covering only the critical paths. → more: {{< eplink "frontend-testing-playwright-intro" "Part 11" >}}

**Coverage**
The percentage of your code that actually ran during a single test run — a number your tools calculate automatically. The catch: "was executed" is not the same as "was verified." Code can be run without anything being checked, and coverage still goes up. So coverage works best not as a target, but as a signal for finding the spots that no test touches at all. And the number shifts depending on how you count it (lines vs. branches) — a distinction sorted out in the **Line / branch coverage** entry in chapter 4 below. → more: {{< eplink "frontend-testing-strategy-coverage" "Part 2" >}}, {{< eplink "frontend-testing-coverage-metrics" "Part 18" >}}

**Smoke test**
The bare-minimum check of "does it even turn on?" It only confirms the page loads without errors and the key elements appear — nothing detailed. It won't catch subtle bugs, but it's a cheap first line of defense against big failures (like the whole screen going blank). The name comes from powering on hardware and watching for smoke.

**Regression**
When something that used to work breaks again after a code change. Adding a feature or refactoring can quietly break a part that seemed unrelated. Catching these automatically is the single biggest reason to have tests — a safety net that keeps a bug you already fixed from sneaking back.

## Unit-testing tools (Ch. 1)

Verifying one function at a time — the vocabulary of writing unit tests with Vitest.

**Vitest**
The **test runner** this series uses. A runner is the tool that finds the test files in your project, executes them, and reports what passed and what failed. Vitest shares its configuration with Vite-based projects (which makes it fast), and its API is nearly compatible with Jest, the long-time standard — so almost everything on this page applies to Jest users as well. → more: {{< eplink "frontend-testing-setup-vitest" "Part 3" >}}

**it / test**
The function that defines a single test. In `it('returns everything for an empty query', () => { ... })`, the first argument is a sentence describing what the test checks, and the function body holds the actual verification. `it` and `test` are the same thing under different names. Since that sentence appears verbatim in the failure report, writing it clearly pays off when you're tracking down what broke. → more: {{< eplink "frontend-testing-setup-vitest" "Part 3" >}}

**expect + matcher**
The part that declares, in code, "this value should be like this." You write `expect(result).toBe(expected)`: `expect()` takes the value to check, and the method after the dot — `toBe`, `toEqual`, `toBeInTheDocument` — is the matcher that decides *how* to compare. `toBe` checks exact equality, `toEqual` checks matching contents, `toBeInTheDocument` checks that it's actually on screen. If a test has no such assertion, the code may run but effectively verifies nothing. → more: {{< eplink "frontend-testing-setup-vitest" "Part 3" >}}

**describe**
A group that bundles several related tests together. Put your tests inside `describe('filterByQuery', ...)`, for instance, and the results read hierarchically — "filterByQuery › ignores case." As your tests grow into the dozens, this keeps it obvious at a glance where and what broke. → more: {{< eplink "frontend-testing-unit-basics" "Part 4" >}}

**AAA pattern**
The three-step skeleton of a readable test. In Arrange you set up the data and state you need, in Act you perform the one action under test, and in Assert you check the result against expectations. Follow this order and a test reads like a small story: "given this setup, I did this, and it should end up like that." Tests with a scrambled order are hard for others — and for you a few months later — to follow. → more: {{< eplink "frontend-testing-unit-basics" "Part 4" >}}

**jsdom**
A library that mimics the browser's DOM inside Node.js. It lets you use things like `document` and `querySelector` without launching a real browser, so component tests run very fast. It doesn't perfectly reproduce real rendering, viewport size, or animation, though. So you split the work: use jsdom for "many fast checks," and E2E for "checks that genuinely need a real browser." → more: {{< eplink "frontend-testing-setup-vitest" "Part 3" >}}

**vi**
Vitest's built-in helper object. It gathers tools like fake timers that let you fast-forward time (`vi.useFakeTimers()`), fake functions that watch or stand in for calls (`vi.fn()`), and whole-module replacement. You reach for these when a situation is awkward to test directly — code that would otherwise make you wait three real seconds, or that calls an external API. → more: {{< eplink "frontend-testing-async" "Part 5" >}}

**Test double**
The umbrella term for the "stand-ins" you use in place of real objects — think movie stunt doubles, in several varieties. A **stub** simply returns fixed values; a **spy** leaves the real behavior intact but quietly records how many times and with what arguments it was called; a **mock** goes further and verifies those calls happened as expected; a **fake** is a lightweight reimplementation (say, an in-memory array instead of a real database). The knack of good testing is telling these apart and faking only exactly as much as you need. → more: {{< eplink "frontend-testing-test-doubles" "Part 6" >}}

**Snapshot test**
Saves a component's rendered output wholesale to a file, then fails on the next run if it differs from that saved version. It catches "something changed" well — but there's a trap: nobody ever verified that the saved output was correct in the first place. So if you fall into updating the snapshot without reading the diff, it ends up protecting nothing. Not overusing it is the point. → more: {{< eplink "frontend-testing-strategy-coverage" "Part 2" >}}, {{< eplink "frontend-testing-visual-regression" "Part 16" >}}

## Component testing (Ch. 2)

Terms from testing screens (components) the way a user experiences them.

**Testing Library**
A family of tools for rendering components under test (`render`) and finding elements on the resulting screen (`screen`). The React flavor (React Testing Library) is the best known, but Vue and Svelte versions exist too, and the philosophy is the same everywhere: test what the user sees. The query and role terms in this chapter all come from this tool. → more: {{< eplink "frontend-testing-testing-library" "Part 7" >}}

**Queries (getBy / queryBy / findBy)**
Ways to find an element on screen, in three flavors for different situations. `getBy` throws an error immediately if the element is missing (use it for things that must be present). `queryBy` quietly returns null when absent, which is how you assert "this should *not* be on screen." `findBy` waits a moment for the element to appear, which suits things that show up asynchronously after data loads. Just choosing the right one of the three makes tests far more stable. → more: {{< eplink "frontend-testing-testing-library" "Part 7" >}}

**Role / accessible name**
A role is what an element *means* (a button, a heading, a search box); the accessible name is what it's called (the "Search" button). Both are what a screen reader announces to the user — and good tests find elements by exactly this information. Because you're locating things by "what they mean on screen" rather than by CSS classes or tag structure, writing tests this way doubles as an accessibility check. → more: {{< eplink "frontend-testing-testing-library" "Part 7" >}}, {{< eplink "frontend-testing-a11y-queries" "Part 10" >}}

**user-event / fireEvent**
Both simulate user interaction in a test. `fireEvent` is the older, lower-level way — it fires a single event directly ("dispatch one change event"). `user-event` reproduces real human behavior more faithfully: a single keystroke moves focus, presses and releases a key, and updates the value in the right order. When you want results close to real usage, user-event is usually the better choice. → more: {{< eplink "frontend-testing-user-event" "Part 8" >}}

**MSW (Mock Service Worker)**
A tool that intercepts the network requests your app makes during tests or development and returns a prepared fake response. Without touching server code or spinning up a real backend, you can conjure any situation you like — success, failure, a slow response. From your code's point of view it's indistinguishable from talking to a real server, so you test under near-real conditions. A bonus is that the same setup can be reused for development and demos. → more: {{< eplink "frontend-testing-msw" "Part 9" >}}

## E2E & Playwright (Ch. 3)

The stage where full user flows run in a real browser.

**Playwright**
The tool that drives a real browser (Chromium, Firefox, WebKit) from code to run E2E tests — opening pages, typing, clicking, and checking, all automated. Most of the remaining terms in this chapter are mechanisms Playwright provides to make that automation reliable. → more: {{< eplink "frontend-testing-playwright-intro" "Part 11" >}}

**Locator**
An object that holds the *method* of finding an element, rather than the element itself. It re-resolves at the exact moment you click or check, so it holds up even when the page re-renders or its structure shifts a little. It's like carrying directions to a place instead of memorizing a fixed address. → more: {{< eplink "frontend-testing-playwright-locators" "Part 12" >}}

**Auto-wait**
Playwright's habit of waiting, before it acts, until the target element has appeared and is ready to be clicked. This spares you from arbitrary waits like "sleep for 3 seconds" — the kind of fixed delay that's enough on one machine and too short on another, and a leading cause of unstable tests. Auto-wait removes much of that problem for you. → more: {{< eplink "frontend-testing-playwright-locators" "Part 12" >}}

**Strict mode**
A safeguard that makes a locator fail immediately when it matches more than one element, instead of silently picking one. It looks inconvenient at first, but it beats quietly clicking the wrong element and passing (or failing) for mysterious reasons. In effect it says "your condition points to two things — please be more specific," which makes your tests sturdier. → more: {{< eplink "frontend-testing-playwright-locators" "Part 12" >}}

**Flaky test**
An unreliable test that passes sometimes and fails other times, with no change to the code. The cause is usually timing (touching an element before it's ready) or an ambiguous selector (matching several elements). Leave flaky tests unaddressed and the team starts ignoring failures — and eventually misses a real bug. That's why it's worth hunting down the cause and eliminating it for good. → more: {{< eplink "frontend-testing-playwright-locators" "Part 12" >}}

**Fixture**
Defines the setup many tests share — navigating to a page, logging in, seeding data — in one place, and injects it into each test automatically. So you don't copy the same setup code into every test, and the body of each test can focus solely on "what am I verifying this time." Think of it as the stage crew that arranges the props and lighting before the actor steps on. → more: {{< eplink "frontend-testing-playwright-fixtures" "Part 13" >}}

**storageState**
A Playwright feature that saves a logged-in state (cookies, tokens, and so on) to a single file for many tests to reuse. Without it, every test has to walk through the login screen — slow and tedious. Picture logging in once to make a "pass," after which your tests simply carry that pass and walk straight in. → more: {{< eplink "frontend-testing-playwright-fixtures" "Part 13" >}}

**Trace**
A recording of the steps a failed E2E test took, kept together with the screen snapshot, network requests, and console logs at each moment. In frustrating cases like "it works on my machine but only breaks in CI," you can replay what actually happened, like footage, and pin down the cause. It plays the same role as a car's dashcam. → more: {{< eplink "frontend-testing-playwright-debug" "Part 14" >}}

**Retry**
A setting that automatically tries a failed test a few more times. It's useful for filtering out genuine flukes like a momentary network hiccup. But passing on a retry is also a signal that the test is fundamentally unstable. A retry is first aid only — the real fix is to dig into *why* it failed the first time and address the cause. → more: {{< eplink "frontend-testing-playwright-debug" "Part 14" >}}

**axe (axe-core)**
An engine that automatically scans a page for accessibility problems, rule by rule. It flags things a machine can judge — insufficient color contrast, an unnamed button, misused ARIA attributes. Judgments like "does this alt text fit the context" still belong to a human, though. axe handles the automatable parts quickly so people can focus where it matters more. → more: {{< eplink "frontend-testing-axe-e2e" "Part 15" >}}

**Baseline / visual regression**
A test that stores a reference screenshot (the baseline) and then compares later screens against it pixel by pixel to find what changed. It catches breakage you can only see with your eyes — like one line of CSS wrecking a layout that looks fine in the code. The flip side: an intentional design change also registers as "different," so you update the baseline when that happens. → more: {{< eplink "frontend-testing-visual-regression" "Part 16" >}}

## Automation & quality (Ch. 4)

Terms from the CI stage, where tests run automatically, always.

**CI (Continuous Integration)**
A setup where, every time you push code to the repository, a server automatically builds it and runs the tests. The key effect is that "but it worked on my machine" disappears. Nobody has to remember to run the checks — the machine does it the moment you push. Like airport security, all code has to pass this gate before moving on. → more: {{< eplink "frontend-testing-ci-github-actions" "Part 17" >}}

**PR (Pull Request)**
The unit for requesting "please merge this change of mine into the main code." A colleague reviews the code, the CI checks must pass, and only then does it get merged. Even on a solo project, using PRs keeps a clean history of changes and lets you enforce automatic checks before anything is merged. → more: {{< eplink "frontend-testing-ci-github-actions" "Part 17" >}}

**Merge gate**
A rule that blocks code from being merged until all the required checks pass. If a test fails or an accessibility check trips, the merge button locks. Because it enforces your quality bar through the system rather than relying on goodwill or memory, it especially pays off as a team grows. It's like a turnstile that only opens once you've inserted your ticket. → more: {{< eplink "frontend-testing-ci-github-actions" "Part 17" >}}

**Artifact**
The output a CI run leaves behind — test reports, traces from failures, screenshots, coverage results. Since CI runs on a remote server rather than your machine, you can't peek in directly when something fails. So these artifacts serve as the evidence from the scene and become the starting point for your investigation. → more: {{< eplink "frontend-testing-ci-github-actions" "Part 17" >}}

**Line coverage / branch coverage**
Two ways of counting coverage. Line coverage is the share of *code lines* that ran; branch coverage is the share of *conditional branches* (both when an `if` is true and when it's false) that were taken. Passing through one line doesn't mean you checked every case inside it, so branch coverage is usually the more honest number. This distinction helps when you're hunting for the untested forks in the road. → more: {{< eplink "frontend-testing-coverage-metrics" "Part 18" >}}

## The AI era (Ch. 5)

What you need to know when you hand testing over to AI.

**LLM (Large Language Model)**
AI like ChatGPT or Claude that, trained on vast amounts of text, generates writing — including code. It's a capable helper that can draft tests in an instant, but it will also hand you code that looks plausible while verifying nothing. So the working assumption is: use it for fast drafts, but always have a human review and refine them. → more: {{< eplink "frontend-testing-ai-generate" "Part 19" >}}

**Mutation check**
A way of asking whether a test really does its job. The idea is simple: deliberately break a bit of the code, then see if the test fails. If you damaged the code and the test still shows green, that test is effectively protecting nothing. It's like lighting a bit of smoke in front of a fire alarm to check that it actually goes off. It's especially handy for judging whether you can trust AI-generated tests. → more: {{< eplink "frontend-testing-ai-generate" "Part 19" >}}

**codegen**
A Playwright tool that transcribes your clicks and typing in the browser directly into test code. It's great for getting a quick first draft when writing selectors by hand feels daunting. That said, auto-generated code can have brittle selectors or extra steps mixed in, so the rule is to treat it as a draft and clean it up by hand. → more: {{< eplink "frontend-testing-ai-playwright" "Part 20" >}}

**MCP (Model Context Protocol)**
A standard that connects an AI agent to external tools like a browser so it can operate them directly. With this link the AI doesn't just describe things in words — it can actually open a page, click buttons, and attempt a test. Think of it as the standard plug that puts tools into the AI's hands. → more: {{< eplink "frontend-testing-ai-playwright" "Part 20" >}}

**Self-healing selector**
An approach where, when a selector breaks because the screen structure changed, the AI finds a substitute and patches it on its own. It's convenient — it reduces the pile of failures caused by a trivial change. But the AI might latch onto the wrong element as the new target, so a human needs to confirm that its choice is right. The point is not to trade away verification for convenience. → more: {{< eplink "frontend-testing-ai-playwright" "Part 20" >}}

---

## Wrapping up

This page keeps getting refined as the series goes on. If there's a term you'd like added, or an explanation that left you *more* confused, feel free to say so in the comments.

> **Back to the series**: [Part 1 — Why Frontend Testing, Why Now](/en/posts/frontend-testing-why-now/)

