CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-storybook--testing-library

Instrumented version of Testing Library for Storybook Interactions addon

Pending
Overview
Eval results
Files

events.mddocs/

Event Handling

Direct DOM event triggering capabilities for lower-level interaction testing, with full instrumentation support. The fireEvent object provides methods for dispatching DOM events directly, useful for testing edge cases and low-level interactions.

Capabilities

Fire Event Object

Main interface for triggering DOM events directly. All fireEvent methods are instrumented for Storybook interaction tracking.

/**
 * Fire DOM events directly on elements
 * All methods are instrumented for Storybook interaction tracking
 */
interface FireEvent {
  /**
   * Dispatch a custom event on an element
   * @param element - Target element
   * @param event - Event object to dispatch
   * @returns Boolean indicating if event was not cancelled
   */
  (element: Element, event: Event): boolean;
  
  /**
   * Fire a click event
   * @param element - Element to click
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  click(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a double-click event
   * @param element - Element to double-click
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  dblClick(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse down event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseDown(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse up event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseUp(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse enter event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseEnter(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse leave event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseLeave(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse move event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseMove(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse over event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseOver(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a mouse out event
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  mouseOut(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a change event (for form elements)
   * @param element - Form element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  change(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire an input event (for form elements)
   * @param element - Form element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  input(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a focus event
   * @param element - Element to focus
   * @param options - Focus event options
   * @returns Boolean indicating if event was not cancelled
   */
  focus(element: Element, options?: FocusEventInit): boolean;
  
  /**
   * Fire a blur event
   * @param element - Element to blur
   * @param options - Focus event options
   * @returns Boolean indicating if event was not cancelled
   */
  blur(element: Element, options?: FocusEventInit): boolean;
  
  /**
   * Fire a focus-in event
   * @param element - Target element
   * @param options - Focus event options
   * @returns Boolean indicating if event was not cancelled
   */
  focusIn(element: Element, options?: FocusEventInit): boolean;
  
  /**
   * Fire a focus-out event
   * @param element - Target element
   * @param options - Focus event options
   * @returns Boolean indicating if event was not cancelled
   */
  focusOut(element: Element, options?: FocusEventInit): boolean;
  
  /**
   * Fire a key down event
   * @param element - Target element
   * @param options - Keyboard event options
   * @returns Boolean indicating if event was not cancelled
   */
  keyDown(element: Element, options?: KeyboardEventInit): boolean;
  
  /**
   * Fire a key up event
   * @param element - Target element
   * @param options - Keyboard event options
   * @returns Boolean indicating if event was not cancelled
   */
  keyUp(element: Element, options?: KeyboardEventInit): boolean;
  
  /**
   * Fire a key press event (deprecated but available)
   * @param element - Target element
   * @param options - Keyboard event options
   * @returns Boolean indicating if event was not cancelled
   */
  keyPress(element: Element, options?: KeyboardEventInit): boolean;
  
  /**
   * Fire a submit event on a form
   * @param element - Form element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  submit(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a reset event on a form
   * @param element - Form element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  reset(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a select event on an input
   * @param element - Input element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  select(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a scroll event
   * @param element - Scrollable element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  scroll(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a wheel event
   * @param element - Target element
   * @param options - Wheel event options
   * @returns Boolean indicating if event was not cancelled
   */
  wheel(element: Element, options?: WheelEventInit): boolean;
  
  /**
   * Fire a context menu event (right-click)
   * @param element - Target element
   * @param options - Mouse event options
   * @returns Boolean indicating if event was not cancelled
   */
  contextMenu(element: Element, options?: MouseEventInit): boolean;
  
  /**
   * Fire a drag event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  drag(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drag start event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  dragStart(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drag end event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  dragEnd(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drag enter event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  dragEnter(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drag leave event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  dragLeave(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drag over event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  dragOver(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a drop event
   * @param element - Target element
   * @param options - Drag event options
   * @returns Boolean indicating if event was not cancelled
   */
  drop(element: Element, options?: DragEventInit): boolean;
  
  /**
   * Fire a touch start event
   * @param element - Target element
   * @param options - Touch event options
   * @returns Boolean indicating if event was not cancelled
   */
  touchStart(element: Element, options?: TouchEventInit): boolean;
  
  /**
   * Fire a touch end event
   * @param element - Target element
   * @param options - Touch event options
   * @returns Boolean indicating if event was not cancelled
   */
  touchEnd(element: Element, options?: TouchEventInit): boolean;
  
  /**
   * Fire a touch move event
   * @param element - Target element
   * @param options - Touch event options
   * @returns Boolean indicating if event was not cancelled
   */
  touchMove(element: Element, options?: TouchEventInit): boolean;
  
  /**
   * Fire a touch cancel event
   * @param element - Target element
   * @param options - Touch event options
   * @returns Boolean indicating if event was not cancelled
   */
  touchCancel(element: Element, options?: TouchEventInit): boolean;
  
  /**
   * Fire a load event
   * @param element - Target element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  load(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire an error event
   * @param element - Target element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  error(element: Element, options?: EventInit): boolean;
  
  /**
   * Fire a resize event
   * @param element - Target element
   * @param options - Event options
   * @returns Boolean indicating if event was not cancelled
   */
  resize(element: Element, options?: EventInit): boolean;
}

declare const fireEvent: FireEvent;

Create Event Function

Creates DOM event objects that can be dispatched manually.

/**
 * Create a DOM event object
 * @param eventType - Type of event to create (e.g., 'click', 'keydown')
 * @param element - Element the event will be dispatched on
 * @param options - Event initialization options
 * @returns Created event object
 */
function createEvent(
  eventType: string,
  element: Element,
  options?: EventInit
): Event;

Usage Examples

Basic Event Firing

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const BasicEventExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    // Fire a click event
    const button = canvas.getByRole('button', { name: /click me/i });
    fireEvent.click(button);
    
    // Verify the click was handled
    await waitFor(() => {
      expect(canvas.getByText(/button clicked/i)).toBeInTheDocument();
    });
  }
};

Form Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const FormEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const input = canvas.getByLabelText(/email/i);
    
    // Fire focus event
    fireEvent.focus(input);
    expect(input).toHaveFocus();
    
    // Fire input event with value change
    fireEvent.input(input, { target: { value: 'user@example.com' } });
    
    // Fire change event
    fireEvent.change(input, { target: { value: 'user@example.com' } });
    
    // Fire blur event
    fireEvent.blur(input);
    
    // Verify form validation
    await waitFor(() => {
      expect(canvas.queryByText(/invalid email/i)).not.toBeInTheDocument();
    });
  }
};

Keyboard Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const KeyboardEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const input = canvas.getByLabelText(/search/i);
    fireEvent.focus(input);
    
    // Fire key down events
    fireEvent.keyDown(input, { key: 'A', code: 'KeyA' });
    fireEvent.keyDown(input, { key: 'B', code: 'KeyB' });
    fireEvent.keyDown(input, { key: 'C', code: 'KeyC' });
    
    // Fire Enter key
    fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
    
    // Verify search was triggered
    await waitFor(() => {
      expect(canvas.getByText(/searching for: ABC/i)).toBeInTheDocument();
    });
  }
};

Mouse Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const MouseEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const draggable = canvas.getByTestId('draggable-item');
    const dropzone = canvas.getByTestId('drop-zone');
    
    // Simulate mouse drag
    fireEvent.mouseDown(draggable, { clientX: 100, clientY: 100 });
    fireEvent.mouseMove(draggable, { clientX: 150, clientY: 150 });
    fireEvent.mouseUp(draggable, { clientX: 200, clientY: 200 });
    
    // Hover events
    fireEvent.mouseEnter(dropzone);
    fireEvent.mouseOver(dropzone);
    fireEvent.mouseLeave(dropzone);
    
    // Context menu
    fireEvent.contextMenu(draggable);
    
    await waitFor(() => {
      expect(canvas.getByRole('menu')).toBeInTheDocument();
    });
  }
};

Drag and Drop Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const DragDropExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const draggable = canvas.getByTestId('draggable');
    const dropzone = canvas.getByTestId('dropzone');
    
    // Start drag operation
    fireEvent.dragStart(draggable, {
      dataTransfer: {
        setData: (format: string, data: string) => {},
        getData: (format: string) => 'dragged-item'
      }
    });
    
    // Drag over drop zone
    fireEvent.dragEnter(dropzone);
    fireEvent.dragOver(dropzone);
    
    // Complete drop
    fireEvent.drop(dropzone, {
      dataTransfer: {
        getData: (format: string) => 'dragged-item'
      }
    });
    
    fireEvent.dragEnd(draggable);
    
    // Verify drop was handled
    await waitFor(() => {
      expect(canvas.getByText(/item dropped/i)).toBeInTheDocument();
    });
  }
};

Touch Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const TouchEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const touchTarget = canvas.getByTestId('touch-target');
    
    // Simulate touch interaction
    fireEvent.touchStart(touchTarget, {
      touches: [{ clientX: 100, clientY: 100 }]
    });
    
    fireEvent.touchMove(touchTarget, {
      touches: [{ clientX: 150, clientY: 150 }]
    });
    
    fireEvent.touchEnd(touchTarget, {
      changedTouches: [{ clientX: 150, clientY: 150 }]
    });
    
    // Verify touch interaction
    await waitFor(() => {
      expect(canvas.getByText(/touched/i)).toBeInTheDocument();
    });
  }
};

Custom Events

import { within, fireEvent, createEvent, waitFor } from "@storybook/testing-library";

export const CustomEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const component = canvas.getByTestId('custom-component');
    
    // Create and fire custom event
    const customEvent = createEvent('customEvent', component, {
      bubbles: true,
      detail: { message: 'Hello from custom event' }
    });
    
    fireEvent(component, customEvent);
    
    // Verify custom event was handled
    await waitFor(() => {
      expect(canvas.getByText(/custom event received/i)).toBeInTheDocument();
    });
  }
};

Event Options and Modifiers

import { within, fireEvent } from "@storybook/testing-library";

export const EventOptionsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const button = canvas.getByRole('button', { name: /special click/i });
    
    // Click with modifier keys
    fireEvent.click(button, {
      ctrlKey: true,
      shiftKey: true,
      button: 0, // Left mouse button
      clientX: 100,
      clientY: 200
    });
    
    // Keyboard event with modifiers
    const input = canvas.getByLabelText(/shortcut input/i);
    fireEvent.keyDown(input, {
      key: 'S',
      code: 'KeyS',
      ctrlKey: true,
      shiftKey: true
    });
  }
};

Form Submission

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const FormSubmissionExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const form = canvas.getByRole('form');
    const emailInput = canvas.getByLabelText(/email/i);
    const passwordInput = canvas.getByLabelText(/password/i);
    
    // Fill form
    fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
    fireEvent.change(passwordInput, { target: { value: 'password123' } });
    
    // Submit form
    fireEvent.submit(form);
    
    // Verify submission
    await waitFor(() => {
      expect(canvas.getByText(/form submitted/i)).toBeInTheDocument();
    });
  }
};

Scroll Events

import { within, fireEvent, waitFor } from "@storybook/testing-library";

export const ScrollEventsExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const scrollableContainer = canvas.getByTestId('scrollable');
    
    // Fire scroll event
    fireEvent.scroll(scrollableContainer, { target: { scrollY: 100 } });
    
    // Fire wheel event for mouse wheel scrolling
    fireEvent.wheel(scrollableContainer, { deltaY: 100 });
    
    // Verify scroll behavior
    await waitFor(() => {
      expect(canvas.getByText(/scrolled/i)).toBeInTheDocument();
    });
  }
};

When to Use fireEvent vs userEvent

Use fireEvent when:

  • Testing low-level event handling
  • Need precise control over event properties
  • Testing edge cases or error conditions
  • Working with custom events
  • Need synchronous event firing

Use userEvent when:

  • Simulating realistic user interactions
  • Testing the complete user experience
  • Want higher-level interaction methods
  • Need async behavior that matches real users
import { within, fireEvent, userEvent } from "@storybook/testing-library";

export const ComparisonExample = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    
    const input = canvas.getByLabelText(/username/i);
    
    // fireEvent - direct, low-level
    fireEvent.change(input, { target: { value: 'testuser' } });
    
    // userEvent - realistic, high-level
    await userEvent.type(input, 'testuser');
  }
};

Install with Tessl CLI

npx tessl i tessl/npm-storybook--testing-library

docs

async-utilities.md

configuration.md

events.md

index.md

queries.md

scoping.md

user-interactions.md

tile.json