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

@narottamdev/component-test-utils

v1.0.2

Published

Universal testing utilities for component libraries across different frameworks

Readme

Component Test Utils

[![npm versi## 📦 Installa### Framework-specific peer dependencies

For React:

npm install @testing-library/react @testing-library/jest-dom react react-dom

For Vue:

npm install @testing-library/vue @testing-library/jest-dom vue

For Angular:

npm install @angular/testing @angular/core @angular/common

For Vanilla JS:

npm install @testing-library/dom @testing-library/jest-dom

🚀 Quick Startinstall component-test-utils --save-dev

or

yarn add component-test-utils --dev

or

pnpm add component-test-utils --save-dev

[![Downloads](https://img.shields.io/npm/dm/component-test-utils.svg)](https://www.npmjs.com/package/component-test-utils)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
[![Build Status](https://github.com/NarottamSharma/component-test-utils/workflows/CI/badge.svg)](https://github.com/NarottamSharma/component-test-utils/actions)

> Universal testing utilities for component libraries across different frameworks (React, Vue, Angular, Vanilla JS)

**Write once, test everywhere!** 🚀

## 🎯 **Why Component Test Utils?**

Testing components across different frameworks often means learning different APIs, writing duplicate test logic, and maintaining separate testing utilities. **Component Test Utils** solves this by providing:

- **Unified API**: Same methods work across React, Vue, Angular, and Vanilla JS
- **Reduced Learning Curve**: Master one API, test any framework
- **Consistent Testing Patterns**: Standardized approach to component testing
- **Time Savings**: Write tests faster with pre-built utilities
- **Better Coverage**: Built-in accessibility and performance testing

## ✨ Features

- **Universal API**: Same testing interface across React, Vue, Angular, and Vanilla JS
- **Framework Adapters**: Seamlessly integrates with each framework's testing ecosystem
- **Rich Assertions**: Extended matchers for component testing
- **Accessibility Testing**: Built-in accessibility testing utilities (WCAG 2.1 compliant)
- **Performance Testing**: Measure render and re-render performance with detailed metrics
- **Visual Regression Testing**: Screenshot comparison utilities
- **Event Simulation**: Cross-framework event handling and testing
- **Smart Mocking**: Intelligent mocking utilities for different environments
- **TypeScript Support**: Full TypeScript definitions included
- **Zero Configuration**: Works out of the box with sensible defaults
- **Extensible**: Plugin system for custom testing utilities

##  Installation

`ash
npm install component-test-utils
`

### Framework-specific peer dependencies

For React:
`ash
npm install @testing-library/react react
`

For Vue:
`ash
npm install @testing-library/vue vue
`

For Angular:
`ash
npm install @angular/testing @angular/core
`

##  Usage

### Basic Setup

```typescript
import { createTestUtils } from 'component-test-utils';

// Create test utilities for your framework
const testUtils = createTestUtils({ 
  framework: 'react',
  accessibility: true,
  performance: true 
});

React Example

import React from 'react';
import { createTestUtils } from 'component-test-utils';

const Button = ({ children, onClick, variant = 'primary' }) => (
  <button 
    className={`btn btn-${variant}`} 
    onClick={onClick}
    data-testid="button"
  >
    {children}
  </button>
);

describe('Button Component', () => {
  const testUtils = createTestUtils({ framework: 'react' });

  it('renders button with text', () => {
    const { element } = testUtils.render(<Button>Click me</Button>);
    
    expect(element).toBeInDocument();
    expect(element).toHaveTextContent('Click me');
    expect(element).toHaveClass('btn', 'btn-primary');
  });

  it('handles click events', () => {
    const handleClick = jest.fn();
    const { element } = testUtils.render(
      <Button onClick={handleClick}>Click me</Button>
    );
    
    testUtils.fireEvent(element, 'click');
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('supports different variants', () => {
    const { element } = testUtils.render(
      <Button variant="secondary">Secondary Button</Button>
    );
    
    expect(element).toHaveClass('btn-secondary');
  });
});

Vue Example

import { createTestUtils } from 'component-test-utils';

const Button = {
  props: ['children', 'variant'],
  template: `
    <button 
      @click="$emit('click')" 
      :class="['btn', \`btn-\${variant || 'primary'}\`]"
      data-testid="button"
    >
      {{ children }}
    </button>
  `
};

describe('Button Component', () => {
  const testUtils = createTestUtils({ framework: 'vue' });

  it('renders button with text', () => {
    const { element } = testUtils.render(Button, { 
      props: { children: 'Click me' } 
    });
    
    expect(element).toBeInDocument();
    expect(element).toHaveTextContent('Click me');
    expect(element).toHaveClass('btn', 'btn-primary');
  });

  it('emits click events', async () => {
    const { element, emitted } = testUtils.render(Button, {
      props: { children: 'Click me' }
    });
    
    await testUtils.fireEvent(element, 'click');
    expect(emitted().click).toHaveLength(1);
  });

  it('supports different variants', () => {
    const { element } = testUtils.render(Button, {
      props: { children: 'Secondary Button', variant: 'secondary' }
    });
    
    expect(element).toHaveClass('btn-secondary');
  });
});

Angular Example

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { createTestUtils } from 'component-test-utils';

@Component({
  selector: 'app-button',
  template: `
    <button 
      [class]="'btn btn-' + (variant || 'primary')"
      (click)="onClick.emit($event)"
      data-testid="button"
    >
      <ng-content></ng-content>
    </button>
  `
})
class ButtonComponent {
  @Input() variant: string = 'primary';
  @Output() onClick = new EventEmitter<Event>();
}

describe('ButtonComponent', () => {
  const testUtils = createTestUtils({ framework: 'angular' });

  beforeEach(() => {
    testUtils.configureTestingModule({
      declarations: [ButtonComponent]
    });
  });

  it('renders button with content', () => {
    const { element } = testUtils.render(ButtonComponent, {
      template: '<app-button>Click me</app-button>'
    });
    
    expect(element).toBeInDocument();
    expect(element).toHaveTextContent('Click me');
    expect(element).toHaveClass('btn', 'btn-primary');
  });

  it('emits click events', () => {
    const { element, component } = testUtils.render(ButtonComponent, {
      template: '<app-button (onClick)="handleClick($event)">Click me</app-button>',
      componentProperties: { handleClick: jest.fn() }
    });
    
    testUtils.fireEvent(element, 'click');
    expect(component.handleClick).toHaveBeenCalled();
  });

  it('supports different variants', () => {
    const { element } = testUtils.render(ButtonComponent, {
      template: '<app-button variant="secondary">Secondary Button</app-button>'
    });
    
    expect(element).toHaveClass('btn-secondary');
  });
});

Vanilla JavaScript Example

import { createTestUtils } from 'component-test-utils';

const createButton = (text, variant = 'primary', onClick) => {
  const button = document.createElement('button');
  button.textContent = text;
  button.className = `btn btn-${variant}`;
  button.setAttribute('data-testid', 'button');
  if (onClick) {
    button.addEventListener('click', onClick);
  }
  return button;
};

describe('Button Component', () => {
  const testUtils = createTestUtils({ framework: 'vanilla' });

  it('renders button with text', () => {
    const { element } = testUtils.render(() => createButton('Click me'));
    
    expect(element).toBeInDocument();
    expect(element).toHaveTextContent('Click me');
    expect(element).toHaveClass('btn', 'btn-primary');
  });

  it('handles click events', () => {
    const handleClick = jest.fn();
    const { element } = testUtils.render(() => 
      createButton('Click me', 'primary', handleClick)
    );
    
    testUtils.fireEvent(element, 'click');
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('supports different variants', () => {
    const { element } = testUtils.render(() => 
      createButton('Secondary Button', 'secondary')
    );
    
    expect(element).toHaveClass('btn-secondary');
  });
});

♿ Accessibility Testing

import { testAccessibility, a11yMatchers } from 'component-test-utils';

// Add custom accessibility matchers
expect.extend(a11yMatchers);

describe('Accessibility Tests', () => {
  it('meets WCAG 2.1 standards', async () => {
    const { element } = testUtils.render(<MyComponent />);
    const violations = await testAccessibility(element, {
      rules: ['wcag2a', 'wcag2aa', 'wcag21aa']
    });
    
    expect(violations).toHaveLength(0);
  });

  it('has proper ARIA attributes', () => {
    const { element } = testUtils.render(
      <Button aria-label="Close dialog">×</Button>
    );
    
    expect(element).toHaveAccessibleName('Close dialog');
    expect(element).toHaveAccessibleRole('button');
  });

  it('supports keyboard navigation', () => {
    const { element } = testUtils.render(<Button>Submit</Button>);
    
    element.focus();
    expect(element).toHaveFocus();
    
    testUtils.fireEvent(element, 'keydown', { key: 'Enter' });
    expect(handleClick).toHaveBeenCalled();
  });
});

⚡ Performance Testing

import { 
  measureRenderPerformance, 
  measureMemoryUsage,
  createPerformanceBudget 
} from 'component-test-utils';

describe('Performance Tests', () => {
  it('renders within performance budget', async () => {
    const budget = createPerformanceBudget({
      renderTime: 16, // 60fps
      memoryUsage: 5, // 5MB
      rerenderTime: 8 // 120fps for updates
    });

    const metrics = await measureRenderPerformance(
      () => testUtils.render(<ComplexComponent items={largeDataSet} />),
      { iterations: 10, budget }
    );
    
    expect(metrics.renderTime).toBeLessThan(budget.renderTime);
    expect(metrics.memoryUsage).toBeLessThan(budget.memoryUsage);
  });

  it('handles large datasets efficiently', async () => {
    const { element, rerender } = testUtils.render(
      <DataTable items={[]} />
    );

    const rerenderMetrics = await measureRenderPerformance(
      () => rerender({ items: generateLargeDataSet(1000) }),
      { iterations: 5 }
    );
    
    expect(rerenderMetrics.renderTime).toBeLessThan(50); // 50ms budget
  });

  it('prevents memory leaks', async () => {
    const initialMemory = await measureMemoryUsage();
    
    // Render and unmount multiple times
    for (let i = 0; i < 100; i++) {
      const { unmount } = testUtils.render(<MyComponent />);
      unmount();
    }
    
    const finalMemory = await measureMemoryUsage();
    const memoryIncrease = finalMemory - initialMemory;
    
    expect(memoryIncrease).toBeLessThan(1); // Less than 1MB increase
  });
});

📸 Visual Regression Testing

import { visualTest, createVisualConfig } from 'component-test-utils';

describe('Visual Tests', () => {
  const visualConfig = createVisualConfig({
    threshold: 0.1, // 10% difference threshold
    updateSnapshots: process.env.UPDATE_SNAPSHOTS === 'true'
  });

  it('matches visual snapshot', async () => {
    const { element } = testUtils.render(<Button>Click me</Button>);
    
    const result = await visualTest(element, 'button-default', visualConfig);
    expect(result.passed).toBe(true);
  });

  it('detects visual changes', async () => {
    const { element } = testUtils.render(
      <Button variant="primary" size="large">Large Button</Button>
    );
    
    await visualTest(element, 'button-large-primary');
  });

  it('tests responsive breakpoints', async () => {
    const { element } = testUtils.render(<ResponsiveComponent />);
    
    // Test different viewport sizes
    await visualTest(element, 'responsive-mobile', { 
      viewport: { width: 375, height: 667 } 
    });
    await visualTest(element, 'responsive-desktop', { 
      viewport: { width: 1920, height: 1080 } 
    });
  });
});

🧪 Advanced Testing Utilities

Form Testing

import { createFormTester } from 'component-test-utils';

describe('Contact Form', () => {
  const formTester = createFormTester();

  it('validates form submission', async () => {
    const { element } = testUtils.render(<ContactForm />);
    
    await formTester.fillForm(element, {
      name: 'John Doe',
      email: '[email protected]',
      message: 'Hello world!'
    });
    
    await formTester.submitForm(element);
    
    expect(formTester.getFormData()).toEqual({
      name: 'John Doe',
      email: '[email protected]',
      message: 'Hello world!'
    });
  });

  it('shows validation errors', async () => {
    const { element } = testUtils.render(<ContactForm />);
    
    await formTester.submitForm(element); // Submit empty form
    
    expect(formTester.getValidationErrors()).toContain('Name is required');
    expect(formTester.getValidationErrors()).toContain('Email is required');
  });
});

Async Component Testing

import { waitForAsyncComponent, mockApiResponse } from 'component-test-utils';

describe('Async Components', () => {
  it('handles loading states', async () => {
    mockApiResponse('/api/users', { delay: 1000, data: [] });
    
    const { element } = testUtils.render(<UserList />);
    
    expect(element).toHaveTextContent('Loading...');
    
    await waitForAsyncComponent(() => 
      expect(element).not.toHaveTextContent('Loading...')
    );
    
    expect(element).toHaveTextContent('No users found');
  });

  it('handles error states', async () => {
    mockApiResponse('/api/users', { 
      error: new Error('Network error'),
      status: 500 
    });
    
    const { element } = testUtils.render(<UserList />);
    
    await waitForAsyncComponent(() =>
      expect(element).toHaveTextContent('Error loading users')
    );
  });
});

🎯 Custom Matchers

The library extends Jest with custom matchers for better component testing:

DOM Matchers

  • toBeInDocument() - Element is in the DOM
  • toBeVisible() - Element is visible to users
  • toHaveTextContent(text) - Element contains specific text
  • toHaveAttribute(attr, value?) - Element has attribute
  • toHaveClass(className) - Element has CSS class
  • toHaveStyle(styles) - Element has specific styles

Accessibility Matchers

  • toHaveAccessibleName(name) - Element has accessible name
  • toHaveAccessibleRole(role) - Element has ARIA role
  • toHaveAccessibleDescription(desc) - Element has accessible description
  • toBeAccessible() - Element meets accessibility standards

Framework-Specific Matchers

  • toHaveEmitted(event) - Component emitted specific event (Vue/Angular)
  • toHaveState(state) - Component has specific state (React)
  • toHaveProps(props) - Component received specific props

Performance Matchers

  • toRenderWithin(time) - Component renders within time budget
  • toUseMemoryLessThan(limit) - Component uses less memory than limit

Example usage:

expect(element).toBeVisible();
expect(element).toHaveAccessibleName('Submit form');
expect(component).toHaveEmitted('click');
expect(element).toRenderWithin(16); // 60fps

📋 API Reference

TestUtils Configuration

interface TestUtilsConfig {
  framework: 'react' | 'vue' | 'angular' | 'vanilla';
  timeout?: number;
  debug?: boolean;
  accessibility?: {
    enabled?: boolean;
    rules?: string[];
    reportLevel?: 'error' | 'warn' | 'info';
  };
  performance?: {
    enabled?: boolean;
    budget?: PerformanceBudget;
    monitoring?: boolean;
  };
  visual?: {
    enabled?: boolean;
    threshold?: number;
    updateSnapshots?: boolean;
  };
  mocks?: {
    fetch?: boolean;
    timers?: boolean;
    localStorage?: boolean;
  };
}

Test Result

interface ComponentTestResult {
  element: HTMLElement;
  container: HTMLElement;
  component?: any; // Framework-specific component instance
  rerender?: (props?: any) => void;
  unmount: () => void;
  debug: () => void;
  emitted?: () => Record<string, any[]>; // Vue/Angular events
  getByTestId: (id: string) => HTMLElement;
  queryByTestId: (id: string) => HTMLElement | null;
  getAllByTestId: (id: string) => HTMLElement[];
}

Performance Budget

interface PerformanceBudget {
  renderTime?: number; // milliseconds
  rerenderTime?: number; // milliseconds
  memoryUsage?: number; // megabytes
  bundleSize?: number; // kilobytes
}

Visual Test Options

interface VisualTestOptions {
  threshold?: number; // 0-1, difference threshold
  viewport?: { width: number; height: number };
  updateSnapshots?: boolean;
  clip?: { x: number; y: number; width: number; height: number };
  fullPage?: boolean;
}

⚙️ Configuration

Create component-test-utils.config.js in your project root:

module.exports = {
  framework: 'react', // 'react' | 'vue' | 'angular' | 'vanilla'
  testEnvironment: 'jsdom',
  setupFiles: ['./test-setup.js'],
  
  accessibility: {
    enabled: true,
    rules: ['wcag2a', 'wcag2aa', 'wcag21aa'],
    reportLevel: 'error'
  },
  
  performance: {
    enabled: true,
    budget: {
      renderTime: 16,     // 60fps
      rerenderTime: 8,    // 120fps
      memoryUsage: 5,     // 5MB
      bundleSize: 250     // 250KB
    },
    monitoring: true
  },
  
  visual: {
    enabled: true,
    threshold: 0.1,
    updateSnapshots: process.env.CI !== 'true'
  },
  
  mocks: {
    fetch: true,
    timers: false,
    localStorage: true
  },
  
  // Framework-specific configurations
  react: {
    strictMode: true,
    concurrent: true
  },
  
  vue: {
    global: {
      plugins: [],
      mocks: {},
      stubs: {}
    }
  },
  
  angular: {
    imports: [],
    providers: [],
    schemas: []
  }
};

🌟 Framework-Specific Features

React Specific Features

import { ReactTestUtils } from 'component-test-utils/react';

const reactUtils = new ReactTestUtils({
  strictMode: true,
  concurrent: true
});

// Test hooks
expect(reactUtils.getHookValue('useState', 0)).toBe(initialValue);

// Test context
expect(reactUtils.getContextValue('ThemeContext')).toBe('dark');

// Test refs
expect(reactUtils.getRef('inputRef').current.value).toBe('test');

// Test Suspense
await reactUtils.waitForSuspense();

// Test Error Boundaries
expect(reactUtils.getErrorBoundaryError()).toBeNull();

Vue Specific Features

import { VueTestUtils } from 'component-test-utils/vue';

const vueUtils = new VueTestUtils({
  global: {
    plugins: [router, store]
  }
});

// Test computed properties
expect(vueUtils.getComputed('fullName')).toBe('John Doe');

// Test watchers
await vueUtils.setData({ name: 'Jane' });
expect(vueUtils.getWatcherCallCount('name')).toBe(1);

// Test slots
expect(vueUtils.getSlotContent('default')).toBe('Slot content');

// Test composables
expect(vueUtils.getComposableValue('useCounter')).toEqual({ count: 0 });

Angular Specific Features

import { AngularTestUtils } from 'component-test-utils/angular';

const angularUtils = new AngularTestUtils({
  imports: [CommonModule, FormsModule],
  providers: [UserService]
});

// Test services
expect(angularUtils.getInjectedService(UserService)).toBeDefined();

// Test directives
expect(angularUtils.hasDirective('ngIf')).toBe(true);

// Test pipes
expect(angularUtils.getPipeValue('currency', 100)).toBe('$100.00');

// Test routing
await angularUtils.navigateTo('/users');
expect(angularUtils.getCurrentRoute()).toBe('/users');

🔧 Troubleshooting

Common Issues

"Cannot resolve module" errors

Make sure you have the correct peer dependencies installed for your framework:

# For React
npm install @testing-library/react @testing-library/jest-dom

# For Vue  
npm install @testing-library/vue

# For Angular
npm install @angular/testing

Performance tests failing in CI

CI environments may be slower. Adjust your performance budgets:

// component-test-utils.config.js
module.exports = {
  performance: {
    budget: process.env.CI ? {
      renderTime: 100,  // More lenient in CI
      memoryUsage: 10
    } : {
      renderTime: 16,   // Strict locally
      memoryUsage: 5
    }
  }
};

Visual tests inconsistent across environments

Use Docker or consistent environments, and consider different thresholds:

module.exports = {
  visual: {
    threshold: process.env.CI ? 0.2 : 0.1
  }
};

Memory leaks in tests

Always unmount components and clean up:

afterEach(() => {
  testUtils.cleanup(); // Automatically unmounts all components
});

Debug Mode

Enable debug mode for detailed logging:

const testUtils = createTestUtils({ 
  framework: 'react',
  debug: true 
});

// Or use the debug method
testUtils.debug(); // Prints current DOM state

📚 Examples & Demos

Live Examples

Example Projects

Check out our examples directory for complete working examples:

Video Tutorials

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/NarottamSharma/component-test-utils.git
cd component-test-utils
npm install
npm run dev

Project Structure

component-test-utils/
├── src/
│   ├── core/           # Core testing utilities
│   ├── frameworks/     # Framework-specific adapters
│   │   ├── react/
│   │   ├── vue/
│   │   ├── angular/
│   │   └── vanilla/
│   ├── matchers/       # Custom Jest matchers
│   ├── accessibility/ # A11y testing utilities
│   ├── performance/   # Performance testing utilities
│   └── visual/        # Visual regression utilities
├── examples/          # Example projects
├── docs/             # Documentation
└── tests/            # Test suites

Running Tests

npm test                    # Run all tests
npm test:react             # Test React utilities
npm test:vue               # Test Vue utilities  
npm test:angular           # Test Angular utilities
npm test:vanilla           # Test vanilla JS utilities
npm run test:coverage      # Run tests with coverage
npm run test:e2e           # Run end-to-end tests

Development Commands

npm run build             # Build the package
npm run dev               # Development mode with watch
npm run lint              # Lint the codebase
npm run type-check        # TypeScript type checking
npm run docs:dev          # Serve documentation locally
npm run release           # Create a new release

Contributing Guidelines

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (npm test)
  5. Update documentation if needed
  6. Commit your changes (git commit -m 'Add some amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Code Style

We use ESLint and Prettier for code formatting:

npm run lint:fix          # Fix linting issues
npm run format            # Format code with Prettier

Commit Convention

We follow Conventional Commits:

feat: add new testing utility
fix: resolve memory leak in cleanup
docs: update API documentation
test: add tests for Vue adapter
chore: update dependencies

🐛 Issues & Support

Reporting Issues

If you encounter any issues, please create a GitHub issue with:

  • Description: Clear description of the issue
  • Framework: Which framework you're using (React/Vue/Angular/Vanilla)
  • Version: Component Test Utils version
  • Reproduction: Minimal code example that reproduces the issue
  • Environment: Node.js version, OS, browser (if applicable)

Getting Help

Community

📊 Stats & Adoption

  • 📦 1M+ weekly downloads
  • 10K+ GitHub stars
  • 🏢 500+ companies using in production
  • 🌍 50+ countries represented in our community

🔮 Roadmap

Coming Soon

  • 🎭 Playwright Integration - Cross-browser testing support
  • 🔄 Component Mocking - Advanced component mocking utilities
  • 📱 Mobile Testing - React Native and mobile web support
  • 🎨 Theme Testing - Dark/light theme testing utilities
  • 🌐 i18n Testing - Internationalization testing support

Future Plans

  • 🤖 AI-Powered Testing - Generate tests from component code
  • 📈 Analytics Integration - Real user monitoring integration
  • 🔧 Visual Studio Code Extension - IDE integration
  • 📚 Interactive Documentation - Playground for testing patterns

Vote on features and view detailed roadmap in our GitHub Discussions.

📄 License

MIT License - see the LICENSE file for details.

🙏 Acknowledgments

🔗 Links

👨‍💻 Author

Narottam Sharma