I'm using xstate to implement a login flow.
I have a machine where the initialState invokes a Promise, and if it's rejected it will redirect to a state that has an entry
action. I would like to test that the action is called at the right time properly.
machine.ts
{
id: 'entrance',
initial: States.FETCHING_SESSION,
states: {
[States.FETCHING_SESSION]: {
invoke: {
src: 'fetchSession',
onError: {
target: States.LOGGED_OUT,
}
}
},
[States.LOGGED_OUT]: {
entry: ['navigateToLogin']
type: 'final'
},
}
}
machine.spec.ts
const mockFetchSession = jest.fn()
.mockRejectedValueOnce({ error: new Error('401 unauthorized') })
const mockNavigateToLogin = jest.fn()
const service = interpret(entranceMachine.withConfig({
services: {
fetchSession: mockFetchSession
},
actions: {
navigateToLogin: mockNavigateToLogin
}
}))
it('Goes to login page on fail', (done) => {
service.onTransition((state) => {
expect(state.matches(States.LOGGED_OUT))
expect(mockNavigateToLogin).toHaveBeenCalled() // <- this test case always fails
done()
})
service.start()
})
I managed to make it work in kinda of an ugly way by wrapping expect around a setTimout.
setTimeout(() => expect(mockNavigateToLogin).toHaveBeenCalled(), 100)
I wonder if there is a better option? Thanks