Fra*_*dez 3 unit-testing reactjs redux enzyme react-redux
我正在尝试使用redux app进行单元测试.所以我需要测试连接的组件,不幸的是我收到了这个错误:
无法读取未定义的属性'contextTypes'我在单元测试中使用酶这是我的组件:
import React from 'react';
import TextFieldGroup from '../common/TextFieldGroup';
import validateInput from '../../server/validations/login';
import { connect } from 'react-redux';
import { login } from '../../actions/authActions';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
errors: {},
isLoading: false
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
isValid() {
const { errors, isValid } = validateInput(this.state);
if (!isValid) {
this.setState({ errors });
}
return isValid;
}
onSubmit(e) {
e.preventDefault();
if (this.isValid()) {
this.setState({ errors: {}, isLoading: true });
this.props.login(this.state).then(
(res) => this.context.router.push('/'),
(err) => this.setState({ errors: err.response.data.errors, isLoading: false })
);
}
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
const { errors, username, password, isLoading } = this.state;
return (
<form onSubmit={this.onSubmit}>
<h1>Login</h1>
{ errors.form && <div className="alert alert-danger">{errors.form}</div> }
<TextFieldGroup
field="username"
label="Username"
value={username}
error={errors.username}
onChange={this.onChange}
/>
<TextFieldGroup
field="password"
label="Password"
value={password}
error={errors.password}
onChange={this.onChange}
type="password"
/>
<div className="form-group"><button className="btn btn-primary" disabled={isLoading}>Login</button></div>
</form>
);
}
}
LoginForm.propTypes = {
login: React.PropTypes.func.isRequired
}
LoginForm.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(null, { login })(LoginForm);
Run Code Online (Sandbox Code Playgroud)
这是我的测试:
import React from 'react';
import { mount, shallow } from 'enzyme';
import {expect} from 'chai';
import sinon from 'sinon';
import { connect } from 'react-redux'
import { Login } from '../../js/react/components/login/LoginForm';
describe('<Login />', function () {
it('should have an input for the username', function () {
const wrapper = shallow(<Login />);
expect(wrapper.find('input[name=username]')).to.have.length(1);
});
it('should have an input for the password', function () {
const wrapper = shallow(<Login />);
expect(wrapper.find('input[name=password]')).to.have.length(1);
});
it('should have a button', function () {
const wrapper = shallow(<Login />);
expect(wrapper.find('button')).to.have.length(1);
});
it('simulates click events', () => {
const onButtonClick = sinon.spy();
const wrapper = shallow(
<Login onButtonClick={onButtonClick} />
);
wrapper.find('button').simulate('click');
expect(onButtonClick).to.have.property('callCount', 1);
});
});
Run Code Online (Sandbox Code Playgroud)
建议和答案非常感谢:)
the*_*ode 14
测试装饰组件
要直接测试组件,您只需导出组件本身功能而不将其传递给Connect.
目前,在测试中,您要导入connect()返回的包装器组件,而不是LoginForm组件本身.如果要测试LoginForm组件与Redux的交互,这很好.如果您没有单独测试组件,那么导出和导入组件的方法就可以了.您需要记住使用专门为此单元测试创建的组件来包装测试中的组件.现在让我们看一下这种情况,我们正在测试一个连接组件,并解释我们为什么要将它包装在我们的单元测试中.
react-redux中Provider和Connect组件之间的关系
react-redux库为我们提供了一个Provider组件.Provider的目的是允许其任何子组件在包装在Connect组件中时访问Redux存储.Provider和Connect之间的这种共生关系允许Connect组件中包含的任何组件通过React的上下文功能访问Redux存储.
测试连接的组件
请记住,连接组件是一个包装在Connect组件中的组件,这个包装使我们的组件可以访问Redux存储?出于这个原因,我们需要在我们的测试文件中创建一个模拟商店,因为我们需要一个商店来测试组件如何与它交互.
在测试中为我们的Connected Component提供商店
但Connect并不知道如何神奇地访问商店.它需要嵌套(包装)在组件中.Provider组件通过React的context api挂钩到Provider,将我们的组件包含在Connect对Store的访问中.
我们可以看到Provider采用由Redux商店组成的道具:
ReactDOM.render(
<Provider store={store}>
<MyRootComponent />
</Provider>,
rootEl
)
Run Code Online (Sandbox Code Playgroud)
因此,要测试连接的组件,您需要使用Provider包装它.记住Provider将Redux商店对象作为prop.对于我们的测试,我们可以使用redux-mock-store库来帮助我们设置模拟存储,并在商店中提供一些方法来跟踪在需要时已分派的操作.
import { Provider } from 'react-redux'
import { mount } from 'enzyme'
import chai, {expect} from 'chai'
import chaiEnzyme from 'chai-enzyme'
import configureMockStore from 'redux-mock-store'
chai.use(chaiEnzyme())
import ConnectedLoginForm, from '../app.js'
const mockStore = configureMockStore(middlewares)
describe.only('<LoginForm Component />', () => {
it('LoginForm should pass a given prop to its child component' () => {
const store = mockStore(initialState)
const wrapper = mount(
<Provider store={store}>
<ConnectedLoginForm />
</Provider>
)
expect(wrapper.type()).to.equal('div')
})
})
Run Code Online (Sandbox Code Playgroud)
但有时您只想测试组件的渲染,而不需要Redux存储.让我们看一下这种情况,我们希望单独测试未连接的LoginForm组件的呈现.
测试未连接的组件
因此,目前您正在测试通过使用Connect包装原始LoginForm组件而创建的新组件.
为了在没有连接的情况下测试原始组件本身,仅为 LoginForm组件创建 第二个导出声明.
import { connect } from 'react-redux'
// Use named export for unconnected component (for tests)
export class App extends Component { /* ... */ }
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)
Run Code Online (Sandbox Code Playgroud)
您现在可以在没有Redux存储的情况下测试组件的呈现.
在测试中导入组件
请记住以这种方式导出组件时 -
现在在您的测试文件中导入未修饰的LoginForm组件,如下所示:
// Note the curly braces: grab the named export instead of default export
import { LoginForm } from './App'
Run Code Online (Sandbox Code Playgroud)
或者导入未经过处理和装饰(连接)的组件:
import ConnectedLoginForm, { LoginForm } from './App'
Run Code Online (Sandbox Code Playgroud)
如果要测试LoginForm组件如何与Redux存储库交互,则必须
| 归档时间: |
|
| 查看次数: |
6327 次 |
| 最近记录: |