Ejaz
Ejaz

Reputation: 8872

Enzyme testing Reactjs component that uses global jQuery object

I'm integrating Reactjs incrementally into a web app frontend built with HTML5 and jQuery. My react component uses global jQuery object (for AJAX and some animations here and there) that would be available when the react component javascript is loaded.

Now, when I try to mount() this component for testing with Enzyme, it get following error

 ReferenceError: jQuery is not defined

How do I make jQuery object available for the mounted component?

Testing a React component that uses jQuery & window object is a similar question with 0 answers...

I'm willing to update the component code if necessary.

ANY help would be greatly appreciated.

Edit

Sample code of my component

  import React from 'react';

  export default class MySimpleComponent extends React.Component {

     constructor(props) {
        super(props);
     }

     componentDidMount() {
        var add_btn = this.refs.btn_add;
        (function ($) {
           $(add_btn).click(function (ev) {
              ev.preventDefault();
              console.log('button was clicked');
           });
        })(jQuery);
     }

     render() {
        return (
           <div className="wrap">
              <form action="/">
                 <input type="text" name="myinput" value="" />
                 <button className="button" ref="btn_add">New Record</button>
              </form>
           </div>
        );
     }
  }

Upvotes: 1

Views: 490

Answers (1)

spirift
spirift

Reputation: 3072

Okay so you might be able to do this with jsdom. You have to setup some globals as they say in the readme. Just add in global.jQuery = () => {}; as well.

var jsdom = require('jsdom').jsdom;

global.document = jsdom('');
global.jQuery = () => {};
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js'
};

I have not had a chance to try out the above. However I would not recommend this as a sustainable solution. A much better approach would be to drop jQuery. Here is your component refactored without it.

  import React from 'react';

  export default class MySimpleComponent extends React.Component {

     constructor(props) {
        super(props);
     }

     clickHanlder(ev) {
       ev.preventDefault();
       console.log('button was clicked');
     }

     render() {
        return (
           <div className="wrap">
              <form action="/">
                 <input type="text" name="myinput" value="" />
                 <button className="button" onClick={this.clickHanlder}>New Record</button>
              </form>
           </div>
        );
     }
  }

As you can see it's not that different. You can attach the event handlers directly to the elements, for me this makes the code easier to read and see where the action is, so to speak.

Upvotes: 1

Related Questions