mocha with redux: expected undefined to equal true - reactjs

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

Jest and RTL: Traget Container is not a DOM element

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.

How to snapshot test connected component that wrapped with connected component?

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?

Consoling shallow(<component />) results in ShallowWrapper {}

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());

Field must be inside a component decorated with reduxForm(), Error in test file

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?

_this.store.getState is not a function when testing react component with enzyme and mocha

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?

Resources