Cypress is not just another Selenium alternative โ it is a fundamentally different approach to browser testing. While Selenium operates outside the browser by sending commands over the WebDriver protocol, Cypress runs inside the browser alongside your application code. This architectural decision gives Cypress direct access to the DOM, network requests, timers and everything else happening in the browser, making tests faster, more reliable, and easier to debug. Understanding this architecture is essential before writing your first test.
Cypress Architecture โ Inside the Browser, Not Outside It
The architectural difference between Cypress and Selenium explains nearly every advantage and limitation of both tools.
// Cypress architecture โ how it works under the hood
/*
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ BROWSER (Chrome / Firefox / Edge / Electron) โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Your Application โ โ Cypress Test Code โ โ
โ โ (the app under โ โ (runs in the SAME โ โ
โ โ test, loaded in โ โ browser context) โ โ
โ โ an iframe) โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ Cypress Driver (orchestrates commands, โโ
โ โ manages retries, captures snapshots) โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Node.js Server
(file system, network
proxying, plugins)
SELENIUM COMPARISON:
Test Code โ HTTP โ WebDriver โ Browser
(outside) (slow) (bridge) (isolated)
CYPRESS:
Test Code โ Direct DOM Access โ Browser
(inside) (instant) (same process)
*/
// Key architectural advantages
const CYPRESS_ADVANTAGES = {
"Automatic waiting": `Cypress automatically retries commands until the element
is found or the timeout expires โ no explicit waits needed. When you write
cy.get('.btn').click(), Cypress retries .get() for up to 4 seconds by default.`,
"Real-time reloading": `The Test Runner watches your test files and re-runs
automatically when you save changes โ instant feedback during development.`,
"Time-travel debugging": `Every command takes a DOM snapshot. You can hover over
any step in the Command Log to see exactly what the page looked like at that
moment โ including before and after states.`,
"Network control": `Cypress can intercept, stub, and modify HTTP requests and
responses without external tools โ cy.intercept() replaces the need for
mock servers in many scenarios.`,
"Consistent results": `Because Cypress controls the test loop synchronously
inside the browser, there are no race conditions between the test and the
application. Commands execute in a deterministic order.`,
};
// Key architectural limitations
const CYPRESS_LIMITATIONS = {
"Single browser tab": `Cypress cannot open or switch between multiple browser
tabs or windows. Multi-tab workflows must be tested differently.`,
"Same-origin only": `Cypress can only visit URLs on the same origin within a
single test. Cross-origin navigation requires cy.origin() (Cypress 12+).`,
"JavaScript/TypeScript only": `Tests must be written in JavaScript or TypeScript.
No Python, Java, or C# support.`,
"Limited browser support": `Chrome, Firefox, Edge, and Electron. No Safari
support (WebKit not available in Cypress).`,
"No native mobile testing": `Cypress tests responsive layouts via viewport
resizing but cannot test native mobile apps.`,
};
console.log("Cypress Architecture: Inside the browser");
console.log("Selenium Architecture: Outside the browser via WebDriver protocol");
cy.get('.product-card'), Cypress does not make a single attempt and fail โ it continuously polls the DOM for up to 4 seconds (configurable), checking every few milliseconds until the element appears. This built-in retry eliminates the need for explicit WebDriverWait calls that Selenium requires for every interaction. Most Selenium flakiness comes from missing or incorrect waits; Cypress avoids this entire category of bugs by design.href and target attributes of links rather than clicking them and switching tabs: cy.get('a.terms-link').should('have.attr', 'href', '/terms').and('have.attr', 'target', '_blank'). This verifies the link will open in a new tab without needing to actually open one.Common Mistakes
Mistake 1 โ Treating Cypress like Selenium and adding explicit waits everywhere
โ Wrong: cy.wait(5000); cy.get('.btn').click(); โ adding fixed waits like Selenium’s time.sleep().
โ
Correct: cy.get('.btn').click(); โ Cypress automatically retries .get() until the element appears or the default timeout (4s) expires. No manual wait needed.
Mistake 2 โ Choosing Cypress without evaluating browser coverage needs
โ Wrong: “Cypress is the best testing tool โ we will use it for everything.” Then discovering it does not support Safari, which 20% of users rely on.
โ Correct: “Cypress is excellent for Chrome/Firefox/Edge E2E testing. For Safari/WebKit coverage, we will supplement with Playwright’s WebKit support or a cloud provider.”