Hello everybody!!
I’m working with Cypress for testing a React application and facing a particular challenge with Cypress spy
. My goal is to observe a specific function, func.call
, which is defined in a separate file and then imported into multiple React components.
Despite setting up cy.spy(func, "call")
, the spy never seems to register the call after cy.visit("/")
. Our test setup mocks network calls (both REST and socket.io
) to run without a real backend, and while I’ve successfully managed to intercept fetches and simulate backend responses, verifying func.call
is triggered remains elusive. I suspect the issue might be related to how the function gets bundled or its accessibility once the application fully loads.
I’m looking for insights on how to correctly spy on external or shared utility functions within a React application when using Cypress. Any guidance on best practices or common pitfalls in such scenarios would be greatly appreciated
Thanks in advance 
Hey @arpanaarora.934 ! Your challenge with Cypress spies on imported functions in React is a very common scenario, and I’ve certainly battled with this myself!
You’ve actually hit on the core issue: Cypress spies work best when the function is truly in the browser context and within your immediate control. If you’re importing a shared module that’s bundled by Webpack (like a utils.js
file), Cypress often can’t directly spy on it after the app is built and loaded, because Cypress code runs outside the React app’s direct scope. By the time you call cy.spy(func, 'call')
, the app already has its own reference to the function that Cypress can’t easily intercept.
To solve this, I’ve used a workaround that might be considered a bit of a hack, but it gives you back that crucial control: exposing the function to the window object inside your application code during development, like this:
window.sharedFunc = sharedFunc;
Then, in your Cypress test, you can access and spy on it via the window
object after the app visits the page:
cy.window().then((win) => {
cy.spy(win.sharedFunc, 'call').as('sharedCall');
});
This approach worked reliably for me. It provides a way to get control when you can’t directly inject mocks into the module system.
Hope this practical solution helps you verify those function calls!
Hello @Rashmihasija and @arpanaarora.934 ! The challenge with Cypress spies on imported functions in React is incredibly common, and you’re definitely not alone in facing it.
Cypress spies are powerful, but they are indeed limited to functions that exist within the same execution context.
When your React app imports a shared module, that function reference is often baked directly into the bundle during the build process, and Cypress can’t easily intercept it post-build in the way you’d expect.
One effective workaround I’ve utilized is dependency injection or, in some cases, mocking the module entirely using something like Webpack aliases specifically for test builds. Alternatively, you could wrap the shared function with a custom React hook or context.
This approach makes the function’s interaction points more explicit and thus more testable, while also avoiding tight coupling.
Hope these strategies provide you with the control you need for spying on those shared utilities!
Hello @arpanaarora.934 and fellow test architects! Adding another perspective to your challenge with Cypress spies on imported functions, and building on the workarounds discussed.
I’ve had this exact same issue myself! Importing a helper function used across components and trying to spy on it from Cypress simply didn’t work out of the box.
You’re right: Cypress can’t magically overwrite imports in a running app’s built bundle.
The workaround that helped me involved mocking the module before the app was bundled, typically by using a custom test build with injected spies (via Jest or a Babel plugin), and then exposing what I needed globally.
It was, however, kind of brittle to maintain. Honestly, for shared logic like that, I’ve found it’s often better to write precise unit tests with Jest and then reserve Cypress to verify the broader behavior through UI side effects.
Hope this experience, and the strategic distinction between testing levels, helps you refine your approach!