jquery doesn't work with jsdom/enzyme - javascript

I have a minimum test react app with following component:
import React from 'react';
import $ from 'jquery';
export default class App extends React.Component {
componentDidMount() {
console.log('componentDidMount', $('#helloDiv').length);
}
render() {
return <div id='helloDiv'>
Hello React!
</div>;
}
}
this works fine when loading it in browser (Chrome). The console.log() in componentDidMount() prints out 1 helloDiv element found
However, if I run the test using mocha + enzyme + jsdom, the same console.log() in App component prints out 0:
import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import App from '../src/client/app/first'
describe('first test', () => {
it('should pass', () => {
const app = mount(<App />);
expect(app.find('#helloDiv').length).to.eq(1);
});
});
Note: I don't have problem with this unit test, it's passing. The real problem is when < App /> is mounted using enzyme, componentDidMount() is called but the console.log() statement inside it prints out 0, instead of 1
Here is how I run mocha:
mocha --require enzyme/withDom --compilers js:babel-core/register test/index.test.js
Any idea why jquery selector doesn't find anything in the test? It should not be mocha issue because the same issue happens if I change to jest

Finally found the issue:
Enzyme mount(<SomeComponent />) by default will do full DOM rendering but not insert the rendered component into current document (JSDom). That's why jQuery cannot find any element in current document
To do full DOM rendering AND attach to current document:
mount(<SomeComponent />, { attachTo: document.getElementById('app') });
Where app is empty div available when jsdom is setup:
global.document = jsdom('<html><head></head><body><div id="app" /></body></html>');

There needs to be some setup done before you could jsdom with jquery in node-env.
Try this if it helps.
Create a test helper file like this -
test_helper.js
import _$ from 'jquery';
import jsdom from 'jsdom';
import chai, { expect } from 'chai';
import chaiJquery from 'chai-jquery';
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = global.document.defaultView;
global.navigator = global.window.navigator;
const $ = _$(window);
chaiJquery(chai, chai.util, $);
export {expect};
While running -
mocha --require enzyme/withDom --compilers js:babel-core/register --require test/test_helper.js test/index.test.js
or another way use jsdom-global without test_helper.js file.
npm install --save-dev jsdom-global
Then :
import 'jsdom-global/register';
//at the top of file , even , before importing react

I couldn't get Phuong Nguyen's answer to work. I did find the relevant page in the enzyme docs. I ended up with something like, based on the final example on that page:
const div = global.document.createElement('div');
global.document.body.appendChild(graphDiv);
const wrapper = mount(<SomeComponent />, { attachTo: div }); // same as the other answer
// clean up after ourselves
wrapper.detach();
global.document.body.removeChild(div);

Related

Substitute or mock import of another file

I want to test functions within foo.js using Jest without altering foo.js. I do not want to test native functions like getBaseOs. Simply importing a function from foo.js will evaluate all the import statements of foo.js. Any import that relies on native code will trigger an error and the test will not run.
Is there a way to substitute imports like getBaseOs but only within the test file, foo.test.js? I simply want to ignore getBaseOs within foo.test.js to allow testing. Is there a way to do that even if substitution is not the way?
// foo.js
import React from 'react';
import { View, } from 'react-native';
import { getBaseOs, } from 'react-native-device-info';
export default function foo(props) {
return null;
}
// foo.test.js
import 'react-native';
import foo from './foo';
describe('test import substitution', () => {
it('test getBaseOs', () => {
const getBaseOs = jest.fn();
expect(true).toBe(true);
});
});
I just found the answer on GitHub by user karimo255 who commented on Jun 20, 2019. Simply putting the code in __mocks__/react-native-device-info.js allows the code to be replaced in tests despite an import. I speculate that Jest imports files from __mocks__ before performing a single test and matches the names of the files to the names of imports to match. Renaming the file will break it.
Here is the file that replaces the import statements of react-native-device-info, __mocks__/react-native-device-info.js:
export default {
getBaseOs: () => 'A',
};

document.execCommand is not a function in vue test utils

Vue testing with vue-test-utils with Jest, gives errors when exec copy command
document.execCommand is not a function.
How can I resolve it?
This is code snippet in component source.
copyToClipboard(){
document.execCommand('copy');
}
And here I had writen test like this;
import Vue from 'vue';
import Vuex from 'vuex';
import {shallowMount} from '#vue/test-utils'
describe('*****.vue', () => {
let wrapper;
beforeAll(()=>{
wrapper = shallowMount(***, {attachToDocument:true, store, localVue});
})
it('should render correct content', () => {
wrapper.vm.copyToClipboard();
);
}
Presumably you're using jsdom for the tests? In which case execCommand is not supported.
Jest doesn't support environments such as headless Chrome, but you may have some success using Puppeteer

Gitlab CI breaking on unit tests

Two of my tests are passing locally but not on GitlabCI, and for the life of me I cannot figure out why.
I have read here that macOS is not case sensitive, and the ci might be, so I double checked all the spelling and everything came looks just fine.
Here's the filesystem layout:
src/
App.jsx
App.test.jsx
components/
A/
index.js
B/
C/
CContainer.jsx
CContainer.test.jsx
Below is the error code:
FAIL src/components/A/B/C/CContainer.test.jsx
● Test suite failed to run
Cannot find module './CContainer' from 'CContainer.test.jsx'
at Resolver.resolveModule (../../../tmp/node_modules/jest-resolve/build/index.js:179:17)
at Object.<anonymous> (src/components/A/B/C/CContainer.test.jsx:3:29)
My code from CContainer.test.jsx:
import React from 'react';
import { shallow } from 'enzyme';
import { CContainer } from './CContainer';
const props = {
saveTempUser: () => '',
history: {},
user: {},
};
it('renders without crashing', () => {
shallow(<CContainer {...props} />);
});
The two files are siblings, and CContainer is simply:
...
export class CContainer extends Component {
...
}
...
export default connect(mapStateToProps, mapDispatchToProps)(CContainer)
What's weird is in the top level App.test.js the same file causes a problem:
FAIL src/App.test.js
● Test suite failed to run
Cannot find module './B/C/CContainer' from 'index.js'
at Resolver.resolveModule (../../../tmp/node_modules/jest-resolve/build/index.js:179:17)
at Object.<anonymous> (src/components/A/index.js:4:29)
And index.js is just:
import ConnectedCContainer, { CContainer} from './B/C/CContainer'
...
export {
...
ConnectedCContainer,
CContainer
}.
Any ideas? I'm currently configuring a local runner to try and debug and will come back with more info when I have some.
Turns out it was the case of the file that was different than what was in git. Removing the file from git and adding a new file with the desired case fixed the problem.

why text is not render in reactjs using enzyme?

could you please tell me why the test case not running in react using enzyme?
I install enzyme js and follow this tutorial
https://javascriptplayground.com/introduction-to-react-tests-enzyme/
here is my code
import React from 'react';
import Hello from './Hello';
import { shallow } from 'enzyme';
it('renders', () => {
const wrapper = shallow(<Hello name="Jack" />);
expect(wrapper.find('h1').text()).toEqual('Hello, Jack!');
});
https://codesandbox.io/s/5x6oqkyknn
The issue you are facing with test not being found was an issue with naming.
codesandbox is using character sensitive regex and you have to make it Hello.spec.js for it to be detected.
Here is the sandbox forked from your code: https://codesandbox.io/s/649owm14o3
Also, to have the test actually work you have to setup a enzyme-adapter-react-16 and have it setup like:
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
Typically you would do this in a different file, but for the purposes of this demo, I have set it up in the same file.
Also note the typo comma "Hello Jack"

How do I add React as a global whilst running unit tests?

In my Rails project, I am using the react-rails gem, which does the following:
window.React = React;
This is pretty handy, but when I run unit tests using Jest, that global is not there and I get an error from the file containing the component I am testing saying that React is not defined.
If I define React in the component file using
import React from 'react';
Then it causes errors due to loading React twice.
How should I define a global React variable in my unit tests so they work?
In your test file, do:
import React from 'react'
describe('something',() => {
window.React = React
// so when you require() your component, window.React is already set
var MyComponent = require('MyComponent').default
it('does something', () => {
// do something
})
})

Categories

Resources