我正在尝试测试依赖于 jquery-placeholder 的 REACT 组件,我已将 jsdom-setup 设置为 mocha 要求,我确实有其他使用 mocha + chai + react + 酶运行的测试,但是当我尝试安装时该组件没有使用酶的浅层,而是由于 jquery 占位符插件而失败。
现在,每当我尝试直接在组件上要求 jquery-placeholder 时,它无法加载组件并出现窗口未定义的错误,或者在访问 $.fn.placeholder 时无法访问未定义的属性,所以它可能是我的 jsdom-setup 上的东西,但我不确定它是什么,你能帮我弄清楚如何将占位符 jquery 插件添加到 mocha 所需的 jsdom-setup 或组件本身,以便我可以正确测试。
我正在从 npm 加载 jquery-placeholder 包,并使用 REACT 0.14.8
这是我的 jsdom-setup.js 文件:
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];
}
});
组件的这个要点(为简洁起见,省略了一些):
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;
这是我想做的测试:
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);
});
});
});
});
以防万一这是我的 gulp 测试:
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();
});
});