Using the Custom Event API

The Custom Event API allows you to record and replay custom events in your application with deterministic timing. This can be useful if your application relies on external services or web APIs which Meticulous does not mock out by default (e.g. browser extensions, EventSource, etc).

  • During recording, you can emit custom events with associated data using the window.Meticulous?.record?.recordCustomEvent method.
  • During replay, Meticulous will emit custom events at the same time they occurred during the recording. You can listen for these custom events using the window.Meticulous?.replay?.addCustomEventListener method:

Examples

Example: Extend Meticulous to support device orientation events

const handleOrientationEvent = (opts) => {
  // Your existing code that handles the orientation event
};

if (window.Meticulous?.replay) {
  window.Meticulous.replay.addCustomEventListener("deviceOrientationChanged",
      (serializedData) => handleOrientationEvent(JSON.parse(serializedData))
    );
} else {
  window.addEventListener(
    "deviceorientation",
    (event) => {
        window.Meticulous?.record?.recordCustomEvent(
          "deviceOrientationChanged",
          JSON.stringify({ rotation: event.alpha })
        );
        handleOrientationEvent({ rotation: event.alpha });
    }
  );
}

Example: Simulate messages from a 3rd party iframe, without rendering that iframe at test time

Imagine you have a 3rd party iframe you process messages from, but don't actually want to run or test the 3rd party code. Instead you wish to test that your application correctly handles the user flow around the iframe, including currently handling any messages received from the iframe.

In this case your code may look like this:

const iframe = createIFrameAndAddToDOM();
iframe.addEventListener("message", handleMessageFromIframe);

You can use the custom event API to configure Meticulous to record any messages received from the iframe at recording time, and then simulate those messages at replay time, without actually rendering the iframe at all at replay time:

if (window.Meticulous?.replay) {
   window.Meticulous.replay.addCustomEventListener(
    "message-from-my-iframe",
    (serializedData) => handleMessageFromIframe(deserialize(serializedData))
  );
} else {
   const iframe = createIFrameAndAddToDOM();
   iframe.addEventListener("message", handleMessageFromIframe);
   if (window.Meticulous?.record) {
       iframe.addEventListener(
        "message",
        msg => window.Meticulous.record.recordCustomEvent(
          "message-from-my-iframe",
          serialize(msg)
        )
      );
   }
}

Best Practices

  • window.Meticulous?.record will only be defined at record time and window.Meticulous?.replay will only be defined at replay time, so you don't need to do a special check to see if you're in recording or replay mode
  • Use descriptive event names that clearly indicate their purpose
  • Keep event data simple and serializable
  • Handle cases where the Meticulous API might not be available (e.g., in development)

TypeScript Types

For TypeScript type definitions for the window.Meticulous object, see TypeScript Types for window.Meticulous.