How do I properly mock third party libraries (like jQuery and Semantic UI) using Jest?
<p>I have been learning React, Babel, Semantic UI, and Jest over the last couple of weeks. I haven't really run into too many issues with my components not rendering in the browser, but I <em>have</em> run into issues with rendering when writing unit tests with Jest.</p>

<p>The SUT is as follows:</p>

<p><strong>EditUser.jsx</strong></p>

<pre><code>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, status, err.toString());
          $('.toast').addClass('sad');
          $('.toast').html("Something bad happened: " + err.toString());
          $('.toast').transition('fade up', '500ms');
          setTimeout(function(){
              $('.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[&lt;script&gt;]',
                      prompt: 'Please enter a valid first name.'
                    }
                ]
            },
            lastName: {
              identifier: 'lastName',
              rules: [
                    {
                      type: 'empty',
                      prompt: 'Please enter a last name.'
                    },
                    {
                      type: 'doesntContain[&lt;script&gt;]',
                      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.'
                    },
                    {
                      type: 'doesntContain[&lt;script&gt;]',
                      prompt: 'Please enter a valid email address.'
                    }
                ]
            },
            role: {
              identifier: 'role',
              rules: [
                    {
                      type: 'empty',
                      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),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });

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

module.exports = EditUser;
</code></pre>

<p>The associated test file is as follows:</p>

<p><strong>EditUser.test.js</strong></p>

<pre><code>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', () =&gt; {
    const component = Renderer.create(
        &lt;EditUser /&gt;
    ).toJSON();
    expect(component).toMatchSnapshot();
});
</code></pre>

<p>The issue that I am seeing when I run <code>jest</code>:</p>

<pre><code> FAIL  test/components/Users/EditUser.test.js
  ● Test suite failed to run

    ReferenceError: jQuery is not defined

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