xstate

xstate - how to properly handle transitions errors?


I'm completely new to Xstate and I'm struggling to find help inside the official documentation.

The problem is pretty easy, I'd like to know if an event is triggered when is not suppose to.

I have a basic workflow that is very strict in terms of transitions, for instance, my state can't go from 'pending' to 'processed' without passing from 'uploaded'.

If I use:

stateService.send('PROCESSED') 

while the state is in 'pending', the state doesn't change ( correct ) but is there any utility or event in Xstate that actually tells me that the transaction was not fired since the event was not allowed/correct?

This is my state

const stateMachine = Machine(
  {
    id: 'vocalTrack',
    initial: 'PENDING',
    context: {},
    states: {
      PENDING: {
        on: {
          UPLOADED: 'UPLOADED',
        },
      },
      UPLOADED: {
        on: {
          PROCESSED: 'PROCESSED',
        },
        entry: 'onUploaded',
      },
      PROCESSED: {
        on: {
          READY: 'READY',
          ERROR: 'ERROR',
        },
        exit: 'onProcessed',
      },
      READY: {
        type: 'final',
      },
      ERROR: {
        on: {
          UPLOADED: 'UPLOADED',
        },
        type: 'final',
      },
    },
  },
  {
    actions: {
      onUploaded: (context, event) => {
        console.log(`++++ onUploaded action: ++++`)
      },
      onProcessed: (context, event) => {
        console.log(`++++ onProcessed action: ++++`)
      },
    },
  },
)

const stateService = interpret(stateMachine)
stateService.init('PENDING')

// I'd like to catch the following workflow errors
stateService.send('UPLOADED')
stateService.send('PROCESSED')


Solution

  • There is no option you can pass to the machine or interpret call that will give you this for "free". You can easily add some logic to the "onTransition" method though:

    Option 1, validate on state.changed:

        service.onTransition(state => {
            if (state.changed) {
                console.log(`The state did change, so ${state.event.type} caused a valid transition`);
            } else {
                console.log(`${state.event.type} did not cause a state change`);
            }
        })
    

    Option 2, validate based on state.value & event name:

        service.onTransition(state => {
            if (state.event.type === 'xstate.init'){
                console.log('Init Transition');
                return;
            }
            if(state.value === state.event.type){
                console.log('Transition Valid');
            }else {
                console.log('Transition Invalid');
            }
        })
    

    Option 1 would probably be the preferred solution! You can read more about it here in the documentation. The following SO question is also related in terms of events that don't exist at all.

    I've created a small demo application in react to demonstrate this:

    Edit cranky-silence-934uu