# Firing Events

Simulate user interactions with automatic act() wrapping for React state updates.

## API

Main utility for firing DOM events. Automatically wrapped in `act()` for proper React state updates.

```typescript { .api }
/**
 * Fire a DOM event on an element
 * @param element - Target element
 * @param event - Event object to fire
 * @returns true if event was not cancelled
 */
const fireEvent: {
  (element: HTMLElement, event: Event): boolean;

  // Mouse Events
  click(element: HTMLElement, options?: MouseEventInit): void;
  dblClick(element: HTMLElement, options?: MouseEventInit): void;
  mouseDown(element: HTMLElement, options?: MouseEventInit): void;
  mouseUp(element: HTMLElement, options?: MouseEventInit): void;
  mouseMove(element: HTMLElement, options?: MouseEventInit): void;
  mouseOver(element: HTMLElement, options?: MouseEventInit): void;
  mouseOut(element: HTMLElement, options?: MouseEventInit): void;
  mouseEnter(element: HTMLElement, options?: MouseEventInit): void;
  mouseLeave(element: HTMLElement, options?: MouseEventInit): void;
  contextMenu(element: HTMLElement, options?: MouseEventInit): void;
  wheel(element: HTMLElement, options?: WheelEventInit): void;

  // Pointer Events
  pointerDown(element: HTMLElement, options?: PointerEventInit): void;
  pointerUp(element: HTMLElement, options?: PointerEventInit): void;
  pointerMove(element: HTMLElement, options?: PointerEventInit): void;
  pointerOver(element: HTMLElement, options?: PointerEventInit): void;
  pointerOut(element: HTMLElement, options?: PointerEventInit): void;
  pointerEnter(element: HTMLElement, options?: PointerEventInit): void;
  pointerLeave(element: HTMLElement, options?: PointerEventInit): void;
  pointerCancel(element: HTMLElement, options?: PointerEventInit): void;
  gotPointerCapture(element: HTMLElement, options?: PointerEventInit): void;
  lostPointerCapture(element: HTMLElement, options?: PointerEventInit): void;

  // Keyboard Events
  keyDown(element: HTMLElement, options?: KeyboardEventInit): void;
  keyUp(element: HTMLElement, options?: KeyboardEventInit): void;
  keyPress(element: HTMLElement, options?: KeyboardEventInit): void;

  // Focus Events
  focus(element: HTMLElement, options?: FocusEventInit): void;
  blur(element: HTMLElement, options?: FocusEventInit): void;
  focusIn(element: HTMLElement, options?: FocusEventInit): void;
  focusOut(element: HTMLElement, options?: FocusEventInit): void;

  // Form Events
  change(element: HTMLElement, options?: EventInit): void;
  input(element: HTMLElement, options?: InputEventInit): void;
  invalid(element: HTMLElement, options?: EventInit): void;
  submit(element: HTMLElement, options?: EventInit): void;
  reset(element: HTMLElement, options?: EventInit): void;
  select(element: HTMLElement, options?: EventInit): void;

  // Clipboard Events
  copy(element: HTMLElement, options?: ClipboardEventInit): void;
  cut(element: HTMLElement, options?: ClipboardEventInit): void;
  paste(element: HTMLElement, options?: ClipboardEventInit): void;

  // Composition Events
  compositionStart(element: HTMLElement, options?: CompositionEventInit): void;
  compositionUpdate(element: HTMLElement, options?: CompositionEventInit): void;
  compositionEnd(element: HTMLElement, options?: CompositionEventInit): void;

  // Drag Events
  drag(element: HTMLElement, options?: DragEventInit): void;
  dragEnd(element: HTMLElement, options?: DragEventInit): void;
  dragEnter(element: HTMLElement, options?: DragEventInit): void;
  dragExit(element: HTMLElement, options?: DragEventInit): void;
  dragLeave(element: HTMLElement, options?: DragEventInit): void;
  dragOver(element: HTMLElement, options?: DragEventInit): void;
  dragStart(element: HTMLElement, options?: DragEventInit): void;
  drop(element: HTMLElement, options?: DragEventInit): void;

  // Touch Events
  touchStart(element: HTMLElement, options?: TouchEventInit): void;
  touchMove(element: HTMLElement, options?: TouchEventInit): void;
  touchEnd(element: HTMLElement, options?: TouchEventInit): void;
  touchCancel(element: HTMLElement, options?: TouchEventInit): void;

  // Animation Events
  animationStart(element: HTMLElement, options?: AnimationEventInit): void;
  animationEnd(element: HTMLElement, options?: AnimationEventInit): void;
  animationIteration(element: HTMLElement, options?: AnimationEventInit): void;

  // Transition Events
  transitionEnd(element: HTMLElement, options?: TransitionEventInit): void;

  // Media Events
  abort(element: HTMLElement, options?: EventInit): void;
  canPlay(element: HTMLElement, options?: EventInit): void;
  canPlayThrough(element: HTMLElement, options?: EventInit): void;
  durationChange(element: HTMLElement, options?: EventInit): void;
  emptied(element: HTMLElement, options?: EventInit): void;
  encrypted(element: HTMLElement, options?: EventInit): void;
  ended(element: HTMLElement, options?: EventInit): void;
  error(element: HTMLElement, options?: EventInit): void;
  load(element: HTMLElement, options?: EventInit): void;
  loadedData(element: HTMLElement, options?: EventInit): void;
  loadedMetadata(element: HTMLElement, options?: EventInit): void;
  loadStart(element: HTMLElement, options?: EventInit): void;
  pause(element: HTMLElement, options?: EventInit): void;
  play(element: HTMLElement, options?: EventInit): void;
  playing(element: HTMLElement, options?: EventInit): void;
  progress(element: HTMLElement, options?: EventInit): void;
  rateChange(element: HTMLElement, options?: EventInit): void;
  seeked(element: HTMLElement, options?: EventInit): void;
  seeking(element: HTMLElement, options?: EventInit): void;
  stalled(element: HTMLElement, options?: EventInit): void;
  suspend(element: HTMLElement, options?: EventInit): void;
  timeUpdate(element: HTMLElement, options?: EventInit): void;
  volumeChange(element: HTMLElement, options?: EventInit): void;
  waiting(element: HTMLElement, options?: EventInit): void;

  // Other Events
  scroll(element: HTMLElement, options?: EventInit): void;
};
```

## Common Patterns

### Click Events
```typescript
const button = screen.getByRole('button', { name: /submit/i });
fireEvent.click(button);

// With modifier keys
fireEvent.click(button, { ctrlKey: true, shiftKey: true });
```

### Form Input
```typescript
const input = screen.getByLabelText(/email/i);

// Text input
fireEvent.change(input, { target: { value: 'user@example.com' } });

// Checkbox
const checkbox = screen.getByRole('checkbox');
fireEvent.click(checkbox);

// Select dropdown
const select = screen.getByLabelText(/country/i);
fireEvent.change(select, { target: { value: 'USA' } });
```

### Keyboard Events
```typescript
const input = screen.getByRole('textbox');

// Single key
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
fireEvent.keyDown(input, { key: 'Escape', code: 'Escape' });

// With modifiers
fireEvent.keyDown(input, {
  key: 's',
  code: 'KeyS',
  ctrlKey: true,
});
```

### Focus/Blur
```typescript
const input = screen.getByRole('textbox');

fireEvent.focus(input);
expect(document.activeElement).toBe(input);

fireEvent.blur(input);
```

### Mouse Hover
```typescript
const button = screen.getByRole('button');

fireEvent.mouseEnter(button);  // Shows hover state
fireEvent.mouseLeave(button);  // Hides hover state
```

## Testing Patterns

### Button Click
```typescript
test('increments counter', () => {
  render(<Counter />);

  const button = screen.getByRole('button', { name: /increment/i });
  fireEvent.click(button);

  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
```

### Form Submission
```typescript
test('submits form', () => {
  const handleSubmit = jest.fn();
  render(<Form onSubmit={handleSubmit} />);

  fireEvent.change(screen.getByLabelText(/email/i), {
    target: { value: 'user@example.com' }
  });

  fireEvent.click(screen.getByRole('button', { name: /submit/i }));

  expect(handleSubmit).toHaveBeenCalledWith({
    email: 'user@example.com'
  });
});
```

### Keyboard Navigation
```typescript
test('navigates with keyboard', () => {
  render(<Menu />);

  const menu = screen.getByRole('menu');

  fireEvent.keyDown(menu, { key: 'ArrowDown', code: 'ArrowDown' });
  expect(screen.getByRole('menuitem', { name: 'Item 1' })).toHaveFocus();

  fireEvent.keyDown(menu, { key: 'Enter', code: 'Enter' });
  // Menu item activated
});
```

### Input Validation
```typescript
test('validates email on blur', () => {
  render(<EmailInput />);

  const input = screen.getByLabelText(/email/i);

  fireEvent.change(input, { target: { value: 'invalid' } });
  fireEvent.blur(input);

  expect(screen.getByText(/invalid email/i)).toBeInTheDocument();
});
```

### Hover Interactions
```typescript
test('shows tooltip on hover', () => {
  render(<Button tooltip="Click me" />);

  const button = screen.getByRole('button');

  fireEvent.mouseEnter(button);
  expect(screen.getByRole('tooltip')).toHaveTextContent('Click me');

  fireEvent.mouseLeave(button);
  expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
```

## React-Specific Event Behaviors

React Testing Library enhances certain events with React-specific behavior:

### mouseEnter / mouseLeave

In React, `mouseEnter` and `mouseLeave` are tracked by native `mouseOver` and `mouseOut` events. fireEvent automatically fires both:

```typescript { .api }
// Fires both mouseEnter and mouseOver
fireEvent.mouseEnter(element);

// Fires both mouseLeave and mouseOut
fireEvent.mouseLeave(element);
```

### pointerEnter / pointerLeave

Similar to mouse events, pointer enter/leave events fire both the synthetic and native events:

```typescript { .api }
// Fires both pointerEnter and pointerOver
fireEvent.pointerEnter(element);

// Fires both pointerLeave and pointerOut
fireEvent.pointerLeave(element);
```

### select Event

React's select event requires the element to be focused and fires a keyUp event:

```typescript { .api }
// Fires select, focuses element, then fires keyUp
fireEvent.select(element);
```

### focus / blur Events

React tracks native focusin/focusout events for focus/blur handlers:

```typescript { .api }
// Fires focusIn then focus
fireEvent.focus(element);

// Fires focusOut then blur
fireEvent.blur(element);
```

## Event Options

All event methods accept an optional options object with event-specific properties:

### MouseEventInit
```typescript { .api }
interface MouseEventInit {
  altKey?: boolean;
  button?: number;     // 0=left, 1=middle, 2=right
  buttons?: number;
  clientX?: number;
  clientY?: number;
  ctrlKey?: boolean;
  metaKey?: boolean;
  relatedTarget?: EventTarget | null;
  screenX?: number;
  screenY?: number;
  shiftKey?: boolean;
}
```

**Example:**
```typescript
fireEvent.click(element, {
  ctrlKey: true,
  shiftKey: true,
  button: 0,
});
```

### KeyboardEventInit
```typescript { .api }
interface KeyboardEventInit {
  key?: string;        // 'Enter', 'Escape', 'a', etc.
  code?: string;       // 'Enter', 'Escape', 'KeyA', etc.
  altKey?: boolean;
  ctrlKey?: boolean;
  metaKey?: boolean;
  shiftKey?: boolean;
  repeat?: boolean;
}
```

**Example:**
```typescript
fireEvent.keyDown(element, {
  key: 'Enter',
  code: 'Enter',
  ctrlKey: false,
});
```

### InputEventInit
```typescript { .api }
interface InputEventInit {
  data?: string | null;
  inputType?: string;
}
```

### FocusEventInit
```typescript { .api }
interface FocusEventInit {
  relatedTarget?: EventTarget | null;
}
```

### Common Keys
```typescript
// Special keys
{ key: 'Enter', code: 'Enter' }
{ key: 'Escape', code: 'Escape' }
{ key: 'Tab', code: 'Tab' }
{ key: 'ArrowDown', code: 'ArrowDown' }
{ key: 'ArrowUp', code: 'ArrowUp' }
{ key: 'ArrowLeft', code: 'ArrowLeft' }
{ key: 'ArrowRight', code: 'ArrowRight' }
{ key: 'Backspace', code: 'Backspace' }
{ key: 'Delete', code: 'Delete' }

// Letter keys
{ key: 'a', code: 'KeyA' }
{ key: 'A', code: 'KeyA', shiftKey: true }
```

## Important Notes

### Automatic act() Wrapping

All fireEvent calls are automatically wrapped in React's `act()` function, ensuring state updates are flushed before assertions:

```typescript
// No need to manually wrap in act()
fireEvent.click(button);
expect(screen.getByText('Updated')).toBeInTheDocument();
```

### Synthetic Events vs Native Events

React uses a synthetic event system. fireEvent fires native DOM events which are then processed by React's event system, matching how real browser events work.

### Event Bubbling

Events fired with fireEvent bubble through the DOM tree like real browser events:

```typescript
render(
  <div onClick={() => console.log('Div clicked')}>
    <button onClick={() => console.log('Button clicked')}>Click</button>
  </div>
);

const button = screen.getByRole('button');
fireEvent.click(button);
// Logs: "Button clicked"
// Then logs: "Div clicked"
```

### User Event Alternative

For more realistic user interactions, consider using `@testing-library/user-event` which simulates complete user interactions (e.g., typing includes keydown, keypress, input, keyup events). However, `fireEvent` is simpler and sufficient for most cases.

```typescript
// fireEvent - simple, fast
fireEvent.change(input, { target: { value: 'hello' } });

// userEvent - more realistic (requires separate package)
import userEvent from '@testing-library/user-event';
await userEvent.type(input, 'hello');
```

## Testing Complex Interactions

### Multi-Step Form
```typescript
test('completes multi-step form', () => {
  render(<WizardForm />);

  // Step 1
  fireEvent.change(screen.getByLabelText(/name/i), {
    target: { value: 'John' }
  });
  fireEvent.click(screen.getByRole('button', { name: /next/i }));

  // Step 2
  fireEvent.change(screen.getByLabelText(/email/i), {
    target: { value: 'john@example.com' }
  });
  fireEvent.click(screen.getByRole('button', { name: /submit/i }));

  expect(screen.getByText(/success/i)).toBeInTheDocument();
});
```

### Drag and Drop
```typescript
test('reorders items with drag and drop', () => {
  render(<DragList />);

  const item = screen.getByText('Item 1');

  fireEvent.dragStart(item);
  fireEvent.dragEnter(screen.getByText('Item 3'));
  fireEvent.drop(screen.getByText('Item 3'));
  fireEvent.dragEnd(item);

  const items = screen.getAllByRole('listitem');
  expect(items[2]).toHaveTextContent('Item 1');
});
```

## Alternative: user-event

For more realistic interactions, consider `@testing-library/user-event` (separate package):

```typescript
import userEvent from '@testing-library/user-event';

// More realistic typing (includes keyDown, keyPress, input, keyUp)
await userEvent.type(input, 'Hello');

// Realistic clicking (includes mouseDown, mouseUp, click)
await userEvent.click(button);
```

**When to use fireEvent:**
- Simpler, faster tests
- Testing specific event handlers
- Legacy codebase

**When to use user-event:**
- More realistic user behavior
- Testing complex interactions
- Accessibility testing
