jQuery matchers and fixture loader for Jasmine framework
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
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');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);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();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');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'}]);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();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');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();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');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();
});
});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);
});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]);
});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 spies are automatically cleaned up between tests:
// Automatic cleanup happens in afterEach
afterEach(function() {
jasmine.jQuery.events.cleanUp(); // Called automatically
});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 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// Spy on namespaced events
var namespacedSpy = spyOnEvent('#element', 'click.myapp');
$('#element').trigger('click.myapp');
expect(namespacedSpy).toHaveBeenTriggered();// Spy on custom events
var customSpy = spyOnEvent('#widget', 'widget:updated');
$('#widget').trigger('widget:updated', {version: '2.0'});
expect(customSpy).toHaveBeenTriggered();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 objectRetrieves 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 argumentChecks 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);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);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);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);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);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();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 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()
*/// 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');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();
});
});