← Back to Cypress Mastery
Advanced20 min read

Advanced Topics

Custom commands, plugins, page objects, and CI integration patterns.

Custom Commands

Cypress.Commands.add defines reusable cy.login() style commands in support/commands.ts. TypeScript augmentation declares command signatures for autocomplete.

Keep commands thin—call API for login token then set cookie rather than slow UI login every test unless testing login itself.

Cypress.Commands.add("login", (email: string, password: string) => {
  cy.session([email, password], () => {
    cy.request("POST", "/api/login", { email, password });
  });
});

declare global {
  namespace Cypress {
    interface Chainable {
      login(email: string, password: string): Chainable<void>;
    }
  }
}

Plugins

Plugins extend config via setupNodeEvents—tasks, browser launch, code coverage, grep filtering. @cypress/grep runs tagged subsets; cypress-real-events adds realistic pointer events.

Evaluate plugin maintenance before adopting—pin versions and test upgrades in branch.

async setupNodeEvents(on, config) {
  require("@cypress/grep/src/plugin")(config);
  on("task", { log(message) { console.log(message); return null; } });
  return config;
}

Page Object Pattern

Page objects encapsulate selectors and actions for a page—LoginPage.visit(), LoginPage.submit(). Reduces duplication without hiding Cypress retry semantics inside async await antipatterns.

Prefer composable functions over deep inheritance hierarchies. Co-locate selectors with page object class.

class LoginPage {
  visit() { cy.visit("/login"); }
  fillEmail(email: string) { cy.get('[data-cy="email"]').type(email); }
  submit() { cy.get('[data-cy="submit"]').click(); }
}

Continuous Integration

Run cypress run in CI with start-server-and-test or wait-on to boot app. Parallelize with Cypress Cloud or sorry-cypress for on-prem.

Record runs to Cypress Cloud for flake detection, timing trends, and spec load balancing.

  • Set CYPRESS_RECORD_KEY secret for Cloud recording
  • Use docker image cypress/included for consistent browser versions
  • Split specs across parallel containers by timing from Cloud data
"ci:e2e": "start-server-and-test dev http://localhost:3000 'cypress run'"

Cross-Origin and Security

cy.origin() navigates and runs commands in different origin after superdomain change. Required for OAuth flows and embedded apps.

Chrome Web Security disabled in Cypress for cross-origin convenience—do not assume identical browser security behavior in production user browsers for all edge cases.

cy.origin("https://auth.example.com", () => {
  cy.get('input[name="username"]').type("user");
});

Get In Touch


Ready to discuss your next project? Drop me a message.