CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jasmine-jquery

jQuery matchers and fixture loader for Jasmine framework

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

event-spying.mddocs/

Event Spying

Comprehensive event spy system for testing jQuery event triggers, with support for event prevention, propagation control, and detailed event inspection. Essential for testing event-driven jQuery applications and components.

Capabilities

Global Event Spy Function

spyOnEvent

Creates an event spy for specified selector and event type.

/**
 * Creates an event spy for given selector and event type
 * Returns spy object with call tracking and control methods
 * @param selector - CSS selector or jQuery element to spy on
 * @param eventName - Event type to spy on (e.g., 'click', 'submit', 'custom-event')
 * @returns EventSpy object with tracking and control methods
 */
function spyOnEvent(selector, eventName);

Usage Examples:

// Basic event spying
var clickSpy = spyOnEvent('#button', 'click');
$('#button').click();
expect(clickSpy).toHaveBeenTriggered();

// Spy on custom events
var customSpy = spyOnEvent('.widget', 'widget-updated');
$('.widget').trigger('widget-updated', {data: 'test'});
expect(customSpy).toHaveBeenTriggered();

// Spy on multiple events
var submitSpy = spyOnEvent('#form', 'submit');
var focusSpy = spyOnEvent('#input', 'focus');

Event Spy Object

The spy object returned by spyOnEvent() provides tracking and control:

/**
 * Event spy object with tracking capabilities
 */
interface EventSpy {
  /** CSS selector being spied on */
  selector: string;
  
  /** Event name being spied on */
  eventName: string;
  
  /** Internal event handler function */
  handler: Function;
  
  /** Reset spy state (clear call count and arguments) */
  reset(): void;
  
  /** Call tracking information */
  calls: {
    /** Number of times event was triggered */
    count(): number;
    
    /** Whether event was triggered at least once */
    any(): boolean;
  };
}

Spy Object Usage:

var spy = spyOnEvent('#element', 'click');

// Trigger events
$('#element').click();
$('#element').click();

// Check call information
expect(spy.calls.count()).toBe(2);
expect(spy.calls.any()).toBe(true);

// Reset spy state
spy.reset();
expect(spy.calls.count()).toBe(0);
expect(spy.calls.any()).toBe(false);

Event Spy Matchers

toHaveBeenTriggered

Checks if spied event was triggered (using spy object).

/**
 * Checks if event spy was triggered at least once
 * Use with spy object returned by spyOnEvent()
 */
expect(eventSpy).toHaveBeenTriggered();

toHaveBeenTriggeredOn

Checks if event was triggered on specific selector (using event name).

/**
 * Checks if event was triggered on the specified selector
 * Use with event name string and selector
 * @param selector - CSS selector to check
 */
expect(eventName).toHaveBeenTriggeredOn(selector);

Trigger Matcher Examples:

// Using spy object
var clickSpy = spyOnEvent('#button', 'click');
$('#button').click();
expect(clickSpy).toHaveBeenTriggered();
expect(clickSpy).not.toHaveBeenTriggered(); // After reset

// Using event name and selector
$('#link').click();
expect('click').toHaveBeenTriggeredOn('#link');
expect('hover').not.toHaveBeenTriggeredOn('#link');

toHaveBeenTriggeredOnAndWith

Checks if event was triggered with specific arguments.

/**
 * Checks if event was triggered on selector with specific arguments
 * @param selector - CSS selector to check
 * @param expectedArgs - Expected event arguments (array or single value)
 */
expect(eventName).toHaveBeenTriggeredOnAndWith(selector, expectedArgs);

Usage Example:

spyOnEvent('#widget', 'data-updated');

// Trigger with custom data
$('#widget').trigger('data-updated', [{id: 123, name: 'test'}]);

// Check trigger with arguments
expect('data-updated').toHaveBeenTriggeredOnAndWith('#widget', [{id: 123, name: 'test'}]);

Event Prevention and Propagation

toHaveBeenPrevented

Checks if spied event was prevented (using spy object).

/**
 * Checks if event's default action was prevented
 * Use with spy object returned by spyOnEvent()
 */
expect(eventSpy).toHaveBeenPrevented();

toHaveBeenPreventedOn

Checks if event was prevented on specific selector (using event name).

/**
 * Checks if event's default action was prevented on selector
 * @param selector - CSS selector to check
 */
expect(eventName).toHaveBeenPreventedOn(selector);

Prevention Examples:

// Set up prevention
$('#form').on('submit', function(e) {
  e.preventDefault();
});

var submitSpy = spyOnEvent('#form', 'submit');
$('#form').submit();

// Check prevention with spy object
expect(submitSpy).toHaveBeenPrevented();

// Check prevention with event name
expect('submit').toHaveBeenPreventedOn('#form');

toHaveBeenStopped

Checks if spied event propagation was stopped (using spy object).

/**
 * Checks if event propagation was stopped
 * Use with spy object returned by spyOnEvent()
 */
expect(eventSpy).toHaveBeenStopped();

toHaveBeenStoppedOn

Checks if event propagation was stopped on specific selector (using event name).

/**
 * Checks if event propagation was stopped on selector
 * @param selector - CSS selector to check
 */
expect(eventName).toHaveBeenStoppedOn(selector);

Propagation Examples:

// Set up propagation stopping
$('.inner').on('click', function(e) {
  e.stopPropagation();
});

var clickSpy = spyOnEvent('.inner', 'click');
$('.inner').click();

// Check propagation stopping
expect(clickSpy).toHaveBeenStopped();
expect('click').toHaveBeenStoppedOn('.inner');

Advanced Event Spying Patterns

Multiple Event Types

describe('Multi-event component', function() {
  var clickSpy, hoverSpy, customSpy;

  beforeEach(function() {
    loadFixtures('<div id="widget">Widget</div>');
    clickSpy = spyOnEvent('#widget', 'click');
    hoverSpy = spyOnEvent('#widget', 'mouseenter'); 
    customSpy = spyOnEvent('#widget', 'widget-activated');
  });

  it('should handle multiple event types', function() {
    $('#widget').click().trigger('mouseenter').trigger('widget-activated');
    
    expect(clickSpy).toHaveBeenTriggered();
    expect(hoverSpy).toHaveBeenTriggered();
    expect(customSpy).toHaveBeenTriggered();
  });
});

Event Sequence Testing

it('should trigger events in correct sequence', function() {
  var focusSpy = spyOnEvent('#input', 'focus');
  var changeSpy = spyOnEvent('#input', 'change');
  var blurSpy = spyOnEvent('#input', 'blur');

  // Simulate user interaction sequence
  $('#input').focus().val('test value').change().blur();

  expect(focusSpy.calls.count()).toBe(1);
  expect(changeSpy.calls.count()).toBe(1);
  expect(blurSpy.calls.count()).toBe(1);
});

Complex Event Data Testing

it('should pass correct data with custom events', function() {
  spyOnEvent('#component', 'data-loaded');
  
  var testData = {
    users: [{id: 1, name: 'Alice'}],
    timestamp: Date.now()
  };
  
  $('#component').trigger('data-loaded', [testData]);
  
  expect('data-loaded').toHaveBeenTriggeredOnAndWith('#component', [testData]);
});

Event Delegation Testing

describe('Event delegation', function() {
  beforeEach(function() {
    setFixtures(`
      <ul id="list">
        <li class="item">Item 1</li>
        <li class="item">Item 2</li>
      </ul>
    `);
    
    // Set up delegated event handler
    $('#list').on('click', '.item', function(e) {
      $(this).addClass('clicked');
    });
  });

  it('should handle delegated events', function() {
    var clickSpy = spyOnEvent('.item', 'click');
    
    $('.item').first().click();
    
    expect(clickSpy).toHaveBeenTriggered();
    expect($('.item').first()).toHaveClass('clicked');
  });
});

Event Spy Lifecycle

Automatic Cleanup

Event spies are automatically cleaned up between tests:

// Automatic cleanup happens in afterEach
afterEach(function() {
  jasmine.jQuery.events.cleanUp(); // Called automatically
});

Manual Spy Management

describe('Manual spy management', function() {
  var spy;

  beforeEach(function() {
    spy = spyOnEvent('#element', 'click');
  });

  it('should reset spy between tests', function() {
    $('#element').click();
    expect(spy.calls.count()).toBe(1);
    
    // Reset manually if needed mid-test
    spy.reset();
    expect(spy.calls.count()).toBe(0);
  });
});

Error Handling

Missing Event Spy Errors

/**
 * Error thrown when accessing spy data for non-existent spy:
 * "There is no spy for [eventName] on [selector]. Make sure to create a spy using spyOnEvent."
 */

Error Example:

// This will throw error - no spy created
try {
  expect('click').toHaveBeenTriggeredOn('#element');
} catch (error) {
  expect(error.message).toContain('There is no spy for click on #element');
}

// Correct usage - create spy first
spyOnEvent('#element', 'click');
$('#element').click();
expect('click').toHaveBeenTriggeredOn('#element'); // Works

Integration with jQuery Event System

Namespace Support

// Spy on namespaced events
var namespacedSpy = spyOnEvent('#element', 'click.myapp');
$('#element').trigger('click.myapp');
expect(namespacedSpy).toHaveBeenTriggered();

Custom Event Support

// Spy on custom events
var customSpy = spyOnEvent('#widget', 'widget:updated');
$('#widget').trigger('widget:updated', {version: '2.0'});
expect(customSpy).toHaveBeenTriggered();

Event Object Access

While jasmine-jquery doesn't directly expose event objects, you can combine with standard Jasmine spies:

var handler = jasmine.createSpy('clickHandler');
$('#element').on('click', handler);

var eventSpy = spyOnEvent('#element', 'click');
$('#element').click();

expect(eventSpy).toHaveBeenTriggered();
expect(handler).toHaveBeenCalled();
// Can inspect handler.calls.argsFor(0)[0] for event object

Advanced Event System Functions

jasmine.jQuery.events.args

Retrieves arguments from spied event for detailed inspection.

/**
 * Gets arguments passed to spied event
 * @param selector - CSS selector that was spied on
 * @param eventName - Event name that was spied on  
 * @returns Array of arguments passed to event handler
 * @throws Error if no spy exists for the selector/event combination
 */
function jasmine.jQuery.events.args(selector, eventName);

Usage Example:

spyOnEvent('#form', 'submit');
$('#form').trigger('submit', [{data: 'test'}, 'extra-arg']);

var eventArgs = jasmine.jQuery.events.args('#form', 'submit');
expect(eventArgs[1]).toEqual({data: 'test'}); // First custom argument
expect(eventArgs[2]).toBe('extra-arg'); // Second custom argument

jasmine.jQuery.events.wasTriggered

Checks if event was triggered (low-level boolean check).

/**
 * Checks if event was triggered on selector (returns boolean)
 * Low-level alternative to toHaveBeenTriggeredOn matcher
 * @param selector - CSS selector to check
 * @param eventName - Event name to check
 * @returns Boolean indicating if event was triggered
 */
function jasmine.jQuery.events.wasTriggered(selector, eventName);

jasmine.jQuery.events.wasTriggeredWith

Checks if event was triggered with specific arguments.

/**
 * Checks if event was triggered with specific arguments
 * @param selector - CSS selector to check
 * @param eventName - Event name to check
 * @param expectedArgs - Expected arguments
 * @param util - Jasmine utility object
 * @param customEqualityTesters - Custom equality testers array
 * @returns Boolean indicating if event was triggered with expected arguments
 */
function jasmine.jQuery.events.wasTriggeredWith(selector, eventName, expectedArgs, util, customEqualityTesters);

jasmine.jQuery.events.wasPrevented

Checks if event default action was prevented (low-level boolean check).

/**
 * Checks if event's default action was prevented (returns boolean)
 * Low-level alternative to toHaveBeenPreventedOn matcher
 * @param selector - CSS selector to check
 * @param eventName - Event name to check
 * @returns Boolean indicating if event was prevented
 */
function jasmine.jQuery.events.wasPrevented(selector, eventName);

jasmine.jQuery.events.wasStopped

Checks if event propagation was stopped (low-level boolean check).

/**
 * Checks if event propagation was stopped (returns boolean)  
 * Low-level alternative to toHaveBeenStoppedOn matcher
 * @param selector - CSS selector to check
 * @param eventName - Event name to check
 * @returns Boolean indicating if event propagation was stopped
 */
function jasmine.jQuery.events.wasStopped(selector, eventName);

jasmine.jQuery.events.spyOn

Creates event spy (internal method, use spyOnEvent() instead).

/**
 * Creates event spy (internal method - use global spyOnEvent() instead)
 * @param selector - CSS selector to spy on
 * @param eventName - Event name to spy on
 * @returns EventSpy object
 * @internal
 */
function jasmine.jQuery.events.spyOn(selector, eventName);

jasmine.jQuery.events.cleanUp

Manually cleans up all event spies (automatically called after each test).

/**
 * Manually clean up all event spies and tracked data
 * Normally called automatically in afterEach hook
 */
function jasmine.jQuery.events.cleanUp();

jasmine.spiedEventsKey

Generates unique key for tracking spied events (internal utility).

/**
 * Creates unique key for spied event storage
 * @param selector - CSS selector being spied on
 * @param eventName - Event name being spied on
 * @returns String key for internal event tracking
 */
function jasmine.spiedEventsKey(selector, eventName);

Error Handling and Messages

Specific Error Messages

/**
 * Error thrown when accessing spy data for non-existent spy:
 * "There is no spy for [eventName] on [selector]. Make sure to create a spy using spyOnEvent."
 * 
 * This error occurs when calling jasmine.jQuery.events.args() or using event
 * matchers without first creating a spy with spyOnEvent()
 */

Best Practices

Descriptive Spy Variables

// Good - descriptive names
var submitSpy = spyOnEvent('#login-form', 'submit');
var validationSpy = spyOnEvent('.form-field', 'validation:failed');

// Less clear
var spy1 = spyOnEvent('#form', 'submit');
var spy2 = spyOnEvent('.field', 'validation:failed');

Combine with Fixture Loading

describe('Interactive component', function() {
  beforeEach(function() {
    loadFixtures('interactive-widget.html');
    loadStyleFixtures('widget-styles.css');
  });

  it('should handle user interactions', function() {
    var clickSpy = spyOnEvent('.widget-button', 'click');
    var hoverSpy = spyOnEvent('.widget', 'mouseenter');
    
    $('.widget').trigger('mouseenter');
    $('.widget-button').click();
    
    expect(hoverSpy).toHaveBeenTriggered();
    expect(clickSpy).toHaveBeenTriggered();
  });
});

docs

css-fixtures.md

event-spying.md

html-fixtures.md

index.md

jquery-matchers.md

json-fixtures.md

tile.json