javascript - 如何测试调度 Redux/Thunk 操作的 React 组件

标签 javascript reactjs unit-testing redux jestjs

我正在为一个组件编写集成测试,该组件应该根据异步(thunk)redux 操作的响应重定向到特定路径。

这是我的组件的简化版本:

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      redirect: false
    }

    this.props.dispatch(asyncThunkAction())
      .then( () => this.setState({redirec: true}) )
      .catch( (err) => console.log('action failed') )
  }

 ...

  render() {

    if (this.state.redirect) {
      return <Redirect to='/whocares' />
    }
    ...
  }
}

function mapStateToProps(state) {
  return {
     ...
  };
}

export default connect(mapStateToProps)(MyComponent);

我想编写一个测试来断言组件已重定向到预期路径。

我正在使用this technique用于检查实际的重定向路径(它并不完美,但不是这个问题的重点)。

我陷入困境的地方是 redux/thunk 操作之后 .then() 中的状态更改。因为这是一个 promise ,所以重定向发生在我的 expect 语句之后,因此我无法对其进行测试。

这是我的测试:

const middlewares = [thunk];
const mockStore = configureStore(middlewares);

  test('redirects after thunk action', () => {
    const redirectUrl = '/whocares'
    const data = {};


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

    act(() => {
      ReactDOM.render(
        <TestRouter
            ComponentWithRedirection={<MyComponent store={mockStore(data)} />}
            RedirectUrl={redirectUrl}
        />, 
        container);
    });
    expect(container.innerHTML).toEqual(
      expect.stringContaining(redirectUrl)
    )
  })

我的 TestRouter 只是将预期的重定向 URL 打印到 DOM 中。 (查看上面的链接以获取此黑客攻击的完整说明。)因此,现在我的测试(正确)识别了 thunk 操作正在进行时出现的加载屏幕,而不是到达预期的路线。

认为执行此操作的正确方法是模拟来自asyncThunkAction的响应,以便它返回具有匹配数据的已解决的 promise ,但到目前为止我还没有能够弄清楚如何做到这一点。我按照 manual mocks 上的 Jest 文档进行操作并创建了相应的模拟文件:

// __mocks__/actions.js
const asyncThunkAction = function(){
    return Promise.resolve({foo: 'bar'});
};
export { asyncThunkAction };

...但我的测试仍然“看到”加载状态。我什至不认为它正在查看我的模拟文件/操作。

执行此操作的正确方法是什么?

最佳答案

这是我如何让它发挥作用的“秘诀”......

使用testing-library/react ...

import { render, fireEvent, waitForElement, act } from '@testing-library/react';

(对此建议+1 给@tmahle)

通过创建一个“manual mock”来模拟axios(或者在我的例子中是包装它的API模块),这基本上需要创建一个__mocks__包含同名文件的实际文件旁边的目录。然后导出一个对象,其属性替换 get方法(或您的代码使用的任何一种)。

//__mocks__/myclient.js
export default {
  get: jest.fn(() => Promise.resolve({ data: {} }))
};

即使您在测试中没有调用模拟代码,您也需要 import它在测试文件中...

import myapi from '../api/myapi';
jest.mock('../api/myai');

您可以像这样模拟模拟 API 调用的响应:

myapi.get.mockResolvedValueOnce({
  data: { foo: "bar" },
});

我对这部分有点模糊...... 即使模拟的 API 请求立即响应并提供已解决的 promise ,您可能需要wait让它写expects

const { getByText, getByTestId, container } = render(<MyComponent />);
await wait(() => getByText('Some text that appears after the '));
expect(container.innerHTML).toEqual('whatever');

所有这些都在各种文档和问题中“存在”......但我花了很长时间才将它们拼凑在一起。希望这可以节省您的时间。

关于javascript - 如何测试调度 Redux/Thunk 操作的 React 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58808887/

相关文章:

javascript - 软键盘可见时无法单击按钮

javascript - 递归 Javascript 数组

javascript - d3.js - 带 slider 的圆形动画

javascript - 在函数中使用 React JS i18n

javascript - (重新安排)Codeigniter。如果它在侧边栏上,我应该在哪里/如何编写登录方法

node.js - Next.js:文档未定义

html - 在 React 组件中导入外部 CDN

python - 使用 Unittest Python 进行测试

python - Django REST Framework 缓存错误

c# - XUnit、AutoFixture 和 Moq 最佳实践