React component using jQuery without require - jest unit tests
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)
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.
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;});