使用Jest和Redux异步组件快照 [英] Async component snapshot using Jest and Redux

查看:124
本文介绍了使用Jest和Redux异步组件快照的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现Jest在测试Redux React应用程序时非常有用.但是,有很多关于如何测试异步操作创建者的示例,但是我真的无法弄清楚如何对异步组件进行快照.

I find Jest to be very useful when testing my Redux React application. However, there are many examples of how to test async action creators, but I can't really figure out how to snapshot async components.

我想做的事情与在Facebook自己的教程中悬停的链接示例.他们调用props函数onMouseEnter()并随后拍摄快照.如果onMouseEnter()调度使用Redux Thunk创建的异步操作,是否有一种简单的方法?

What I would like to do is something similar to the hovered link example from Facebook's own tutorial. They call a props function onMouseEnter() and subsequently take the snapshot. Is there an easy way to do that if onMouseEnter() dispatches an async action created with Redux Thunk?

这是我使用axios的重击的样子.

This is how my thunk looks like, which uses axios.

  // test-api.js

  export function getLinkInfo() {
  return function(dispatch) {
    return axios.get('/api/get-link-info')
    .then(response => {
        dispatch(getLinkInfoSuccess(response.data));
        return response;
    });
  };
}

这是我自己的链接组件.

Here comes my own Link component.

import React from 'react';
import { connect } from 'react-redux';
import * as api from '../../api/test-api';

class Link extends React.Component {
  render() {
    return (
      <a href='#' onMouseEnter={this.props.getLinkInfo}>
        Hover me
      </a>
      <div>{this.props.linkInfo}</div>
    );
  }
}

const mapDispatchToProps = function(dispatch) {
  return {
    getLinkInfo: function() {
      dispatch(api.getLinkInfo());
    }
  }
}

const mapStateToProps = function(store) {
  return {
    linkInfo: store.getIn(['testState', 'linkInfo'], "")
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Link);

最后是测试文件.

import React from 'react';
import Link from '../link';
import renderer from 'react-test-renderer';

test('Link changes linkInfo when hovered', () => {
  const component = renderer.create(
    <Link></Link>
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();

  // manually trigger the callback
  tree.props.onMouseEnter();
  // re-rendering
  tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

推荐答案

问题是,当您想测试异步内容时,您需要在测试中使用Promise的实例,或者将其从测试中返回,所以开玩笑地知道它可以等待它,也可以在自己的测试中使用异步等待(docs ).

The problem is that when you like to test async stuff you need the instance of the promise in your test, either to return it from test, so jest knows about it and can wait for it, or use async await inside the test it self (docs).

您可以做的是在测试中模拟api:

What you could do, is to mock the api inside of your test:

从'path/to/the/api'导入{getLinkInfo} jest.mock('path/to/the/api',()=>({ getLinkInfo:jest.fn() }))

import {getLinkInfo} from 'path/to/the/api' jest.mock('path/to/the/api', () = > ({ getLinkInfo: jest.fn() }))

这将使用具有getLinkInfo间谍的对象覆盖模块.然后导入模块,以便您可以在测试中设置间谍程序的实际实现.

This will overwrite the module with an object that has a spy for getLinkInfo. Then import the module so you can set the actual implementation of the spy in your test.

test('Link changes linkInfo when hovered', () = > {
  //create a new promise that can be returned from your test
  const p = new Promise((resolve) = > {
    //set the spy to make the request and resolve the promise
    getInfo.mockImplementation(function (dispatch) {
      return axios.get('/api/get-link-info')
        .then(response = > {
          dispatch(getLinkInfoSuccess(response.data));
          resolve(response);
        });
    };)
  };)
  const component = renderer.create(
    <Link></Link>
  );
  let tree = component.toJSON();
  expect(tree)
    .toMatchSnapshot();
  // manually trigger the callback
  tree.props.onMouseEnter();
  return p.then(() = > {
    tree = component.toJSON();
    expect(tree)
      .toMatchSnapshot()
  })
});

虽然这可能会解决您的实际问题,但我建议不要通过调用您的真实API来像这样运行您的测试,而且还要自己模拟请求.首先,您的测试将更快,并且不依赖于某些正在运行的后端.

While this may solve you actual problem, I would suggest to not run your test like this, with a call to your real API, but also mock the request it self. First your test will be much faster and it does not dependent to some running backend.

重点是您想将React组件作为一个单元进行测试,因此它并不关心在调用getLinkInfo之后发生的事情.这些是getLinkInfo的单元测试的详细信息.您的组件所知道的就是,它在回调中调用getLinkInfo pass,有时会调用此回调.何时调用它以及在两者之间发生的事情不属于该组件的责任.如果您考虑这样的测试,最简单的解决方案是立即调用回调.

The point is that you want to test your React component as a unit, so it does not care what happened after it called getLinkInfo. These are details for the unit test of getLinkInfo. All that your component knows is, it calls getLinkInfo pass in an callback and this callback will be called sometimes. When it is called and what happened in between is not part of the responsibility of the component. If you think about the test like this, the simplest solution is to call the callback immediately.

test('Link changes linkInfo when hovered', () = > {
  getInfo.mockImplementation(function (dispatch) {
    dispatch({
      some: 'Data'
    });
  };)
  const component = renderer.create(
    <Link></Link>
  );
  let tree = component.toJSON();
  expect(tree)
    .toMatchSnapshot();
  // manually trigger the callback
  tree.props.onMouseEnter();
  tree = component.toJSON();
  expect(tree).toMatchSnapshot()
});

这篇关于使用Jest和Redux异步组件快照的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆