Sunday 8 September 2019

Testing in JSDOM: Jquery not finding the elements in Enzyme Mocha on successive runs

I am running my test cases by npm run test -- --watch where test is mocha --require babel-polyfill --require babel-core/register --require ./test/withDom.js --require ./test/test_helper.js --recursive ./test command to run test cases using mocha.

My components uses Jquery actively to manipulate DOM and handle the events.

In my first run all the test cases runs fine. But as soon as I modify some test cases and the watcher re-runs the test cases automatically; the jquery is not able to find the dom elements using selectors hereafter. This is evident because page DOM is not modified when I console log the wrapper.html() or body.innerHTML.

I will be very grateful if any of you resolve this.

Here is the code

withDom.js

import { JSDOM } from 'jsdom';

const jsdom = new JSDOM('<!doctype html><html><body><div id="root"></div></body></html>');
const { window } = jsdom;

function copyProps(src, target) {
  Object.defineProperties(target, {
    ...Object.getOwnPropertyDescriptors(src),
    ...Object.getOwnPropertyDescriptors(target),
  });
}

global.window = window;
global.document = window.document;
global.navigator = {
  userAgent: 'node.js',
};
global.requestAnimationFrame = function (callback) {
  return setTimeout(callback, 0);
};
global.cancelAnimationFrame = function (id) {
  clearTimeout(id);
};
copyProps(window, global);

test_helper.js

import _$ from 'jquery';
import { mount, render, shallow, configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { expect } from 'chai';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-dom/test-utils';
import { MemoryRouter, Route } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducers from '../src/reducers';

configure({ adapter: new Adapter() });
global.expect = expect;
global.mount = mount;
global.render = render;
global.shallow = shallow;
const $ = _$(window);

function renderComponent(ComponentClass, props = {}, state = {}) {
  const componentInstance =  ReactTestUtils.renderIntoDocument(
    <Provider store = {createStore(reducers, state)}>
      <MemoryRouter>
        <ComponentClass {...props} />
      </MemoryRouter>
    </Provider>
  );
  console.log('helper',componentInstance);
  return $(ReactDOM.findDOMNode(componentInstance));
}
export {renderComponent};

example_test.js

import React from 'react';
import configureMockStore from 'redux-mock-store';
import { MemoryRouter, Link } from 'react-router-dom';
import thunk from 'redux-thunk';

import ItemList from '../../src/components/ItemList';
import RandomRater from '../../src/containers/RandomRater';
import { loadBooks } from '../../src/actions/index';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
let store, books, wrapper, params;

describe('<RandomRater/> Component',() => {

    beforeEach(()=>{
        store = mockStore();
        store.dispatch(loadBooks());
        books = store.getActions()[0].payload;
        params = { 'params': {'title' : 'Html & CSS Design & Build website' } };
    });

    it('renders <RandomRater/> containing <ItemList/> and <Link/>',()=>{     
        wrapper = mount(
                    <MemoryRouter>
                        <RandomRater store={store} books={books} match={params} />
                    </MemoryRouter>,
                    { attachTo: document.getElementById('root') }
                    );
        expect(wrapper).to.exist;
        expect(wrapper.contains(ItemList)).to.equal(true);
        expect(wrapper.contains(Link)).to.equal(true);
        expect(wrapper.text()).to.contains('Start Random Rating');
        expect(wrapper.text()).to.contains('Back');
    });

    it('<RandomRater/> random rates the books',()=>{
        //Below line is not modifying the dom after the first run. 
        wrapper.find('#btn-random-rate').simulate('click',{button:0});
        console.log('body',document.body.innerHTML);

        //This functions only runs on first run and not after that.
        setTimeout(()=>{
             expect(wrapper.text()).to.contains('Stop Random Rating')   
        },200);
        wrapper.detach();    
    });

    after(()=>{
       wrapper.detach(); 
    });
});

Note:

If I run the given mocha command manually each time the issue does not occur. It only occurs when I run with --watch.

I have referred following SO post but the my issue remain unresolved.

Update:

Here is the github repo with complete code. You can modify the test cases for RandomRater (see given RandomRater test file here) and Rater to reproduce the problem. (See DOM after the simulating click event at the Start Rating button for RandomRater and similarly for stars in Rater)



from Testing in JSDOM: Jquery not finding the elements in Enzyme Mocha on successive runs

No comments:

Post a Comment