I am using Jest with Enzyme for unit testing. I have a component that renders components based on the media type. Under unit testing, I am checking if the appropriate component has been rendered.
My Component
const getComponent = {
'image': ImageComp,
'video': VideoComp,
'other': DocumentComp
}
const MediaDisplay = (props) => {
let { assetInfo } = props;
let source = assetInfo.assetUrl;
const PreviewComponent = getComponent[assetInfo.type];
return ( <div>
{source && <PreviewComponent assetInfo={assetInfo} />}
</div>
);
}
In unit testing,
import React from 'react';
import MediaDisplay from './../MediaDisplay';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
describe('<MediaDisplay/>', () => {
it('should render Image component when asset type is image', () => {
const mockAssetInfo = {
assetUrl:'https://example.com/image001.jpg',
type:'image'
};
const component = mount(<MediaDisplay assetInfo={mockAssetInfo} />);
expect(component).toMatchSnapshot();
});
});
I don't think I am writing the test case correctly. Can someone help me write this test case?
P.S - I have a separate test case inside the image component to check if image is rendered, where I am checking if the tag has length.
Thanks a ton in advance.
I think your test is not doing what is suppose to test, because your case is telling that it should render Image component when asset type is image but you're just checking that the component is matching the snapshot, if you're using mount you should be able to see the content of the child components, so for example if your PreviewComponent displays different things depending on the props passed you could test those behaviors. Or if you want to check just that the assetInfo.type is 'image' you can always do:
it("contains an assetInfo image type", () => {
expect(component.prop("assetInfo").type).toEqual(mockAssetInfo.type);
});
And if you only want to check that the child is present and renders successfully you could use shallow instead mount and do this:
import PreviewComponent from "your-component-route"
describe("renders a PreviewComponent", () => {
beforeAll(() => {
const mockAssetInfo = {
assetUrl:'https://example.com/image001.jpg',
type:'image'
};
const component = shallow(<MediaDisplay assetInfo={mockAssetInfo} />);
});
it("wraps a PreviewComponent component", () => {
expect(component.find(PreviewComponent).length).toBe(1);
});
});
Related
I have this component
import React, { useEffect } from 'react';
import './App.css';
import { connect } from 'react-redux';
import { CircularProgress } from '#material-ui/core';
import { loadPhones } from './redux/actions/actions.js';
import TablePhones from './Table.js';
const mapStateToProps = (state) => state;
function mapDispatchToProps(dispatch) {
return {
loadPhones: () => {
dispatch(loadPhones());
},
};
}
export function App(props) {
useEffect(() => {
props.loadPhones();
}, []);
if (props.phones.data) {
return (
<div className="App">
<div className="introductoryNav">Phones</div>
<TablePhones phones={props.phones.data} />
</div>
);
}
return (
<div className="gridLoadingContainer">
<CircularProgress color="secondary" iconStyle="width: 1000, height:1000" />
<p className="loadingText1">Loading...</p>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
For whom ive written
import React from 'react';
import { render } from '#testing-library/react';
import { Provider } from "react-redux";
import App from './App';
import { shallow, mount } from "enzyme";
import configureMockStore from "redux-mock-store";
const mockStore = configureMockStore();
const store = mockStore({});
describe('App comp testing', () => {
it("should render without throwing an error", () => {
const app = mount(
<Provider store={store}>
<App />
</Provider>
).dive()
expect(app.find('.introductoryNav').text()).toContain("Phones");
});
})
But that test keeps failing
ypeError: Cannot read property 'data' of undefined
I also tried importing App as {App} instead and using shallow testing, but no luck. It gives the same erros, so im left without access to the context, and I cant keep doing my tests
How can I solve this?
You could use the non-default export of your component here and shallow render test if you pass your component the props and don't try to mock the store (if I recall correctly).
I was thinking something like this might work, tesing the "pure" non-store connected version of the component. This seems to be a popular answer for this question as this was asked (in a different way) before here:
import React from 'react';
import { App } from './App';
import { shallow } from "enzyme";
// useful function that is reusable for desturcturing the returned
// wrapper and object of props inside of beforeAll etc...
const setupFunc = overrideProps => {
const props = {
phones: {
...phones, // replace with a mock example of a render of props.phones
data: {
...phoneData // replace with a mock example of a render of props.phones.data
},
},
loadPhones: jest.fn()
};
const wrapper = shallow(<App {...props} />);
return {
wrapper,
props
};
};
// this is just the way I personally write my inital describe, I find it the easiest way
// to describe the component being rendered. (alot of the things below will be opinios on test improvements as well).
describe('<App />', () => {
describe('When the component has intially rendered' () => {
beforeAll(() => {
const { props } = setupFunc();
});
it ('should call loadPhones after the component has initially rendered, () => {
expect(props.loadPhones).toHaveBeenCalled();
});
});
describe('When it renders WITH props present', () => {
// we should use describes to section our tests as per how the code is written
// 1. when it renders with the props present in the component
// 2. when it renders without the props
beforeAll(() => {
const { wrapper, props } = setupFunc();
});
// "render without throwing an error" sounds quite broad or more like
// how you would "describe" how it rendered before testing something
// inside of the render. We want to have our "it" represent what we're
// actually testing; that introductoryNave has rendered with text.
it("should render an introductoryNav with text", () => {
// toContain is a bit broad, toBe would be more specific
expect(wrapper.find('.introductoryNav').text()).toBe("Phones");
});
it("should render a TablePhones component with data from props", () => {
// iirc toEqual should work here, you might need toStrictEqual though.
expect(wrapper.find('TablePhones').prop('phones')).toEqual(props.phones);
});
});
describe('When it renders WITHOUT props present', () => {
it("should render with some loading components", () => {
expect(wrapper.find('.gridLoadingContainer').exists()).toBeTruthy();
expect(wrapper.find('CircularProgress').exists()).toBeTruthy();
expect(wrapper.find('.loadingText1').exists()).toBeTruthy();
});
});
});
I have a component which have this structure
return <Element>
{(a, b): React.ReactElement => (
...some elements here
)}
</Element>;
When I'm testing it I'm getting this with debug
<Element>
[function]
</Element>
My question is what is usually the way to get inside this function to check the elements which it returns?
My test
import React from 'react';
import {createShallow} from '#material-ui/core/test-utils';
import Component from './Component';
let shallow;
function setup() {
const props = {};
const wrapper = shallow(<Component {...props} />);
return {
props,
wrapper,
};
}
beforeAll(() => {
shallow = createShallow({ dive: true });
});
describe('Components', () => {
describe('Element', () => {
it('Should render self', () => {
const {wrapper, props} = setup();
console.log(wrapper.debug())
expect(wrapper.exists()).toBeTruthy();
});
});
});
There are two solutions:
Use wrapper.dive() or wrapper.shallow() that would cause your ShallowWrapper to render child of your top-level component. However, I do not recommend using shallow at all as there are many issues with it and you've just experienced one - it does not render everything.
Use mount instead of shallow and you would have your children function rendered by default.
I have a component in react that renders another component based on the type using Enum properties. I am testing if appropriate component is rendered by mocking various types using Jest and Enzyme. I am new to react and Jest and I am having trouble with my test cases. Please can someone help me resolve this?
React Component:
const getComponent = {
'image': ImageComp,
'video': VideoComp,
'other': DocumentComp
}
const MediaDisplay = (props) => {
let { assetInfo } = props;
let source = assetInfo.assetUrl;
const PreviewComponent = getComponent[assetInfo.type];
return ( <div>
{source && <PreviewComponent assetInfo={assetInfo} />}
</div>
);
}
Unit Test:
import React from 'react';
import MediaDisplay from './../MediaDisplay';
import Enzyme, { shallow ,mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ImageComp from './../ImageComp';
import { mockAssetInfo } from '../../mocks/index';
Enzyme.configure({ adapter: new Adapter() });
describe('renders a PreviewComponent', () => {
it("wraps a ImageComp component", () => {
const component = shallow(<MediaDisplay assetInfo={mockAssetInfo} />);
expect(component.find(ImageComp)).toHaveLength(1);
});
});
MockAssetInfo:
export const mockAssetInfo = {
url: "https://example.com/image002.jpg",
name: "example",
type: "image",
thumb: "https://example.com?image0011.jpgch_ck=1212334354",
isAssetPublished:true
}
The error,
expect(received).toHaveLength(expected)
Expected length: 1
Received length: 0
Received object: {}
mockAssetInfo object does not have the key assetUrl. So, PreviewComponent is not rendered as source is undefined in the line
{source && <PreviewComponent assetInfo={assetInfo} />}
This is my test case
import React from 'react';
import { mount } from 'enzyme';
import CustomForm from '../index';
describe('Custom Form mount testing', () => {
let props;
let mountedCustomForm;
beforeEach(() => {
props = {
nav_module_id: 'null',
};
mountedCustomForm = undefined;
});
const customform = () => {
if (!mountedCustomForm) {
mountedCustomForm = mount(
<CustomForm {...props} />
);
}
return mountedCustomForm;
};
it('always renders a div', () => {
const divs = customform().find('div');
console.log(divs);
});
});
Whenever I run the test case using yarn test. It gives the following error TypeError: Cannot read property 'nav_module_id' of undefined.
I have already placed console at multiple places in order to see the value of props. It is getting set. But it couldn't just pass through the components and give the error mentioned above.
Any help would be appreciated been stuck for almost 2-3 days now.
You have to wrap the component that you want to test in beforeEach method such that it becomes available for all the 'it' blocks, and also you have to take the mocked props that you think you are getting into the original component.
import React from 'react'
import {expect} from 'chai'
import {shallow} from 'enzyme'
import sinon from 'sinon'
import {Map} from 'immutable'
import {ClusterToggle} from '../../../src/MapView/components/ClusterToggle'
describe('component tests for ClusterToggle', () => {
let dummydata
let wrapper
let props
beforeEach(() => {
dummydata = {
showClusters: true,
toggleClustering: () => {}
}
wrapper = shallow(<ClusterToggle {...dummydata} />)
props = wrapper.props()
})
describe(`ClusterToggle component tests`, () => {
it(`1. makes sure that component exists`, () => {
expect(wrapper).to.exist
})
it('2. makes sure that cluster toggle comp has input and label', () => {
expect(wrapper.find('input').length).to.eql(1)
expect(wrapper.find('label').length).to.eql(1)
})
it('3. simulating onChange for the input element', () => {
const spy = sinon.spy()
const hct = sinon.spy()
hct(wrapper.props(), 'toggleClustering')
spy(wrapper.instance(), 'handleClusterToggle')
wrapper.find('input').simulate('change')
expect(spy.calledOnce).to.eql(true)
expect(hct.calledOnce).to.eql(true)
})
})
})
So, my goal is to reach the func cashedImageCheker which must return the string , based on recived from this.props -> imageFetchedURL value. And my problem is that I cannot understand how to put this value into the corresponding func cashedImageCheker of my component Banners.
I tried to use Enzyme .setProps({}) method to transfer mock props inside my testing Component, but for now I just gets undefined. Here is my test and component codes below.
Thank you for any help...
TEST FILE:
import React from 'react'
import { mount, shallow } from 'enzyme'
import Banners from '../'
describe('<Banners />', () => {
it('imageFetchedURL must return true', () => {
const Component = shallow(<Banners />)
Component.setProps({
imageFetchedURL: 'https://google.com/la-la-la/1.jpg'
})
const { imageFetchedURL } = Component.instance().cashedImageCheker()
expect(imageFetchedURL.length).toBe(33)
})
})
COMPONENT FILE:
import PropTypes from 'prop-types'
import React, { Component } from 'react'
class Banners extends Component {
cashedImageCheker = () => {
const { imageFetchedURL } = this.props
const imageFetchCached = imageFetchedURL && imageFetchedURL.length > 1
return imageFetchCached
}
render() {
const isLocalImgCached = this.cashedImageCheker()
return (
<div className='bannerWrap'>
{isLocalImgCached}
</div>
)
}
}
export default Banners
When testing your component, you can pass the props required by it while shallow mounting the component like
describe('<Banners />', () => {
it('imageFetchedURL must return true', () => {
const Component = shallow(<Banners imageFetchedURL={'https://google.com/la-la-la/1.jpg'}/>)
const imageFetchedURL = Component.instance().cashedImageCheker()
expect(imageFetchedURL.length).toBe(33)
})
})
Also the major problem in code test case is that cashedImageChecker doesn't return you an object but a value and hence you need to write
const imageFetchedURL = Component.instance().cashedImageCheker()
instead of
const { imageFetchedURL } = Component.instance().cashedImageCheker()
Doing the above change will allow you to setProps and test the component method too.
describe('<Banners />', () => {
it('imageFetchedURL must return true', () => {
const Component = shallow(<Banners />)
Component.setProps({
imageFetchedURL: 'https://google.com/la-la-la/1.jpg'
})
const imageFetchedURL = Component.instance().cashedImageCheker()
expect(imageFetchedURL.length).toBe(33)
})
})
So, my goal is to reach the func cashedImageCheker which must return
the string , based on recived from this.props -> imageFetchedURL
value.
Based on this one way is this
import React from 'react';
import { shallow } from 'enzyme';
import Banners from '../'
describe('<Banners />', () => {
const url = 'https://google.com/la-la-la/1.jpg';
it('imageFetchedURL must return true', () => {
const Component = shallow(<Banners imageFetchedURL= url />)
const imageFetchedURL = Component.instance().cashedImageCheker();
expect(imageFetchedURL.length).toBe(33)
})
})
And my problem is that I cannot understand how to put this value into
the corresponding func cashedImageCheker of my component Banners.
For this query you must know a thing when something is connected to props then during testing you can pass it on as actual props as I have done it
<Banners imageFetchedURL= url />
I tried to use Enzyme .setProps({}) method to transfer mock props
inside my testing Component
This is absolutely correct way too. It is another way of doing so.
But you were getting undefined because you were destructuring the return value which had nothing to do in your case.