Extensive List of Cypress Interview QAns — Continued….

sheelu ksheelu k
12 min read

Q: What is Cypress and why would you use it?

A:

Cypress is a modern end-to-end (E2E) and component testing framework.

It operates directly within the browser’s event loop,

  • providing deep insights and control.

  • delivers auto-waiting,

  • time-travel debugging, and the

  • ability to stub network requests,

resulting in faster and more reliable tests compared to traditional WebDriver-based tools.

Why Cypress :

  • In-browser execution → no remote WebDriver hop.

  • Auto-wait & retries → fewer sleep()s.

  • cy.intercept() → deterministic API stubs in CI.

  • Time-travel snapshots, screenshots/videos out-of-box.

  • Component + E2E; Chrome/Edge/Firefox coverage.

Trade-offs:

  • Limited multi-tab/cross-origin;

  • not for native mobile;

  • WebKit/Safari limited.


Q: What are the key advantages of Cypress over other testing tools?

A:

  • Real-time browser preview and time-travel debugging

  • Automatic waiting (no need for explicit waits)

  • Network traffic control and stubbing

  • Screenshots and videos on failures

  • Easy setup with zero configuration

  • Consistent results across different environments:

Cypress runs inside the browser, so you get live preview, auto-waiting, and tight network control, which makes tests fast, debuggable, and stable.


Q: How do you handle asynchronous operations in Cypress?

A:

Cypress automatically handles async operations through its command queue.

Commands are automatically chained and waited for

Key Points:

  • Automatic Command Chaining: Cypress enqueues commands and executes them sequentially, handling async behavior natively.

  • Built-In Retries: Automatically retries commands until conditions are met or timeouts occur, reducing flakiness.

  • No Manual Promises: Unlike traditional JavaScript, no need for .then() or async/await for most operations.

  • Waiting for Async Events: Implicitly waits for elements, network requests, or assertions to resolve.

Press enter or click to view image in full size

  • Custom Timeouts: Override default timeouts if needed for specific async operations.

  • Commands are Queued, not Executed Immediately: When a command like cy.get() is called, it doesn't immediately find the element. Instead, it's placed in a queue.

  • Network sync: cy.intercept() + cy.wait('@alias') aligns UI with XHR/fetch.

  • Time control: cy.clock() / cy.tick() for timers and debounce flows.

Caveats to respect:

  • Don’t mix Cypress commands with plain await—stay in-chain or cy.wrap(...).

  • Commands don’t return assignable values; use aliases or .then(...).

  • Tune defaultCommandTimeout for slow endpoints.

Press enter or click to view image in full size


Q) How do you organize your Cypress tests?

A)

  • Group specs by feature/domain,

  • keep consistent names,

  • centralize helpers in support/, and

  • use fixtures for deterministic data.

Press enter or click to view image in full size

Conventions that keep tests readable:

  • Spec naming: <feature>.<behavior>.cy.ts (e.g., login.happy-path.cy.ts).

  • Selectors: stable data-testid attrs; avoid styling-driven CSS.

  • Setup: beforeEach for common cy.visit/seed; keep tests independent.

  • Network: fixtures + cy.intercept() for fast, deterministic CI.

  • Reuse: move flows (e.g., login) into support/commands.ts.

Reality check / caveats:

  • Don’t over-nest folders — 2 levels is usually enough.

  • Avoid shared state across specs; prefer cy.session() for repeat logins.

  • Keep fixtures small; generate data on demand if variety explodes.

Handy Snippet:

Press enter or click to view image in full size


Q) How do you mock API responses in Cypress?

A)

Mocking API responses in Cypress is a powerful way to test your application’s front end in isolation from the backend. This allows for faster, more reliable, and deterministic tests, as you can control the data and network conditions. The primary command for this is cy.intercept().

Use cy.intercept() to match requests, stub the response, and wait on an alias for deterministic UI tests.

💻 Using cy.intercept()

The cy.intercept() command lets you control network requests by intercepting them and responding with your own data. This means you can:

  • Stub a Response: Intercept a request and immediately send back a predetermined response, such as a fixture file.

  • Manipulate Requests: Modify requests as they are sent out.

  • Wait for Requests: Ensure a test doesn’t proceed until a specific network call has been made and completed. This is crucial for synchronizing tests with asynchronous API calls.

What I actually do:

  • Fixture stubs: serve stable JSON from cypress/fixtures/.

  • Dynamic handlers: modify requests/responses in-code for edge cases.

  • Sync UI & network: Always cy.wait('@alias') before asserting.

  • Failure/latency sims: force errors or add delays to exercise retries.

  • Stable matching: use globs/regex or route-matcher objects (method, path, query).

Press enter or click to view image in full size

Edge cases / caveats:

  • Don’t over-stub critical journeys — keep at least one end-to-end path real.

  • Match precisely (e.g., **/api/users*) to avoid accidental intercepts.

  • Update fixtures when API contracts change to prevent “green but wrong.”


Q) What are Cypress Custom Commands?

A)

Cypress custom commands are functions that you create to extend Cypress’s API (Cypress.Commands).

They allow you to encapsulate a series of actions into a single, reusable command, making your tests more readable, concise, and maintainable

When to Use Custom Commands

You should use custom commands for any action that is repeated across multiple tests. This follows the Don’t Repeat Yourself (DRY) principle.

Common use cases include:

  • Authentication and Login: Instead of writing the login steps (cy.visit(), cy.get(), cy.type()) in every test file, you can create a single cy.login() command.

  • Complex UI Interactions: For multi-step interactions like filling out a complex form or navigating a modal, a custom command simplifies the test and hides the implementation details.

  • Data Stubbing: Encapsulate the cy.intercept() logic for common API responses into a command like cy.stubApi().

Example

Here’s how you define and use a simple login custom command.

  1. Define the Command in cypress/support/commands.js:

Press enter or click to view image in full size

2. Use the Command in a Test File:

Press enter or click to view image in full size


Q: How do you debug failing Cypress tests?

A)

Cypress provides powerful tools to debug failing tests efficiently,

Lean on time-travel + artifacts (screenshots/videos), interactive runner/devtools, and targeted pauses/logs to isolate the failure fast.

Triage checklist :

  • Time-travel in Runner: click each command to inspect DOM, props, and console at that moment.

  • .debug() / cy.pause() to halt where it breaks and poke around.

  • Screenshots & videos: review CI artifacts; add cy.screenshot() at tricky points.

  • Browser DevTools: run with --headed, open console/network, inspect app state.

  • cy.log() / alias data: print payloads; log intercepted responses.

  • Tighten selectors & waits: assert on visible/stable elements, not transient ones.

Pro tips:

  • Sync with network: cy.intercept() + cy.wait('@alias') before UI assertions.

  • Prefer data-testids; avoid brittle CSS/XPath.

Press enter or click to view image in full size


Q) How do you configure Cypress for different environments?

A)

Cypress is highly configurable to handle different environments like development, staging, and production

Cypress allows configuration for different environments using cypress.config.js

Use env-driven config (baseUrl + env), optionally per-env config files, and CLI/CI overrides—no code changes between envs.

⚙️ Using cypress.config.js and Environment Variables

The cypress.config.js file is where you define all global settings for your project. To manage different environments, you can define configuration objects or use environment variables to dynamically change settings at runtime.

  • cypress.config.js: This file is the central hub for all configuration. You can define global settings like baseUrl, viewportWidth, and video settings.

  • Environment Variables: The best practice is to use environment variables to handle secrets and environment-specific settings. This keeps sensitive information out of your codebase. Cypress automatically loads environment variables prefixed with CYPRESS_ and makes them available within your configuration and tests.

Approach:

  • Single config, env overrides: read from OS env (CYPRESS_*) and config.env.

  • Per-env files (optional): run with --config-file cypress.config.staging.ts.

  • CLI flags: --config baseUrl=... and --env ENV=staging,username=ci-user.

  • Secrets: put in CI secrets or cypress.env.json (gitignored).

  • In tests: always Cypress.env('apiUrl'); keep cy.visit('/') relative to baseUrl.

Professional guardrails:

  • Don’t hardcode creds; prefer CYPRESS_ OS vars → Cypress.env(...).

  • Keep env logic in config, not scattered in specs.

  • Ensure one true E2E path points to real services in at least one pipeline.

Configuration File: Use cypress.config.js to define environment-specific settings like baseUrl or custom env variables.

Press enter or click to view image in full size

  • Accessing Variables: Use Cypress.env() in tests to retrieve environment-specific values.

cy.visit(Cypress.env(‘baseUrl’));

Press enter or click to view image in full size


Q) What is the purpose of cypress.json vs cypress.config.js?

A)

cypress.config.js is the modern configuration file for Cypress (version 10.0 and above), and it completely replaces the older cypress.json file,

offering dynamic JavaScript-based configuration and improved TypeScript support,

while supporting separate setups for end-to-end (E2E) and component testing.

moving from a static JSON file to a dynamic JavaScript file.

  • cypress.json (Legacy): Used in Cypress versions

  • cypress.config.js (Modern): Introduced in v10, uses JavaScript for dynamic, programmatic configuration.

Press enter or click to view image in full size

  • Separate Test Types: Configures E2E and component testing independently in one file.

  • JavaScript-based Configuration: As a JavaScript file, cypress.config.js allows for dynamic and conditional logic within your configuration. You can use variables, environment checks (process.env), and functions to customize settings, which was not possible with the static cypress.json.

Then vs Now (cheat sheet):

  • Old (cypress.json): static JSON; single test type.

  • New (cypress.config.js/ts): JS/TS, defineConfig, e2e & component blocks, programmatic tweaks.

  • Plugins moved to setupNodeEvents(on, config).

  • Support files/paths live under the respective test-type key.

Why it matters:

  • TypeScript-friendly (autocomplete & types).

  • Dynamic env/overrides per CI/env without hacks.

  • One place for both E2E and Component test setup.

Heads-up:

  • cypress.json is deprecated in v10+ projects.

  • Many top-level keys now sit under e2e or component.

Press enter or click to view image in full size


Q) What’s the recommended approach for element selection in Cypress?

A)

The recommended approach for selecting elements in Cypress is to use data attributes (e.g., data-cy, data-testid). This method creates robust and stable tests that are not affected by avoiding fragile selectors like CSS classes or IDs or JavaScript changes, which are common during development.

Comparison of Selectors

Here’s a quick comparison demonstrating why data attributes are the best practice:

  • Best Practice ✅: Use data-cy or data-testid. This selector is the most stable and intentional.

  • Avoid ❌: Don’t rely on CSS classes (.btn-primary). These can easily change for styling reasons, causing your test to fail.

  • Avoid ❌: Don’t rely on IDs (#submit-button) unless you're absolutely sure they're unique and will never change. IDs are often generated dynamically or reused.

Nice-to-have (ergonomic helper):

Press enter or click to view image in full size


Q) How do you handle elements that are not immediately visible in Cypress?

A)

Cypress is designed to handle elements that are not immediately visible by automatically waiting for them to become available and actionable. This built-in behavior is one of its core strengths.

When an element is initially hidden, you can use explicit assertions to verify its state and then perform actions once it becomes visible.

The Cypress Waiting Mechanism

  • Automatic Retries: By default, Cypress will automatically retry get, contains, and other commands for a short period (typically 4 seconds) until the element is found and is actionable. This eliminates the need for manual sleep() commands, making tests more stable.

Cypress retries commands until elements meet conditions or timeout, no manual waits needed.

  • Explicit Assertions: You can use .should() assertions to explicitly command Cypress to wait for a certain condition to be met before proceeding. This is the recommended approach for handling elements that appear after an animation or an asynchronous event.

Check if an element exists in the DOM, even if not visible, with .should(‘exist’).

.should(‘be.visible’) => to wait for elements to appear

or

.should(‘not.be.visible’) => for hidden ones.

Press enter or click to view image in full size

  • Scroll into View: Use .scrollIntoView() for elements hidden off-screen.

Press enter or click to view image in full size

Playbook:

Assert the right thing:

\=> Appears later → should('be.visible')

\=> Present but hidden → should('exist').and('not.be.visible')

  • Sync first: cy.intercept(...).as('req')cy.wait('@req') before UI checks.

  • Kill spinners/overlays: wait for spinner/backdrop to not exist.

  • Offscreen control: .scrollIntoView() before click.

  • State gates: assert not.be.disabled / have.attr etc. before interacting.

Caveats & tips:

  • Avoid click({ force: true })—use it only after proving the element can’t become visible.

  • If content is conditional, assert both paths: visible when expected, not.exist when not.

  • For slow transitions, prefer app signals (aliases/overlays) over arbitrary wait().

Press enter or click to view image in full size


Q) How do you interact with iframes in Cypress?

A)

Cypress has limited native iframe support, but you can interact with iframes using .then() to access their content or by leveraging plugins/custom commands for reliable interactions.

Interacting with an iframe in Cypress requires a workaround because iframes are treated as entirely separate documents. Cypress commands are designed to operate on the main application’s DOM, so you must first gain access to the iframe’s content before running your standard commands

Accessing iframe Content: Use .then() to extract the iframe’s DOM and interact with elements inside.

Press enter or click to view image in full size

Method: The .contents() Workaround

The most common and effective method is to use a combination of .contents(), .find(), and cy.wrap().

  1. Find the Iframe: Use a cy.get() command to select the iframe element itself.

  2. Access the Iframe’s Content: Use the .then() method to handle the result of the cy.get(). Inside the .then() callback, use .contents() to access the document of the iframe and .find('body') to get its body element.

  3. Wrap the Body: Use cy.wrap(body) to create a new Cypress subject out of the iframe's body. This allows you to chain Cypress commands on the content of the iframe.

After wrapping the body, you can use any standard Cypress commands like cy.find(), cy.get(), or cy.click() to interact with elements inside the iframe.

Code Example

This snippet demonstrates the entire process of getting into an iframe and interacting with an element within it.

Press enter or click to view image in full size

  • Plugins for Simplicity: Use cypress-iframe plugin to simplify iframe handling.

Press enter or click to view image in full size

  • Custom Commands: Create reusable commands for frequent iframe interactions.

Press enter or click to view image in full size

or

Press enter or click to view image in full size

When origins differ (reality check):

  • You cannot poke into a cross-origin iframe’s DOM (SOP).

  • Test the iframe directly by visiting its URL (optionally with cy.origin(...)), or validate via network contracts/stubs.

  • If possible, host the iframe under the same domain in test envs.

Pro tips:

  • Assert it’s ready: .its('0.contentDocument.body').should('not.be.empty').

  • Prefer data-testid inside the iframe content.

  • Avoid hacks like force: true—fix visibility/overlay first.


Disclaimer:

Used it in my own learning. But Some ideas are also help from ChatGPT for this guide.

Happy Learning,

Suseela :)

0
Subscribe to my newsletter

Read articles from sheelu k directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sheelu k
sheelu k