Skip to content

Add integration tests for EventManager (Eve) system #12

Description

@Monpolymet

The event system (EventManager / Eve) is central to component communication in SoonFx, with 100+ event type constants. Despite its critical role, there are no tests validating event dispatch, listener management, or event propagation.

Event System Components

Component File Purpose
EventManager (Eve) src/core/events/EventManager.ts Global event bus singleton
CallCenter src/communication/messaging/CallCenter.ts Instance-level event handling
EventTypes src/core/types/EventTypes.ts Type definitions

Key Event Constants (Examples)

// From EventManager
Eve.PLAYER_INSTANCE_LEVEL_UP
Eve.ADD_DATABASE_DATA
Eve.ADD_OPERAND_DATA
Eve.FORMULA_CHANGED
Eve.VARIABLE_UPDATED
// ... 95+ more events

Test Scenarios

EventManager Core Tests

describe('EventManager', () => {
  describe('Listener Registration', () => {
    it('should register a listener for an event type')
    it('should allow multiple listeners for same event')
    it('should return unsubscribe function')
    it('should not duplicate identical listeners')
  })

  describe('Event Dispatch', () => {
    it('should call all registered listeners')
    it('should pass event data to listeners')
    it('should handle listeners that throw errors')
    it('should dispatch events synchronously by default')
    it('should support async dispatch mode')
  })

  describe('Listener Removal', () => {
    it('should remove listener via unsubscribe function')
    it('should remove listener by reference')
    it('should clear all listeners for an event type')
    it('should handle removing non-existent listener')
  })

  describe('Event Filtering', () => {
    it('should only trigger matching event types')
    it('should support wildcard listeners')
    it('should respect event namespacing')
  })
})

CallCenter Tests

describe('CallCenter', () => {
  describe('Instance Binding', () => {
    it('should bind events to specific instance')
    it('should isolate events between instances')
    it('should clean up on instance disposal')
  })

  describe('Listen/Dispatch Pattern', () => {
    it('should dispatch to instance-specific listeners')
    it('should bubble to global EventManager')
    it('should support priority ordering')
  })
})

Integration Tests

describe('Event System Integration', () => {
  describe('Player Events', () => {
    it('should emit PLAYER_INSTANCE_LEVEL_UP on level change')
    it('should include player data in event payload')
    it('should trigger in correct order with combat events')
  })

  describe('Formula Events', () => {
    it('should emit FORMULA_CHANGED when formula updates')
    it('should trigger recalculation in dependent components')
    it('should batch rapid changes')
  })

  describe('Data Events', () => {
    it('should emit ADD_DATABASE_DATA on data insertion')
    it('should emit ADD_OPERAND_DATA for operands')
    it('should propagate to visual editor')
  })
})

Edge Case Tests

describe('Event System Edge Cases', () => {
  it('should handle circular event triggers')
  it('should maintain order with nested dispatches')
  it('should recover from listener exceptions')
  it('should handle high-frequency event bursts')
  it('should prevent memory leaks from abandoned listeners')
  it('should work after system reset')
})

Performance Tests

describe('Event System Performance', () => {
  it('should handle 1000 listeners efficiently')
  it('should dispatch 10000 events under 100ms')
  it('should not degrade with listener churn')
})

Test Utilities

// tests/helpers/EventTestUtils.ts
export function createEventSpy(eventType: string) {
  const spy = vi.fn()
  const unsubscribe = Eve.listen(eventType, spy)
  return { spy, unsubscribe }
}

export function waitForEvent(eventType: string, timeout = 1000) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => reject(new Error('Timeout')), timeout)
    Eve.listen(eventType, (data) => {
      clearTimeout(timer)
      resolve(data)
    })
  })
}

export function collectEvents(eventType: string, count: number) {
  const events: unknown[] = []
  return new Promise((resolve) => {
    const unsub = Eve.listen(eventType, (data) => {
      events.push(data)
      if (events.length >= count) {
        unsub()
        resolve(events)
      }
    })
  })
}

File Structure

tests/
├── core/
│   └── events/
│       └── EventManager.test.ts
├── communication/
│   └── messaging/
│       └── CallCenter.test.ts
├── integration/
│   └── EventSystem.integration.test.ts
└── helpers/
    └── EventTestUtils.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions