VOOZH about

URL: https://dev.to/swmcc/cypress-component-isolation-issues-54bm

⇱ Cypress Component Isolation Issues - DEV Community


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.