npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cypress-context-aware

v1.0.0

Published

A context-aware command system for Cypress that enables component-based test interactions

Readme

Cypress Context-Aware Commands

A powerful context-aware command system for Cypress that enables component-based test interactions with automatic command scoping and validation.

Table of Contents

Installation

npm install cypress-context-aware

Quick Start

// cypress/support/commands.js
import { ChainContext } from 'cypress-context-aware';

// Define your component commands
const Modal = {
  // Root command that establishes context
  modal(_, { waitForInteractive = true } = {}) {
    const modal = () => cy.get('[data-testid="modal"]');
    
    if (waitForInteractive) {
      modal().should('be.visible');
    }
    
    return modal();
  },

  // Context-aware commands
  header($subject) {
    return $subject.find('[data-testid="modal-header"]');
  },

  body($subject) {
    return $subject.find('[data-testid="modal-body"]');
  },

  footer($subject) {
    return $subject.find('[data-testid="modal-footer"]');
  }
};

// Register the commands
ChainContext.register('modal', Modal, { prevSubject: 'optional' });

Now you can use context-aware commands in your tests:

// These commands are scoped to the modal context
cy.modal()
  .header().should('contain', 'Welcome')
  .body().should('be.visible')
  .footer().find('button').click();

Core Concepts

Context-Aware Commands

Context-aware commands automatically understand their execution context based on the command chain. This enables:

  • Automatic Scoping: Commands know which component they're operating within
  • Command Validation: Prevents invalid command combinations
  • Custom Behavior: Commands can behave differently based on context
  • Better Error Messages: Clear errors when commands are used incorrectly

Root Commands vs Child Commands

  • Root Commands: Establish a new context (e.g., modal(), table())
  • Child Commands: Operate within an established context (e.g., header(), body())

Command Chain Tracking

The system automatically tracks the command chain using Cypress internals, eliminating the need for manual state management.

API Reference

ChainContext

The main export that provides the context-aware functionality.

ChainContext.register(name, commands, options)

Registers a set of context-aware commands.

  • name (string): The root command name
  • commands (object): Object containing command implementations
  • options (object): Cypress command options (e.g., { prevSubject: 'optional' })

ChainContext.preceedsCommand(commandName)

Checks if a specific command appears earlier in the current command chain.

// Example: Add debouncing when typing in search
type(originalFn, $subject, text, options) {
  if (ChainContext.preceedsCommand('search')) {
    originalFn($subject, text, options);
    return cy.wait(300); // Debounce search
  }
  return originalFn($subject, text, options);
}

ChainContext.rootCommand(command)

Returns the root command name for a given command in the chain.

ChainContext.validateCommand(commandName, currentCommand)

Validates that a command is allowed in the current context. Throws an error if invalid.

Helper Functions

s(func, defaultRoot)

A helper function for creating commands with optional subject handling.

import { s } from 'cypress-context-aware';

Cypress.Commands.add('customCommand', 
  { prevSubject: 'optional' },
  s(($subject, arg1, arg2) => {
    // $subject will be cy.root() if no subject provided
    return $subject.find('.something');
  })
);

Examples

Modal Component

import { ChainContext } from 'cypress-context-aware';

const Modal = {
  modal(_, { waitForInteractive = true } = {}) {
    const modal = () => cy.get('[data-testid="modal"]');
    
    if (waitForInteractive) {
      modal().should('be.visible');
    }
    
    return modal();
  },

  header($subject) {
    return $subject.find('[data-testid="modal-header"]');
  },

  body($subject) {
    return $subject.find('[data-testid="modal-body"]');
  },

  footer($subject) {
    return $subject.find('[data-testid="modal-footer"]');
  },

  close($subject) {
    return $subject.find('[aria-label="Close"]').click();
  }
};

ChainContext.register('modal', Modal, { prevSubject: 'optional' });

// Usage
cy.modal()
  .header().should('contain', 'Confirmation')
  .body().should('contain', 'Are you sure?')
  .footer().contains('button', 'OK').click();

cy.modal().close();

Table Component with Custom Type Behavior

import { ChainContext } from 'cypress-context-aware';

const Table = {
  table($subject = cy.root()) {
    return $subject.find('[data-testid="table"]');
  },

  search($subject) {
    return $subject.find('[data-testid="search-input"]');
  },

  rows($subject) {
    return $subject.find('tbody tr');
  },

  // Custom behavior for type command within search context
  type(originalFn, $subject, text, options = {}) {
    if (ChainContext.preceedsCommand('search')) {
      originalFn($subject, text, options);
      // Auto-debounce search queries
      return cy.wait(500);
    }
    
    return originalFn($subject, text, options);
  }
};

ChainContext.register('table', Table, { prevSubject: 'optional' });

// Usage - typing in search will automatically debounce
cy.table()
  .search().type('[email protected]') // Automatically waits 500ms
  .table().rows().should('have.length', 1);

Form Component

const Form = {
  form($subject = cy.root()) {
    return $subject.find('form');
  },

  field($subject, name) {
    return $subject.find(`[name="${name}"]`);
  },

  submit($subject) {
    return $subject.find('[type="submit"]').click();
  },

  // Custom validation
  shouldBeValid($subject) {
    return $subject.should('not.have.class', 'error');
  }
};

ChainContext.register('form', Form, { prevSubject: 'optional' });

// Usage
cy.form()
  .field('email').type('[email protected]')
  .field('password').type('secret123')
  .shouldBeValid()
  .submit();

Migration Guide

From Inline Implementation

If you're migrating from an inline context-aware implementation:

  1. Install the package:

    npm install cypress-context-aware
  2. Update imports:

    // Before
    import { ChainContext } from '../context-aware';
       
    // After
    import { ChainContext } from 'cypress-context-aware';
  3. Remove inline files:

    • Delete your local context-aware.js file
    • Update your support file imports
  4. Keep your component definitions:

    • Your existing component command objects remain unchanged
    • Only the import and registration system changes

Breaking Changes

  • None for v1.0.0 - this is the initial stable release

Advanced Usage

Error Handling and Validation

The system provides clear error messages when commands are used incorrectly:

// This will throw a clear error if 'header' is not available in current context
cy.someContext().header(); // Error: Command 'header' is not available in current root command: someContext

Command Chain Introspection

// Check what commands precede the current command
if (ChainContext.preceedsCommand('search')) {
  // We're in a search context
}

// Get the root command for current context
const root = ChainContext.rootCommand(cy.state('current'));

Custom Command Validation

const MyComponent = {
  root() {
    return cy.get('.my-component');
  },
  
  action($subject, actionType) {
    // Validate the action type
    if (!['create', 'edit', 'delete'].includes(actionType)) {
      throw new Error(`Invalid action type: ${actionType}`);
    }
    
    return $subject.find(`[data-action="${actionType}"]`).click();
  }
};

Best Practices

  1. Root Commands: Always make your root command return a chainable Cypress element
  2. Subject Handling: Use the s() helper for consistent subject handling
  3. Naming: Use descriptive names that reflect the component structure
  4. Validation: Add custom validation for command parameters when needed
  5. Documentation: Document expected DOM structure and dependencies

Troubleshooting

Common Issues

Q: Commands not working after registration A: Ensure you're importing the commands in your cypress/support/commands.js file.

Q: "Command not available in context" errors A: Check that you're calling child commands after establishing the root context.

Q: Type/clear commands not working as expected A: These commands have special handling due to Cypress internals. The system automatically handles this.

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to the main repository.

License

MIT License - see LICENSE file for details.


Made with ❤️ for the Cypress testing community