React Jest Test Failing - type.toUpperCase is not a function - javascript

I'm trying to write tests using Jest for React. However, I'm getting the following error:
TypeError: type.toUpperCase is not a function
React (images.js):
import React, { Component } from 'react';
export class Images extends Component {
render() {
return (
<div class="images">
</div>
);
}
}
Test (Jest):
jest.autoMockOff();
import React from 'react';
import TestUtils from 'react-addons-test-utils';
const ImagesComponent = require('../src/Components/images');
describe('ImagesComponent', () => {
it('Render instance of div class=images in DOM', () => {
const shallowRenderer = TestUtils.createRenderer();
shallowRenderer.render(<ImagesComponent className="images" />);
imagesDivComponent = shallowRenderer.getRenderOutput();
expect(imagesDivComponent.props.className).toEqual('images');
});
});

Redefine your React component from:
export class Images extends Component {...}
to:
var Images = React.createClass ({...)};
module.exports = Images;

Related

Getting the error as " Cannot read property 'wait' of null" while testing my component containing i18next library using react testing library in react

This is my file which I am trying to test
So this is my about file which contains i18next library beacuse of which I am getting the error as "cannot read property wait of null
import React, { Component } from 'react';
import LoadingImg from '../../assets/images/loader.gif'
import {getChapterData,fetchChapterData,htmlDecode} from '../helpers/common'
import { Trans, withNamespaces } from 'react-i18next';
class AboutReportChapter extends Component {
constructor(props){
super(props)
this.state={
isDataLoaded:false
}
}
render() {
return (
<div className="drChapterContainer aboutChapterReport" id="pills-AboutReportChapter">
{this.state.isDataLoaded?
<div className="aboutReport">
{this.state.chapterDescription ?
<div className="aboutReportHeader flexContainer">
<div className="hideShowAll show unselectable" id="about_HS"><Trans>HIDE_ALL</Trans></div>
</div>
:null
}
</div>
:
<div className="loading" key="loading_key">
<img src={LoadingImg} alt ="Loading"/>
</div>
}
</div>
)
}
componentDidMount= async()=> {
let result = await fetchChapterData('AboutReportChapter')
this.setState({...result});
}
}
export default withNamespaces() (AboutReportChapter);
And this is my testing file
This is my testing file which I am testing using react testing library jest and I am getting null value on rendering the component
import React from 'react'
import About from '../about'
import { render,unmountComponentAtNode} from "react-dom";
import { screen,getByText,getByTestId,queryByText } from '#testing-library/dom'
import {fetchChapterData,htmlDecode} from '../../helpers/common'
import { act } from "react-dom/test-utils";
jest.mock('../../helpers/common', () => ({
fetchChapterData:jest.fn(),
htmlDecode:jest.fn()
}))
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
describe("Introduction component testing",() => {
const fakeData=require('../_Mock Data_/about.json');
fetchChapterData.mockResolvedValue({...fakeData})
it("check if about component is rendered or not", async () => {
await act(async () => {
render(<About t={key => key} />, container);
});
//Assertions
expect(container.getElementsByClassName('aboutReport').length).toBe(1);
expect(container.getElementsByClassName('loading').length).toBe(0);
});
})

Best practice to test propTypes with jest + enzyme + react-redux?

I have tried many solutions I found on google to test if Component.propTypes was set properly at a react component, but none of them worked for me. Even though I get a console warning when running my React application on the browser if the properties are passed incorrectly, when I run jest I can't capture that warning in any way that I tried. Here is my best attempt:
App.js:
export class App extends Component {
constructor(props) {
super(props);
}
render() {
return <div/>;
}
}
App.propTypes = {
images: PropTypes.array.isRequired
};
function mapStateToProps(state) {
const {images} = state;
return {images: images};
}
export default connect(mapStateToProps)(App);
App.test.js:
import React from 'react';
import chai from 'chai';
import chaiEnzyme from 'chai-enzyme';
import {shallow} from 'enzyme';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import sinon from 'sinon'
import {Provider} from 'react-redux';
import App from './App';
const expect = chai.use(chaiEnzyme()).expect
const mockStore = configureStore([thunk]);
const wrap = (initialState, props) => {
return shallow(<Provider store={mockStore(initialState)}><App {...props} /></Provider>)
};
describe('App container', () => {
it('validates properties', () => {
const stub = sinon.stub(console, 'warn');
console.warn.reset();
React.createElement(App, {});
expect(stub.calledOnce).to.equal(true);
expect(stub.calledWithMatch(/Failed prop type/)).to.equal(true);
console.warn.restore();
});
it('renders without crashing', () => {
wrap();
});
it('is react-redux connected', () => {
const wrapper = wrap();
expect(wrapper.find('Connect(App)')).to.have.length(1);
});
it('correctly maps properties', () => {
const wrapper = wrap({images: []});
expect(wrapper.props().images).to.equal([]);
});
});
According to what I've read online on various GitHub issue threads, it seems like a common approach is to make console.warn/console.error throw.
So when you are writing your tests you can do something like
expect(// Render Component //).to.throw();
Hope this helps.
More info: https://github.com/airbnb/enzyme/issues/588

React Jest test Cannot read property 'pathname' of undefined

Not sure why I'm getting this error in my simple Main.test file.
The constructor of Main.js
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
location: splitString(props.location.pathname, '/dashboard/')
}
if (R.isEmpty(props.view)) {
isViewServices(this.state.location)
? this.props.gotoServicesView()
: this.props.gotoUsersView()
}
}
Main.test
import React from 'react'
import * as enzyme from 'enzyme'
import toJson from 'enzyme-to-json'
import { Main } from './Main'
import Sidebar from '../../components/Common/sidebar'
const main = enzyme.shallow(<Main />);
describe('<Main /> component', () => {
it('should render', () => {
const tree = toJson(main);
expect(tree).toMatchSnapshot();
});
it('contains the Sidebar', () => {
expect(main.find(Sidebar).length).toBe(1);
});
});
Is there a way to mock up the 'pathname'?
It seems you might have a few errors one being that in your test your not passing in any props.
And another from you accessing this.props in your constructor.
See your if statement but I'll put the fix here to be explicit
if (R.isEmpty(props.view)) {
isViewServices(this.state.location)
? props.gotoServicesView()
: props.gotoUsersView()
}
In Main.test
const location = { pathname: '/dashboard/' };
const main = enzyme.shallow(<Main location={ location }/>);

Using custom mocks for components with jest

I'm writing a React-Native application in which I have a screen I need to test:
MyScreen.js
import React, { Component } from "react";
import CustomTable from "./CustomTable";
export default MyScreen extends Component {
render() {
return <CustomTable />;
}
}
CustomTable.ios.js
import React, { Component } from "react";
import { View } from "react-native";
import TableView from "react-native-tableview";
export default MyScreen extends Component {
render() {
return (
<View>
...some stuff
<TableView />
</View>
);
}
}
react-native-tableview calls some iOS specific code so I have mocked it out by simply returning the android version (CustomTable.android.js) in the __mocks__ folder
__mocks__/CustomTable.ios.js
import CustomAndroidTable from "../CustomTable.android";
export const CustomTable = CustomAndroidTable;
What I want to do is test MyScreen.js with Jest, but I want it to use the __mock__/CustomTable.ios. How do I go about getting it to do that? Is that even possible with Jest? My current test file looks like:
tests/MyScreen.test.js
import React from "react";
import renderer from "react-test-renderer";
import MyScreen from "../src/MyScreen";
describe("test", () => {
it("works", () => {
jest.mock("../src/CustomTable.ios");
const tree = renderer.create(
<MyScreen />,
).toJSON();
expect(tree).toMatchSnapshot();
});
But it still calls the original version of CustomTable.ios. What am i doing wrong?
You should call jest.mock outside of your suite test. It should be immediately after your imports.
import React from "react";
import renderer from "react-test-renderer";
import MyScreen from "../src/MyScreen";
jest.mock("../src/CustomTable.ios");
describe("test", () => {
it("works", () => {
const tree = renderer.create(
<MyScreen />,
).toJSON();
expect(tree).toMatchSnapshot();
});

React/Redux Testing w/ Enzyme

I'm learning how to test React/Redux components using enzyme. The component takes app-level state as props. When I run the test, I get the errors:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
TypeError: Cannot read property 'contextTypes' of undefined
with my console.log of wrapper in the below test file logging as undefined.
I know that there's something wrong with my setup here, and have spent a couple hours trying to figure this out. Can anybody see anything obvious in the way that I'm importing and trying to use the component? I can't figure out why it is undefined. Thanks in advance for any help or insight!
BackendDisplay.js
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
var BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props.loginState;
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
const mapStateToProps = function(store) {
return store;
}
module.exports = connect(mapStateToProps)(BackendDisplay);
BackendDisplay.test.js
'use strict';
import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import { BackendDisplay } from '../components/BackendDisplay';
describe('<BackendDisplay />', () => {
it('Correctly displays username, node_version, app_path, and timestamp', () => {
const wrapper = shallow(<BackendDisplay />);
console.log(wrapper);
});
});
Edited after changes:
BackendDisplay.js
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
var BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props.loginState;
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
const mapStateToProps = function(store) {
return store;
}
// module.exports = connect(mapStateToProps)(BackendDisplay);
export default connect(mapStateToProps)(BackendDisplay);
BackendDisplay.test.js
'use strict';
import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import store from '../store';
import { Provider } from 'react-redux';
import ConnectedBackendDisplay, {BackendDisplay} from '../components/BackendDisplay';
describe('<BackendDisplay />', () => {
it('Correctly displays username, node_version, app_path, and timestamp', () => {
const wrapper = shallow(
<Provider store={store}>
<BackendDisplay />
</Provider>
);
console.log(wrapper.find(BackendDisplay));
expect(wrapper.find(BackendDisplay).length).to.equal(1);
});
});
Error message:
TypeError: Enzyme::Selector expects a string, object, or Component Constructor
Your BackendDisplay is a container component and it is connected to the Redux store through the use of the connect api.
You should export the undecorated component for testing purposes. Since it is undecorated this exported component will not be wrapped with react-redux's Connect component.
var BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props.loginState;
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
Then you can import it as follows to make the test work
import {BackendDisplay} from 'BackendDisplay'
As a bonus you can also export the decorated BackendDisplay component by changing the following line
module.exports = connect(mapStateToProps)(BackendDisplay);
to
export default connect(mapStateToProps)(BackendDisplay);
This is how to import both the decorated and undecorated components
import ConnectedBackendDisplay, {BackendDisplay} from 'BackendDisplay'
ConnectedBackendDisplay refers to the decorated component which is
exported through the unnamed export (export default BackendDisplay).
We just give it this name so that its clear it is wrapped in a connect component.
I have updated the following component to use export default which gives an unnamed export.
BackendDisplay
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
export const BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props;
// removed reference to this.props.loginState
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
const mapStateToProps = function(store) {
return store;
}
export default connect(mapStateToProps)(BackendDisplay);
Here is the test suite to demonstrate testing the above component both as a decorated and undecorated component with enzyme.
I am using the chai library to make test assertions easier.
The jsdom library is also being used to create a DOM environment so we can test components using Enzyme's mount function which fully renders components.
test
'use strict';
import React from 'react';
import jsdom from 'jsdom'
import { expect } from 'chai'
import { shallow , mount} from 'enzyme';
import { Provider } from 'react-redux';
import ConnectedBackendDisplay, // decorated component
{BackendDisplay} from 'app/components/BackendDisplay'; // undecorated component
// for mocking a store to test the decorated component
import configureMockStore from 'redux-mock-store';
// create a fake DOM environment so that we can use Enzyme's mount to
// test decorated components
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>')
global.document = doc
global.window = doc.defaultView
describe.only('<BackendDisplay />', () => {
it('undecorated component correctly displays username', () => {
// define the prop we want to pass in
const username = 'Foo'
// render the component with the prop
const wrapper = mount(<BackendDisplay username={username} />);
// test that the text of the first <p> equals username prop that we passed in
expect(wrapper.find('h1').first().text()).to.equal(username);
});
it('decorated component correctly displays username', () => {
// define the prop we want to pass in
const username = 'Foo'
const initialState = { }
// create our mock store with an empyty initial state
const store = configureMockStore(initialState)
// render the component with the mockStore
const wrapper = shallow(<Provider store={store}>
<ConnectedBackendDisplay username={username}/>
</Provider>);
// test that the text of the first <p> equals username prop that we passed in
expect(wrapper.find('h1').first().text()).to.equal(username);
});
});

Categories

Resources