10

I have a very simple React mixin which uses jQuery to trigger an event

MyMixin = {
  trackStructEvent: function () {
    args = Array.prototype.slice.call(arguments);
    $('body').trigger('myEvent', args);
  }
module.exports = MyMixin

This is imported into the main site as part of a new set of components using browserify. As the main site holding these components will always include jQuery, I don't want to require jQuery with browserify, as it will be duplicated.

This isn't an issue in terms of behaviour - however it causes problems when running jest to unit test the components using this mixin throwing the error.

ReferenceError: $ is not defined

I know I can fix this by including jQuery through browserify, but that will load 2 copies into my site.

Is there any way in jest to tell my react component that jQuery already exists on the window and not to worry about it?

6
  • Did you try var $ = window.jQuery? Commented Nov 28, 2014 at 13:19
  • 1
    Another way is to use the external option in browserify Commented Nov 28, 2014 at 13:22
  • @David - using external seemed to work ok in my component, but I couldn't get it to play nice with jest. For now I have added a check that $ is defined before calling it. I won't put it as an answer as it's not a real solution to the problem. It just let me safely pass my jests Commented Nov 28, 2014 at 16:33
  • I would also be interested in an answer for this question, for me it's React itself which is loaded already. maybe global.React = require('react/addons') at the top of your tests will do... Commented Feb 11, 2015 at 9:57
  • 1
    or in your case global.$ = require('jquery') :) Commented Feb 11, 2015 at 10:03

3 Answers 3

7

I have a similar problem but I think where i've got to so far solves your problem. You need to use require inside your react files to define jQuery under $

var $ = require('jquery');

MyMixin = {
   trackStructEvent: function () {
      args = Array.prototype.slice.call(arguments);
      $('body').trigger('myEvent', args);
   }
module.exports = MyMixin

You then need to tell jest not to mock jquery

jest.dontMock('jquery')

Then your jest unit tests should pass (assuming they aren't verifying things that jQuery is doing - this is where my tests are falling over).

You also need to tell browserify that jQuery is external then the result will be that all your references to $ have been defined, the jquery library is loaded for testing but is not included in your browserify bundle. (use browserify-shim)

Sign up to request clarification or add additional context in comments.

1 Comment

We've ended up removing jQuery from our site now we have a full react set up, so no need for DOM manipulation. This does look like it would solve the problems we were having though, and as it solved your issue it makes sense to be the accepted answer. thanks!
2

What I'm going with is:

if (process.env.NODE_ENV === 'test') window.$ = require('jquery');

I hope this helps someone!

UPDATE:

I've begun to import $ from 'jquery' in all React files that use jQuery. This removes the dependency on window.$ being the type of jQuery I expect (I have run into problems with other libraries messing with window.$. At first, I was concerned about importing jQuery everywhere, because I was afraid that this would increase my bundle size. But the way bundling works, all these imports will point to a singleton, so bundle size would not increase.

Comments

2

For my part, I am not interested in testing the jQuery functionality in my components. In addition, I have not included jQuery in my bundle because it is used and included all over the website my app is on. So I have, for example, done the following:

// SubmitRender.js

// ...import statements...

var SubmitRender = React.createClass({
  componentWillMount: function () {
    $('form').on('submit', (e)=>{
      this.handleSubmit(e);
    });
  },

  // ...more code...
});
export default SubmitRender;

.

// SubmitRender.spec.js

// ...import statements...

describe('SubmitRender', () => {
  beforeAll(() => {
    // mocking jQuery $()
    global.window.$ = jest.fn(() => {return {on: jest.fn()}});
  });

  it('renders without error', () => {
    expect( () => render(<SubmitRender />) ).not.toThrow();
  });
});

I know my component will not mount without calling the $ function. So I just mock out that function with jest.fn in a beforeAll(). Now, I also know that my jQuery function inside my actual component is chained. So I know that I also need to account for jQuery's .on(), so I make sure to return an object with an on function. There is no further chaining, so that is where I can stop.

If I had a more complex set of chained functions, I could do something like this:

beforeAll(() => {
  // mocking jQuery $()
  var fakeQuery = jest.fn(() => {
    return {
      on: fakeQuery,
      off: fakeQuery,
      click: fakeQuery
    }
  })
  global.window.$ = fakeQuery;
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.