我将从头开始。 我已经为忘记密码表单编写了一些测试。我使用过酶,柴,sinon等一些东西(参见附带代码中的导入列表)。
表单的代码:
import React from 'react';
import 'whatwg-fetch';
import { connect } from 'react-redux';
import { Form, Button, Input } from '@omnius/react-ui-elements';
import { resendPassword } from '../../actions/index';
import { translate } from 'react-i18next';
const styles = {
wrapper: {
padding: '30px 20px',
background: '#fff',
borderRadius: '3px',
border: '1px solid #e5e5e5'
},
subTitle: {
opacity: 0.3
}
};
@connect(store => {
return {
config: store.config.components.Authentication,
loading: store.authentication.forgotpassword_loading,
errorMessage: store.authentication.forgotpassword_errorMessage,
passwordSent: store.authentication.forgotpassword_passwordSent
};
})
@translate(['authentication'], { wait: true })
class ForgotPassword extends React.Component {
constructor() {
super();
this.state = {
email: null
};
this.handleForm = this.handleForm.bind(this);
}
handleForm(e) {
e.preventDefault();
this.props.dispatch(resendPassword(this.state.email));
}
render() {
const { t } = this.props;
if(this.props.passwordSent) {
return (
<div style={styles.wrapper}>
<h3>{t('Forgot password')}</h3>
<p>{t('If an account is connected with the given email address, you will receive an email with a link to reset your password')}</p>
</div>
);
} else {
return (
<Form style={styles.wrapper} onSubmit={this.handleForm}>
<h3>{t('Forgot password')}</h3>
<p>{this.props.errorMessage}</p>
<Form.Field>
<Input onChange={e => this.setState({email: e.target.value})} label={t('Email')}/>
</Form.Field>
<Form.Field>
<Button loading={this.props.loading} disabled={this.props.loading} type='submit' primary fluid>{t('Resend password')}</Button>
</Form.Field>
</Form>
);
}
}
}
export default ForgotPassword;
测试代码:
import React from 'react';
import { translate } from 'react-i18next';
import i18n from '../../../src/i18n.js';
import configureStore from 'redux-mock-store';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
import { ForgotPassword } from '../../../src';
import thunk from 'redux-thunk';
import 'es6-promise/auto';
import sinon from 'sinon';
const initialConfig = {
authentication: {
loginform_loading: false,
loginform_errorMessage: null,
forgotpassword_loading: false,
forgotpassword_errorMessage: null,
forgotpassword_passwordSent: false
},
config: {
components: {
Authentication: {
'login_endpoint': '/api/auth/login',
'forgotpassword_enabled': true,
'forgotpassword_path': '/auth/forgot-password',
'forgotpassword_endpoint': '/auth/forgot-password'
}
}
}
};
const mockStore = configureStore([thunk]);
let config;
let store;
let translator;
let context;
let HocElement;
let wrapper;
describe('components/ForgotPassword', () => {
beforeEach(function () {
config = clone(initialConfig);
recreateWrapper();
});
function recreateWrapper(){
store = mockStore(config);
translator = createTranslator({});
context = {
i18n: translator
};
HocElement = translate(['authentication'], { nsMode: 'fallback' })(ForgotPassword);
wrapper = mount(<HocElement store={store} />, { context });
}
it('renders into DOM', () => {
// Check whether the expected elements are rendered
expect(wrapper.find('form')).to.have.length(1);
expect(wrapper.find('h3')).to.have.length(1);
expect(wrapper.find('p')).to.have.length(1);
expect(wrapper.find('button')).to.have.length(1);
expect(wrapper.find('input')).to.have.length(1);
console.log(wrapper.find('a').html());
expect(wrapper.find('a')).to.have.length(0);
});
it('should trigger the authentication method on form submit', () => {
const callback = sinon.spy();
const form = shallow(<ForgotPassword store={store} onSubmit={callback} />);
// Submit isn't called yet so expected be not be called
expect(callback.calledOnce).to.be.false;
form.simulate('submit');
// Submit is called so expected this to be true
expect(callback.calledOnce).to.be.true;
// Just another check to make sure the button isn't triggered to many times
expect(callback.calledTwice).to.be.false;
});
});
/**
* Clones the given object, so it isn't linked to the original object.
* @param objectToClone The object that will be cloned.
* @return The cloned object.
*/
function clone(objectToClone){
return JSON.parse(JSON.stringify(objectToClone));
}
/**
* Create a translator with the given translations
* @param translations The translations
* @return The translator
*/
function createTranslator(translations){
const newI18n = i18n.createInstance();
newI18n
.init({
lng: 'en',
fallbackLng: 'en',
resources: {
en: translations
},
interpolation: {
escapeValue: false, // not needed for react!!
}
});
return newI18n;
}
问题:
在'渲染到DOM'测试中有一个expect(wrapper.find('a')).to.have.length(0);
然而这会返回false,因为找到了一些元素。它显示:
expected { Object (component, root, ...) } to have a length of 0 but got 1
因此我添加了一些日志记录:console.log(wrapper.find('a').html());
此日志记录输出以下内容:
LOG: '<form class="ui form" style="padding: 30px 20px; background-color: rgb(255, 255, 255); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; border: 1px solid rgb(229, 229, 229); background-position: initial initial; background-repeat: initial initial;"><h3>Forgot password</h3><p></p><div class="field"><div class="ui labeled input ovn-ui-input"><div class="ui label label"><!-- react-text: 8 -->Email<!-- /react-text --></div><input type="text"></div></div><div class="field"><button type="submit" class="ui fluid primary button ovn-ui-button"><!-- react-text: 12 -->Resend password<!-- /react-text --></button></div></form>'
我也在表格中加了<a>hello</a>
进行了测试。在这种情况下,它返回2个元素。第一个元素是表单/包装,第二个元素是实际的<a>
摘要
当我用.find('a')
搜索包装器时,它会以某种方式返回整个包装器而不是任何内容。