The new Cypress features you should be using
End-to-end testing has evolved. Today, Cypress offers more than just a slick UI and an intuitive syntax, it now comes packed with powerful features that make tests faster, more realistic and easier to debug. In this article, we’ll dive into three of the most exciting additions to Cypress: cy.session() — for smarter state caching cy.press() — for realistic keyboard navigation cy.stop() — for precise control of test execution Whether you're scaling tests across CI, validating accessibility flows or debugging a tricky edge case, these new commands will upgrade your test suite. cy.session(): cache once, reuse everywhere We’ve all repeated login flows in every test: beforeEach(() => { cy.visit('/login'); cy.get('input[name="email"]').type('test@example.com'); cy.get('input[name="password"]').type('passwordExample'); cy.get('button[type="submit"]').click(); }); It works, but it’s slow. And flaky. cy.session() solves this by caching browser state (like cookies and localStorage) after a one-time setup. How to use it: beforeEach(() => { cy.session('admin-session', () => { cy.request('POST', '/api/login', { email: 'admin@example.com', password: 'admin123' }).then((res) => { window.localStorage.setItem('auth_token', res.body.token); }); }); }); Now your tests run faster and skip repeated login steps. Cypress restores the session seamlessly between tests in the same spec. Bonus: If you're using Cypress Cloud, session state is even visible in replays. cy.press(): simulate real keyboard navigation Testing keyboard behavior used to feel like a workaround. cy.type('{tab}') could only go so far, it didn’t trigger real focus movement in most browsers. Now Cypress supports cy.press(), a new command designed for real keyboard event simulation (currently supporting Tab). Perfect for: Testing keyboard accessibility Navigating forms Validating focus order cy.get('input[name="email"]').focus(); cy.press(Cypress.Keyboard.Keys.TAB); cy.focused().should('have.attr', 'name', 'password'); What you should know: ✅ Works in Chromium and Firefox (v135+) ❌ Not yet supported in WebKit (e.g., Safari) ⚠️ Currently only supports Tab, more keys coming soon It’s a big win for accessibility-first development and progressive enhancement strategies. cy.stop(): pause Cypress execution programmatically Imagine this: your test is halfway through, and you want to inspect the DOM, view state or manually interact with the app before continuing. cy.stop() lets you pause test execution at any point, from code. Example: cy.visit('/dashboard'); cy.get('.notification').should('be.visible'); cy.stop(); // Open Cypress runner and inspect manually This is incredibly useful for: Debugging Live demos Investigating CI failures You don’t need to add breakpoints manually anymore or pause via DevTools — Cypress now supports it natively. Pro tip: Use it alongside .only and .debug() for powerful test inspection sessions. Bonus: use cy.stop() in afterEach() to halt further test execution In some scenarios, especially in CI environments or resource-intensive apps, you might want to stop the entire suite after a certain test runs, for example, if a critical failure occurs or if you're debugging and don’t want Cypress to continue running all remaining tests. afterEach(() => { // Stop further tests from running cy.stop(); }); This can be helpful when: You’re investigating a specific test failure and want to reduce test time You’ve already hit a known issue and want to skip everything else You’re preventing high memory or CPU usage in CI after a failure It gives you fine-grained control over your test pipeline without needing to reconfigure your runner or manually skip specs. Real-world combo: use all three Here’s what a more modern, robust Cypress test could look like: describe('Keyboard-first login flow', () => { beforeEach(() => { cy.session('admin-session', () => { cy.request('POST', '/api/login', { email: 'admin@example.com', password: 'admin123' }).then(({ body }) => { window.localStorage.setItem('auth_token', body.token); }); }); }); it('should navigate through the login form with keyboard', () => { cy.visit('/login'); cy.get('input[name="email"]').focus(); cy.press(Cypress.Keyboard.Keys.TAB); cy.focused().should('have.attr', 'name', 'password'); }); it('should pause before interacting with dashboard', () => { cy.visit('/dashboard'); cy.stop(); // Inspect DOM or state here cy.contains('Welcome, admin'); }); }); This test: Logs in once using cy.session() Simulates keyboard navigation with cy.press() Pauses for inspection with cy.stop() Clean. Performant. Inspectable. Conclusion These new Cypress features are small additions, but

End-to-end testing has evolved. Today, Cypress offers more than just a slick UI and an intuitive syntax, it now comes packed with powerful features that make tests faster, more realistic and easier to debug.
In this article, we’ll dive into three of the most exciting additions to Cypress:
-
cy.session()
— for smarter state caching -
cy.press()
— for realistic keyboard navigation -
cy.stop()
— for precise control of test execution
Whether you're scaling tests across CI, validating accessibility flows or debugging a tricky edge case, these new commands will upgrade your test suite.
cy.session()
: cache once, reuse everywhere
We’ve all repeated login flows in every test:
beforeEach(() => {
cy.visit('/login');
cy.get('input[name="email"]').type('test@example.com');
cy.get('input[name="password"]').type('passwordExample');
cy.get('button[type="submit"]').click();
});
It works, but it’s slow. And flaky.
cy.session()
solves this by caching browser state (like cookies and localStorage) after a one-time setup.
How to use it:
beforeEach(() => {
cy.session('admin-session', () => {
cy.request('POST', '/api/login', {
email: 'admin@example.com',
password: 'admin123'
}).then((res) => {
window.localStorage.setItem('auth_token', res.body.token);
});
});
});
Now your tests run faster and skip repeated login steps. Cypress restores the session seamlessly between tests in the same spec.
Bonus: If you're using Cypress Cloud, session state is even visible in replays.
cy.press()
: simulate real keyboard navigation
Testing keyboard behavior used to feel like a workaround. cy.type('{tab}')
could only go so far, it didn’t trigger real focus movement in most browsers.
Now Cypress supports cy.press()
, a new command designed for real keyboard event simulation (currently supporting Tab
).
Perfect for:
- Testing keyboard accessibility
- Navigating forms
- Validating focus order
cy.get('input[name="email"]').focus();
cy.press(Cypress.Keyboard.Keys.TAB);
cy.focused().should('have.attr', 'name', 'password');
What you should know:
- ✅ Works in Chromium and Firefox (v135+)
- ❌ Not yet supported in WebKit (e.g., Safari)
- ⚠️ Currently only supports
Tab
, more keys coming soon
It’s a big win for accessibility-first development and progressive enhancement strategies.
cy.stop()
: pause Cypress execution programmatically
Imagine this: your test is halfway through, and you want to inspect the DOM, view state or manually interact with the app before continuing.
cy.stop()
lets you pause test execution at any point, from code.
Example:
cy.visit('/dashboard');
cy.get('.notification').should('be.visible');
cy.stop(); // Open Cypress runner and inspect manually
This is incredibly useful for:
- Debugging
- Live demos
- Investigating CI failures
You don’t need to add breakpoints manually anymore or pause via DevTools — Cypress now supports it natively.
Pro tip: Use it alongside
.only
and.debug()
for powerful test inspection sessions.
Bonus: use cy.stop()
in afterEach()
to halt further test execution
In some scenarios, especially in CI environments or resource-intensive apps, you might want to stop the entire suite after a certain test runs, for example, if a critical failure occurs or if you're debugging and don’t want Cypress to continue running all remaining tests.
afterEach(() => {
// Stop further tests from running
cy.stop();
});
This can be helpful when:
- You’re investigating a specific test failure and want to reduce test time
- You’ve already hit a known issue and want to skip everything else
- You’re preventing high memory or CPU usage in CI after a failure
It gives you fine-grained control over your test pipeline without needing to reconfigure your runner or manually skip specs.
Real-world combo: use all three
Here’s what a more modern, robust Cypress test could look like:
describe('Keyboard-first login flow', () => {
beforeEach(() => {
cy.session('admin-session', () => {
cy.request('POST', '/api/login', {
email: 'admin@example.com',
password: 'admin123'
}).then(({ body }) => {
window.localStorage.setItem('auth_token', body.token);
});
});
});
it('should navigate through the login form with keyboard', () => {
cy.visit('/login');
cy.get('input[name="email"]').focus();
cy.press(Cypress.Keyboard.Keys.TAB);
cy.focused().should('have.attr', 'name', 'password');
});
it('should pause before interacting with dashboard', () => {
cy.visit('/dashboard');
cy.stop(); // Inspect DOM or state here
cy.contains('Welcome, admin');
});
});
This test:
- Logs in once using
cy.session()
- Simulates keyboard navigation with
cy.press()
- Pauses for inspection with
cy.stop()
Clean. Performant. Inspectable.
Conclusion
These new Cypress features are small additions, but they enable big wins:
- Shorter, faster tests
- Realistic user interaction simulation
- Easier debugging and flow validation
If you haven’t tried them yet, now’s the time to experiment.
Cypress isn’t just about writing tests. It’s about creating confidence through repeatable, human-like workflows. And these features bring us closer than ever.