【问题标题】:Enzyme async await mock function not being called酶异步等待模拟函数未被调用
【发布时间】:2019-08-23 00:42:40
【问题描述】:

我正在尝试测试异步等待功能,但是我遇到了错误。

● 应该处理getGIF 事件 › 应该处理getGIF 事件

expect(jest.fn()).toHaveBeenCalledTimes(1)

Expected mock function to have been called one time, but it was called zero times.

我不确定如何测试异步等待函数,所以我以这个博客为例 https://medium.com/@rishabhsrao/mocking-and-testing-fetch-with-jest-c4d670e2e167

App.js

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import Card from './Card';
import PropTypes from "prop-types";
const Styles = {
    marginTop: '100px',
    inputStyle: {
        borderRadius: '0px',
        border: 'none',
        borderBottom: '2px solid #000',
        outline: 'none',
        focus: 'none'
    }
}
class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            query: '',
            title: undefined,
            url: undefined
        }
        this.onChange = this.onChange.bind(this);
    }
    onChange(e) {
        this.setState({query: e.target.value})
    }
    // testing this function 
    getGIY = async(e) => {
        e.preventDefault();
        const { query } = this.state;
        await fetch(`http://api.giphy.com/v1/gifs/search?q=${query}&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5`)
        .then(response => response.json())
        .then(({ data }) => {
          this.setState({
            title: data[0].title,
            url: data[0].images.downsized.url
          });
        })
        .catch( (err) =>{
            console.log(err)
        });

    }
    render() {
        return (
            <div className="col-md-6 mx-auto" style={Styles}>
                <h1 className="gif-title">Random GIF fetch</h1>
                <form className="form-group" onSubmit={this.getGIY}>
                    <input
                        style={Styles.inputStyle}
                        className="form-control"
                        type="text"
                        value={this.state.query}
                        onChange={this.onChange}
                        placeholder="Search GIF..."/>
                    <button type="submit" className="btn btn-primary mt-4">Get GIF</button>
                </form>
                <Card title={this.state.title} url={this.state.url}/>
            </div>
        );
    }
}
PropTypes.propTypes = {
    onChange: PropTypes.func.isRequired,
    getGIY:PropTypes.func.isRequired,
    title:PropTypes.string.isRequired,
    url:PropTypes.string.isRequired
}
export default App;

App.test.js

import React from 'react';
import ReactDOM from 'react-dom';
import {shallow} from 'enzyme';
import App from './App';



describe('Should handle getGIF event', ()=> {
  it('should handle getGIF event', done => {
    const component = shallow(<App/>)

    const mockSuccessResponse = {};
    const mockJsonPromise = Promise.resolve(mockSuccessResponse);
    const mockQuery = "Owl"

    const mockFetchPromise = Promise.resolve({
      json:() => mockJsonPromise,

    });
    jest.spyOn(global, 'fetch').mockImplementation(()=> mockFetchPromise);

    expect(global.fetch).toHaveBeenCalledTimes(1);
    expect(global.fetch).toHaveBeenCalledWith(`http://api.giphy.com/v1/gifs/search?q=${mockQuery}&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5`);

    process.nextTick(() => { // 6
      expect(component.state()).toEqual({
        // ... assert the set state
      });

      global.fetch.mockClear(); // 7
      done(); // 8
    });

  })
})

【问题讨论】:

    标签: javascript reactjs jestjs enzyme


    【解决方案1】:

    你可以这样测试:

    import React from 'react';
    import { shallow } from 'enzyme';
    import App from './App';
    
    describe('Should handle getGIF event', () => {
    
      let mock, actualFetch;
      beforeEach(() => {
        mock = jest.fn();
        actualFetch = global.fetch;
        global.fetch = mock;
      });
      afterEach(() => {
        global.fetch = actualFetch;
      });
    
      it('should handle getGIF event', async () => {
        const component = shallow(<App />);
        component.setState({ query: 'Owl' });
        mock.mockResolvedValue({ 
          json: () => Promise.resolve({
            data: [{
              title: 'the title',
              images: { downsized: { url: 'the url' }}
            }]
          })
        });
        const form = component.find('form');
    
        await form.props().onSubmit({ preventDefault: () => {} });
    
        expect(mock).toHaveBeenCalledWith('http://api.giphy.com/v1/gifs/search?q=Owl&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5');  // Success!
        expect(component.state('title')).toBe('the title');  // Success!
        expect(component.state('url')).toBe('the url');  // Success!
      });
    });
    

    详情

    fetch 可能未在 Node.js 环境中定义,因此只需抓住它的任何内容并用模拟替换它,然后恢复它是一个好方法。

    使用.setState 设置组件状态。

    使用.find 获取form 并使用.props 访问其道具并调用其onSubmit 函数。

    使用async 测试函数和awaitonSubmit 返回的Promise,以便在继续之前完全完成。

    使用.state查询组件状态。

    【讨论】:

    • 感谢这个工作,我会更深入地研究这个。 beforeEach 和 afterEach 背后的目的是什么如果你不使用它们会发生什么?
    • beforeEachafterEach 总是在测试前后运行,因此在其中进行模拟(尤其是 global 模拟)更安全。 (如果全局fetch在测试结束时恢复,但是测试失败并且没有运行到最后,那么fetch之后仍然会被mock)。 @randal
    • 仅供参考,我只是通过使用findprops 调用formonSubmit 属性对测试进行了一些改进。 @randal
    • 就文档而言,JestEnzyme 文档非常适合发现可用的工具集。它们都在不断地得到增强,因此最好查看更新日志以获取最新的增强功能。 SO 上的答案是一个很好的资源,它们通常遵循最佳实践。 @randal
    • 非常感谢布赖恩,这对您有很大帮助。 :)
    猜你喜欢
    • 2016-04-26
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多