1. What is Cypress? How is it different from Selenium?
Cypress is a next-generation front-end testing tool built for the modern web. Unlike Selenium, which operates outside the browser and communicates through the WebDriver protocol, Cypress runs directly inside the browser alongside the application code.
Deep Dive Explanation
This architectural difference means Cypress has native access to the DOM, local storage, network requests, and window objects. This results in faster execution, built-in automatic waiting, and consistent test results without the flakiness often associated with Selenium's asynchronous network calls.
2. Can you explain Cypress architecture?
Cypress executes its tests within the same run-loop as your application. It runs a Node.js server in the background, while the tests execute inside the browser. The Node server and browser communicate using WebSockets.
Deep Dive Explanation
Because Cypress runs inside the browser, it can intercept network requests, stub responses, and modify application state synchronously. The Node server handles tasks that require higher privileges, like reading from the file system, taking screenshots, or connecting to databases.
3. What are Cypress commands? Why are they asynchronous?
Cypress commands (like cy.get, cy.click) are the building blocks of tests. They don't execute immediately; instead, they are enqueued to be run sequentially later. Behind the scenes, Cypress commands are essentially asynchronous promises.
Deep Dive Explanation
By queuing commands, Cypress manages the execution order perfectly and can automatically retry assertions until they pass or time out. This design eliminates the need for explicit waits or thread sleeps, solving the synchronization issues common in other tools.
// Commands are queued, not executed sequentially right away
cy.get('.btn').click()
// Even though it looks synchronous, Cypress orchestrates the execution4. How does Cypress handle waiting for elements?
Cypress has built-in 'Auto-Waiting'. It automatically waits for elements to exist in the DOM, become visible, become actionable (not disabled, not covered), and finish animating before it executes a command like clicking or typing.
Deep Dive Explanation
You almost never need to use explicit waits like `cy.wait(5000)` or thread sleeps. Cypress will continuously retry querying the DOM until the element reaches the actionable state or until the default command timeout (usually 4 seconds) is reached.
5. What are fixtures in Cypress? How do you use them?
Fixtures are external files (usually JSON) that store static mock data. They are used to stub network responses, provide test data for form inputs, or mock application state, keeping your test files clean and data-driven.
Deep Dive Explanation
Using fixtures ensures your tests are not dependent on live backend data, making them faster and more reliable. You load them using `cy.fixture('filename.json')`.
// 1. Store user.json in the cypress/fixtures folder
// 2. Use it in your test:
cy.fixture('user.json').then((userData) => {
cy.get('#username').type(userData.username);
});
// Or use it in an intercept:
cy.intercept('GET', '/api/users', { fixture: 'user.json' });6. Explain the purpose of the cypress configuration file.
The Cypress configuration file (cypress.config.js or ts in v10+, previously cypress.json) stores global project settings. It defines parameters like baseUrl, default command timeouts, viewport dimensions, environment variables, and folder structures.
Deep Dive Explanation
This file acts as the single source of truth for the project's execution environment. Setting a `baseUrl` here is a critical best practice because it speeds up the initial `cy.visit()` and simplifies test URLs.
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
defaultCommandTimeout: 5000,
viewportWidth: 1280,
viewportHeight: 720,
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
})7. How do you write a test to check if a button is disabled?
You use the `should` assertion with the Chail-jQuery matcher `be.disabled`.
Deep Dive Explanation
Cypress bundles Chai and jQuery, giving you a rich syntax for assertions. You can chain `.should('be.disabled')` directly to the `cy.get()` command.
// Asserting the button is disabled
cy.get('#submit-btn').should('be.disabled');
// Asserting the button is NOT disabled
cy.get('#submit-btn').should('not.be.disabled');8. How do you handle API calls in Cypress tests?
Cypress handles API calls using `cy.request()` to make direct HTTP requests, and `cy.intercept()` to spy on or stub network traffic initiated by the browser application.
Deep Dive Explanation
`cy.request()` is ideal for fast data setup (like creating a user before a test) or API testing because it bypasses the UI completely. `cy.intercept()` is used during UI tests to mock backend responses, simulating different application states (like a 500 server error).
9. What is the use of cy.intercept()? Explain with an example.
`cy.intercept()` is used to spy on, stub, or modify network requests and responses made by the browser. It allows you to simulate backend behavior without needing a real server.
Deep Dive Explanation
You can use it to force a server error to test UI error handling, delay a response to test loading spinners, or return mock data via a fixture to ensure consistent test conditions.
// Intercept a GET request and return mock data from a fixture
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/dashboard');
// Wait for the specific intercepted call to finish before asserting UI
cy.wait('@getUsers');
cy.get('.user-list').should('have.length', 5);10. What is the difference between cy.get() and cy.contains()?
`cy.get()` selects elements based on CSS selectors (like ID, class, or data attributes). `cy.contains()` selects elements based on the text content visible inside them.
Deep Dive Explanation
While `cy.get` is faster and more precise when using dedicated test IDs (e.g., `data-cy`), `cy.contains` is incredibly useful for testing from the user's perspective, as users interact with text labels (like 'Submit' or 'Login'), not CSS classes.
// Using cy.get with a CSS selector
cy.get('.btn-primary').click();
// Using cy.contains to find a button by its text content
cy.contains('Submit Order').click();
// Combining them to find text within a specific element
cy.get('.modal').contains('Confirm').click();