首页 > 解决方案 > 使用 Jest 和 Enzyme 模拟“提交”后测试更新的状态

问题描述

所以我在 React 中有一个 Classical 组件,RecipesNew,它具有以下初始状态:

        this.state = {
            recipe: {
                title: '',
                description: '',
                prepTime: '',
                cookingTime: ''
            },
            errors: false
        }

它有一个表单和以下 onSubmit 方法:

        handleOnSubmit = (e) => {
            e.preventDefault()
    
            this.props.startAddRecipe(recipe)
                .then(recipe => this.props.history.push(`/recipes/${recipe._id}`))
                .catch(err => this.setState({ errors: err }))
        }

props 上的 startAddRecipe 方法重新返回一个 Promise,当其中的 axios 调用时,该 Promise 将解析到我的数据库,解析然后分发一个更新 redux 状态的操作。当其中的 axios 调用拒绝时,promise 会拒绝。

我想测试 startAddRecipe 何时拒绝 startAddRecipe 并设置 this.state.errors。

在我的测试文件中,我有一个函数,它返回一个承诺并立即拒绝作为 startAddRecipe 道具传递给 RecipesNew:

const startAddRecipeRejectsSpy = jest.fn((recipeData = {}) => {
    return Promise.reject(['Test Error', 'Test Error 2']) 
})

这是我在 Promise 拒绝时测试的测试。我假设 state.errors 将用这个数组填充:['Test Error', 'Test Error 2']

test('startAddRecipe rejects correctly', () => {

    const wrapper = shallow(<RecipesNew startAddRecipe={startAddRecipeRejectsSpy} />);
    const mockRecipe = {
        title: 'Test Title',
        description: 'Test Description',
        prepTime: 10,
        cookingTime: 10
    }
    wrapper.setState({ recipe: mockRecipe })
    wrapper.find('form').simulate('submit',{ preventDefault: () => { } })
    expect(startAddRecipeRejectsSpy).toHaveBeenLastCalledWith(mockRecipe)
    expect(startAddRecipeRejectsSpy(mockRecipe)).rejects.toEqual(['Test Error', 'Test Error 2'])
    expect(wrapper.update().state().errors).toBe(['Test Error', 'Test Error 2']);
    expect(wrapper.update()).toMatchSnapshot();
})

除了最后2个之外,一切都有效。

倒数第二个说:

    Expected: ["Test Error", "Test Error 2"]
    Received: false

所以基本上状态似乎没有改变?

最后,最后一个快照不是我所期望的,因为当this.state.errors不是错误的时候,我映射错误数组并生成一个列表——这个列表不会出现在快照中。

有任何想法吗?我已经阅读了很多关于此的主题,但似乎没有什么与我的问题相匹配。

任何帮助表示赞赏。

谢谢!

标签: reactjsasynchronousjestjsenzymesetstate

解决方案


startAddRecipe 是异步的,因此在测试完成之前它可能不会完成。在检查状态之前,您需要等待 startAddRecipe 完成。您可以通过执行类似的操作确保在检查状态之前刷新所有承诺。

const tick = async () => {
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
};

.
.

test('startAddRecipe rejects correctly', async () => {

    const wrapper = shallow(<RecipesNew startAddRecipe={startAddRecipeRejectsSpy} />);
    const mockRecipe = {
        title: 'Test Title',
        description: 'Test Description',
        prepTime: 10,
        cookingTime: 10
    }
    wrapper.setState({ recipe: mockRecipe })
    wrapper.find('form').simulate('submit',{ preventDefault: () => { } })
    await tick();
    expect(startAddRecipeRejectsSpy).toHaveBeenLastCalledWith(mockRecipe)
    expect(startAddRecipeRejectsSpy(mockRecipe)).rejects.toEqual(['Test Error', 'Test Error 2'])
    expect(wrapper.update().state().errors).toBe(['Test Error', 'Test Error 2']);
    expect(wrapper.update()).toMatchSnapshot();
})

试一试,让我知道它是否适合你。


推荐阅读