Cypress Architecture & Component Testing
Cypress is a JavaScript-native E2E testing framework that runs directly in the browser — giving it unique capabilities that distinguish it from Selenium and Playwright. Its killer features are real-time test reloading during development, time-travel debugging, and native component testing. Cypress is the preferred choice for React, Vue, and Angular teams doing test-driven development.
Cypress Architecture vs Selenium/Playwright
- In-browser execution: Cypress runs inside the browser (not over WebDriver), giving it direct access to DOM, window, and app state
- Automatic retries: Cypress retries all commands and assertions automatically until they pass or timeout — no explicit waits
- Real-time reloading: cypress open watches test files and reruns tests on every save — instant feedback during TDD
- Time-travel debugging: Click any command in the test runner to see the DOM snapshot at that exact moment
- Component Testing: Test individual React/Vue/Angular components in isolation without a full browser E2E setup
- Limitation: Only supports Chromium-based browsers natively (Chrome, Edge); Firefox supported but experimental; no Safari/WebKit
- Best for: Frontend teams doing TDD on React/Vue/Angular; not ideal for multi-browser compatibility testing
Cypress E2E and Component Tests
// ══════════════════════════════════════════════════════════════
// SETUP: npm install -D cypress
// npx cypress open (interactive) OR
// npx cypress run (headless/CI)
// ══════════════════════════════════════════════════════════════
// ── E2E TEST (cypress/e2e/login.cy.ts) ────────────────────────
describe('Login Flow', () => {
beforeEach(() => {
cy.visit('/login');
});
it('logs in with valid credentials', () => {
cy.get('[data-testid="email"]').type('alice@test.com');
cy.get('[data-testid="password"]').type('Test@1234');
cy.get('[data-testid="login-btn"]').click();
// Cypress auto-retries until condition is met (default 4s)
cy.url().should('include', '/dashboard');
cy.get('.welcome-message').should('contain', 'Welcome, Alice');
});
it('shows error for wrong credentials', () => {
cy.get('#email').type('wrong@test.com');
cy.get('#password').type('wrongpass');
cy.get('button[type="submit"]').click();
cy.get('.error-message')
.should('be.visible')
.and('contain', 'Invalid email or password');
});
// CUSTOM COMMANDS — reusable login via cy.login()
// cypress/support/commands.ts:
// Cypress.Commands.add('login', (email: string, password: string) => {
// cy.request('POST', '/api/auth/login', { email, password })
// .then((res) => cy.setCookie('auth_token', res.body.token));
// });
it('uses custom login command (API login — faster)', () => {
cy.login('alice@test.com', 'Test@1234'); // Skips UI login
cy.visit('/dashboard');
cy.get('.welcome-message').should('be.visible');
});
});
// ── COMPONENT TEST (cypress/component/LoginForm.cy.tsx) ────────
// Tests the LoginForm React component in complete isolation
import LoginForm from '../../src/components/LoginForm';
describe('LoginForm Component', () => {
it('renders all form fields', () => {
cy.mount(<LoginForm onSubmit={cy.stub()} />);
cy.get('input[type="email"]').should('exist');
cy.get('input[type="password"]').should('exist');
cy.get('button[type="submit"]').should('contain', 'Sign In');
});
it('calls onSubmit with credentials when form is submitted', () => {
const onSubmit = cy.stub().as('submitHandler');
cy.mount(<LoginForm onSubmit={onSubmit} />);
cy.get('input[type="email"]').type('alice@test.com');
cy.get('input[type="password"]').type('Test@1234');
cy.get('button[type="submit"]').click();
cy.get('@submitHandler').should('have.been.calledOnceWith', {
email: 'alice@test.com',
password: 'Test@1234'
});
});
it('shows validation error for empty email', () => {
cy.mount(<LoginForm onSubmit={cy.stub()} />);
cy.get('button[type="submit"]').click();
cy.get('.email-error').should('contain', 'Email is required');
});
});Common Mistakes
- Using cy.wait(2000) everywhere — Cypress has built-in retry; using wait() is the same anti-pattern as Selenium's time.sleep()
- Logging in via UI for every test — use cy.request() to call the login API directly and set the session cookie; 10x faster
- Not using custom commands — repetitive multi-step flows should be abstracted into Cypress.Commands.add() for DRY, maintainable tests
- Ignoring component testing — component tests catch prop and state bugs at the component level without needing a full E2E setup
Tip
Tip
Practice Cypress Architecture Component Testing in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
Test behavior, not implementation. Query by role first.
Practice Task
Note
Practice Task — (1) Write a working example of Cypress Architecture Component Testing from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Quick Quiz
Common Mistake
Warning
A common mistake with Cypress Architecture Component Testing is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready software testing code.
Key Takeaways
- Cypress is a JavaScript-native E2E testing framework that runs directly in the browser — giving it unique capabilities that distinguish it from Selenium and Playwright.
- In-browser execution: Cypress runs inside the browser (not over WebDriver), giving it direct access to DOM, window, and app state
- Automatic retries: Cypress retries all commands and assertions automatically until they pass or timeout — no explicit waits
- Real-time reloading: cypress open watches test files and reruns tests on every save — instant feedback during TDD