Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save JamieMason/c78e27f4281049a6d9b72f6cf9782fb8 to your computer and use it in GitHub Desktop.
Save JamieMason/c78e27f4281049a6d9b72f6cf9782fb8 to your computer and use it in GitHub Desktop.
Log XState inspector events to the Browser Console

Log XState inspector events to the Browser Console

A small inspect function to log events to the browser console, when you expand a group you see a log of the full event object.

Screenshot

Screenshot

Usage

const [state, send, actor] = useActor(myMachine, {
  inspect: logInspectionEvent,
});

Implementation

I know right 🤮, mainly this is down to the API for applying colours to browser console logs and this is about 30 minutes' work.

If you do any clean up on this, please comment and let me know. You'll notice there is a ts: Property 'id' does not exist on type 'ActorRefLike' – but they can have an ID.

import type { InspectionEvent, StateValue } from 'xstate';

export function logInspectionEvent(event: InspectionEvent): void {
  const internalEvent = event.type;
  const style = {
    action: 'color:#F48FB1',
    actor: 'color:inherit',
    eventType: 'color:#81D4FA',
    internalEvent: 'color:#999',
  } as const;

  switch (event.type) {
    case '@xstate.snapshot': {
      const actor = event.actorRef?.id;
      console.groupCollapsed(`%c${internalEvent} %c${actor}`, style.internalEvent, style.actor);
      break;
    }
    case '@xstate.event': {
      const eventType = event.event?.type;
      const sourceId = event.sourceRef?.id;
      const actorId = event.actorRef?.id;
      if (sourceId && actorId) {
        console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${sourceId}${actorId}`, style.internalEvent, style.eventType, style.actor);
      } else {
        console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${actorId}`, style.internalEvent, style.eventType, style.actor);
      }
      break;
    }
    case '@xstate.actor': {
      const actorId = event.actorRef?.id;
      console.groupCollapsed(`%c${internalEvent} %c${actorId}`, style.internalEvent, style.actor);
      break;
    }
    case '@xstate.microstep': {
      const actorId = event.actorRef?.id;
      const eventType = event.event?.type;
      const stateValue = getStateValueStrings(event.snapshot.value).sort().join('\n  ');
      console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${actorId}\n  %c${stateValue}`, style.internalEvent, style.eventType, style.actor, style.internalEvent);
      break;
    }
    case '@xstate.action': {
      const actorId = event.actorRef?.id;
      const actionType = event.action?.type;
      if (actionType === 'xstate.emit') {
        const eventType = event.action.params?.event?.type;
        console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId} %c${eventType}`, style.internalEvent, style.action, style.actor, style.eventType);
      } else if (actionType === 'xstate.stopChild' || actionType === 'xstate.spawnChild') {
        const childSrc = event.action.params?.src;
        console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId} ➤ %c${childSrc}`, style.internalEvent, style.action, style.actor, style.actor);
      } else if (actionType === 'xstate.sendTo') {
        const targetId = event.action.params?.to?.id;
        const eventType = event.action.params?.event?.type;
        console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${eventType} %c${actorId} ➤ %c${targetId}`, style.internalEvent, style.action, style.eventType, style.actor, style.actor);
      }

      // console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId}`, style.internalEvent, style.action, style.actor);
      break;
    }
  }
  console.log(event);
  console.groupEnd();
}

function getStateValueStrings(stateValue: StateValue): string[] {
  if (typeof stateValue === 'string') {
    return [stateValue];
  }
  const valueKeys = Object.keys(stateValue);
  return valueKeys.concat(...valueKeys.map(key => getStateValueStrings(stateValue[key]!).map(s => key + '.' + s)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment