skip to content

Wiring Providers & Stores

What a subtree needs before it renders at all — ancestor values, a router at a URL, a seeded store, a warm cache — and the helper that supplies them. Interviewers read the setup as evidence of design.

on this pageshow

questions

6

A component test fails to mount because the tree reads values from ancestors it does not have. What must the test supply?

level: juniorimportance: must knowfreq 60%

answer

  1. the component is never alone
  2. everything the tree reads from above
  3. values, location, store, cache
  4. wrap around, never a test-only prop
  5. fresh instances per mount

basics

~20 s

Everything the tree reads from above it: the ancestor-provided values it expects (theme, locale, session), a router, any external store it subscribes to, and a data client. The test wraps the component in those providers before mounting.

solid answer

~50 s

A component in a running application is never alone: it reads values handed down by ancestors, it asks a router where it is, it subscribes to a store, it asks a data client for cached results. A test that mounts only the component gives it none of that, so it throws or renders a fallback. The fix is to recreate the environment in the test: wrap the component under test in the same providers the application puts above it, positioned at a URL and seeded with the state the case needs, and only then mount. Wiring belongs *around* the component, not inside it — you should not change the component to make it mountable. If the list of things you must wire is long, that is information: it says the component reaches for a lot of ambient context.

go deeper

for a junior

Remember the four things a subtree can read from above: ancestor-provided values, a router, an external store, a data cache. A test has to supply the ones the component actually uses.

for a middle

Explain why a missing ancestor value sometimes throws and sometimes silently renders the default, and why nesting order matters once one provider reads another.

for a senior

Show that you read a heavy setup block as a design signal, and that you refuse test-only branches in production components — splitting the component instead.

for a principal

Frame the tradeoff: ambient context makes components terse to use and expensive to test. Decide where your codebase draws that line and how reviews enforce it.

## The thing a test forgets When you mount a component in a test you get the component and its children — and nothing above it. In the running application that "above" is doing real work: it hands values down the tree, answers the question "what URL are we at", holds state that outlives any one component, and caches server data. A component that reads any of those is not a self-contained function of its own inputs; it is a function of its inputs **plus its ancestry**. Wiring that ancestry is the setup step every component test starts with. ## The four things a subtree reads from above - **Ancestor-provided values** — a value put into the tree by an ancestor and read by any descendant without being passed through every level: theme, locale, formatting rules, the current session or permissions. Most frameworks expose this as a provider at the top and a read at the bottom. - **A router** — the component asks which route matched, what the path parameters are, or renders a link. That answer comes from a router placed above it, not from the component. - **External state** — a store that lives outside the component tree, which components subscribe to and re-read when it changes. - **A data client / cache** — the layer that holds fetched results and hands a component either a cached value or a pending state. ## Symptom to cause | What the test sees | What is missing | |---|---| | Throws on mount, complaining a value or context is absent | The ancestor provider was never wrapped around the component | | Renders but every ancestor-provided value is the default | A provider exists somewhere but not around *this* mount, so the read fell back | | Throws when rendering a link, or route parameters read as empty | No router above the tree, or the router has no location | | Renders an empty list forever | Store present but never seeded; or the data client has no cached entry and nothing resolves it | Read the failure before you patch it. "Renders the default" is the dangerous one, because the test passes while asserting on a tree that is not the tree users get. ## Wrapping, in order 1. **Decide what the test is about.** The provider that supplies the value under test gets the case-specific value; everything else gets a plausible default. 2. **Build fresh instances.** A store, a router location and a cache are *state*; create them per test so one test cannot hand its leftovers to the next. 3. **Nest outermost-first.** Providers that others depend on go outside: session and locale usually outside a router, a router outside the data client if loaders read the location, the component last. Where two providers depend on each other, order stops being cosmetic. 4. **Mount, then settle.** The tree may read a store, schedule work, and render again; assert after the framework has processed that queue, not before. ## Wire it around, never inside The tempting shortcut is to give the component a prop that lets it skip the ancestor read "for tests". That ships a test-only branch into production code and means the path users take is now the path no test covers. If a component is hard to mount, the honest fixes are structural: pull the ancestor reads up into a thin wrapper and leave a presentational child that takes plain inputs, or accept the wiring as the price of a component that legitimately needs ambient context. ## The setup is evidence Interviewers read the setup block as a design review. A mount that needs three providers and a seeded store for a component that only formats a date says the component reaches too far. A mount that needs exactly the session and a location for a component whose job is "show the signed-in user's current page" is telling you the component is honest about its dependencies. Neither reading is about the test framework; both are about the component. ## What this is not Supplying the environment is not the same as deciding which parts of it should be real and which should be stand-ins, and it is not the same as making the tree *settle* after it mounts. Those are separate decisions that come after you know what has to be there at all. First get the tree mountable; then choose fidelity.

  • Why is adding a prop that lets the component skip its ancestor read a bad way to make it testable?
    It creates a branch that exists only for tests, so the production path — the one users take, where the value comes from an ancestor — is now the path no test exercises. It also spreads test concerns into the component's public inputs. If mounting is painful, split the component: a thin wrapper that reads ambient context and a presentational child that takes plain inputs.
  • A test mounts without errors and asserts successfully, yet the component never received the session you thought you provided. How does that happen?
    Ancestor reads usually fall back to a default when no provider is found above them, so a mis-nested or forgotten provider degrades silently instead of throwing. The test then asserts against default-rendered output. Guard against it by asserting something only the provided value can produce, and by having the provider's read fail loudly when a value is genuinely required.

saying these in an interview costs you the question

  • Says a component test only ever needs the component and its props
  • Adds a test-only prop so the component can skip its ancestor read
  • Reuses one shared store instance across every test in the file
  • Assumes a missing ancestor value always throws rather than falling back to a default
  • Mounts a component that needs a router without giving the router any location
open as a page

How do you wire a component test so the tree renders as if the user arrived at a particular URL, and what can it then assert?

level: middleimportance: must knowfreq 52%

basics

~20 s

Wrap the tree in a router whose history is an in-memory list rather than the host's address bar, seeded with the URL under test. The test can then assert which route's content rendered, and where a redirect left the location.

open as a page

Why do teams put component-test provider wiring behind one shared mount helper, and what must each test still control?

level: middleimportance: should knowfreq 55%

basics

~20 s

Because the provider stack is near-identical in every test, and hand-wiring it duplicates the application's composition in hundreds of files. Each test still controls its own values: the starting URL, seeded store state, cached entries, collaborator overrides.

open as a page

Your mount helper builds a fresh provider per test, yet a value one test wrote is still visible in the next. Where is the leak?

level: seniorimportance: should knowfreq 44%

basics

~10 s

In state created once when a module first loads — a store, cache or client built at module scope. The provider is new each test, but it hands the tree the same long-lived instance.

open as a page

Why seed a store or prewarm a data cache before mounting, instead of driving the tree through the steps that would produce that state?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Because the state is the case's precondition, not its subject. Seeding puts the tree straight into the situation under test, keeps the setup readable and deterministic, and stops every test from depending on the correctness of an unrelated flow.

open as a page

As the owner of a large component-test suite, how do you decide how much of the application's real provider stack the default mount wires?

level: principalimportance: nice to knowfreq 32%

basics

~10 s

Per collaborator, by cost and evidence: run in-process deterministic ones for real, stand in for anything crossing a boundary or a clock. Publish the default, make deviations explicit, revise it when defects escape.

open as a page