Matchers
DLest provides custom matchers specifically designed for analytics testing, plus common Jest-like matchers for general assertions.
Analytics Matchers
toHaveEvent(eventName, eventData?)
Check if a specific event exists in the dataLayer, optionally with specific data.
// Check event exists
await expect(dataLayer).toHaveEvent('page_view');
// Check event with exact data
await expect(dataLayer).toHaveEvent('purchase', {
value: 99.99,
currency: 'USD'
});
// Check event with flexible matching
await expect(dataLayer).toHaveEvent('purchase', {
transaction_id: expect.any(String),
value: expect.any(Number),
currency: 'USD',
items: expect.arrayContaining([
expect.objectContaining({
item_id: 'prod-123'
})
])
});
// Negation
await expect(dataLayer).not.toHaveEvent('error');
Parameters:
eventName(string): Name of the event to findeventData(object, optional): Expected event data (uses deep equality)
toHaveEventData(eventData)
Check if any event in the dataLayer contains specific data.
// Find event with specific data
await expect(dataLayer).toHaveEventData({
category: 'electronics',
value: 99.99
});
// With flexible matching
await expect(dataLayer).toHaveEventData({
user_id: expect.any(String),
timestamp: expect.any(Number)
});
Parameters:
eventData(object): Data to search for in any event
toHaveEventCount(eventName, count)
Verify the exact number of times an event occurred.
// Expect exactly 1 page view
await expect(dataLayer).toHaveEventCount('page_view', 1);
// Expect 3 button clicks
await expect(dataLayer).toHaveEventCount('button_click', 3);
// Expect 0 errors
await expect(dataLayer).toHaveEventCount('error', 0);
Parameters:
eventName(string): Name of the event to countcount(number): Expected number of occurrences
Use cases:
- Verify page views in SPAs
- Count user interactions
- Ensure no duplicate events
- Validate error tracking
toHaveEventSequence(eventNames)
Validate that events occurred in a specific order.
// Verify purchase funnel
await expect(dataLayer).toHaveEventSequence([
'view_item',
'add_to_cart',
'begin_checkout',
'purchase'
]);
// Verify navigation flow
await expect(dataLayer).toHaveEventSequence([
'page_view',
'scroll',
'form_start',
'form_submit'
]);
Parameters:
eventNames(string[]): Array of event names in expected order
Important: The matcher looks for the exact sequence in order. Other events can occur before, after, or between the sequence events.
toHaveGA4Event(eventName, eventData?)
Validate that a Google Analytics 4 network request was sent with the correct event.
// Check GA4 event was sent
await expect(network).toHaveGA4Event('purchase');
// Check with specific parameters
await expect(network).toHaveGA4Event('purchase', {
transaction_id: expect.any(String),
value: expect.any(Number),
currency: 'USD'
});
Parameters:
eventName(string): GA4 event nameeventData(object, optional): Expected event parameters
Note: Requires the network fixture. See Network Validation.
General Matchers
DLest includes Jest-compatible matchers for general assertions.
Type Checking
toBeDefined()
Check if value is defined (not undefined or null).
const events = await dataLayer.getEvents();
expect(events).toBeDefined();
toBeUndefined()
Check if value is undefined.
const missingEvent = events.find(e => e.event === 'nonexistent');
expect(missingEvent).toBeUndefined();
toBeTruthy()
Check if value is truthy.
const hasEvents = events.length > 0;
expect(hasEvents).toBeTruthy();
toBeFalsy()
Check if value is falsy.
const isEmpty = events.length === 0;
expect(isEmpty).toBeFalsy();
Equality
toBe(expected)
Strict equality using Object.is().
expect(event.currency).toBe('USD');
expect(event.value).toBe(99.99);
expect(event.items.length).toBe(1);
Best for: Primitives (string, number, boolean, null, undefined)
Numeric Comparisons
toBeGreaterThan(expected)
Check if number is greater than expected.
expect(purchaseEvent.value).toBeGreaterThan(0);
expect(events.length).toBeGreaterThan(5);
toBeLessThan(expected)
Check if number is less than expected.
expect(event.price).toBeLessThan(1000);
expect(loadTime).toBeLessThan(3000);
Collections
toHaveLength(expected)
Check array or string length.
const events = await dataLayer.getEvents();
expect(events).toHaveLength(3);
expect(event.name).toHaveLength(10);
toContain(expected)
Check if array or string contains a value.
const eventNames = events.map(e => e.event);
expect(eventNames).toContain('purchase');
expect(event.description).toContain('special offer');
toHaveProperty(property, value?)
Check if object has a property, optionally with specific value.
expect(purchaseEvent).toHaveProperty('transaction_id');
expect(purchaseEvent).toHaveProperty('currency', 'USD');
expect(purchaseEvent).toHaveProperty('items');
Strings
toMatch(expected)
Check if string matches pattern (string or regex).
// With string (substring match)
expect(event.transaction_id).toMatch('TXN-');
// With regex
expect(event.coupon_code).toMatch(/^SAVE[0-9]+$/);
expect(event.email).toMatch(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
Functions
toThrow(expected?)
Check if function throws an error.
// Expects any error
expect(() => {
throw new Error('oops');
}).toThrow();
// Expects specific error message
expect(() => {
throw new Error('Invalid event');
}).toThrow('Invalid event');
// Expects error matching regex
expect(() => {
throw new Error('Invalid event name');
}).toThrow(/Invalid event/);
// Expects specific error type
expect(() => {
throw new TypeError('Bad type');
}).toThrow(TypeError);
Jest Helpers
DLest supports Jest's expect helpers for flexible matching.
expect.any(Type)
Match any value of a specific type.
await expect(dataLayer).toHaveEvent('purchase', {
transaction_id: expect.any(String),
value: expect.any(Number),
items: expect.any(Array)
});
Supported types: String, Number, Boolean, Array, Object, Function
expect.objectContaining(object)
Partial object matching (subset of properties).
await expect(dataLayer).toHaveEvent('purchase', {
user: expect.objectContaining({
id: '12345'
// Other properties don't matter
})
});
expect.arrayContaining(array)
Check if array contains specific items (order doesn't matter).
await expect(dataLayer).toHaveEvent('purchase', {
items: expect.arrayContaining([
expect.objectContaining({
item_id: 'prod-123'
}),
expect.objectContaining({
item_id: 'prod-456'
})
])
});
expect.stringContaining(string)
Check if string contains substring.
await expect(dataLayer).toHaveEvent('form_error', {
error_message: expect.stringContaining('required')
});
expect.stringMatching(regex)
Check if string matches regex pattern.
await expect(dataLayer).toHaveEvent('purchase', {
transaction_id: expect.stringMatching(/^TXN-[A-Z0-9]+$/),
email: expect.stringMatching(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)
});
Negation
All matchers support negation with .not:
// Event should not exist
await expect(dataLayer).not.toHaveEvent('error');
// Event count should not be zero
await expect(dataLayer).not.toHaveEventCount('page_view', 0);
// Value should not be zero
expect(purchaseEvent.value).not.toBe(0);
// String should not contain word
expect(event.description).not.toContain('discontinued');
Common Patterns
E-commerce Purchase
await expect(dataLayer).toHaveEvent('purchase', {
transaction_id: expect.any(String),
value: expect.any(Number),
currency: 'USD',
items: expect.arrayContaining([
expect.objectContaining({
item_id: expect.any(String),
item_name: expect.any(String),
price: expect.any(Number),
quantity: expect.any(Number)
})
]),
user: expect.objectContaining({
id: expect.any(String)
})
});
Form Validation
await expect(dataLayer).toHaveEvent('form_submit', {
form_name: 'contact',
form_destination: 'sales',
timestamp: expect.any(Number)
});
// Verify no errors
await expect(dataLayer).not.toHaveEvent('form_error');
User Journey
// Verify complete sequence
await expect(dataLayer).toHaveEventSequence([
'page_view',
'view_item',
'add_to_cart',
'begin_checkout',
'add_payment_info',
'purchase'
]);
// Verify counts
await expect(dataLayer).toHaveEventCount('page_view', 3);
await expect(dataLayer).toHaveEventCount('add_to_cart', 2);
await expect(dataLayer).toHaveEventCount('purchase', 1);
Tips
- Use
expect.any()for dynamic values like timestamps, IDs, or generated strings - Use
expect.objectContaining()to match partial objects - don't force exact matches - Use
expect.arrayContaining()for arrays where order doesn't matter - Test sequences to validate complete user flows
- Use negation to verify events that shouldn't happen
- Combine matchers for powerful, flexible assertions
Next Steps
- See real-world examples
- Learn about test fixtures
- Explore network validation
- Read the Test API reference