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.
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 functional react component and I want to change a property value inside the component in an enzyme unit test (in my case the ready attribute). The unit test should use shallow to avoid rendering any children components.
Here is the simplified component code:
import {useTranslation} from 'react-i18next';
// ...
const MyComponent: React.FC<IProps> = (props: IProps) => {
const {t, ready} = useTranslation('my-translation-namespace');
// ...
return (
<React.Fragment>
{ready &&
<div className="my-component">some more content...</div>
}
</React.Fragment>)
};
export default MyComponent;
And this is the corresponding test:
describe('MyComponent', () => {
let component: ShallowWrapper;
it('should be displayed', () => {
component = shallow(<MyComponent/>);
// HERE I WOULD LIKE TO SET: component.ready = true
expect(component.find('.my-component').length).toBe(1);
});
});
Any idea how to change the ready attribute to true in my test?
This can be accomplished by mocking the react-i18next module with jest.
const mockT = jest.fn((a) => a)
const mockReady = true
jest.mock('react-i18next', () =>
jest.fn().mockImplementation(() => ({
useTranslation: () => ({ t: mockT, ready: mockReady })
}))
);
Take a look at the documentation or this article if you are using ES modules or this answer for other options.
edit: use module factory for second param of jest.mock instead if passing a plain object.
I have 3 component structured as follows:
const Parent = () => {
// this component uses hooks
return (
<div>
Test
<Child />
</div>
)
}
const Child = () => {
// this component uses hooks
return (
<>
Other content
<Child2>
{stuff}
</Child2>
</>
)
}
const Child2 = () => {
return <div>{children}</div>
}
In my test I'm mocking Child like:
import * as renderer from "react-test-renderer";
jest.doMock("./Child", () => () => <div>MockChild</div>);
describe("Snapshot", () => {
it('renders correctly', () => {
const tree = renderer
.create(<Parent />)
.toJSON();
expect(tree).toMatchSnapshot();
});
})
But upon running the test I'm getting this error: TypeError: Cannot read property 'children' of null.
Following the stacktrace I can see the error is from the children in Child2. My question is, why is jest mounting Child2 when I'm mocking Child in my test? Shouldn't it get disregarded? How can I solve this?
jest.doMock is not hoisted
That is why you have to doMock first then import the Component below respectively.
import * as renderer from "react-test-renderer";
jest.doMock("./Child", () => () => <div>MockChild</div>);
// here is where you should import Parent
import Parent from './Parent';
describe("Snapshot", () => {
it('renders correctly', () => {
const tree = renderer
.create(<Parent />)
.toJSON();
expect(tree).toMatchSnapshot();
});
})
By the way, i recommend you to use the famous Enzyme instead of react-test-renderer. It has Shallow Rendering which exactly does what you wanted out of the box (mock every child component). It also offers Full render and static render.
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)
})
})
})
There are three things I want to figure out. For now I am using shallow render. I use Enzyme and Jest.
I am wondering how I can test the branches in my React component. I
would like to test both sides of the if-else statement (? :). And I
do not want to pull it out in an own function.
How can I check if this.props.myFuncFromProps(value) is been called
when the input changes?
What is the best practice to test mapStateToProps and
mapDispatchToProps?
Here is an example of how my component would look like:
import React from 'react';
import MyChildComponent from 'wherever'; // This component is an input field in this example
export class MyComponent extends React.Component {
render() {
const myFunc(value) {
this.props.myFuncFromProps(value);
}
return (
<div>
{ this.props.isTrue ?
<MyChildComponent
value={this.props.value}
onChange={(value) => myFunc(value)}
/>
: null
}
</div>
);
}
}
To test the different states just render your component with the different attributes and make a snapshot (note, that you have to check the first time the snapshot was created). To test event callback, you have to pass a spy function (jest.fn()) into to component and use simulate to call the event, then test that the spy was called.
describe('MyComponent', () => {
describe('with isTrue is true', () => {
let myComponent
let myFuncFromProps
beforeEach(() => {
myFuncFromProps = jest.fn()
myComponent = shallow(
<MyComponent isTrue myFuncFromProps={myFuncFromProps} />
)
})
it('renders correct', () => {
expect(myComponent).matchSnapshot()
})
it('onchange will call myFuncFromProps', () => {
myComponent
.find('MyChildComponent')
.simulate('onChange', 'someValue')
expect(myFuncFromProps).toHaveBeenCalledWith('someValue')
})
})
it('with isTrue is false it renders correct', () => {
const myComponent = shallow(<MyComponent />)
expect(myComponent).matchSnapshot()
})
})