SoftwareTestPilot
46 curated Cypress Q&A

Cypress Interview Questions & Answers (2026)

Forty-six Cypress questions built around what is true of Cypress specifically — the command queue and subjects, retry-ability rules, cy.intercept, cy.session, cy.origin, iframe and tab limits, component testing, spec-level parallelisation, and flake diagnosis.

  • 19 min read
  • Difficulty: Mixed (Easy → Medium)
  • Freshers → 5+ yrs
  • Updated July 2026
  • Avinash Kamble
Cypress Skill Track
Avinash Kamble
Founder & QA Engineer at SoftwareTestPilot
Published:
0 / 46 reviewed
0%

1. Execution model: command queue and subjects

Hard Very Common 1 minQ1 / 46

Q1.Cypress commands are not promises. What are they, and why does the distinction matter?

Why interviewers ask this

This is the root cause of most Cypress mistakes; everything else follows from it.

Detailed explanation

Calling cy.get('#name') does not perform anything. It enqueues a command. Cypress builds the entire chain synchronously as your test function runs, then executes the queue asynchronously, one command at a time, after the function has returned.

The consequence: you cannot assign a command's result to a variable, and await cy.get(...) is meaningless because a command is not thenable in the way a promise is.

// Wrong — text is a Chainable, not a string
const text = cy.get('h1').text();

// Right — work inside the callback
cy.get('h1').invoke('text').then(text => { expect(text).to.contain('Orders'); });
Common mistakes
  • Mixing async/await with cy commands and expecting values back.
  • Writing if/else on a cy result outside a .then() — the condition evaluates before the queue runs.
RelatedQ3
Medium Very Common 1 minQ2 / 46

Q2.What is 'the subject' in Cypress and how does it flow through a chain?

Why interviewers ask this

Subject management explains why some commands chain and others do not.

Detailed explanation

Each command yields a subject to the next one. cy.get('form') yields a jQuery-wrapped element; .find('input') receives it and yields the matching inputs; .type('x') receives those and yields them unchanged.

Commands fall into three kinds: parent commands start a fresh chain and ignore the incoming subject (cy.get, cy.visit, cy.request); child commands require a subject (.click, .find); dual commands work either way (cy.contains). Chaining a parent command after a child silently discards your subject — a common source of confusion.

Medium Very Common 1 minQ3 / 46

Q3.What does .then() do in Cypress, and how is it different from .should()?

Why interviewers ask this

Misusing .then() for assertions is one of the biggest flakiness sources.

Detailed explanation

.then() runs your callback once with the current subject and does not retry. .should() attaches an assertion that Cypress retries until it passes or times out.

// Retries until the badge reads 3
cy.get('[data-cy=cart-count]').should('have.text', '3');

// Runs once — flaky if the count is still updating
cy.get('[data-cy=cart-count]').then($el => {
  expect($el.text()).to.eq('3');
});

Use .then() when you genuinely need imperative logic (extracting a value, branching), and put the waiting-sensitive assertion in .should().

Medium Very Common 1 minQ4 / 46

Q4.What is the difference between .then() and .should() with a callback?

Why interviewers ask this

A precise follow-up that trips up candidates who only know the headline rule.

Detailed explanation

.should(callback) retries the entire callback until it stops throwing. That makes it the right place for multi-part assertions on state that is still settling.

cy.get('li.item').should($items => {
  expect($items).to.have.length(3);
  expect($items.eq(0)).to.contain('Alpha');
});

Because it retries, the callback must be side-effect free — never put a cy.request, a click or a counter increment inside it, or it will fire multiple times.

Hard Very Common 1 minQ5 / 46

Q5.Why can't you use a plain if/else on the state of the DOM in Cypress?

Why interviewers ask this

Conditional testing is explicitly discouraged in Cypress; the reasoning is what matters.

Detailed explanation

Because at the moment your if evaluates, the queue has not run — and even inside a .then(), the DOM may not have finished settling, so the branch you take is a race.

Cypress's position is that tests should be deterministic: you should know whether the banner appears. Where the state genuinely varies, make it deterministic first — seed the account through the API, stub the response with cy.intercept, or set the feature flag via cy.setCookie/local storage — rather than branching.

If you truly must branch, do it on a source that is already resolved (a cy.request response body), not on the rendered DOM.

Medium Very Common 1 minQ6 / 46

Q6.Cypress runs inside the browser alongside your app. What does that buy you, and what does it cost?

Why interviewers ask this

Architecture question that frames every limitation later in the interview.

Detailed explanation

Buys: direct access to the application's window, document, local storage and even app internals; native access to the same event loop, which is why command feedback is instant; time-travel snapshots per command; and stubbing of browser APIs (cy.clock, cy.stub on window).

Costs: the runner is subject to the same browser rules as the app. That is the direct source of the origin restrictions, the absence of real multi-tab support, and the limits on native OS dialogs and file pickers. A Node-side process (the plugin/setup layer) exists precisely to do the things the browser cannot.

Medium Very Common 1 minQ7 / 46

Q7.What are Cypress hooks and what is the recommended way to reset state between tests?

Why interviewers ask this

Test-isolation defaults changed in modern Cypress; knowing this signals a current candidate.

Detailed explanation

Cypress uses Mocha hooks: before, beforeEach, afterEach, after.

With testIsolation enabled (the default in current Cypress), the browser context is cleared before each test — cookies, local storage and session storage are wiped and the page is reset to about:blank. So you do not need manual clearCookies calls; you need a beforeEach that establishes the state your test requires, ideally via API or cy.session.

Cleanup in after is unreliable — if a test fails hard, later hooks may not run. Prefer creating uniquely-named data so leftovers are harmless.

Medium Very Common 1 minQ8 / 46

Q8.Why does Cypress discourage cleanup in afterEach, and what should you do instead?

Why interviewers ask this

Shows whether the candidate has hit the failure mode where cleanup masks the real error.

Detailed explanation

Two reasons: a failing test may abort before afterEach completes, leaving state behind anyway; and a failure inside cleanup produces a confusing second error that hides the original one.

The recommended pattern is set-up-forward: create fresh, uniquely identified data at the start of each test (order-${Date.now()}), so previous runs never interfere. Reserve teardown for resources that genuinely cost money or block others, and run bulk cleanup as a scheduled job rather than per test.

Confidence check

If you can confidently answer the Execution model: command queue and subjects questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

2. Retry-ability, assertions and synchronisation

Hard Very Common 1 minQ9 / 46

Q9.Explain Cypress retry-ability precisely. Which part of a chain is retried?

Why interviewers ask this

Candidates usually say 'Cypress retries everything', which is wrong and leads to real bugs.

Detailed explanation

Cypress retries only the last query command before an assertion, together with the assertions attached to it. Action commands such as click or type are not retried; they are attempted once the element passes actionability checks.

// Both get and find are re-queried until the assertion passes
cy.get('table').find('tr').should('have.length', 5);

// The .then() breaks retry-ability — everything before it ran once
cy.get('table').then($t => $t.find('tr')).should('have.length', 5);

This is why inserting .then() in the middle of a chain is the most common way people accidentally make a stable test flaky.

Medium Very Common 1 minQ10 / 46

Q10.Why does cy.wait() with a fixed number of milliseconds count as a code smell?

Why interviewers ask this

Tests whether the candidate knows the Cypress-native alternatives.

Detailed explanation

Because it is either too short (flaky under CI load) or too long (wasted minutes across a suite), and it never states what you were actually waiting for.

Cypress gives you better tools: assertions retry automatically, so cy.get('.row').should('have.length', 10) already waits; cy.wait('@alias') waits for a specific intercepted request to complete; and cy.get(sel, { timeout: 20000 }) raises the wait for one known-slow element without slowing the rest of the suite.

Medium Very Common 1 minQ11 / 46

Q11.What are the timeout settings in Cypress and how do they differ?

Why interviewers ask this

Practical configuration knowledge that surfaces in any real suite.

Detailed explanation
  • defaultCommandTimeout (4 s) — how long query commands and assertions retry. The one you tune most.
  • requestTimeout (5 s) — waiting for an intercepted request to be sent.
  • responseTimeout (30 s) — waiting for the response, and for cy.request.
  • pageLoadTimeout (60 s) — cy.visit and navigation.
  • execTimeout, taskTimeout — Node-side commands.

Prefer a per-command { timeout } override to raising the global value; a global increase makes every genuine failure take longer to report.

Medium Very Common 1 minQ12 / 46

Q12.How do you assert that something is absent or has disappeared?

Why interviewers ask this

Negative assertions have subtle failure modes in Cypress.

Detailed explanation
cy.get('[data-cy=spinner]').should('not.exist');       // removed from DOM
cy.get('[data-cy=banner]').should('not.be.visible');   // present but hidden

The distinction matters: not.be.visible fails if the element was removed entirely, because the query finds nothing to assert on. Use not.exist for elements the app unmounts and not.be.visible for elements it merely hides.

Also beware asserting absence immediately after page load — the element may not have rendered yet, so the assertion passes for the wrong reason. Anchor it: assert the loading state appeared first, then that it disappeared.

Medium Very Common 1 minQ13 / 46

Q13.How do you wait for an element that appears only after an animation?

Why interviewers ask this

Actionability and animation handling is Cypress-specific behaviour.

Detailed explanation

Cypress already waits for an element to stop animating before acting on it (waitForAnimations, with an animationDistanceThreshold). Problems usually come from assertions on position or from CSS transitions that never quite settle.

Practical options: assert on a stable end-state class the app adds when the transition completes; disable animations in the test environment via injected CSS, which also speeds up the suite; or as a last resort pass { force: true } — while being clear that force bypasses actionability and can hide a genuine bug.

Medium Very Common 1 minQ14 / 46

Q14.What does { force: true } actually do, and when is it legitimate?

Why interviewers ask this

Overused escape hatch; interviewers want to hear the caveat.

Detailed explanation

It skips the actionability checks — visibility, not-covered, not-disabled, scroll-into-view — and dispatches the event directly at the element.

Legitimate uses are narrow: interacting with an element that is intentionally offscreen in a virtualised list, or a hidden file input. Illegitimate use is far more common: forcing a click on a button covered by a modal or cookie banner. That makes the test pass while a real user would be blocked — exactly the bug the test existed to catch.

Medium Very Common 1 minQ15 / 46

Q15.How do you handle an element that is detached from the DOM mid-command?

Why interviewers ask this

The classic 'cy failed because the element you are chaining off has become detached' error.

Detailed explanation

It happens when a re-render replaces the node between the query and the action. Fixes, in order of preference:

  • Re-query rather than reusing a stale subject: chain cy.get(...) again instead of holding an element from an earlier .then().
  • Wait for the cause of the re-render first — usually the network call, via cy.wait('@alias').
  • Assert the list has settled (should('have.length', n)) before clicking into it.

Retrying the click blindly is a workaround; the underlying issue is acting during a render cycle.

Medium Very Common 1 minQ16 / 46

Q16.What is cy.clock() and cy.tick() used for?

Why interviewers ask this

Time control is available in Cypress because it runs in-browser; many candidates miss it.

Detailed explanation

cy.clock() replaces the browser's timer functions and Date with controllable fakes; cy.tick(ms) advances them instantly.

cy.clock();
cy.visit('/session');
cy.tick(15 * 60 * 1000);            // jump 15 minutes
cy.contains('Your session expired').should('be.visible');

This turns untestable time-based behaviour — idle timeouts, polling intervals, auto-dismissing toasts, countdown timers — into fast deterministic tests instead of tests that literally wait.

Confidence check

If you can confidently answer the Retry-ability, assertions and synchronisation questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

3. Selectors, aliases and custom commands

Medium Very Common 1 minQ17 / 46

Q17.What is the Cypress-recommended selector strategy, and why data-cy attributes?

Why interviewers ask this

Maintainability; interviewers want the reasoning, not just the convention.

Detailed explanation

Prefer a dedicated test attribute — data-cy, data-test or data-testid — because it is the only selector both you and the developers agree is contractual. CSS classes change with restyling, IDs are reused, tag structure changes with refactors, and text changes with copy edits or localisation.

Configure e2e.experimentalStudio aside, the practical rule most teams adopt: user-visible text via cy.contains for things a user would genuinely read, data-cy for everything else, and never a chained descendant CSS selector more than two levels deep.

Medium Very Common 1 minQ18 / 46

Q18.What is the difference between cy.get() and cy.contains()?

Why interviewers ask this

Simple on the surface, but the matching rules catch people out.

Detailed explanation

cy.get(selector) queries by CSS selector (or alias). cy.contains(text) queries by rendered text content, returning the deepest element containing that text — which is often not the element you intended to click.

cy.contains('Delete');                              // could match a <span> inside the button
cy.contains('button', 'Delete');                    // scope by selector — safer
cy.get('[data-cy=row-22]').contains('Delete');      // scope by container — safest

cy.contains does substring, case-sensitive matching by default; pass a regex for exact control.

Medium Common 1 minQ19 / 46

Q19.How do aliases work in Cypress and what can you alias?

Why interviewers ask this

Aliases are the idiomatic way to carry state across commands without variables.

Detailed explanation

.as('name') stores a reference; cy.get('@name') retrieves it. You can alias DOM elements, intercepted routes, fixtures and arbitrary values from cy.wrap.

cy.intercept('POST', '/api/orders').as('createOrder');
cy.fixture('user.json').as('user');
cy.get('[data-cy=submit]').as('submitBtn');

cy.get('@submitBtn').click();
cy.wait('@createOrder').its('response.statusCode').should('eq', 201);

Note that a DOM alias is re-queried when used, so it does not go stale — but aliases are cleared between tests, which is why setting them in before rather than beforeEach causes 'alias not found' errors.

Hard Common 1 minQ20 / 46

Q20.When should you write a custom command instead of a helper function?

Why interviewers ask this

Over-produced custom commands are a common review finding.

Detailed explanation

Write a custom command when the operation belongs in the command queue — it uses other cy.* commands, needs to appear in the command log, or is used across many spec files (cy.login(), cy.seedOrder()).

Write a plain function when the logic is synchronous and has nothing to do with the browser — building a payload, formatting a date, generating test data. Turning those into commands adds queue overhead and log noise for no benefit.

Cypress.Commands.add('login', (email, password) => {
  cy.session([email], () => {
    cy.request('POST', '/api/login', { email, password })
      .then(({ body }) => window.localStorage.setItem('token', body.token));
  });
});
Medium Common 1 minQ21 / 46

Q21.What are Cypress environment variables and how do you supply them safely?

Why interviewers ask this

Every real suite needs this; secrets handling is the part candidates skip.

Detailed explanation

Read with Cypress.env('KEY'). Values can come from cypress.config.js (env block — for non-secrets), a gitignored cypress.env.json, the CLI (--env key=value), or the OS as CYPRESS_KEY.

Precedence runs CLI > OS env > cypress.env.json > config file. Never commit credentials in the config file: anything shipped to the browser is visible in the runner, so keep genuinely sensitive values in CI secrets and prefer minting short-lived test tokens over storing passwords.

Medium Common 1 minQ22 / 46

Q22.How do you parameterise the same test across environments and data sets?

Why interviewers ask this

Data-driven testing in Cypress has a specific idiom.

Detailed explanation

Because the spec file is JavaScript, you loop at build time rather than using a runner feature:

const users = require('../fixtures/roles.json');
users.forEach(({ role, canDelete }) => {
  it(`${role} delete permission is ${canDelete}`, () => {
    cy.login(role);
    cy.visit('/orders');
    cy.get('[data-cy=delete]').should(canDelete ? 'exist' : 'not.exist');
  });
});

For environments, drive baseUrl from config per environment rather than branching inside tests. Keep the loop over a small, meaningful set — generating hundreds of near-identical tests slows CI without adding coverage.

Medium Common 1 minQ23 / 46

Q23.What is cy.task() and why would you need it?

Why interviewers ask this

The Node escape hatch; knowing it exists shows the candidate has done non-trivial setup.

Detailed explanation

cy.task() runs code in the Node process rather than the browser, so it can do things the browser cannot: query a database directly, read or write files, call an internal service that is not CORS-enabled, or generate a file to upload.

// cypress.config.js
setupNodeEvents(on) {
  on('task', { async resetDb() { await db.query('TRUNCATE orders'); return null; } });
}
// spec
cy.task('resetDb');

A task must return a value or null — returning undefined is an error, which catches most people once.

Medium Common 1 minQ24 / 46

Q24.How do you validate database state from a Cypress test, and should you?

Why interviewers ask this

Legitimately relevant in Cypress because of cy.task; the 'should you' half matters.

Detailed explanation

You can, via cy.task() calling a Node database client. It is genuinely useful for setup (seeding a known record) and for verifying side effects the UI never shows — an audit row, a queued job.

Be sparing about assertions on internal tables in UI tests: they couple the test to a schema that will change, and a failure tells you little about user impact. Prefer asserting through an API the product already exposes, and reserve direct database checks for cases where no such surface exists.

Confidence check

If you can confidently answer the Selectors, aliases and custom commands questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

4. Network control, fixtures and API testing

Medium Common 1 minQ25 / 46

Q25.What can cy.intercept() do that the older cy.route() could not?

Why interviewers ask this

Version awareness plus the core network API in one question.

Detailed explanation

cy.intercept operates at the proxy layer, so it handles all request types — fetch, XHR, page loads, static assets, fonts, images — whereas the removed cy.route only saw XHR.

It also supports dynamic request handlers, request-body modification, response delay and throttle, per-request matching on headers or query, and spying without stubbing (omit the response argument).

cy.intercept('GET', '/api/orders*', req => {
  req.headers['x-test-run'] = runId;
  req.reply(res => { res.setDelay(1500); });
}).as('orders');
Medium Common 1 minQ26 / 46

Q26.What is the difference between spying and stubbing with cy.intercept?

Why interviewers ask this

Basic but decisive — many candidates stub when they meant to observe.

Detailed explanation

Spying: cy.intercept('/api/orders').as('orders') — the real request goes through and you can assert on it afterwards. Stubbing: adding a response ({ fixture }, { statusCode, body } or req.reply()) — the request never reaches the server.

Spy when you want to synchronise on a real call or verify the payload the app sent. Stub when you need a state the backend will not reliably give you: an error, an empty list, a thousand rows, a slow response.

Medium Common 1 minQ27 / 46

Q27.How do you assert on the request payload the application sent?

Why interviewers ask this

Frequently needed for analytics and form-submission testing.

Detailed explanation
cy.intercept('POST', '/api/orders').as('create');
cy.get('[data-cy=submit]').click();
cy.wait('@create').then(({ request, response }) => {
  expect(request.body).to.deep.include({ sku: 'A-1', qty: 2 });
  expect(request.headers).to.have.property('authorization');
  expect(response.statusCode).to.eq(201);
});

Two things to watch: cy.wait('@alias') yields the first matching call, so for repeated requests you either wait multiple times or use cy.get('@create.all'); and interception matching is order-sensitive, with later definitions taking precedence.

Medium Common 1 minQ28 / 46

Q28.How do fixtures work and when do they become a liability?

Why interviewers ask this

Fixture drift is a real maintenance problem worth naming.

Detailed explanation

cy.fixture('orders.json') loads a file from cypress/fixtures; cy.intercept('/api/orders', { fixture: 'orders.json' }) serves it as the response.

The liability is drift: once every test asserts against a hand-written fixture, a backend field rename breaks production while the suite stays green. Mitigations that work in practice — generate fixtures from a real recorded response and refresh them periodically, validate fixtures against the API's schema in CI, and always keep at least one unstubbed end-to-end path per critical flow.

Medium Common 1 minQ29 / 46

Q29.How do you use cy.request() and how does it differ from cy.intercept()?

Why interviewers ask this

The two are regularly confused despite doing unrelated jobs.

Detailed explanation

cy.request() makes an HTTP call from the Node process — it bypasses the browser entirely, ignores CORS, and does not involve your application. It is the tool for setup, teardown and pure API assertions.

cy.intercept() observes or replaces calls the application makes.

cy.request('POST', '/api/orders', { sku: 'A-1' })
  .its('body.id')
  .then(id => cy.visit(`/orders/${id}`));

Note that cy.request automatically fails the test on a non-2xx status unless you pass failOnStatusCode: false, which you need when deliberately testing an error response.

Medium Common 1 minQ30 / 46

Q30.Is Cypress a reasonable tool for pure API testing?

Why interviewers ask this

Honest scoping question; both extreme answers are wrong.

Detailed explanation

For a modest set of endpoint checks alongside a UI suite, yes — cy.request plus Chai assertions is perfectly workable and you keep one report and one CI job.

As a primary API-testing platform it is a poor fit: you are booting a browser to make HTTP calls, there is no native schema-contract workflow, and the runtime cost per test is high compared with a plain HTTP test runner. Most teams keep Cypress for the browser and run API regression separately.

Hard Common 1 minQ31 / 46

Q31.How would you test that the UI handles a 429 rate-limit response correctly?

Why interviewers ask this

Concrete interception scenario with a realistic business requirement.

Detailed explanation
let calls = 0;
cy.intercept('GET', '/api/search*', req => {
  calls += 1;
  if (calls === 1) req.reply({ statusCode: 429, headers: { 'retry-after': '1' }, body: {} });
  else req.continue();
}).as('search');

cy.get('[data-cy=search]').type('invoice{enter}');
cy.contains('Too many requests').should('be.visible');
cy.wait(1100);                       // the Retry-After the API asked for
cy.get('[data-cy=retry]').click();
cy.get('[data-cy=result]').should('have.length.greaterThan', 0);

This is a case where a numeric wait is defensible: you are honouring a contract value the server returned, not guessing at rendering speed.

Medium Common 1 minQ32 / 46

Q32.How do you stop a third-party script (analytics, chat widget, ads) from destabilising tests?

Why interviewers ask this

Very common real cause of Cypress flakiness and slow load times.

Detailed explanation

Block or stub them at the network layer. cy.intercept with { statusCode: 204, body: '' } for the script URL, or use the blockHosts config option to drop entire domains for the whole run.

Two benefits beyond stability: page loads get noticeably faster, and you stop polluting real analytics with test traffic. Keep one dedicated test that does load the widget if its presence is a genuine requirement.

Confidence check

If you can confidently answer the Network control, fixtures and API testing questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

5. Sessions, state and architectural limits

Hard Common 1 minQ33 / 46

Q33.What is cy.session() and why was it introduced?

Why interviewers ask this

The main modern answer to slow, login-heavy suites.

Detailed explanation

cy.session(key, setupFn) runs the setup once, caches the resulting cookies, local storage and session storage, and restores them for every later test that requests the same key — including across spec files when cacheAcrossSpecs is set.

cy.session([email, role], () => {
  cy.request('POST', '/api/login', { email, password })
    .then(({ body }) => window.localStorage.setItem('token', body.token));
}, { validate: () => cy.request('/api/me').its('status').should('eq', 200) });

The validate option matters: without it a cached-but-expired session silently produces logged-out tests. With it, Cypress re-runs setup when validation fails.

Medium Common 1 minQ34 / 46

Q34.How do you manage cookies and local storage explicitly?

Why interviewers ask this

Still needed for feature flags, consent banners and partial state seeding.

Detailed explanation

Cypress exposes cy.setCookie, cy.getCookie, cy.clearCookies, and cy.clearLocalStorage; local storage itself is reachable via cy.window().its('localStorage') or directly inside a cy.then.

Typical uses: dismissing a cookie-consent banner by pre-setting its cookie so every test does not start by clicking it, and enabling a feature flag for one spec. With test isolation on, these must be set in beforeEach (or inside cy.session), because everything is cleared between tests.

Hard Occasional 1 minQ35 / 46

Q35.Why does Cypress restrict navigating to a different origin, and how do you handle it now?

Why interviewers ask this

The single most-cited Cypress limitation; current Cypress has a real answer.

Detailed explanation

The restriction comes from the in-browser architecture: the runner and the app share a browser context, and same-origin policy applies to it.

Current Cypress provides cy.origin(), which runs a block of commands in the context of another origin:

cy.origin('https://auth.example.com', { args: { email } }, ({ email }) => {
  cy.get('#email').type(email);
  cy.get('#next').click();
});

Two practical constraints: the callback is serialised, so it cannot close over outer variables (pass them via args), and custom commands are not available inside unless you re-register them. For routine tests, skipping the third-party screen by seeding a session is still faster.

Medium Occasional 1 minQ36 / 46

Q36.Cypress does not support multiple browser tabs. How do you test a flow that opens one?

Why interviewers ask this

A genuine limitation; interviewers want a workaround, not a complaint.

Detailed explanation

Test the contract rather than the tab. Practical approaches:

  • Assert the link's target and href, then visit that URL directly in the same tab.
  • Remove the target before clicking: cy.get('a').invoke('removeAttr', 'target').click().
  • Stub window.open with cy.stub and assert it was called with the expected URL.

Be explicit in the interview that this is a workaround: you are verifying the application's intent, not the browser's tab behaviour. If genuinely multi-tab interaction is core to the product, that is a legitimate reason to choose a different tool for those specific tests.

Medium Occasional 1 minQ37 / 46

Q37.What are the practical limits with iframes in Cypress, and how do you work around them?

Why interviewers ask this

Payment and embedded-widget flows make this a real interview scenario.

Detailed explanation

There is no first-class frame locator. You reach into the frame's document yourself:

cy.get('iframe[title="Card"]')
  .its('0.contentDocument.body').should('not.be.empty')
  .then(cy.wrap)
  .find('#card-number').type('4242424242424242');

Caveats: the frame must be same-origin or the document is inaccessible; you must wait for the frame to actually load before wrapping; and the wrapped body does not get Cypress's usual retry behaviour on the initial access. Many teams use the cypress-iframe plugin to hide this boilerplate, or stub the payment provider entirely and test the card form separately.

Medium Occasional 1 minQ38 / 46

Q38.What is Cypress component testing and when is it the better choice than E2E?

Why interviewers ask this

Component testing is a major part of modern Cypress and often overlooked.

Detailed explanation

Component testing mounts a single React/Vue/Angular/Svelte component in the real browser with the same command API, no server required. You get real rendering and real events without the cost of a full app boot.

Use it for the layer below your journeys: form validation, conditional rendering, prop and state permutations, edge cases in a data table, accessibility of a single control. Keep E2E for the flows that only break when routing, auth and the backend meet. The practical effect is a much smaller, faster E2E suite.

Hard Occasional 1 minQ39 / 46

Q39.How do you organise a Cypress project so it stays maintainable?

Why interviewers ask this

Framework design; Cypress's idioms differ from POM-heavy stacks.

Detailed explanation

Cypress does not need a heavy Page Object layer — custom commands and small helper modules usually serve better. A structure that works:

  • cypress/e2e/ grouped by user journey, not by page.
  • cypress/support/commands.js — cross-cutting commands (login, seed, apiCreateOrder) with TypeScript declarations.
  • cypress/fixtures/ — small, refreshed, schema-validated.
  • Selector constants co-located with the feature rather than a global selectors file that becomes a dumping ground.

Conventions to enforce in review: no fixed cy.wait(ms), no force: true without a comment, and setup through API rather than UI wherever the UI is not the thing under test.

Confidence check

If you can confidently answer the Sessions, state and architectural limits questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

6. CI, parallelisation and debugging

Medium Occasional 1 minQ40 / 46

Q40.How do you run Cypress in CI, and what are the common first-time failures?

Why interviewers ask this

Everyone claims CI experience; the failure modes reveal who has actually done it.

Detailed explanation

cypress run executes headlessly and records video by default. Use the official cypress/included Docker image or the setup action to get the required system libraries.

First-time failures, in rough order of frequency: the app under test is not up yet (fix with start-server-and-test or a health-check wait); missing OS dependencies for the browser; the default 1000×660 headless viewport differing from the developer's screen so responsive layouts change; and time-zone differences producing date mismatches.

Medium Occasional 1 minQ41 / 46

Q41.How does parallelisation work in Cypress and what is the unit of distribution?

Why interviewers ask this

Distinct from other runners — Cypress balances whole spec files.

Detailed explanation

Cypress parallelises at the spec file level across machines, coordinated by a recording service (Cypress Cloud or a compatible alternative) that hands each machine the next spec based on previous durations.

The consequence for design: one enormous spec file cannot be split, so it becomes the critical path and caps your total speedup. Keeping specs roughly balanced in duration matters more than having few files. Without a coordination service you can still shard manually by passing different --spec globs to each machine, but you lose duration-based balancing.

Medium Occasional 1 minQ42 / 46

Q42.Which artifacts does Cypress produce on failure and how do you use them?

Why interviewers ask this

Debugging workflow; screenshots-only answers are shallow.

Detailed explanation

By default: a screenshot at the moment of failure, and a video of the entire spec in cypress run. Both should be uploaded from CI unconditionally.

The most useful diagnostic is the command log embedded in the video, which shows exactly which command failed and what came before it. Add cy.screenshot() at meaningful checkpoints for long journeys, and disable video for stable suites where the storage cost outweighs the value.

Medium Occasional 1 minQ43 / 46

Q43.What debugging tools does Cypress give you during development?

Why interviewers ask this

The in-browser model gives Cypress genuinely distinctive debugging affordances.

Detailed explanation
  • Time-travel in the runner — hover any command in the log to see the DOM snapshot at that moment. This is the single most useful feature.
  • .debug() — pauses and exposes the current subject in the console.
  • cy.pause() — halts the queue so you can step command by command.
  • debugger inside a .then() — a real breakpoint, because your code runs in the browser.
  • The browser DevTools console, where the last command's subject is available as a variable.
Hard Occasional 1 minQ44 / 46

Q44.A spec passes on its own but fails when the whole suite runs. How do you diagnose it?

Why interviewers ask this

Order-dependence is the most common Cypress-specific flakiness pattern.

Detailed explanation

It is almost always shared state. Check, in order: data created by an earlier spec that this one assumes or collides with; a cached cy.session whose validate is missing so it restores an expired login; a feature flag or cookie set in one spec and relied on by another; and a machine-level resource such as a single test account used by two specs in parallel.

Reproduce by running the pair rather than the whole suite, then bisect. The permanent fix is to make each spec create the state it needs with uniquely identified data — not to add ordering constraints, which just push the failure into the future.

Medium Occasional 1 minQ45 / 46

Q45.Your Cypress suite takes 50 minutes and has intermittent failures. What do you change first?

Why interviewers ask this

Prioritisation scenario; there are several valid orderings but a wrong one (parallelise first).

Detailed explanation

Stability before speed, because parallelising an unstable suite just produces failures faster.

Order that tends to pay off: replace UI login with cy.session or API login (usually the single largest time saving); remove fixed cy.wait(ms) calls and replace them with alias waits or retrying assertions; stub or block third-party scripts; move component-level checks out of E2E into component tests; split oversized spec files so parallelisation can actually balance them; and only then add machines.

Medium Occasional 1 minQ46 / 46

Q46.When would you honestly recommend a different tool over Cypress?

Why interviewers ask this

Panels value candidates who can scope a tool rather than defend it.

Detailed explanation

When the requirement collides with the architecture rather than the API: heavy multi-tab or multi-window interaction; genuine Safari/WebKit coverage as a release gate; a large native-mobile surface; a suite dominated by API contract testing; or a need for many browser sessions per test (for example real-time collaboration between two users).

Cypress remains a strong choice where its strengths dominate: fast feedback for front-end teams, excellent debugging, component testing alongside E2E, and a low barrier for developers who already live in the browser.

RelatedQ44
Confidence check

If you can confidently answer the CI, parallelisation and debugging questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Quick revision

  1. Q1: Cypress commands are not promises. What are they, and why does the distinction matter — Calling cy.get('#name') does not perform anything.
  2. Q2: What is 'the subject' in Cypress and how does it flow through a chain — Each command yields a subject to the next one.
  3. Q3: What does .then() do in Cypress, and how is it different from .should() — .then() runs your callback once with the current subject and does not retry.
  4. Q4: What is the difference between .then() and .should() with a callback — .should(callback) retries the entire callback until it stops throwing.
  5. Q5: Why can't you use a plain if/else on the state of the DOM in Cypress — Because at the moment your if evaluates, the queue has not run — and even inside a .then() , the DOM may not have finished settling, so the branch you take is a race.

Frequently asked questions

1.Is Cypress still worth learning given Playwright's growth?
<p>Yes — plenty of teams run large Cypress suites and hire for them, and Cypress component testing has no exact equivalent elsewhere. The interview risk is different: panels increasingly ask why you would pick one over the other, so be ready to answer on architecture (in-browser vs out-of-process) rather than feature lists.</p>
2.Do Cypress interviews expect knowledge of cy.route or the old API?
<p>No. <code>cy.route</code> was removed and mentioning it as your primary network tool dates your experience. Know that it existed, know <code>cy.intercept</code> replaced it, and be able to say what changed — proxy-level interception covering fetch and static assets rather than XHR only.</p>
3.What is the most common Cypress mistake candidates make in a live coding round?
<p>Treating commands as promises — writing <code>const el = cy.get(...)</code> or <code>await cy.get(...)</code> and then using the value. The second most common is breaking retry-ability by putting an assertion inside <code>.then()</code> instead of <code>.should()</code>.</p>
4.How much JavaScript do I need for a Cypress role?
<p>Enough to be comfortable with callbacks, closures, array methods and modules. You do not need deep async/await knowledge — in fact the command queue means you use it less — but you do need to understand why a value from inside a callback is not available outside it.</p>
5.Should I mention Cypress limitations in an interview?
<p>Yes, with the workaround attached. Saying 'Cypress has no multi-tab support, so I assert the href and visit the URL directly, and I'd flag it as a tool-fit question if the product is genuinely multi-tab' reads as experienced. Claiming Cypress can do everything reads as untested.</p>

Cypress jobs hiring now

Live, indexable Cypress openings — updated daily in Jobs Radar.

Browse all QA jobs on Jobs Radar

Loading current openings…

Home