You can test responsive layouts in Cypress by simulating different mobile viewports directly within your tests.
Let’s see it in action. Imagine you have a website that displays a different navigation menu on mobile versus desktop. You want to ensure the mobile menu appears correctly when the viewport is small enough.
// cypress/integration/responsive_spec.js
describe('Responsive Navigation', () => {
beforeEach(() => {
// Visit the page before each test
cy.visit('/');
});
it('should display mobile navigation on small viewports', () => {
// Set the viewport to a common mobile size
cy.viewport(375, 667); // iPhone 6/7/8 width and height
// Assert that the mobile navigation element is visible
cy.get('.mobile-nav-menu').should('be.visible');
// Assert that the desktop navigation element is NOT visible
cy.get('.desktop-nav-menu').should('not.be.visible');
});
it('should display desktop navigation on large viewports', () => {
// Set the viewport to a common desktop size
cy.viewport(1280, 720); // A typical desktop resolution
// Assert that the desktop navigation element is visible
cy.get('.desktop-nav-menu').should('be.visible');
// Assert that the mobile navigation element is NOT visible
cy.get('.mobile-nav-menu').should('not.be.visible');
});
it('should switch navigation when viewport is resized', () => {
// Start with a desktop viewport
cy.viewport(1280, 720);
cy.get('.desktop-nav-menu').should('be.visible');
cy.get('.mobile-nav-menu').should('not.be.visible');
// Resize to a mobile viewport
cy.viewport(375, 667);
cy.get('.mobile-nav-menu').should('be.visible');
cy.get('.desktop-nav-menu').should('not.be.visible');
// Resize back to desktop
cy.viewport(1280, 720);
cy.get('.desktop-nav-menu').should('be.visible');
cy.get('.mobile-nav-menu').should('not.be.visible');
});
});
This code demonstrates how to use cy.viewport(width, height) to programmatically change the browser window’s dimensions within your Cypress tests. By asserting the visibility or non-visibility of specific elements (like .mobile-nav-menu or .desktop-nav-menu), you can verify that your CSS media queries and JavaScript logic are correctly adapting your layout for different screen sizes. Cypress runs these tests in a real browser, so you’re not just checking code; you’re visually confirming the responsive behavior.
The core problem this solves is ensuring a consistent and usable experience across a wide range of devices without needing to manually test on every single one. You can define a set of representative viewports — common phone sizes (like iPhone 13, Samsung Galaxy S21), tablets (like iPad), and various desktop resolutions — and automate the checks for each. This significantly increases test coverage and confidence in your application’s responsiveness.
Internally, cy.viewport() directly instructs the browser driver (like ChromeDriver or WebKit) to resize the browser window. Cypress then re-renders the application within this new viewport, allowing your assertions to pick up the state of the DOM as it would appear on a device with those dimensions. The key levers you control are the width and height arguments passed to cy.viewport(), and the selectors you use in your assertions to target the elements that should appear or disappear based on the viewport size. You can also use cy.viewport() without arguments to set it to a device preset, e.g. cy.viewport('iphone-x').
Many developers think that just checking for element visibility at a few breakpoints is enough. However, the actual rendering of CSS, especially complex layouts involving flexbox or grid, can sometimes have subtle differences or unexpected behaviors when transitioning between breakpoints that aren’t immediately obvious from a simple be.visible assertion. It’s crucial to also consider asserting on layout-specific properties, like the number of columns in a grid, the display property of certain elements, or even performing visual regression tests on specific components at different viewports to catch these nuanced issues.
The next concept you’ll likely explore is how to handle dynamic content loading or network requests that might change based on viewport size.