I'm trying to wrote test for my react component which using redux and react-intl:
import React from 'react';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
import Navbar from 'Navbar';
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux';
import messages from '../src/l10n/en.json'
import { IntlProvider } from 'react-intl'
const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)
const store = mockStore({})
describe('<Navbar />', () => {
it('calls componentDidMount', () => {
const wrapper = mount(
<Provider store={store}>
<IntlProvider locale={ "en" } messages={ messages }>
<Navbar />
</IntlProvider>
</Provider>
);
expect(Navbar.prototype.componentDidMount.calledOnce).to.equal(true);
});
});
But I got this result:
<Navbar />
1) calls componentDidMount
0 passing (73ms)
1 failing
1) <Navbar /> calls componentDidMount:
AssertionError: expected undefined to equal true
Can some one give me an advise how can I fix it?
The error is because, componentDidMount is not spy'ed in the test. You could use sinon to do fix this issue. For instance,
import React from 'react';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
import Navbar from 'Navbar';
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux';
import messages from '../src/l10n/en.json'
import { IntlProvider } from 'react-intl'
import { spy } from 'sinon';
const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)
const store = mockStore({})
describe('<Navbar />', () => {
it('calls componentDidMount', () => {
spy(Navbar.prototype, 'componentDidMount');
const wrapper = mount(
<Provider store={store}>
<IntlProvider locale={ "en" } messages={ messages }>
<Navbar />
</IntlProvider>
</Provider>
);
expect(Navbar.prototype.componentDidMount.calledOnce).to.equal(true);
});
});
On a side note:- If you want to use react-intl in tests, I would suggest to use helper functions as described here
Related
I am trying to test my component with jest and react testing library but jest seems to think ReactDOM.render is not a DOM element. Running the test gives this error
Below is my code and the things I tried to do:
index.tsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import { applyMiddleware, compose, createStore } from 'redux';
import {Provider} from 'react-redux';
import './index.css';
import thunk from 'redux-thunk';
import combinedReducer from './main/reducers/combinedReducer';
import { MyProvider } from './CustomProviders';
import reportWebVitals from './reportWebVitals';
import { App } from './main/components/App';
const devTool = process.env.NODE_ENV === 'development' && (window as any).__REDUX_DEVTOOLS_EXTENSION__ ? (window as any).__REDUX_DEVTOOLS_EXTENSION__() : (f) => f;
export const store = createStore(combinedReducer, compose(applyMiddleware(thunk), devTool));
if (process.env.NODE_ENV === 'development') {
require('css-framework.css');
}
ReactDOM.render(
<React.StrictMode>
<MyProvider>
<Provider store={store}>
<App/>
</Provider>
</MyProvider>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.tsx file:
import { useDispatch } from 'react-redux';
import {getFeatures, setContextInStoreActn, setUser, setProduct} from '../actions/GeneralActions';
import { useContext, useEffect } from 'react';
import { MyContext } from '../MyContext';
import { BasePage } from './BasePage';
export const App = () => {
const dispatch = useDispatch();
const context = useContext(MyContext);
useEffect(() => {
dispatch(setContextInStoreActn(context));
void context.getSelectedProduct().then((selectedProduct) => dispatch(setProduct(selectedProduct)));
void context.getImpersonatingUser().then((impersonatingUser) => dispatch(setUser(impersonatingUser)));
dispatch(getFeatures());
}, []);
return (
<div>
<BasePage />
</div>
);
};
App.test.tsx file:
import { Provider } from 'react-redux';
import { render } from '#testing-library/react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { App } from '../../main/components/App';
const middlewares = [thunk];
const general = {
general: ''
};
const store = configureMockStore(middlewares)({
general
});
const mockWait = () => new Promise((resolve) => setTimeout(resolve, 550));
test('renders without crashing', () => {
render(
<Provider store={store}>
<App/>
</Provider>
);
expect(render).toHaveBeenCalledWith(<Provider store={store}> <App/> </Provider>); //this never gets executed in the test
});
I looked at a couple solutions that suggest appending a div or root element to my test render but that did not seem to do anything.
Another thing I tried to do was upgrading everything to the latest versions (latest react, react-dom, jest, RTL, etc...) and test with that but there were too many dependency issues so I abandoned that route.
Edit:
After playing around with my App.tsx file I found out that the reason it fails is because of the useEffect, removing it makes the test pass but that is not ideal.
I need to ask about testing React using enzyme and jest. The case is I have a redux connected component wrapped by also connected component.
wrapper.js
import React from "react";
import { connect } from "react-redux";
import { state, actions } from "src/services/common-store/user";
function ApplicationLayout(props) {
return (
<div>
<h1>{props.title}</h1>
<div id="content">
{props.children}
</div>
</div>
);
}
export default connect(state, actions)(ApplicationLayout);
User.js
import React from "react";
import { connect } from "react-redux";
import { state, actions } from "src/services/common-store/user";
import ApplicationLayout from './ApplicationLayout';
function User(props) {
return (
<ApplicationLayout>
<h1>{props.user.name}</h1>
<img src={props.user.img} />
</ApplicationLayout>
);
}
export default connect(state, actions)(User);
in my test file, I already provided Provider with redux mock store.
User.test.js
import React from "react";
import { mount } from "enzyme";
import configureMockStore from "redux-mock-store";
import { Provider } from "react-redux";
import toJson from "enzyme-to-json";
import thunk from "redux-thunk";
import User from "./User.js";
// Mocking Redux store
const mockStore = configureMockStore([thunk]);
const store = mockStore({ title: "Application Layout", user: { name: "andri", img: "https://ava.com/img.jpg" } });
const setup = () => {
return mount(
<Provider store={store}>
<User />
</Provider>
);
};
describe("Test Component", () => {
let wrapper;
beforeEach(() => {
wrapper = setup();
});
describe("Components rendering", () => {
it("Should render without error and match snapshot", () => {
expect(toJson(wrapper)).toMatchSnapshot();
});
});
});
but I keep getting error said that props like title and user are undefined TypeError: Cannot read property 'user' of undefined. what can I do to address this?
this is my collegeName.test.js
import React from 'react';
import Enzyme, { shallow, mount } from 'enzyme';
import PersonalProfile from '../../../components/Profile/Tabs/Personal';
import Adapter from "enzyme-adapter-react-16";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import configureStore from "../../../redux/configureStore";
import { fetchData, mutateData } from "../../../utils/graphqlUtility";
Enzyme.configure({ adapter: new Adapter() })
const store = configureStore();
//const store = mockStore({});
jest.mock('../../../utils/graphqlUtility', () => {
return {
A:"hihihi"
};
});
describe('Personal Profile', () => {
test('renders', () => {
const wrapper = shallow(
<Provider store={store}>
<PersonalProfile />
</Provider>
);
console.log(wrapper)
let tree = wrapper.toJSON();
expect(tree).toMatchSnapshot();
//<div className="row pad"></div>
//expect(wrapper.contains(<label>Bond Expiration Date</label>)).to.equal(true);
//const paragraph = wrapper.find('div')
//console.log("dsdsds",paragraph)
//expect(paragraph).toHaveLength(1)
});
});
In this file, I am shallowing personalprofile component and this personal profile component calls some methods of graphqlutility file so I mocked graphqlutility file. And then while I am consoling the wrapper its showing me like this in console ShallowWrapper {}.I don't know why the console is showing empty?
I have also attached the screenshot of the console. Can anybody help me with this ?
Use the enzyme's debug() function:
console.log(wrapper.debug());
When i run my tests, i get the error:
Field must be inside a component decorated with reduxForm()
I am mocking a store, so i would think that would take care of injecting redux on the test but, i'm not really sure.
Inside appointments.js I have a component that has a redux form
import React from 'react';
... other imports
import configureMockStore from 'redux-mock-store';
import { mount } from 'enzyme';
import expect from 'expect';
import { Provider } from 'react-redux';
import { IntlProvider } from 'react-intl';
import LoginSection from '../User/LoginSection';
import AppointmentsContainer from './AppointmentsContainer';
import Appointments from './Appointments';
import AppointmentStatus from .../Layout/AppointmentStatus/AppointmentStatusContainer';
jest.mock('./Appointments');
jest.mock('../User/LoginSection');
jest.mock('../Layout/AppointmentStatus/AppointmentStatusContainer');
const store = configureMockStore()({
form: 'Appointments',
});
const setup = (newProps) => {
const props = {
handleSubmit: jest.fn(),
},
form: 'appointmentsContainer',
locale: 'en',
...newProps,
};
const root = mount(
<Provider store={store}>
<IntlProvider {...props}>
<AppointmentsContainer {...props} />
</IntlProvider>
</Provider>
,
);
const wrapper = root.find(Appointments);
return {
root,
wrapper,
props,
};
};
describe('AppointmentsContainer', () => {
beforeEach(() => {
store.clearActions();
});
Any idea how can i fix this?
I'm trying to test a React component with enzyme and mocha as follows
import { mount, shallow } from 'enzyme';
import React from 'react';
import chai, { expect } from 'chai'
import chaiEnzyme from 'chai-enzyme'
import sinon from 'sinon'
import MyComponent from 'myComponent'
chai.use(chaiEnzyme())
describe('MyComponent', () => {
const store = {
id: 1
}
it ('renders', () => {
const wrapper = mount(<MyComponent />, {context: {store: store}})
})
})
haven't actually written the test as it fails at the declaration of wrapper
Error message: TypeError: _this.store.getState is not a function
No idea what the problem is and cant find anything addressing this!
Any help would be great!
This error means that store can't get the state correctly.
I would recommend mocking the store using redux-mock-store
and import configureStore
import configureStore from 'redux-mock-store';
then mock the state by doing this
const initialState = { id: 1 };
const mockStore = configureStore();
and you can continue by wrapping your component with provider
import { Provider } from 'react-redux'; // add this to the top of your file
const wrapper = mount(
<Provider store={mockStore(initialState)}>
<MyComponent />
</Provider>,
);
Also, shouldn't chai.user() be chai.use() in your code example?