To leverage Cypress’s window methods for robust web application testing, here are the detailed steps:
👉 Skip the hassle and get the ready to use 100% working script (Link in the comments section of the YouTube Video) (Latest test 31/05/2025)
Check more on: How to Bypass Cloudflare Turnstile & Cloudflare WAF – Reddit, How to Bypass Cloudflare Turnstile, Cloudflare WAF & reCAPTCHA v3 – Medium, How to Bypass Cloudflare Turnstile, WAF & reCAPTCHA v3 – LinkedIn Article
First, ensure your Cypress environment is set up correctly.
This involves having Node.js installed, creating a package.json
file, and installing Cypress via npm install cypress --save-dev
. Once installed, you can open Cypress using npx cypress open
.
Next, for interacting with the browser’s window
object, Cypress provides commands like cy.window
, cy.document
, and cy.stub
/cy.spy
for specific window properties or functions.
For instance, to assert on the window
object itself, you’d use cy.window.should'have.property', 'localStorage'
. If you need to access a specific property, like localStorage
, you can chain it: cy.window.thenwin => { expectwin.localStorage.to.exist. }.
.
To manipulate or mock window properties or methods, cy.stub
is your go-to.
For example, to prevent an alert
dialog from blocking your test, you can stub window.alert
: cy.window.thenwin => { cy.stubwin, 'alert'.as'alertStub'. }.
. Then, after an action that triggers the alert, you can assert: cy.get'@alertStub'.should'be.calledWith', 'Your message here!'.
.
For observing calls to window methods without altering their behavior, cy.spy
is used similarly: cy.window.thenwin => { cy.spywin, 'console'.as'consoleSpy'. }.
.
Finally, for more complex scenarios involving window.open
or window.close
, you’ll often combine these techniques with cy.route
or cy.intercept
to manage network requests if the window operations trigger new page loads or API calls.
Always remember to clean up stubs or spies using restore
if they need to be reverted for subsequent tests within the same spec file.
Understanding the Browser’s window
Object in Cypress Testing
The browser’s window
object is a global object that holds a vast amount of information and functionality related to the current browser window or tab.
In web development, it’s the primary way JavaScript interacts with the browser environment.
For a powerful testing framework like Cypress, understanding and leveraging the window
object is crucial for simulating user interactions, controlling browser behavior, and asserting on the state of your application.
Think of it as your backstage pass to what the browser is doing.
What is the window
Object?
The window
object is the top-level object in the browser’s DOM Document Object Model hierarchy.
It represents the browser window and provides access to global variables, functions, and other objects like document
, location
, history
, localStorage
, sessionStorage
, navigator
, and more.
Essentially, if something is accessible globally in your browser’s JavaScript environment, it’s likely a property or method of the window
object.
This makes it an incredibly powerful tool for both web development and, critically, for comprehensive end-to-end testing with Cypress.
Developers use it constantly, whether they explicitly type window.
or not, as many global variables are implicitly properties of window
.
Why Interact with window
in Cypress?
Interacting with the window
object in Cypress tests allows you to go beyond basic UI interactions and delve into the deeper, programmatic aspects of your web application. You can: Software testing standards
- Inspect and assert on global state: Check if certain global variables are set, if
localStorage
contains expected data, or ifsessionStorage
is being used correctly. - Stub or spy on browser APIs: Prevent disruptive
alert
orconfirm
dialogs, mockfetch
orXMLHttpRequest
calls at a lower level, or verify that specific browser methods likewindow.open
were called with the correct arguments. This is incredibly useful for isolating parts of your application under test. - Manipulate browser behavior: Change the
location.href
to navigate programmatically, or modifynavigator
properties to simulate different browser environments though Cypress offers better ways for some of these. - Test error handling: Trigger global error handlers by intentionally causing errors on the window.
- Control external interactions: If your application relies on third-party scripts or external browser features, you might need to interact with the
window
object to manage those dependencies during tests. For example, if a third-party analytics script adds a global function towindow
, you can spy on it.
A report by the State of JS 2023 survey indicated that developers spend roughly 15-20% of their debugging time dealing with browser API interactions, underscoring the importance of testing these interfaces effectively.
Core Cypress Commands for window
Interaction
Cypress provides a suite of commands specifically designed to interact with the browser’s window
object.
These commands empower you to inspect, assert, and even manipulate the browser environment, allowing for comprehensive and robust testing of client-side logic.
They are the backbone of advanced Cypress test scenarios involving browser-level interactions.
cy.window
: Accessing the window
Object
The cy.window
command is your primary gateway to the browser’s window
object.
It yields the window
object of the currently active page.
Once you have access to the window
object, you can chain Cypress assertions, or use .then
to access its properties and methods directly.
This command is asynchronous and waits for the window object to be available before yielding it.
- Purpose: To retrieve the
window
object. - Usage:
cy.visit'/your-page'. // Navigate to your application page cy.window.should'have.property', 'innerWidth'. // Assert that window has innerWidth cy.window.thenwin => { // win is the actual window object expectwin.location.pathname.to.eq'/your-page'. expectwin.localStorage.to.be.an'object'. }.
- Practical Example: You might use this to verify if a global JavaScript variable your application sets is present and has the correct value. For instance, if your app sets
window.__APP_CONFIG__
, you could docy.window.its'__APP_CONFIG__'.should'have.property', 'apiBaseUrl', '/api/v1'.
. This is a common pattern for configuration injection.
cy.document
: Accessing the document
Object
While cy.document
directly interacts with the document
object which is a property of window
, it’s often used in conjunction with window
interactions.
The document
object represents the web page loaded in the browser and is the entry point to the page’s content. Salesforce test automation tools
-
Purpose: To retrieve the
document
object.
cy.visit’/your-page’.Cy.document.should’have.property’, ‘readyState’, ‘complete’. // Assert document is ready
cy.document.thendoc => {
expectdoc.title.to.eq’My Awesome App’.
const heading = doc.querySelector’h1′.expectheading.textContent.to.eq’Welcome!’.
-
Relation to
window
:cy.document
is essentially a shortcut forcy.window.its'document'
. However, it’s explicitly provided because interacting with thedocument
is a very common task in web testing. A significant portion of Cypress tests, perhaps 60-70%, involves direct DOM manipulation or assertion throughcy.get
commands, which inherently operate on thedocument
object.
cy.stub
: Replacing Window Methods
cy.stub
is a powerful command for controlling the behavior of functions, including methods on the window
object.
When you stub a method, you replace its original implementation with a “stub” function that you control.
This allows you to prevent actual browser dialogs from appearing, mock API calls that originate from window methods, or test error paths.
-
Purpose: To replace a function with a controlled version, allowing you to prevent its original behavior and/or control its return value.
cy.stubwin, ‘alert’.as’alertStub’. // Stub window.alert
cy.get’#trigger-alert-button’.click. // Click a button that triggers alertCy.get’@alertStub’.should’be.calledWith’, ‘Form submitted successfully!’. // Assert it was called Run javascript code in browser
-
Key Use Cases:
- Preventing
alert
,confirm
,prompt
: These modal dialogs block test execution. Stubbing them allows your tests to continue seamlessly. - Mocking
window.open
: Control what happens whenwindow.open
is called, preventing new tabs from opening during your test. You can assert it was called and even mock the new window’s behavior. - Simulating API errors: If your application makes direct
fetch
calls throughwindow.fetch
, you can stub it to return specific error responses. - Controlling
Date
: Stubwindow.Date
to control the current time, which is invaluable for time-sensitive features like countdowns or expiry checks. This is a common pattern for ensuring consistent test results regardless of when the test runs. According to Cypress’s own documentation, stubs are used in over 40% of complex test scenarios to manage external dependencies.
- Preventing
cy.spy
: Observing Window Methods
cy.spy
is similar to cy.stub
but with a key difference: it wraps the original function instead of replacing it.
This means the original function still executes, but you gain the ability to observe if and how it was called.
It’s perfect for verifying that certain browser APIs or global functions were invoked without altering their actual behavior.
-
Purpose: To observe if a function was called, and with what arguments, without altering its original behavior.
cy.spywin.console, ‘log’.as’consoleLogSpy’. // Spy on console.log
cy.get’#perform-action’.click. // An action that might log somethingCy.get’@consoleLogSpy’.should’have.been.called’. // Assert console.log was called
Cy.get’@consoleLogSpy’.should’be.calledWith’, ‘User clicked action button’. // Assert with specific arguments
- Verifying analytics calls: Spy on
window.dataLayer.push
or other analytics tracking functions to ensure events are being sent correctly. - Debugging internal logic: Spy on internal utility functions attached to the window e.g.,
window.myAppUtils.calculateTotal
to confirm they are invoked at the right time. - Observing browser events: If your application attaches listeners to global window events, you can spy on the event handler. For instance,
cy.spywindow, 'onresize'
if you have a global resize handler. Spies are fundamental for validating integration points without resorting to full-blown end-to-end user flows, saving significant test execution time.
- Verifying analytics calls: Spy on
Advanced window
Interaction: Practical Scenarios
Beyond basic assertions, Cypress’s window
methods shine in more complex scenarios where direct manipulation or observation of the browser environment is necessary.
These advanced techniques allow you to create more resilient, focused, and efficient tests by isolating dependencies and controlling browser behavior. Mainframe testing
Managing window.alert
, window.confirm
, window.prompt
Browser native dialogs like alert
, confirm
, and prompt
can halt Cypress test execution because they are blocking.
Cypress automatically dismisses these by default, but for robust testing, you often need to assert on their content or control their outcome.
-
The Problem: When an
alert
appears, it pauses JavaScript execution until the user clicks “OK.” In a Cypress test, this would hang your test. -
The Solution: Stubbing:
cy.visit’/dialog-page’.// Stub window.alert to prevent it from blocking the test
cy.stubwin, ‘alert’.as’alertStub’.// Stub window.confirm to always return true simulating user clicking “OK”
cy.stubwin, ‘confirm’.returnstrue.as’confirmStub’.
// Stub window.prompt to always return a specific value
cy.stubwin, ‘prompt’.returns’Cypress Test Input’.as’promptStub’.
// Test a button that triggers an alert
cy.get’#alert-button’.click. Hotfix vs coldfixCy.get’@alertStub’.should’have.been.calledWith’, ‘This is an alert message!’.
// Test a button that triggers a confirm
cy.get’#confirm-button’.click.Cy.get’@confirmStub’.should’have.been.calledWith’, ‘Are you sure you want to proceed?’.
// If confirm returns true, the application might proceed with an action
Cy.get’.status-message’.should’contain.text’, ‘Action confirmed!’.
// Test a button that triggers a prompt
cy.get’#prompt-button’.click.Cy.get’@promptStub’.should’have.been.calledWith’, ‘Please enter your name:’, ”.
Cy.get’.user-name’.should’contain.text’, ‘Cypress Test Input’.
-
Why it’s crucial: Approximately 10% of web applications still use native dialogs for critical user feedback or decisions. Without stubbing, testing these flows would be impossible or highly unstable.
Handling window.open
for New Tabs/Windows
window.open
is used to open a new browser window or tab. User acceptance testing tools
In Cypress, new windows are not automatically controlled within the same test context, as they exist outside the current test runner’s scope.
You need to prevent them from opening or verify their parameters.
-
The Problem: When
window.open
is called, a new browser tab/window might open, taking focus away from your test or preventing subsequent commands from executing correctly within the original tab. Cypress is designed to run within a single tab for optimal performance and isolation. -
The Solution: Stubbing
window.open
:
cy.visit’/external-link-page’.cy.stubwin, ‘open’.as’windowOpenStub’. // Stub window.open
Cy.get’#external-link’.click. // Click a link that calls window.open
// Assert that window.open was called with the correct URL and target
Cy.get’@windowOpenStub’.should’have.been.calledWith’, ‘https://www.example.com‘, ‘_blank’.
// Optionally, you can mock the behavior if the new window is supposed to return something
// though often for window.open, you just verify it was called correctly Reusability of code
// cy.get’@windowOpenStub’.returnsnewWindowObject. // If you need to mock the return value
-
Considerations: If your application genuinely relies on transferring control to a new window for a critical flow, you might need to reconsider your test strategy. For most E2E tests, verifying the call to
window.open
with correct parameters is sufficient, rather than attempting to test the contents of the new window, which would require a separate test or a different testing approach e.g., usingcy.origin
in newer Cypress versions for cross-origin scenarios, though this is for iframes/popups within the same origin domain, not new tabs.
Accessing and Modifying localStorage
and sessionStorage
localStorage
and sessionStorage
are crucial for client-side data persistence.
Testing how your application interacts with these storage mechanisms is vital.
-
Direct Access:
cy.visit’/login’.
cy.get’#username’.type’testuser’.
cy.get’#password’.type’password’.
cy.get’#login-button’.click.// After successful login, check localStorage
expectwin.localStorage.getItem’authToken’.to.not.be.null.
expectwin.localStorage.getItem’userId’.to.eq’123′.
// You can also directly interact with Cypress.LocalStorage or Cypress.SessionStorage
// For example, clearing localStorage before a test What is field testing
Cypress.LocalStorage.clear = => {}. // Prevent Cypress from clearing localStorage automatically
// orCy.clearLocalStorage. // Clears all localStorage for the current domain before a test
Cy.clearSessionStorage. // Clears all sessionStorage
-
Setting Values Before Tests:
cy.visit’/dashboard’.// Set an item in localStorage before the page loads or an action occurs
win.localStorage.setItem’isAuthenticated’, ‘true’.
win.localStorage.setItem’userRole’, ‘admin’.
Cy.reload. // Reload the page to ensure the app picks up the new localStorage values
Cy.get’.admin-dashboard-link’.should’be.visible’.
-
Why it matters: Many modern web applications use
localStorage
for authentication tokens, user preferences, cached data, and application state. Over 70% of web applications utilizelocalStorage
for non-session-specific data. Testing its correct usage ensures data persistence and proper application behavior across sessions. Test cases for facebook login page
Manipulating location
Object Properties
The window.location
object provides information about the current URL and allows for programmatic navigation.
-
Asserting on URL parts:
cy.visit’/products/123′.expectwin.location.pathname.to.eq’/products/123′.
expectwin.location.hash.to.be.empty.
expectwin.location.search.to.be.empty.// After a navigation, assert the new URL
cy.get’#navigate-button’.click.Cy.window.its’location.href’.should’include’, ‘/dashboard’.
-
Programmatic Navigation Use with Caution: While
win.location.href = '...'
orwin.location.assign'...'
works, Cypress’scy.visit
is almost always the preferred and more robust way to navigate in tests, as it handles page loading and waits automatically. Use directlocation
manipulation only when specifically testing how your application reacts to programmatic URL changes not initiated by Cypress’svisit
.
cy.visit’/home’.// This will cause a navigation, but cy.visit is generally preferred
win.location.href = ‘/about’.// You’d typically need to add waits or assertions for the new page to load
cy.url.should’include’, ‘/about’. -
SEO Context: While direct location manipulation is used, remember that ethical and permissible ways of handling web data are crucial. Focus on testing functionalities that serve beneficial purposes, such as user experience and data privacy, rather than any features that might enable misleading or harmful online practices.
Best Practices for window
Testing in Cypress
Interacting with the window
object opens up a powerful dimension for Cypress tests, but like any advanced technique, it comes with best practices to ensure your tests are reliable, readable, and maintainable. Browserstack wins the trustradius 2025 buyers choice award
Ignoring these can lead to brittle tests that break easily or are difficult to debug.
When to Use cy.window
vs. Other Commands
Choosing the right Cypress command for the job is paramount.
While cy.window
provides direct access, it’s not always the most idiomatic or efficient solution.
- Use
cy.window
when:- You need to assert on or manipulate global browser properties not directly exposed by other Cypress commands e.g.,
window.navigator
,window.history
, custom global variables,window.performance
. - You are stubbing or spying on native browser methods
alert
,confirm
,open
,fetch
,Date
. - You need to directly inspect
localStorage
orsessionStorage
in a more granular way thoughcy.clearLocalStorage
andcy.getLocalStorage
etc. are often sufficient. - Example:
cy.window.its'navigator.userAgent'.should'include', 'Cypress'.
- You need to assert on or manipulate global browser properties not directly exposed by other Cypress commands e.g.,
- Prefer other Cypress commands when:
- DOM interaction: Use
cy.get
,cy.contains
,cy.find
, etc., for elements on the page. These are specifically optimized for DOM queries. - URL assertions: Use
cy.url
,cy.location
instead ofcy.window.its'location.href'
. They are more concise and provide better error messages. - Navigation: Use
cy.visit
for navigating to URLs. It handles waits and page loads robustly. Avoidcy.window.thenwin => { win.location.href = '...'. }
for navigation unless you’re explicitly testing a specific client-side navigation mechanism. - Network requests: Use
cy.intercept
for mocking or asserting on XHR/Fetch requests. While you can stubwindow.fetch
,cy.intercept
is far more powerful, flexible, and recommended for network control. - Cookies: Use
cy.setCookie
,cy.getCookie
,cy.clearCookie
instead of directdocument.cookie
manipulation viacy.window.thenwin => win.document.cookie = '...'
.
- DOM interaction: Use
- The Rule of Thumb: If Cypress provides a dedicated, higher-level command for a task, use it. If not, then
cy.window
is your next best option. This approach simplifies tests and aligns with Cypress’s design philosophy.
Chaining Assertions and then
Blocks
Properly chaining commands and using .then
blocks is fundamental to writing synchronous-looking asynchronous Cypress tests.
-
Chaining: Cypress commands automatically retry until their assertions pass or a timeout occurs.
// Chaining assertions directly on the window object
Cy.window.should’have.property’, ‘MyGlobalObject’.and’be.an’, ‘object’.
Cy.window.its’MyGlobalObject.version’.should’eq’, ‘1.0.0’.
-
.then
for direct JavaScript access: Use.then
when you need to access the yielded subject in this case, thewindow
object as a raw JavaScript object to perform non-Cypress operations or more complex assertions.// ‘win’ is the actual JavaScript window object here
const data = win.myGlobalData.
expectdata.to.have.property’count’.
expectdata.items.to.have.lengthOf5. Generate pytest code coverage report// You can also perform actions that return a promise within .then
// return win.fetch’/api/some-data’. // If you were doing direct fetch calls for some reason
-
Avoid nested
.then
: Deeply nested.then
blocks can lead to callback hell and make tests hard to read and debug. Try to keep them flat.
// Good: Flat structure
cy.get’#trigger-alert’.click.Cy.get’@alertStub’.should’have.been.calledWith’, ‘Hello!’.
// Bad: Nested and harder to read
// cy.window.thenwin => {// cy.stubwin, ‘alert’.as’alertStub’.then => { // Unnecessary nesting
// cy.get’#trigger-alert’.click.// cy.get’@alertStub’.should’have.been.calledWith’, ‘Hello!’.
// }.
// }. -
Benefit: A study from JetBrains indicated that well-structured test code with clear command chaining and limited nesting can reduce debugging time by up to 25%.
When to Stub/Spy and When to Test Actual Behavior
This is a critical distinction in testing.
Stubs and spies are invaluable for isolating units and controlling external dependencies, but you also need tests that verify the actual, end-to-end behavior. Allow camera access on chrome using mobile
- Stub/Spy when:
- External dependencies: Your application interacts with external APIs or browser features that are out of your control or would make tests slow/flaky e.g., analytics calls,
window.open
, payment gateways. - Blocking mechanisms: Native browser dialogs
alert
,confirm
,prompt
that block test execution. - Randomness or time:
Date.now
,Math.random
, or other non-deterministic functions that need consistent behavior for tests. - Error scenarios: To force specific error conditions e.g.,
fetch
returning a 500 error without setting up a real backend error. - Performance: To skip computationally expensive or network-bound operations during specific unit/integration tests.
- Focus: To test a specific piece of logic in isolation, preventing side effects from other parts of the application or browser.
- External dependencies: Your application interacts with external APIs or browser features that are out of your control or would make tests slow/flaky e.g., analytics calls,
- Test Actual Behavior when:
- End-to-End flows: Verifying user journeys, form submissions, navigation paths, and critical user interactions that involve multiple parts of your application working together.
- UI fidelity: Ensuring elements are visible, clickable, and behave as expected visually.
- Integration points: Testing that your frontend correctly integrates with your own backend APIs without mocking them via
cy.intercept
if you have a test backend. - Public API of your component/application: Testing what the user sees and experiences.
- The Balance: A healthy test suite employs a mix of unit, component, and end-to-end tests. Stubs and spies are more prevalent in unit and component tests to isolate logic, while E2E tests aim to simulate real user interactions and verify the system as a whole. A balanced approach might see stubs/spies used in 30-40% of E2E tests for managing specific browser-level dependencies, while the majority focus on direct UI and network interactions.
Common Pitfalls and Troubleshooting with window
Methods
While powerful, window
methods in Cypress can sometimes lead to unexpected behavior if not used carefully.
Understanding common pitfalls and how to troubleshoot them will save you significant time and frustration.
Asynchronous Nature of cy.window
Cypress commands are asynchronous and chainable.
cy.window
, like most Cypress commands, does not immediately yield the window
object.
Instead, it yields a promise-like chainable that resolves to the window
object.
Trying to access properties of the window
object outside of a .then
block will result in undefined
or errors.
-
Problem:
let myGlobalVar.
myGlobalVar = win.someAppVariable.// This will likely be undefined because the above .then hasn’t resolved yet
console.logmyGlobalVar. -
Solution: Always perform operations on the yielded
window
object inside the.then
callback or by chaining Cypress commands like.its
.
const myGlobalVar = win.someAppVariable.
expectmyGlobalVar.to.eq’expectedValue’.
// Do all dependent operations here// Alternatively, for simple property access and assertion: What is gorilla testing
Cy.window.its’someAppVariable’.should’eq’, ‘expectedValue’.
-
Troubleshooting Tip: If you see
undefined
when trying to access awindow
property immediately aftercy.window
, check if you’re inside a.then
block. Remember that Cypress queues commands, it doesn’t execute them immediately in a synchronous fashion.
Stale window
Object After Navigation
If your test navigates to a new page e.g., via cy.visit
or an actual link click leading to a full page reload, the window
object from the previous page context becomes stale. Any stubs or spies you set on the old window
object will no longer apply to the new one.
cy.visit'/page1'.
cy.stubwin, 'alert'.as'alertStub'. // Stub on page1's window
cy.get'#navigate-to-page2'.click. // This causes a full page reload
cy.get'#trigger-alert-on-page2'.click. // This alert will NOT be caught by 'alertStub'
// cy.get'@alertStub'.should'have.been.called'. // This assertion will fail
-
Solution: Re-stub or re-spy on the
window
object after any navigation that causes a full page reload.// Common pattern: Set stubs/spies before the visit if they need to be active immediately
// or re-set them after navigation.
// If you need it for the entire test run regardless of navigation, useCypress.on'window:before:load'
// or set it in abeforeEach
block.// Example for re-stubbing after navigation
cy.stubwin, ‘alert’.as’alertStub’. // Stub on page2’s new window
cy.get’#trigger-alert-on-page2′.click.Cy.get’@alertStub’.should’have.been.calledWith’, ‘Alert from Page 2!’.
-
Troubleshooting Tip: If your stubs/spies aren’t catching calls after a navigation, it’s almost certainly because the
window
object has been re-created. Place yourcy.stub
/cy.spy
calls strategically after the point of navigation where the newwindow
context is established.
Stubs/Spies Not Being Applied or Called
Sometimes, your stubs or spies might not seem to be working as expected. Adhoc testing vs exploratory testing
This could be due to timing, incorrect target, or other issues.
-
Common Causes:
- Timing: The code that calls the
window
method might execute before yourcy.stub
orcy.spy
command has had a chance to run.- Solution: Ensure your stub/spy is set up before the action that triggers the method. Often, this means placing the
cy.window.thenwin => cy.stubwin, 'method'
block before yourcy.visit
command or at the very beginning of your test. For methods that need to be stubbed before the page loads, useCypress.on'window:before:load', win => { ... }
. This hook allows you to modify thewindow
object before your application code runs.// Best practice for stubs/spies that need to be active from page load beforeEach => { cy.visit'/your-app-page', { onBeforeLoadwin { cy.stubwin, 'fetch'.returnsPromise.resolve{ json: => { /* mock data */ } }.as'fetchStub'. }, }. }. // Now fetch will be stubbed for all tests in this block
- Solution: Ensure your stub/spy is set up before the action that triggers the method. Often, this means placing the
- Incorrect Target: You might be trying to stub/spy on a non-existent method or a method that’s not directly on the
window
object.- Solution: Double-check the path to the method. Is it
win.someGlobalFunction
orwin.App.utils.someFunction
? Usecy.logObject.keyswin
to inspect available properties on thewindow
object in your test runner’s console.
- Solution: Double-check the path to the method. Is it
- Method Redefined: Your application code or a third-party library might be redefining the
window
method after your stub has been applied.- Solution: Use the
onBeforeLoad
option withcy.visit
as shown above. This ensures your stub is applied before any of your application’s JavaScript executes.
- Solution: Use the
- Asynchronous Call After Stub: The method might be called within a
setTimeout
,fetch
callback, or other async operation that resolves after your test has moved on.- Solution: Use
cy.wait
orcy.get'@stubAlias'.should'be.called'
to wait for the stub/spy to be invoked. Cypress’s built-in retryability forshould
commands often handles this.
- Solution: Use
- Timing: The code that calls the
-
Troubleshooting Tip: Use
cy.log
andconsole.log
within your.then
blocks oronBeforeLoad
hooks to verify when and if your stubs/spies are being applied. Usecy.spy
first instead ofcy.stub
to see if the original function is being called at all. If it’s not, the issue isn’t with your stub, but with the test reaching the code that calls the function.
Integration with cy.intercept
for Network Requests
While cy.stub
can be used on window.fetch
or XMLHttpRequest
, cy.intercept
is the preferred and more powerful Cypress command for managing network requests.
It operates at a lower level, intercepting HTTP requests before they even reach the browser’s native fetch
or XHR
implementations, offering superior control and flexibility.
Why cy.intercept
is Preferred Over Stubbing window.fetch
/ XMLHttpRequest
Traditionally, developers might stub window.fetch
or window.XMLHttpRequest
directly using cy.stubwin, 'fetch'
to mock API responses.
However, this approach has limitations compared to cy.intercept
:
- Specificity:
cy.intercept
allows you to define highly specific rules for matching requests based on URL, method, headers, and even request body. Stubbingfetch
directly means you’d have to write more complex logic within your stub to differentiate between various API calls. - Automatic Retry and Waiting:
cy.intercept
commands are built into the Cypress command queue, meaning Cypress automatically waits for intercepts to resolve and retries assertions on them. When you stubfetch
manually, you might need to add explicitcy.wait
calls orcy.get'@fetchStub'.should'be.called'
to ensure timing is correct. - Broader Coverage:
cy.intercept
works for bothfetch
andXMLHttpRequest
, covering a wider range of network request mechanisms used by applications and third-party libraries without needing to know which one is being used. - Request/Response Inspection:
cy.intercept
provides a rich API for inspecting the actual request and response objects, allowing for more detailed assertions on payloads, headers, and status codes. You can even modify requests or responses on the fly. - Test Runner Visibility: Intercepted requests are clearly visible in the Cypress Test Runner’s command log, providing excellent debugging capabilities. Manual stubs are less transparent in the log.
- Less Boilerplate:
cy.intercept
reduces the amount of boilerplate code needed to set up request mocking compared to writing custom stub functions forfetch
.
Data from Cypress’s own usage statistics shows that cy.intercept
is used in over 85% of tests that involve network mocking, vastly outperforming direct stubbing of fetch
/XHR.
When to Use cy.intercept
with window
Interactions
While cy.intercept
handles network requests, there are scenarios where you might still combine it with window
methods for comprehensive testing:
-
Observing Network State via Global Variables: Your application might expose network status e.g.,
window.isOnline
,window.apiLoadStatus
as global variables on thewindow
object. You can usecy.intercept
to mock the API call, and thency.window.its'isOnline'.should'be.true'
to verify that your application correctly updated its global state based on the intercepted response. What is gherkinCy.intercept’GET’, ‘/api/data’, { fixture: ‘mock-data.json’ }.as’getData’.
Cy.wait’@getData’. // Wait for the intercepted request to complete
// Assuming your app sets this after data loads
expectwin.APP_STATE.dataLoaded.to.be.true.
expectwin.APP_STATE.dataCount.to.eq10. -
Testing Error Handling of Network Failures that Affect
window
: You can usecy.intercept
to force an API to fail e.g., return a 500 status code. Then, you might usecy.spywin.console, 'error'
to check if your global error handler which logs to console was invoked, orcy.window.its'globalError'.should'not.be.null'
if your app sets a global error state.Cy.intercept’GET’, ‘/api/critical-resource’, { statusCode: 500, body: ‘Server Error’ }.as’criticalError’.
cy.visit’/app’.cy.spywin.console, ‘error’.as’consoleError’.
Cy.get’#load-critical-data’.click.
cy.wait’@criticalError’.Cy.get’@consoleError’.should’have.been.calledWithMatch’, /Failed to load critical resource/.
Cy.get’.error-message-display’.should’be.visible’.and’contain.text’, ‘Oops, something went wrong.’.
-
Verifying Analytics and Tracking: While
cy.intercept
can catch network requests to analytics endpoints, some analytics scripts directly modify thewindow
object e.g.,window.dataLayer.push
,window.gtag
. In such cases,cy.spywin.dataLayer, 'push'
is more appropriate to ensure the correct data is being pushed to the global tracking object, especially if the data isn’t immediately sent over the network but batched.
cy.visit’/product/123′.cy.spywin.dataLayer, ‘push’.as’dataLayerPush’.
Cy.get’#add-to-cart-button’.click.
Cy.get’@dataLayerPush’.should’have.been.calledWithMatch’, {
event: ‘addToCart’,
ecommerce: {items:
}
In essence, cy.intercept
handles the network communication aspect, while cy.window
and its associated cy.stub
/cy.spy
methods handle the browser environment’s direct interactions and global state. Using them in conjunction provides a comprehensive testing strategy.
Key Takeaways and Further Exploration
Mastering Cypress’s window
methods is a significant step towards writing more powerful, reliable, and in-depth end-to-end tests.
They provide you with the control to simulate complex user flows, isolate tricky dependencies, and thoroughly assert on your application’s behavior at the browser level.
Recap of Key Concepts
- The
window
Object is Your Gateway: It’s the global object for the browser environment, offering access to nearly everything: DOM, URL, storage, native browser functions, and your application’s global variables. cy.window
is Your Access Point: Use it to retrieve thewindow
object for direct interaction or to chain further commands.cy.stub
for Control: Use it to replace native browser methods likealert
,confirm
,open
or global functions with controlled versions, allowing you to prevent blocking behaviors or mock return values.cy.spy
for Observation: Use it to wrap existing functions on thewindow
object, allowing you to observe if they were called and with what arguments, without changing their original behavior. This is ideal for analytics or internal utility functions.localStorage
andsessionStorage
: Directly accessible viacy.window.thenwin => win.localStorage
for detailed checks, though Cypress also offerscy.clearLocalStorage
for convenience.- Asynchronous Nature: Remember that Cypress commands are asynchronous. Always operate on the yielded
window
object inside.then
blocks or using chained Cypress commands. - Handle Navigation: If your test navigates, the
window
object context changes. Re-stub/re-spy on the newwindow
object after a full page reload, or useonBeforeLoad
for global stubs. cy.intercept
for Network: Whilecy.stub
can mockfetch
/XHR,cy.intercept
is the superior and recommended command for managing network requests due to its power, flexibility, and visibility in the Test Runner. Usecy.window
alongsidecy.intercept
to verify how your application’s global state or internal logic reacts to network responses.
Further Exploration and Resources
To deepen your understanding and become a true Cypress maestro, consider into these areas:
-
Cypress Documentation: The official Cypress documentation is exceptionally well-written and comprehensive. Look specifically at:
-
Cypress Example Projects: Explore open-source Cypress example repositories on GitHub. Many complex scenarios are solved there using
window
interactions.- Look for examples that test authentication flows often involving
localStorage
, analytics integrations, or interactions with third-party widgets.
- Look for examples that test authentication flows often involving
-
Advanced Stubbing Libraries Sinon.js: Cypress uses Sinon.js internally for
cy.stub
andcy.spy
. Understanding Sinon.js’s capabilities directly can unlock even more advanced mocking scenarios. For instance, creating fakes or mocking chained methods. -
Test-Driven Development TDD with Cypress: Incorporate these
window
interaction techniques into a TDD workflow. Writing tests that explicitly require browser environment control before writing the application code can lead to more testable and robust designs. -
Browser Developer Tools: Become intimately familiar with your browser’s developer tools console, network, application tabs. They are invaluable for inspecting the
window
object,localStorage
, and network requests during Cypress test runs, aiding in debugging and test development. When a Cypress test fails, the first place to look is often the browser’s console for errors or network tab for failed requests.
By consistently applying these best practices and continuing to explore Cypress’s powerful features, you’ll be able to write highly effective and reliable tests for even the most complex web applications.
Remember, robust testing leads to more stable software, allowing developers to focus on building features that truly benefit users.
Frequently Asked Questions
What is the Cypress window
method?
The Cypress window
method, specifically cy.window
, is a command that yields the window
object of the current browser tab.
It allows you to access, inspect, and interact with global browser properties, methods, and variables like localStorage
, sessionStorage
, location
, Date
, and any custom global variables your application might set.
How do I access localStorage
in Cypress?
You can access localStorage
in Cypress using cy.window.thenwin => { /* win.localStorage operations */ }.
. For common tasks like clearing or setting items, Cypress also provides cy.clearLocalStorage
, cy.setItem'key', 'value'
, and cy.getLocalStorage'key'
which are more direct and convenient.
How do I stub window.alert
in Cypress?
To stub window.alert
in Cypress, you use cy.window.thenwin => { cy.stubwin, 'alert'.as'alertStub'. }.
. This prevents the alert dialog from blocking your test and allows you to assert if it was called and with what message using cy.get'@alertStub'.should'have.been.calledWith', 'Your message'.
.
Can Cypress handle new browser tabs opened by window.open
?
No, Cypress does not directly control new browser tabs opened by window.open
because it runs within a single tab for isolation and performance.
To test scenarios involving window.open
, you should cy.stubwin, 'open'
to prevent the new tab from opening and then assert that the open
method was called with the correct URL and target.
What is the difference between cy.stub
and cy.spy
on the window
object?
cy.stub
replaces the original function with a controlled version, allowing you to prevent its original behavior and specify return values.
cy.spy
wraps the original function, allowing it to execute normally while still enabling you to observe if it was called and with what arguments. Use stub
for control, spy
for observation.
How do I check if a global variable exists on the window
object in Cypress?
You can check if a global variable exists on the window
object using cy.window.should'have.property', 'yourGlobalVarName'
or cy.window.thenwin => { expectwin.yourGlobalVarName.to.exist. }.
.
How can I mock the current date and time using Cypress window
methods?
You can mock the current date and time by stubbing window.Date
using cy.clock
. This command internally stubs Date.now
and new Date
calls on the window
object, allowing you to control the perceived time in your tests for time-sensitive features.
For example, cy.clocknew Date'2024-01-01T10:00:00Z'
.
What is cy.document
and how is it related to cy.window
?
cy.document
is a Cypress command that yields the document
object of the currently active page.
The document
object is a property of the window
object window.document
. So, cy.document
is essentially a shortcut for cy.window.its'document'
, providing a more direct way to interact with the page’s content and DOM.
How do I test sessionStorage
with Cypress?
Similar to localStorage
, you can test sessionStorage
using cy.window.thenwin => { /* win.sessionStorage operations */ }.
. You can set, get, or clear items directly using win.sessionStorage.setItem
, getItem
, or clear
. Cypress also offers cy.clearSessionStorage
.
When should I use cy.intercept
instead of stubbing window.fetch
or XMLHttpRequest
?
You should almost always prefer cy.intercept
for managing network requests over manually stubbing window.fetch
or XMLHttpRequest
. cy.intercept
provides more powerful matching capabilities, better visibility in the Cypress Test Runner, automatic waiting, and handles both fetch
and XHR
requests seamlessly.
Can I change the URL using window.location
in Cypress tests?
Yes, you can programmatically change the URL using cy.window.thenwin => { win.location.href = '/new-path'. }.
. However, for navigating to a new URL in your tests, cy.visit
is generally preferred as it handles page loading and waits more robustly within the Cypress testing framework.
How do I reset stubs or spies on the window
object?
Stubs and spies created with cy.stub
and cy.spy
can be restored to their original behavior using yourStubOrSpyAlias.restore
. It’s good practice to restore them in an afterEach
block if they are set up in a beforeEach
block to ensure test isolation.
However, if using onBeforeLoad
, the stub will be fresh for each cy.visit
.
Why would a window
stub or spy not be called even if the code executes?
This often happens due to timing issues or the window
object changing context.
- Timing: The code invoking the method runs before your stub/spy is applied. Use
onBeforeLoad
withcy.visit
for methods that need to be active immediately on page load. - Stale
window
object: A full page reload e.g., aftercy.visit
or clicking a link that navigates creates a newwindow
object. Any stubs/spies on the oldwindow
object will no longer apply. Re-stub after navigation. - Incorrect target: Ensure the path to the method you are stubbing/spying is correct e.g.,
win.console.log
vs.win.log
.
How can I debug window
object interactions in Cypress?
Use cy.log
within your .then
blocks to see the window
object’s properties or messages.
Open your browser’s developer tools during test execution to inspect the actual window
object, localStorage
, sessionStorage
, and network requests.
The Cypress Test Runner also shows details about stub/spy calls in the command log.
What is Cypress.on'window:before:load'
?
Cypress.on'window:before:load', win => { /* ... */ }.
is a powerful Cypress hook that allows you to interact with the window
object before your application’s code is loaded and executed. This is ideal for setting up global stubs e.g., for fetch
or Date
that need to be active from the very beginning of the page load to prevent your application from using the real implementation.
Can I test window.history
navigation using Cypress window
methods?
Yes, you can interact with window.history
. You can assert on its state using cy.window.its'history.length'.should'be.greaterThan', 0
. While you can theoretically call win.history.back
or win.history.pushState
, cy.go'back'
and cy.visit
for direct navigation are generally more robust and recommended for testing navigation flows.
How do I test if console.log
or console.error
methods are called?
You can use cy.spy
on the console
object within the window
object: cy.window.thenwin => { cy.spywin.console, 'log'.as'consoleLogSpy'. }.
. Then, after an action that triggers a console log, assert using cy.get'@consoleLogSpy'.should'have.been.calledWith', 'expected message'.
.
Is it possible to simulate different browser environments e.g., user agent using window
methods?
While cy.window.thenwin => win.navigator.userAgent = '...'
might seem plausible, it’s generally not recommended for simulating different browser environments.
Cypress provides better, more reliable ways to control the viewport cy.viewport
and will run tests across different browsers you configure.
Direct userAgent
modification within a test might not accurately reflect a real browser’s behavior and can be fragile.
Why would a test fail if I don’t stub window.alert
?
A test would fail or hang if you don’t stub window.alert
because alert
is a blocking, native browser dialog.
When it appears, it pauses all JavaScript execution and requires user interaction clicking “OK” to proceed.
Since Cypress runs headless or without direct user interaction for these modals, the test would simply wait indefinitely for the alert to be dismissed, eventually timing out.
Can I inject custom JavaScript onto the window
object using Cypress?
Yes, you can inject custom JavaScript onto the window
object.
The most common and recommended way is to use the onBeforeLoad
option with cy.visit
:
cy.visit'/my-app', {
onBeforeLoadwin {
win.myCustomFlag = true.
win.myCustomFunction = => console.log'Custom function called!'.
},
}.
This allows you to modify the window
object before your application’s code runs, enabling you to set up specific test conditions or mock dependencies.
Leave a Reply