Back to Test Automation
2026-03-296 min read

Stub (Test Automation)

Learn Stub (Test Automation) step by step with clear examples and exercises.

Why This Matters

Test automation plays a crucial role in modern software development by ensuring applications work as intended. External dependencies like APIs, databases, or third-party libraries can introduce unpredictability and make tests brittle. Stubs provide a solution to this problem by allowing developers to replace these external dependencies with controlled responses during testing, leading to more reliable and repeatable tests.

Prerequisites

To follow this lesson, you should have a basic understanding of JavaScript, Node.js, and test automation frameworks like Cypress. Familiarity with the Cypress API is helpful but not required, as we will cover the necessary concepts in this lesson. It's also beneficial to have some experience working with APIs and external dependencies in your application code.

Core Concept

Cypress offers a utility function called cy.stub() that allows us to replace functions or methods of external dependencies with controlled responses during testing. This can be particularly useful when dealing with APIs, where you want to simulate specific responses for certain test scenarios.

Here's an example of how to use cy.stub():

// Assume we have an API endpoint that returns user data
const apiUrl = 'https://example-api.com/users';

// Stub the API response for a specific user ID
cy.stub(Cypress, 'request').as('userApi');

cy.server();
cy.route({
method: 'GET',
url: apiUrl,
response: {
body: {
id: 1,
name: 'John Doe',
email: 'john.doe@example.com'
}
}
});

// Now when we make a request to the API, Cypress will return our stubbed response
cy.visit('/user/1');
cy.get('[data-cy=name]').should('contain', 'John Doe');

In this example, we're replacing the request function of the Cypress global object with a stub that returns a specific user when the API endpoint is called. This allows us to control the response for our test and isolate the component under test from external dependencies.

Stubbing Fetch API calls

If your application uses the fetch API, you can still use cy.stub() to replace its behavior during testing:

// Stub the fetch API response for a specific user ID
cy.wrap(globalThis).as('global');

cy.server();
cy.route({
method: 'GET',
url: '/api/users/1',
response: {
body: {
id: 1,
name: 'John Doe',
email: 'john.doe@example.com'
}
}
});

// Now when we call fetch(), Cypress will return our stubbed response
cy.wrap(globalThis.fetch).as('fetch');
const user = await (await globalThis.fetch('/api/users/1')).json();
expect(user.id).to.equal(1);

In this example, we're wrapping the globalThis object with cy.wrap() to access the global scope and replace the fetch function with a stub. This allows us to control the response for our test and isolate the component under test from external dependencies.

Worked Example

Let's create a more complex test suite that demonstrates the use of cy.stub() in detail:

  1. First, we set up a basic Cypress project by following the official documentation (https://docs.cypress.io/guides/getting-started/installing-cypress).
  1. Next, let's create a new file integration/user_stubs.spec.js and write our test suite:
describe('User Stubs', () => {
beforeEach(() => {
// Stub the API response for a specific user ID
cy.wrap(globalThis).as('global');

cy.server();
cy.route({
method: 'GET',
url: '/api/users/1',
response: {
body: {
id: 1,
name: 'John Doe',
email: 'john.doe@example.com'
}
}
});

cy.route({
method: 'GET',
url: '/api/users/999',
status: 404,
response: {
body: {
error: 'User not found'
}
}
});
});

it('should display user details when loading a user profile', () => {
// Visit the user profile page for ID 1
cy.visit('/user/1');

// Assert that the name and email are displayed correctly
cy.get('[data-cy=name]').should('contain', 'John Doe');
cy.get('[data-cy=email]').should('contain', 'john.doe@example.com');
});

it('should display an error message when loading a non-existent user profile', () => {
// Visit the user profile page for ID 999
cy.visit('/user/999');

// Assert that an error message is displayed
cy.get('[data-cy=error]').should('contain', 'User not found');
});

it('should call the correct API endpoint when creating a new user', () => {
const newUser = { name: 'Jane Doe', email: 'jane.doe@example.com' };

// Stub the API response for creating a new user
cy.route({
method: 'POST',
url: '/api/users',
response: {
body: {
id: 2,
name: 'Jane Doe',
email: 'jane.doe@example.com'
}
}
});

// Simulate form submission with the new user data
cy.get('[data-cy=create-user-form]').submit(newUser);

// Assert that the new user was created and displayed correctly
cy.get('[data-cy=name]').should('contain', 'Jane Doe');
cy.get('[data-cy=email]').should('contain', 'jane.doe@example.com');
});
});
  1. Run the test suite with npm run cypress run and verify that all tests pass.

Common Mistakes

  1. Not aliasing the stub: Remember to alias your stub using the as() method, as shown in the worked example. This allows you to reference the stub later in your test suite.
  1. Not setting up the stub before making requests: Make sure to set up your stubs before making any requests that depend on them. You can do this by placing your cy.stub() calls inside a beforeEach() block, as demonstrated in the worked example.
  1. Not handling errors correctly: When using cy.route(), you can specify an error response by setting the status and response properties. Make sure to handle these errors appropriately in your tests.
  1. Stubbing functions that don't exist: If you try to stub a function that doesn't exist, Cypress will throw an error. Before attempting to stub a function, make sure it is defined and accessible within the scope where you are trying to stub it.
  1. Not considering side effects: When stubbing functions, be aware of any potential side effects they may have on your application or test environment. For example, if a function writes to a database or logs information, these actions might not occur when using a stub, which could lead to incorrect test results.

Practice Questions

  1. How would you stub a function that interacts with a third-party library like lodash or moment?
  2. How can you test a component that relies on a random number generator during testing?
  3. How would you handle asynchronous API calls when using cy.stub() to simulate responses?
  4. What are some potential side effects to consider when stubbing functions in your application code?
  5. How can you ensure that your stubbed responses accurately reflect real-world scenarios while still being predictable during testing?

FAQ

  1. Can I use cy.stub() to stub functions inside my application code?

Yes, you can use cy.stub() to replace any function in your application code with a controlled response. However, be careful when doing this, as it may introduce unexpected behavior or side effects.

  1. Can I chain multiple cy.route() calls together to stub multiple API endpoints?

Yes, you can chain multiple cy.route() calls together to stub multiple API endpoints. Each route will be added to the list of intercepted requests in the order they are defined.

  1. What happens if I call cy.stub() on a function that doesn't exist?

If you call cy.stub() on a function that doesn't exist, Cypress will throw an error indicating that the function is not found. Make sure to check for the existence of the function before attempting to stub it.

  1. How can I test asynchronous API calls using cy.stub()?

To test asynchronous API calls, you can use a combination of cy.wait() and cy.route(). You can set up your stub with a delay using the responseDelay option in cy.route(), and then use cy.wait() to pause the test until the expected response is received.

  1. How can I ensure that my stubbed responses accurately reflect real-world scenarios while still being predictable during testing?

To create realistic stubbed responses, you can analyze the actual API responses from your application and use them as a basis for your stubs. This ensures that your tests are testing the correct behavior while still being repeatable and predictable. You may also want to consider using data-driven testing approaches to generate a variety of test scenarios from a single set of data.

Stub (Test Automation) | Test Automation | XQA Learn