在xstate中模拟调用的诺言

问题描述 投票:0回答:1

我试图测试状态转换发生时是否调用了promise。

我遵循了the official xState tutorial中概述的方法,但是出现以下错误

Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout

这是我的状态机,当您从初始状态过渡时,它所做的就是调用一个Promise。

export const statsMachine = Machine(
  {
    id: 'stats',
    initial: 'incomplete',
    states: {
      incomplete: {
        on: {
          MODAL_OPENED: 'loading',
        },
      },
      loading: {
        invoke: {
          id: 'setRatioDefaultsInFirebase',
          src: (context, event) => setStatDefaults(event.payload && event.payload.userId),
          onDone: {
            target: 'modal',
          },
          onError: {
            target: 'incomplete',
          },
        },
      },
      modal: {...}
    }
  })

这是我的测试。而不是像本教程中那样触发真正的api调用,我想模拟我的api调用。我在开玩笑来模拟副作用。我想断言是嘲笑的副作用被调用了。但是我得到上面列出的错误。

jest.mock('../statsAPI');

test('stats should start off with minimum ratios', done => {
      setStatDefaults.mockResolvedValueOnce();

      const statsBoxService = interpret(statsMachine)
        .onTransition(state => {
          if (state.matches({ selected: 'modal' })) {
            expect(setStatDefaults).toHaveBeenCalled();
            done();
          }
        })
        .start();

      statsBoxService.send('MODAL_OPENED');
    });

我必须更改什么才能断言在机器转换时我的嘲笑副作用被调用了?

reactjs testing jestjs state-machine xstate
1个回答
1
投票

我认为这可能与您的if语句错误一样简单:

if (state.matches({ selected: 'modal' })) {

应该是

if (state.matches('modal')) {

在示例中,'initial','loading','loaded','failed'是状态为'selected'的子级>

话虽这么说,但我还是在研究您的示例,发现它可以正常工作,在模拟方面与您的实现稍有不同:

machines.test.ts:

import { interpret } from 'xstate';
import { statsMachine } from './machines';

test('stats should start off with minimum ratios', done => {

  global.fetch = jest.fn().mockImplementation(
    () => Promise.resolve({ json: () => Promise.resolve({}) })
  );

  const statsBoxService = interpret(statsMachine)
    .onTransition(state => {
      if (state.matches('modal')) {
        expect(global.fetch).toHaveBeenCalledTimes(1);
        done();
      }
    })
    .start();

  statsBoxService.send('MODAL_OPENED');
});

machines.ts:

import { Machine } from 'xstate';

export const setStatDefaults = async (t: any) => {
  const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
  return response.json();
};

export const statsMachine = Machine(
  {
    id: 'stats',
    initial: 'init',
    states: {
      init: {
        on: {
          MODAL_OPENED: 'loading',
        }
      },
      incomplete: {
        on: {
          MODAL_OPENED: 'loading',
        }
      },
      loading: {
        invoke: {
          id: 'setRatioDefaultsInFirebase',
          src: (context, event) => setStatDefaults(event.payload && event.payload.userId),
          onDone: {
            target: 'modal',
          },
          onError: {
            target: 'incomplete',
          },
        },
      },
      modal: {

      }
    }
  });
© www.soinside.com 2019 - 2024. All rights reserved.