使用Jest如何正确地模拟第三方库(如jQuery和语义UI)?

前端之家收集整理的这篇文章主要介绍了使用Jest如何正确地模拟第三方库(如jQuery和语义UI)?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在过去的几周里,我一直在学习React,Babel,Semantic UI和Jest。我没有遇到太多的问题,我的组件不能在浏览器中呈现,但是我在使用Jest编写单元测试时遇到了渲染问题。

SUT如下:

EditUser.jsx

var React = require('react');
var { browserHistory,Link } = require('react-router');
var $ = require('jquery');

import Navigation from '../Common/Navigation';

const apiUrl = process.env.API_URL;
const phoneRegex = /^[(]{0,1}[0-9]{3}[)]{0,1}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{4}$/;

var EditUser = React.createClass({
  getInitialState: function() {
    return {
      email: '',firstName: '',lastName: '',phone: '',role: ''
    };
  },handleSubmit: function(e) {
    e.preventDefault();

    var data = {
      "email": this.state.email,"firstName": this.state.firstName,"lastName": this.state.lastName,"phone": this.state.phone,"role": this.state.role
    };

    if($('.ui.form').form('is valid')) {
      $.ajax({
        url: apiUrl + '/api/users/' + this.props.params.userId,dataType: 'json',contentType: 'application/json',type: 'PUT',data: JSON.stringify(data),success: function(data) {
          this.setState({data: data});
          browserHistory.push('/Users');
          $('.toast').addClass('happy');
          $('.toast').html(data["firstName"] + ' ' + data["lastName"] + ' was updated successfully.');
          $('.toast').transition('fade up','500ms');
          setTimeout(function(){
              $('.toast').transition('fade up','500ms').onComplete(function() {
                  $('.toast').removeClass('happy');
              });
          },3000);
        }.bind(this),error: function(xhr,status,err) {
          console.error(this.props.url,err.toString());
          $('.toast').addClass('sad');
          $('.toast').html("Something bad happened: " + err.toString());
          $('.toast').transition('fade up','500ms').onComplete(function() {
                  $('.toast').removeClass('sad');
              });
          },3000);
        }.bind(this)
      });
    }
  },handleChange: function(e) {
    var nextState = {};
    nextState[e.target.name] = e.target.value;
    this.setState(nextState);
  },componentDidMount: function() {
    $('.dropdown').dropdown();

    $('.ui.form').form({
      fields: {
            firstName: {
              identifier: 'firstName',rules: [
                    {
                      type: 'empty',prompt: 'Please enter a first name.'
                    },{
                      type: 'doesntContain[<script>]',prompt: 'Please enter a valid first name.'
                    }
                ]
            },lastName: {
              identifier: 'lastName',prompt: 'Please enter a last name.'
                    },prompt: 'Please enter a valid last name.'
                    }
                ]
            },email: {
              identifier: 'email',rules: [
                    {
                      type: 'email',prompt: 'Please enter a valid email address.'
                    },{
                      type: 'empty',prompt: 'Please enter an email address.'
                    },prompt: 'Please enter a valid email address.'
                    }
                ]
            },role: {
              identifier: 'role',prompt: 'Please select a role.'
                    }
                ]
            },phone: {
              identifier: 'phone',optional: true,rules: [
                    {
                      type: 'minLength[10]',prompt: 'Please enter a valid phone number of at least {ruleValue} digits.'
                    },{
                      type: 'regExp',value: phoneRegex,prompt: 'Please enter a valid phone number.'
                    }
                ]
            }
        }
    });

    $.ajax({
      url: apiUrl + '/api/users/' + this.props.params.userId,dataType:'json',cache: false,success: function(data) {
        this.setState({data: data});
        this.setState({email: data.email});
        this.setState({firstName: data.firstName});
        this.setState({lastName: data.lastName});
        this.setState({phone: data.phone});
        this.setState({role: data.role});
      }.bind(this),err) {
        console.error(this.props.url,err.toString());
      }.bind(this)
    });

  },render: function () {
    return (
      <div className="container">
        <Navigation active="Users"/>
        <div className="ui segment">
            <h2>Edit User</h2>
            <div className="required warning">
                <span className="red text">*</span><span> required</span>
            </div>
            <form className="ui form" onSubmit={this.handleSubmit} data={this.state}>
                <h4 className="ui dividing header">User Information</h4>
                <div className="ui three column grid field">
                    <div className="row fields">
                        <div className="column field required">
                            <label>First Name</label>
                            <input type="text" name="firstName" value={this.state.firstName}
                                onChange={this.handleChange}/>
                        </div>
                        <div className="column field required">
                            <label>Last Name</label>
                            <input type="text" name="lastName" value={this.state.lastName}
                                onChange={this.handleChange}/>
                        </div>
                        <div className="column field required">
                            <label>Email</label>
                            <input type="text" name="email" value={this.state.email}
                                onChange={this.handleChange}/>
                        </div>
                    </div>
                </div>
                <div className="ui three column grid field">
                    <div className="row fields">
                        <div className="column field required">
                            <label>User Role</label>
                            <select className="ui dropdown" name="role"
                                onChange={this.handleChange} value={this.state.role}>
                                <option value="SuperAdmin">Super Admin</option>
                            </select>
                        </div>
                        <div className="column field">
                            <label>Phone</label>
                            <input name="phone" value={this.state.phone}
                                onChange={this.handleChange}/>
                        </div>
                    </div>
                </div>
                <div className="ui three column grid">
                    <div className="row">
                        <div className="right floated column">
                            <div className="right floated large ui buttons">
                                <Link to="/Users" className="ui button">Cancel</Link>
                                <button className="ui button primary" type="submit">Save</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="ui error message"></div>
            </form>
        </div>
      </div>
    );
  }
});

module.exports = EditUser;

相关的测试文件如下:

EditUser.test.js

var React = require('react');
var Renderer = require('react-test-renderer');
var jQuery = require('jquery');
require('../../../semantic/dist/components/dropdown');

import EditUser from '../../../app/components/Users/EditUser';

it('renders correctly',() => {
    const component = Renderer.create(
        <EditUser />
    ).toJSON();
    expect(component).toMatchSnapshot();
});

我跑的时候看到的问题:

FAIL  test/components/Users/EditUser.test.js
  ● Test suite Failed to run

    ReferenceError: jQuery is not defined

      at Object.<anonymous> (semantic/dist/components/dropdown.min.js:11:21523)
      at Object.<anonymous> (test/components/Users/EditUser.test.js:6:370)
      at process._tickCallback (node.js:369:9)

解决方法

你正在做正确的做法,但一个简单的错误

You have to tell jest not to mock jquery

要清楚,

from 07000 under 4th subtitle Testing Vanilla

[It talks about testing a Vanilla app,but it perfectly describe about Jest]

The thing about Jest is that it mocks everything. Which is priceless for unit testing. But it also means you need to declare when you don’t want something mocked.

那是

jest.unmock(moduleName)

From Facebook’s documentation
unmock Indicates that the module system should never return a mocked version of the specified module from require() (e.g. that it should always return the real module).

The most common use of this API is for specifying the module a given test intends to be testing (and thus doesn’t want automatically mocked).

It returns the jest object for chaining.

Note : PrevIoUsly it was dontMock.

When using babel-jest,calls to unmock will automatically be hoisted to the top of the code block. Use dontMock if you want to explicitly avoid this behavior.
You can see the full documentation here 07001.

在require中也使用const而不是var。那是

const $ = require('jquery');

所以代码看起来像

jest.unmock('jquery'); // unmock it. In prevIoUs versions,use dontMock instead
var React = require('react');
var { browserHistory,Link } = require('react-router');
const $ = require('jquery');

import Navigation from '../Common/Navigation';

const apiUrl = process.env.API_URL;
const phoneRegex = /^[(]{0,render: function () {
    return (
      <div className="container">
        <Navigation active="Users"/>
        <div className="ui segment">
            <h2>Edit User</h2>
            <div className="required warning">
                <span className="red text">*</span><span> required</span>
            </div>
            <form className="ui form" onSubmit={this.handleSubmit} data={this.state}>
                <h4 className="ui dividing header">User Information</h4>
                <div className="ui three column grid field">
                    <div className="row fields">
                        <div className="column field required">
                            <label>First Name</label>
                            <input type="text" name="firstName" value={this.state.firstName}
                                onChange={this.handleChange}/>
                        </div>
                        <div className="column field required">
                            <label>Last Name</label>
                            <input type="text" name="lastName" value={this.state.lastName}
                                onChange={this.handleChange}/>
                        </div>
                        <div className="column field required">
                            <label>Email</label>
                            <input type="text" name="email" value={this.state.email}
                                onChange={this.handleChange}/>
                        </div>
                    </div>
                </div>
                <div className="ui three column grid field">
                    <div className="row fields">
                        <div className="column field required">
                            <label>User Role</label>
                            <select className="ui dropdown" name="role"
                                onChange={this.handleChange} value={this.state.role}>
                                <option value="SuperAdmin">Super Admin</option>
                            </select>
                        </div>
                        <div className="column field">
                            <label>Phone</label>
                            <input name="phone" value={this.state.phone}
                                onChange={this.handleChange}/>
                        </div>
                    </div>
                </div>
                <div className="ui three column grid">
                    <div className="row">
                        <div className="right floated column">
                            <div className="right floated large ui buttons">
                                <Link to="/Users" className="ui button">Cancel</Link>
                                <button className="ui button primary" type="submit">Save</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="ui error message"></div>
            </form>
        </div>
      </div>
    );
  }
});

module.exports = EditUser;
原文链接:https://www.f2er.com/jquery/183033.html

猜你在找的jQuery相关文章