Talently
Talently
Cypress

Cypress

The end-to-end testing framework for modern web applications

Cypress is an end-to-end testing framework specifically designed for modern web applications. Unlike Selenium-based solutions, Cypress runs directly in the browser with full access to the application, offering a smooth development experience with real-time reloading, visual debugging, and an intuitive API. It supports E2E tests, integration tests, and component tests.

JavaScriptTypeScriptE2ETesting

Market demand

Cypress is the most widely adopted E2E testing framework in the JavaScript ecosystem, with high demand in teams working with React, Vue, or Angular that want to automate user tests without Selenium's complexity.

Most popular E2E framework in JavaScriptHigh demand in modern frontend teamsStandard in CI/CD for web applications

Technical requirements

Intermediate

Requires mastery of JavaScript or TypeScript and understanding of testing concepts like assertions, fixtures, and mocking. Familiarity with the application under test and with CI/CD tools is important for integrating Cypress into continuous delivery pipelines.

Use cases

Real Projects

Cypress is used to develop:

  • E2E tests of critical user flows like registration and checkout
  • Integration tests of React, Vue, or Angular components
  • Automated regression tests in CI/CD pipelines
  • API tests with cy.request to validate endpoints

Types of Company

Cypress is adopted by:

  • Startups with web products that need regression coverage
  • Teams with agile development that automate acceptance tests
  • Companies with CI/CD where E2E tests are a deployment gate
  • Agencies with web projects where the client requires test coverage

Production Scenarios

Cypress is widely used in production environments such as:

  • CI/CD pipelines with Cypress in GitHub Actions or CircleCI
  • Smoke tests after each production deployment
  • Visual regression tests with screenshots
  • Recording of failed tests with video for debugging

Scalability

Cypress offers multiple mechanisms to scale applications:

  • Cypress Cloud for test parallelization across multiple machines
  • Test grouping by tags for selective execution
  • Fixtures and custom commands to reduce duplication
  • Integration with Slack and Jira for failure notification

Advantages and Disadvantages

Advantages

Execution in the same browser process with direct access to the DOM and app APIs.

Time-travel debugging with snapshots of each executed command.

Automatic test reloading and interactive development experience.

Disadvantages

Limited support for multiple tabs and cross-domain in the same test.

Does not support multiple browsers simultaneously in the same test.

E2E tests are inherently slower and more fragile than unit tests.

Comparison

Advantages of Playwright

  • Native support for multiple tabs and cross-domain
  • Parallel tests by default with better performance
  • Better support for mobile applications with emulated devices

Considerations

Playwright is Microsoft's modern alternative with better capabilities for complex multi-tab and multi-domain scenarios. Cypress has a better interactive development experience and greater adoption in the JavaScript frontend ecosystem.

Basic questions

Cypress runs directly in the browser with access to the DOM and application APIs, offering better reliability without Selenium's synchronization issues. The development experience is significantly better with automatic reloading, time-travel debugging, and a fluent API without setup boilerplate.
Cypress is preferable when the team already has experience with it, the project is a SPA without requirements for multiple tabs or cross-domain, and the interactive development experience is valued. Playwright is preferable when tests across multiple tabs, better native parallelization, or advanced mobile capabilities are needed.
Cypress covers the top of the pyramid with E2E tests that verify complete user flows and the middle layer with component integration tests. It is complemented by Jest or Vitest for unit tests at the base of the pyramid. E2E tests are the slowest and most expensive to maintain so they should cover critical flows and not replace unit tests.
They are custom commands that extend Cypress's API with project-specific reusable actions like cy.login(), cy.createUser(), or cy.fillForm(). They are defined in commands.js and used across all tests, reducing code duplication and making tests more readable and maintainable.
Cypress uses a queued command system that executes sequentially with automatic retry until the element exists and meets the condition, or until the timeout expires. No await or explicit callbacks are needed as Cypress manages asynchrony internally, making the code more readable.
They are static data files in JSON or JavaScript format that provide reusable test data for tests. They are loaded with cy.fixture() and allow centralizing test data separately from test code, facilitating maintenance when data changes and allowing reuse across multiple tests.
By running cypress run in headless mode in the pipeline, configuring environment variables for the application URL in each environment, using Cypress Cloud for parallelization and result recording, configuring retries for tests that fail due to network instability, and setting Cypress results as a deployment gate.
For E2E tests of complete user flows in SPAs with React, Vue, or Angular, component integration tests in a real browser, API tests with cy.request that verify the backend contract, and visual regression tests with screenshots that detect unintended UI changes.

Technical questions

By creating classes or modules that encapsulate each page's selectors and actions in descriptively named methods. Tests use Page Object methods instead of directly accessing the DOM, making tests more readable and centralizing the impact of UI changes in Page Objects instead of across multiple tests.
Using cy.intercept() to intercept HTTP requests by URL or method, being able to return mocked responses with fixtures, modify the real response, or add delays to simulate latency. It allows testing error states, slow responses, or specific data without depending on the real backend, making tests faster and more predictable.
By programmatically setting the authentication state with cy.request() to obtain the token and setting it in localStorage or cookies with cy.setCookie(), or using a custom cy.login() command that calls the login API directly without going through the UI. This makes tests faster and less fragile than navigating through the login form in each test.
By configuring Cypress with the devServer from Vite, Webpack, or the project's bundler, mounting individual components with cy.mount(), and testing their behavior in isolation in a real browser. It is useful for components with complex behavior that depends on the real browser environment like drag and drop or Canvas APIs.
Using .as('aliasName') to create an alias to an element, an interception, or a fixture, and accessing it later with cy.get('@aliasName'). Aliases persist during the test and allow referencing elements or data created in previous steps without having to search for or redefine them.
Using the cypress-axe plugin that integrates axe-core with Cypress. The plugin is installed, axe is injected with cy.injectAxe() after loading the page, and the analysis is run with cy.checkA11y() which fails the test if it finds accessibility violations according to the configured WCAG rules.
By creating the necessary data for each test in beforeEach with cy.request() calling backend setup APIs, or using database commands to reset state. Sharing state between tests is avoided since execution order may vary and tests must be independent and executable in any order.
By reviewing the videos and screenshots recorded by Cypress in CI, adding cy.log() for traceability in the test, checking for race conditions with network requests using cy.intercept() to explicitly wait for responses, verifying if there are timing differences between environments with waitFor, and reviewing if selectors are sufficiently specific.

Advanced questions

By organizing tests by feature or business domain in folders, using Page Objects or App Actions to abstract UI interactions, defining custom commands for common actions like authentication and data creation, using tags to classify tests by criticality and speed, and separating smoke tests from full regression tests.
Using plugins like cypress-image-snapshot or integrating with Applitools or Percy that compare screenshots with approved baselines. Visual tests are configured to capture components or full pages after specific actions, differences are reviewed in the service dashboard, and intentional changes are approved by updating the baseline.
By disabling CSS animations in the test environment with a global command that adds a CSS class setting transition-duration and animation-duration to zero, using cy.wait() only when essential and preferring cy.intercept().as().wait() to wait for specific network operations, and verifying state conditions with assertions instead of fixed timeouts.
Using Cypress Cloud with the --parallel flag that distributes specs among available workers based on each spec's duration history. The number of parallel machines is configured in the CI pipeline and Cypress Cloud automatically balances the load. Alternatively, specs are manually divided among parallel jobs in the pipeline.
By first mapping the critical business flows like registration, authentication, checkout, or core product actions, prioritizing by impact and risk, starting with smoke tests that cover the happy path of each flow, gradually adding the most frequent edge cases and error flows, and measuring critical functionality coverage instead of code coverage.
By running smoke tests on every PR as a mandatory check, full regression tests on merges to main, making tests part of the Definition of Done for new features, integrating results into the team dashboard with Slack notifications for failures, and rotating the responsibility of maintaining tests among developers so it's not solely QA's responsibility.

Common interview mistakes

Choosing Cypress without being able to articulate its advantages and limitations compared to Playwright reflects a lack of judgment. Knowledge of when Playwright's multi-tab capabilities and better parallelization justify its greater complexity over Cypress's better interactive experience is expected.
Selecting elements with cy.get('.btn-primary') or fragile DOM paths generates tests that break with any style or structure change. Using data-cy or data-testid attributes specific for testing, or selectors based on accessible text like labels and roles is expected.
Tests that depend on the real backend state are slow, non-deterministic, and break for reasons unrelated to the code under test. Not knowing cy.intercept for mocking responses reflects inexperience writing maintainable E2E tests.
Navigating through the full login flow in each test makes the suite slow and fragile. Not knowing how to programmatically set authentication state reflects inexperience optimizing Cypress test suites in real projects.
Having Cypress tests that only run manually locally without CI integration reflects not having implemented Cypress in a real production project. Knowledge of how to configure headless mode and video and screenshot artifacts in CI is expected.
Not knowing that Cypress can do both complete E2E tests and individual component tests reflects not following the framework's evolution. Knowledge of when to use each modality based on which level of the testing pyramid needs to be covered is expected.