skip to content

How much of your real build should a Cypress component harness reuse?

level: principalimportance: should knowfreq 36%

answer

  1. Reuse is the default position
  2. Every difference narrows the claim
  3. Divergence must argue for itself
  4. Import and spread, never copy
  5. Name the diff, check it elsewhere

basics

~20 s

Reuse the application's real bundler config by default. Every difference between the harness build and the real build is a class of defect the component suite cannot see, so keep divergence to a short, named list you can justify and re-check elsewhere.

solid answer

~40 s

Default to reuse, because `component.devServer` is built for it: name a framework and a bundler and Cypress finds the `vite.config` or `webpack.config` you already have. The suite's claim is that a component behaves correctly compiled the way you ship it, and every harness-only knob quietly narrows that claim. Divergence still has honest reasons — a plugin that uploads source maps or contacts a service, a bundle analyser that pays for nothing under test, one alias pointing at a fixture copy — so the standard I would set is not *no differences* but *a short list of named differences, each with a reason in the config file and a place it is re-verified*. Reuse by import and spread, never by copying the config, because a copy is wrong from the next commit.

go deeper

for a junior

Know that the Cypress component dev server is meant to reuse the project's existing bundler config, not to be given a second one written for tests.

for a middle

Explain what the harness inherits and what it does not, and why importing and spreading the real config beats copying it into the Cypress config file.

for a senior

Argue from failure modes you have seen: a plugin that landed in the real build and not the harness, and the misattributed failures that followed.

for a principal

Own the standard. Say how many differences the team may carry, how each is recorded and re-verified, and what the component suite is therefore allowed to claim.

## Start from reuse, and make each divergence argue for itself The design of `component.devServer` pushes you this way: name a framework and a bundler, and Cypress finds and reuses the `vite.config` or `webpack.config` you already have. The default answer to "how much should the harness share with the real build?" is therefore **as much as it can**, and the burden of proof sits on every deliberate difference. The reason is not tidiness. A component suite's entire claim is *this component behaves correctly when compiled and styled the way we ship it*. Each knob the harness sets differently narrows that claim, silently, and the narrowing is invisible in a green run. ## What a divergence actually costs - **Defect classes you can no longer see.** A different PostCSS or utility-CSS setup means the class names the component emits under test are not the ones production compiles. A different alias map means the module the spec imports is not the module the app imports. - **A second thing to maintain.** Someone adds a plugin to the real build, nobody adds it to the harness, and six weeks later a whole suite fails on a change no one connects to it. - **Misattributed failures.** A harness-only failure looks exactly like a component bug, and the time spent proving it is not is paid on every occurrence. - **A credibility problem.** Once a team has been burned by a harness-only failure, the reflex becomes "it's the test setup", and genuine failures get the same shrug. ## When a test-only override earns its place Not never. A short list of honest reasons: - A plugin that must not run under test — anything that uploads source maps, injects analytics, or contacts an external service. - A step whose cost is never repaid — a bundle analyser, a legacy-browser transpile target, an image-optimisation pass. - A seam the harness needs and production does not — one extra alias pointing a design-token build or a fixture module at a test copy. - A hard incompatibility — a plugin that assumes an application entry point the harness does not have. Each of those is a sentence you could defend in review. "It was easier" is not. ## Keeping the difference nameable 1. **Reuse by import, never by copy.** `viteConfig: async () => ({ ...(await import('./vite.config')).default, ...testOnly })`. A copied config is correct on the day it is copied and wrong from the next commit. 2. **Do the same for runtime setup.** One `src/setup.js` that imports the global stylesheets, imported by both the application entry file and `cypress/support/component.js`, so a new stylesheet reaches the harness for free. 3. **Write the reason beside each override**, in the config file. A one-line comment is the cheapest audit trail available. 4. **Re-verify anything you excluded somewhere else** — an end-to-end run, a production build check — and say where. An untested difference is not a tradeoff, it is a gap. ## What reuse still cannot buy you Even perfect reuse of the real build leaves the harness short of the real page, and it is worth being explicit about the residue rather than letting a green suite imply more than it proves: - The mount page is not your application's page. A toast that stacks correctly in isolation can still be clipped by an ancestor's `overflow` in the app. - Compiling like the development build is not compiling like the production build: minification, chunking and dead-code elimination are not exercised. - A correctly styled mount proves the styles compiled and applied. It is not an approved picture, and treating a component render as one is a separate discipline with its own baselines and review workflow. The strategic form of the decision, then, is not "reuse or not". It is **how many named, defended differences the team is willing to carry**, and whether each one is checked somewhere else. ## Making the standard survive contact A position nobody can find is not a standard. Three cheap moves make this one stick across a fleet of repositories: - **Put the list somewhere a reviewer meets it.** The Cypress config file itself is usually the right place, because that is where the next override will be written. - **Make the harness fail loudly on drift rather than quietly.** A spec that imports the design tokens the application imports will break the moment the two builds stop agreeing, which is exactly when you want to hear about it. - **Review the diff on a schedule, not on incident.** Overrides added to unblock a release are the ones that outlive their reason; the question to ask of each is simply whether the thing it worked around is still true.

  • A team keeps a separate cypress.vite.config copied from the app's. What goes wrong?
    It is correct on the day it is copied and wrong from the next commit. Plugins, aliases and CSS pipeline changes land in the real config and never reach the copy, so the harness slowly compiles a different application than the one you ship, and the divergence surfaces weeks later as an unexplained spec failure. Import the real config and spread it instead.
  • How would you decide that a harness-only difference has grown too large?
    When you can no longer state the differences as a short list with a reason each, or when a spec failure routinely prompts "is that real, or the harness?" Both mean the component suite has stopped being evidence about the shipped build. The honest moves at that point are to shrink the diff, or to move the affected coverage to a level that exercises the real build.

saying these in an interview costs you the question

  • Maintains a hand-written copy of the bundler config for tests
  • Treats any harness difference as harmless because the suite is green
  • Argues the harness must never differ from production at all
  • Cannot name which differences exist or why they are there