I'm learning about react testing but I have some issues.
I'm trying to test a functional component in react
import React, {useState, useEffect, useContext} from 'react';
import DayPicker from 'react-day-picker/DayPickerInput';
import MomentLocaleUtils, {
formatDate,
parseDate,
} from 'react-day-picker/moment';
import 'react-day-picker/lib/style.css';
import 'moment/locale/pt-br';
import Swal from 'sweetalert2';
import $ from 'jquery';
import api from 'config/api';
import {InvestmentsContext} from 'context/InvestmentsContext';
export default props => {
const [investments, setInvestments] = useContext(InvestmentsContext);
const [investment, setInvestment] = useState({
type: 'RENDA_FIXA',
value: '',
date: new Date(),
});
...
return (
<>
<form onSubmit={e => save(e, investment)} className="investment-form">
...
</form>
</>
);
};
But i'm getting this error when I try to test it with Jest and Enzyme
TypeError: Invalid attempt to destructure non-iterable instance
13 | import {InvestmentsContext} from 'context/InvestmentsContext';
14 |
> 15 | export default props => {
| ^
My Spec:
import React from 'react';
import {configure, mount} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import Form from 'components/investment/Form';
configure ({adapter: new Adapter ()});
let wrapper;
describe ('<Form />', () => {
beforeEach (() => {
wrapper = mount (<Form onCountChange={'a'} />);
});
it ('button should be disabled if investment value is empty', () => {
expect (wrapper.find ('.btn-action')).toHaveAttribute ('disabled');
});
});
Why am I getting this? Due to my component be a function?
Related
Im using jest to test a simple button in React and it keeps failing. My latest iteration complains about render. I'm new to testing and I've been at it for a while and cannot figure this out. What am I missing here?
Here's my App.js
function clickMe() {
alert("Hello")
}
function App() {
return (
<div className="App">
<button id="btn" onClick={clickMe}>Click Me!!</button>
</div>
)
}
export default App;
Here's my App.test.js
import React from 'react'
import {render} from 'react-dom'
import App from './App'
test("Click", () => {
const {container} = render(<App />)
const button = getByTestId(container, 'btn')
fireEvent.click(button)
})
You can simulate some events with the enzyme library
For this first install this by npm, then import that
import {shallow} from 'enzyme';
After using this structure to simulate a click on a bottom
Create a wrapper
let wrapper = shallow(<App />);
beforeEach( ()=>{
wrapper = shallow(<CounterApp />);
});
This creates a simulation of render components and gives you the capacity to simulate events, this method is working in my project counterApp
test('Click', ()=>{
wrapper.find('button').at(0).simulate('click');
expect(//The action of your botton).toBe(//the result expected);
});
Not exactly the same but something like this also worked
import { shallow } from 'enzyme'
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import App from './App'
configure({ adapter: new Adapter() })
it('renders the link inside the output area', () => {
const output = shallow(<App />)
expect(output.find('div').find('button').length).toEqual(1)
})
Please help.
I cannot run test because in my util langProvider is package that drops tests.
I have to mock langProvider function or strings variable.
How I can do that?
import React, { ReactElement, useState } from 'react';
import langProvider from 'utils/langProvider';
import { HeaderStyled, DropDownStyled } from './styled';
import './style.scss';
function Header(props: any): ReactElement {
const [state, setState] = useState({
isDropDownOpened: false,
isDrawerOpened: false,
});
const strings = langProvider(props.language, 'components.header');
return (
<HeaderStyled className="header">
...
</HeaderStyled>
);
}
const mapStateToProps = (state: any) => ({
language: state.language,
});
export default connect(mapStateToProps)(Header);
My test file
import { configure, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './index';
configure({ adapter: new Adapter() });
describe('<Header />', () => {
const wrapper = shallow(<Header />);
it('My test', () => {
expect('').toEqual('Header');
});
});
not sure, but you can try to insert in your test file before describe function, something like that:
jest.mock("utils/langProvider", () => ({langProvider: ()=> []}));
I want to write an integration test to assert that a when a parent component drills certain values or properties to a child component, that component receives said values and renders them properly. Below I have two component examples and an example test. Of course, the test is not accurate, but I'm wondering how I can use enzyme to accomplish this? Thanks!
sampleComponent.js:
import React from 'react';
const SampleComponent = () => (
<div test-attr="div">
<SampleChildComponent title="Sample title" />
</div>
);
export default SampleComponent;
sampleChildComponent.js:
import React from 'react';
const SampleChildComponent = ({ title }) => <h3 test-attr="h">{title}</h3>;
export default SampleChildComponent;
sampleComponent.test.js:
import React from 'react';
import { shallow } from 'enzyme';
import SampleComponent from './sampleComponent';
import SampleChildComponent from './sampleChildComponent';
test('renders component without errors', () => {
const wrapper = shallow(<SampleComponent />);
const childWrapper = shallow(<SampleChildComponent />);
expect(childWrapper.text()).toEqual('sample title');
});
To render child components you should use mount instead of shallow:
import { mount } from 'enzyme'
import React from 'react'
import SampleChildComponent from './sampleChildComponent'
import SampleComponent from './sampleComponent'
test('renders component without errors', () => {
const wrapper = mount(<SampleComponent />)
expect(wrapper.find(SampleChildComponent).text()).toEqual('sample title')
})
I've pasted my Component below which is very, very basic. When the Component is mounted, it will basically call the fetchMessage Action, which returns a message from an API. That message will in turn get set as state.feature.message in the mapStateToProps function.
I'm at a complete loss on where to begin testing this Component. I know that I want to test that:
1) The Feature Component is rendered
2) The fetchMessage function in props is called
3) It displays or has the correct message property when rendered using that
I've tried setting my test file up as you can see below, but I just end up with repeated error after error with everything that I try.
Could anyone point me in the right direction with what I'm doing wrong?
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from './actions';
class Feature extends Component {
static propTypes = {
fetchMessage: PropTypes.func.isRequired,
message: PropTypes.string
}
componentWillMount() {
this.props.fetchMessage();
}
render() {
return (
<div>{this.props.message}</div>
);
}
}
function mapStateToProps(state) {
return { message: state.feature.message };
}
export default connect(mapStateToProps, actions)(Feature);
Test file:
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import expect from 'expect';
import { shallow, render, mount } from 'enzyme';
import React from 'react';
import sinon from 'sinon';
import Feature from '../index';
const mockStore = configureStore([thunk]);
describe('<Feature />', () => {
let store;
beforeEach(() => {
store = mockStore({
feature: {
message: 'This is the message'
}
});
});
it('renders a <Feature /> component and calls fetchMessage', () => {
const props = {
fetchMessage: sinon.spy()
};
const wrapper = mount(
<Provider store={store}>
<Feature {...props} />
</Provider>
);
expect(wrapper.find('Feature').length).toEqual(1);
expect(props.fetchMessage.calledOnce).toEqual(true);
});
});
You can use shallow() instead of mount() to test your component. The shallow() method calls the componentWillMount() life-cycle method so there is no reason to use mount(). (Disclaimer: I am not quite well at mount() yet.)
For connected components, you can pass a store object like this:
<connectedFeature {...props} store={store} />
And you should call shallow() method twice to make it work for connected components:
const wrapper = shallow(<connectedFeature {...props} store={store} />).shallow()
Testing Connected React Components
Use separate exports for the connected and unconnected versions of the components.
Export the unconnected component as a named export and the connected as a default export.
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from './actions';
// export the unwrapped component as a named export
export class Feature extends Component {
static propTypes = {
fetchMessage: PropTypes.func.isRequired,
message: PropTypes.string
}
componentWillMount() {
this.props.fetchMessage();
}
render() {
return (
<div>{this.props.message}</div>
);
}
}
function mapStateToProps(state) {
return { message: state.feature.message };
}
// export the wrapped component as a default export
export default connect(mapStateToProps, actions)(Feature);
Remember connected components must be wrapped in a Provider component as shown below.
Whereas unconnected components can be tested in isolation as they do not need to know about the Redux store.
Test file:
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import expect from 'expect';
import { shallow, render, mount } from 'enzyme';
import React from 'react';
import sinon from 'sinon';
// import both the wrapped and unwrapped versions of the component
import ConnectedFeature, { feature as UnconnectedFeature } from '../index';
const mockStore = configureStore([thunk]);
describe('<Feature />', () => {
let store;
beforeEach(() => {
store = mockStore({
feature: {
message: 'This is the message'
}
});
});
it('renders a <Feature /> component and calls fetchMessage', () => {
const props = {
fetchMessage: sinon.spy()
};
const wrapper = mount(
<Provider store={store}>
<connectedFeature {...props} />
</Provider>
);
expect(wrapper.find('Feature').length).toEqual(1);
expect(props.fetchMessage.calledOnce).toEqual(true);
});
});
I am using Mocha, Chai, Nock, Sinon, Webpack for Unit tests.
I used the following link to test my actions, reducers
http://redux.js.org/docs/recipes/WritingTests.html
I was able to test dumb components from other react articles. Currently I am trying to test my smart component and i get errors.
my react-redux component (SmartComponent.js)
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import * as componentActions from '../actions/componentActions'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
export class SmartComponent extends Component {
constructor(props) {
super(props)
this.updateText = this.updateText.bind(this)
}
updateText(event){
this.props.actions.updateText(event.target.value)
}
render() {
return(
<div>
<input type='text' onChange={this.action1} placeholder='type something'
/>
<span>{this.props.inputText}
</div>
)
}
}
function mapStateToProps(state) {
const inputText = state.inputText
return{
inputText
}
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators(componentActions, dispatch)
}
}
const SmartComponentContainer = connect(
mapStateToProps,
mapDispatchToProps
)(SmartComponent)
module.exports = SmartComponentContainer
this is my unit test file
import setupDom from '../setup'
import chai from 'chai'
import jsxChai from 'jsx-chai'
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import TestUtils from 'react-addons-test-utils'
import {Provider} from 'react-redux'
import {findAllWithType, findWithType, findWithClass} from 'react-shallow-testutils'
import SmartComponentContainer,{SmartComponent} from "../containers/SmartComponent"
chai.use(jsxChai)
let expect = chai.expect
/**
* Mock out the top level Redux store with all the required
* methods and have it return the provided state by default.
* #param {Object} state State to populate in store
* #return {Object} Mock store
*/
function createMockStore(state) {
return {
subscribe: () => {},
dispatch: () => {},
getState: () => {
return {...state};
}
};
}
function setup() {
const storeState={
inputText : ''
}
let renderer = TestUtils.createRenderer()
renderer.render(<SmartComponentContainer store={createMockStore(storeState)} />)
let output = renderer.getRenderOutput()
return {
output,
renderer
}
}
function setUpComponent(){
const props ={}
let renderer = TestUtils.createRenderer()
renderer.render(<SmartComponent {...props} />)
let output = renderer.getRenderOutput()
return {
output,
renderer
}
}
describe('test smart component container',()=>{
it('test input value change',()=>{
const {output,renderer} = setup()
console.log(output)
// when i do the console.log output here , i am getting my actions and state variable but i do not get the html inside render method
})
it('test component',()=>{
const {output,renderer} = setUpComponent()
console.log(output)
})
})
The first test is successful and i prints the output with actions and state variables but not able to get render html printed.
The second test throws an error "TypeError: Cannot read property 'propTypes' of undefined" . I want access to html and have ability test like with normal component
expect(output.props.children[0].type).to.equal('input')