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?
Some familiarity with Jest as a test runner or framework is helpful but not required. Because Jest is pre-packaged with Create React App, you do not need to install it separately.
json, and you will find that when you use create-react-app for creating a react project, it has default support for jest and react testing library. This means that we do not have to install them manually.
Jest provides a great iteration speed combined with powerful features like mocking modules and timers so you can have more control over how the code executes. React Testing Library is a set of helpers that let you test React components without relying on their implementation details.
Jest is a test runner that finds tests, runs the tests, and determines whether the tests passed or failed. Additionally, Jest offers functions for test suites, test cases, and assertions. React Testing Library provides virtual DOMs for testing React components.
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;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With