Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

75
Views
Testing actions reliably

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

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

First, I suspect setTimeout just skips the expect..

I ran into the same issue using withConfig. The actions at least, are not called at all even if they appear in machine.options.actions.

My code looks like this:

const myAction = jest.fn();
const actions = { myAction };
const withCfg = machine.withConfig({
  actions,
});
const spy = jest
  .spyOn(actions, 'myAction')
  .mockImplementation(() => myAction());
// ...

expect(spy).toHaveBeenCalledTimes(1);

Note that in application those actions are executed just fine

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!