Mocha + enzyme test React component placeholder error

448 Views Asked by At

I'm trying to test a REACT component that depends on jquery-placeholder, I've set a jsdom-setup as a mocha requirement, I do have other tests running with mocha + chai + react + enzyme, however when I try to mount this component, instead of using enzyme's shallow, it fails because of the jquery placeholder plugin.

Now whenever I try to require jquery-placeholder directly on the component it fails loading the component with an error of window undefined or can't access property of undefined when accesing $.fn.placeholder so it might be something on my jsdom-setup, but I'm not sure what it is, can you help me figure out how to add the placeholder jquery plugin to the jsdom-setup required by mocha or to the component itself so that I can test properly.

I'm loading jquery-placeholder package from npm, and using REACT 0.14.8

Here is my jsdom-setup.js file:

var jQuery = require('jquery');
var jsdom = require('jsdom').jsdom;
var _ = require('lodash');
var mockSettings = require('./mocks/api/clinical.json');
var appStarter = require('../app/public/resources/react/app');
var exposedProperties = ['window', 'navigator', 'document', 'App'];

global.document = jsdom('');
global.window = global.document.defaultView;
global.window.locale = locale;
global.navigator = {
    userAgent: 'node.js'
};

var $ = global.jQuery = require('jquery')(global.window);
global.$ = global.jQuery;
global.window.jQuery = global.jQuery;
global.window.$ = global.jQuery;


var App = _.assign({ settings: mockSettings.settings.interactive }, mockApp);
appStarter(App);
global.window['App'] = App;

Object.keys(document.defaultView).forEach(function(property) {
    if (typeof global[property] === 'undefined') {
        exposedProperties.push(property);
        global[property] = document.defaultView[property];
    }
});

this gist of the component (left out some of it for brevity):

var React = require('react');
var ConnectApi = require('../../connect-api');
var SuggestionList = require('../layout/suggestion-list');
var i18nTools = require('../../utils/i18n');

var SearchForm = React.createClass({
    propTypes: {
        onClear: React.PropTypes.func,
        onSubmit: React.PropTypes.func,
        onSelection: React.PropTypes.func,
        currentSearch: React.PropTypes.string,
        selectBy: React.PropTypes.string,
        onPinpoint: React.PropTypes.func,
        filters: React.PropTypes.object
    },

    getInitialState: function () {
        return {
            currentSearch: this.props.currentSearch || '',
            selectBy: this.props.selectBy || '',
            currentSuggestions: [],
            submitted: false,
            locationSupported: (App.settings.geoLocation === true)
        };
    },

    componentDidMount: function () {
        var query = {};
        $('input, textarea').placeholder();

        if (this.state.currentSearch === '' ||
            App.settings.useSearchSuggestions === false) {
            return;
        }

        this.getSuggestions(this.state.currentSearch);
    },



    clearInput: function () {
        this.setState({
            submitted: false,
            currentSearch: ''
        });

        this.props.onClear();
    },


    onSubmit: function (e) {
        var query = {};
        if (e) {
            e.preventDefault();
            e.stopPropagation();
        }
        if (this.refs.search.value === '') {
            this.setState({ inputError: true });
            return;
        }

        this.setState({
            inputError: false,
            submitted: true
        });
    },


    renderSearchActions: function () {
        if (this.state.submitted) {
            return (
                <a className='searchCTA' onClick={this.clearInput} style={ { display: 'block'} }>
                    <span className='icon ion-hapi-close'></span>
                </a>
            );
        } else {
            return (
                <a className='searchCTA' onClick={this.onSubmit}>
                    <span className='icon hapi-search'></span>
                </a>
            );
        }
    },

    renderLocationActions: function() {
        if (this.state.locationSupported) {
            return (
                <a className='pinpointCTA' onClick={this.props.onPinpoint}>
                    <span className='icon hapi-geo'></span>
                </a>
            );
        } else {
            return;
        }
    },

    render: function () {
        var sPlaceholder = App.settings.strings.searchBarPlaceholder || i18nTools.translate('searchBarPlaceholder');

        return (
            <div id='searchform-wrap'>
                <form onSubmit={this.onSubmit}>
                    <div className='input-wrap search'>
                        <input type='text'
                                className={this.state.inputError ? 'error' : ''}
                                ref='search'
                                onChange={this.handleChange}
                                placeholder={sPlaceholder}
                                value={this.state.currentSearch}
                                style={ { display: 'block'} }
                                autoComplete='off' />
                        {this.renderLocationActions()}
                    </div>
                    {this.renderSearchActions()}
                </form>
                <SuggestionList onSelection={this.onSelection} sources={this.state.currentSuggestions}/>
            </div>
        );
    }
});

module.exports = SearchForm;

and this is the test I want to do:

var React = require('react');
var shallow = require('enzyme').shallow;
var mount = require('enzyme').mount;
var expect = require('chai').expect;
var SearchForm = require('../components/clinical/search-form');
var sinon = require('sinon');

describe("Search Form Component", function() {
    var wrapper;
    var onSubmit;

    beforeEach(function () {
        onSubmit = sinon.spy();
    });

    afterEach(function () {
        onSubmit = null;
        wrapper = null;
    });
    describe("when submit search form", function () {
        describe("with query on search form", function  () {
            it("should call onSubmit", function () {
                wrapper = mount(<SearchForm onSubmit={onSubmit}/>);
                var search = wrapper.ref('search')
                // var input = wrapper.find('input');
                // console.log(input.ref('search'));
                // input.ref('search').node.value = "kaiser";
                // input.simulate('change', input)
                // wrapper.find('form').simulate('submit');
                // expect(onSubmit.calledOnce).to.equal(true);
            });

        });
    });
});

and just in case this is my gulp test:

gulp.task('test', ['lint'], function() {
    var mochaOpts = {
        compilers: {
            js: babel
        },
        require: ['./test/jsdom-setup.js'],
        reporter: 'spec'
    };
    if (!!opts.grep) mochaOpts.grep = opts.grep;

    return gulp.src([
        './test/components/**/*.test.js'
    ])
    .pipe(mocha(mochaOpts))
    .once('end', function () {
        process.exit();
    });
});
0

There are 0 best solutions below