Cypress Component Isolation Issues
Working on a personal project, I hit a frustrating limitation with Cypress: component state bleeding between tests.
The Problem
Cypress mounts components in the same browser context across tests. Even with beforeEach cleanup, some state persists:
- Event listeners accumulate
- CSS-in-JS styles duplicate
- Global window objects leak between tests
- Memory usage grows linearly with test count
Example that failed intermittently:
describe('User form', () => {
beforeEach(() => {
cy.mount(<UserForm />)
})
it('validates email', () => {
cy.get('[data-testid="email"]').type('invalid')
cy.get('[data-testid="error"]').should('contain', 'Invalid email')
})
it('submits successfully', () => {
cy.get('[data-testid="email"]').type('valid@example.com')
cy.get('[data-testid="submit"]').click()
// Fails intermittently - previous test's error message still in DOM
})
})
Why This Happens
Cypress reuses the browser instance. Components unmount, but:
- The iframe stays alive
- JavaScript heap isn’t cleared
- Event listeners require explicit cleanup
- Third-party libraries may not clean up properly
The Workaround
Force full remount between tests:
afterEach(() => {
cy.window().then((win) => {
win.location.reload()
})
})
This works but adds ~500ms per test. With 200+ component tests, that’s 100 seconds of wasted time.
Playwright Does This Better
Playwright’s component testing uses isolated browser contexts per test. Each test gets:
- Fresh browser context
- Clean JavaScript heap
- No state leakage
- Parallel execution by default
Same test in Playwright:
test('submits successfully', async ({ mount }) => {
const component = await mount(<UserForm />)
await component.getByTestId('email').fill('valid@example.com')
await component.getByTestId('submit').click()
// Always works - completely isolated from previous test
})
No manual cleanup. No intermittent failures. No performance workaround.
Migration Considerations
Switching to Playwright would mean:
- Rewriting 200+ Cypress tests (different API)
- Learning new assertion patterns
- Different debugging workflow
- But: genuine test isolation and faster execution
The isolation model is compelling. Cypress is great for E2E, but for component testing, Playwright’s architecture is superior.
Might be time to migrate.