Event Recorder
EventRecorder is part of the developer-tools
package, accessible via globalThis.objectiv.devTools.EventRecorder
.
It automatically records events and errors from all Tracker instances in the Application. It's commonly used in combination with end-to-end testing frameworks, e.g. to create snaphots of expected tracking Events and Errors, or as a debugging tool during development.
How to get it
There are several ways to import the
developer-tools
package in your application.
For some applications it may be as easy as importing the package globally, while for others there will probably be some logic to load them when needed, e.g. in a specific environment.
For example, you may require them conditionally by checking the Node environment:
if (process.env.NODE_ENV.startsWith('dev')) {
require('@objectiv/developer-tools');
}
Other approaches may include:
- Configuring the Application bundler to transpile out the Developer Tools when generating a production build.
- Injecting the Developer Tools in the application globals at runtime.
- Delegating loading the Developer Tools to an Application Wrapper.
EventRecorder interface
type EventRecorder = {
enabled: boolean;
recording: boolean;
errors: string[];
events: RecordedEvents {
filter(eventName: string): RecordedEvents;
filter(eventNames: string[]): RecordedEvents;
filter(predicate: (recordedEvent: RecordedEvent) => boolean): RecordedEvents;
withLocationContext(locationContextName: string, locationContextId?: string): RecordedEvents;
withGlobalContext(globalContextName: string, globalContextId?: string): RecordedEvents;
};
clear: () => void;
start: () => void;
stop: () => void;
};
Attributes and methods
boolean
enabled
Whether EventRecorder is enabled at all.
boolean
recording
Whether EventRecorder is currently recording.
string[]
errors
Sorted list of recorded errors. This can be useful to spot regressions, such as Collisions or Validation errors. For example, in our Cypress commands, this is part of the snapshot we take. Any new entry in it will fail the tests.
RecordedEvents
events
Gets a RecordedEvents instance initialized with a sorted list of recorded events.
All RecordedEvents methods are chainable, meaning that they return a new instance of RecordedEvents. These include:
- Filtering events by their name or names.
- Filtering events by their Location Contexts. Name, id or both.
- Filtering events by their global Contexts. Name, id or both.
The main purpose of filtering events, apart from easier debugging, is to reduce noise and overall size of snapshots.
clear()
Deletes all recorded events and errors. This can be useful when snapshot-testing multiple flows in the same test.
start()
Starts recording, if EventRecorder was previously stopped or configured to not automatically record.
stop()
Stops recording, if EventRecorder is running.
Filtering RecordedEvents
RecordedEvents is a small wrapper around a sorted list of recorded events. It has a few methods to filter out noise, as in unwanted asynchronous Events, or Events that belong to other scenarios.
Here are some examples of how one would use it in the Browser's console.
Get specific Events
Get all PressEvents:
objectiv.devTools.EventRecorder.events
.filter('PressEvent')
Get all PressEvents or InputChangeEvents:
objectiv.devTools.EventRecorder.events
.filter(['PressEvent', 'InputChangeEvent'])
Filter on a Context
Get all events that originated from ContentContext locations:
objectiv.devTools.EventRecorder.events
.withLocationContext('ContentContext')
Or from a specific ContentContext:
objectiv.devTools.EventRecorder.events
.withLocationContext('ContentContext', 'hero-element')
Get events that have a specific ContentContext:
objectiv.devTools.EventRecorder.events
.withGlobalContext('ApplicationContext', 'public-application')
objectiv.devTools.EventRecorder.events
.withGlobalContext('ApplicationContext', 'admin')
Combine filters
Get all PressEvents or InputChangeEvents originating from the hero-element in the main app:
objectiv.devTools.EventRecorder.events
.filter(['PressEvent', 'InputChangeEvent'])
.withLocationContext('ContentContext', 'hero-element')
.withGlobalContext('ApplicationContext', 'main-application')
Complex queries via predicate
The same example as above, written via a predicate instead:
objectiv.devTools.EventRecorder.events
.filter(
(event) =>
['PressEvent', 'InputChangeEvent'].includes(event._type)
&& Cypress._.find(
event.location_stack,
({ _type, id }) => _type === 'ContentContext' && id === 'hero-element'
)
&& Cypress._.find(
event.global_contexts,
({ _type, id }) => _type === 'ApplicationContext' && id === 'main-application'
)
)
Next: E2E testing with CI Frameworks
EventRecorder becomes even more useful when paired with a testing framework.
Check out how to set up E2E Testing with CI Frameworks in the next section.