I am getting Error: Uncaught [Error: Child(...): Nothing was returned from render when running a test file for the Parent component.
These are the relevant files
/components/Page/Children/Child.js
import React from "react"
export default function Child() {
return <div>abc</div>
}
/components/Page/Children/index.js
export { default } from "./Child"
/components/Page/Parent.js
import React from "react"
import Child from "./Children"
export default class Parent extends React.Component {
constructor(props) {
super(props)
}
render() {
return <Child />
}
}
/components/Page/_tests_/Parent.spec.js
import Parent from "../Parent"
jest.mock("../Children")
describe("<Parent/>", () => {
let wrapper
let props = ...
describe("render", () => {
it("renders", () => {
wrapper = mount(<Parent props={props} />)
expect(wrapper).toMatchSnapshot()
})
})
changing the Child.js file to a react class component (as updated below) resolves the issue but I do not understand why that would be.
/components/Page/Children/Child.js
import React from "react"
export default class Child extends React.Component {
render() {
return <div>abc</div>
}
}
The reason why this error happened is you are mocking the ./Children module and you didn't provide a mocked Child component. So, if you want to mock the Child component, you need to provide a return statement.
E.g.
Parent.spec.js:
import React from 'react';
import Parent from './Parent';
jest.mock('./Children', () => {
return jest.fn(() => <div>mocked child</div>);
});
describe('<Parent/>', () => {
let wrapper;
let props = {};
describe('render', () => {
it('renders', () => {
wrapper = mount(<Parent props={props} />);
expect(wrapper).toMatchSnapshot();
});
});
});
unit test result:
PASS src/stackoverflow/63607465/Page/Parent.spec.js
<Parent/>
render
✓ renders (37ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 passed, 1 total
Time: 2.792s, estimated 3s
snapshot:
// Jest Snapshot v1,
exports[`<Parent/> render renders 1`] = `
<Parent
props={Object {}}
>
<mockConstructor>
<div>
mocked child
</div>
</mockConstructor>
</Parent>
`;
Related
I am new to Jest, I am trying to mock my context HOC function to test my component
Here is my folder structure
Folder Structure
Basically I am trying to mock the homeContext.js file which is being used by my HomeScreen component. As per the docs I have created a __mocks__ folder under the contexts folder and created a homeContext.js file
Here are the contents of the files:
/contexts/__mocks__/homeContext.js
const mock = jest.fn().mockImplementation(() => {
console.log('Mocking');
return {
withHomeContext: jest.fn(() => {}),
};
});
module.exports = mock;
contexts/homeContext.js
export const withHomeContext = ChildComponent => props => {
console.log('Not Hitting');
return (
<HomeContext.Consumer>
{context => <ChildComponent {...props} homeContext={context} />}
</HomeContext.Consumer>
);
};
Here is how I am trying to use it in my scenes/home/index.test.js
jest.mock('../../contexts/homeContext');
import React from 'react';
import {mount} from 'enzyme';
import HomeScreen from './index';
describe('<HomeScreen /> renders', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<HomeScreen />);
expect(wrapper).toBeDefined();
});
})
This is how the component which I am testing uses it
import * as React from 'react';
//Context
import {withHomeContext} from '../../contexts/homeContext';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
relatedItems: [],
};
}
render() {
//Some render logic
}
}
export default withHomeContext(HomeScreen);
Please help me why my __mocks__/homeContext.js never gets hit, it is hitting the actual file, which console logs ('Not Hitting')
I want to start my React microapp with props I'm passing from Single SPA (customProps). The only way I've figured out is:
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import App from './where/my/root/is.js';
function domElementGetter() {
return document.getElementById("mounting-node")
}
let EnhancedRootComponent = App; /* 1 */
const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: EnhancedRootComponent, /* 1 */
domElementGetter,
})
export const bootstrap = [
(args) => {
/* 2 */ EnhancedRootComponent = () => <App myArgs={args.thePropsIWannaPass} />;
return Promise.resolve();
},
reactLifecycles.bootstrap,
];
export const mount = [reactLifecycles.mount];
export const unmount = [reactLifecycles.unmount];
This does work (I can see and use the passed props in my component) but I'm not completely OK with the fact that the root component changes in between calling singleSpaReact (1) and calling bootstrap(2). Would there be side effects to this that I'm not seeing now? Does anyone know a better approach for this?
You have this value inside the props variable without this reassign.
Check this out:
Root-config.js, file responsible for passing prop to microfrontend
import { registerApplication, start } from 'single-spa';
import * as isActive from './activity-functions';
registerApplication('#company/micro2', () => System.import('#company/micro2'), isActive.micro2);
registerApplication('#company/micro1', () => System.import('#company/micro1'), isActive.micro1, { "authToken": "test" });
start();
micro1 Root.tsx
import React from 'react';
export default class Root extends React.Component {
constructor(props: any){
super(props)
}
state = {
hasError: false,
};
componentDidCatch() {
this.setState({ hasError: true });
}
render() {
console.log(this.props)
return (
<div>test</div>
);
}
}
console.log output:
props:
authToken: "test" <---- props which you pass
name: "#company/micro1"
mountParcel: ƒ ()
singleSpa: {…}
__proto__: Object
for more advance usage
const lifecycles = singleSpaReact({
React,
ReactDOM,
loadRootComponent: (props) =>
new Promise((resolve, reject) => resolve(() =>
<Root {...props} test2={'test2'}/>)),
domElementGetter,
});
So I converted an import used in a class component to React.lazy import api and wrapped it in a Suspense tag. When I test that class component, enzyme throws an error "Enzyme Internal Error: unknown node with tag 13". Is there a way to render and test the mount of the lazy loaded component rather than using shallow render?
I've already tried async await to wait until the promise of the lazy load resolved but that didn't work neither, like so:
it('async await mount', () async () => {
const wrapper = await mount(<Component />)
}
here's example code:
Component.js
import React, { PureComponent, Suspense } from 'react'
const ChildComponent = React.lazy(() => import('../ChildComponent'))
export default class Component extends PureComponent {
constructor() {
super()
this.state = {
example: null
}
}
doSomething = () => this.setState({
example: 'example'
})
render() {
return (
<div>
<p>Example</p>
<Suspense fallback={<div>...loading</div>}>
<ChildComponent
example={this.state.example}
doSomething={this.doSomething}
/>
</Suspense>
</div>
)
}
}
Component.test.js
import React from 'react'
import renderer from 'react-test-renderer'
import { mount } from 'enzyme'
import Component from '../../Component'
describe('Component', () => {
// snapshot renders loading and not children
it('example snapshot of tree', () => {
const tree = renderer.create(<Component />).toJSON()
expect(tree).toMatchSnapshot()
})
it('example mount test', () => {
// this test fails and throws error I state above
const wrapper = mount(<Component />)
wrapper.setState({ example: 'example' })
expect(wrapper.state.example).toBe('example')
})
})
I read that Enzyme does not support React 16.6 Suspense API yet but I wanted to know if there was still a way to test the mounted so I can use things like simulate and find API from Enzyme.
Solution
The GitHub issue linked by ChuckJHardy has been resolved merged and released. You are now able to use the mount API in enzyme as of 1.14.0.
References
https://github.com/airbnb/enzyme/pull/1975
I needed to test my lazy component using Enzyme. Following approach worked for me to test on component loading completion:
const myComponent = React.lazy(() =>
import('#material-ui/icons')
.then(module => ({
default: module.KeyboardArrowRight
})
)
);
Test Code ->
//mock actual component inside suspense
jest.mock("#material-ui/icons", () => {
return {
KeyboardArrowRight: () => "KeyboardArrowRight",
}
});
const lazyComponent = mount(<Suspense fallback={<div>Loading...</div>}>
{<myComponent>}
</Suspense>);
const componentToTestLoaded = await componentToTest.type._result; // to get actual component in suspense
expect(componentToTestLoaded.text())`.toEqual("KeyboardArrowRight");
This is hacky but working well for Enzyme library.
For jest test file I want to import component and that method.
For example I have this component :
import React from 'react'
class Dashboard extends React.Component {
constructor(props) {
super(props)
}
sum(one, two) {
return one + two
}
render() {
return(
<div>
<h1>{this.sum(12, 14)}</h1>
</div>
)
}
}
export default Dashboard
So, in the test file I like to test component with render and sum function with toEqual :
import React from 'react';
import ReactDOM from 'react-dom';
import Dashboard from '../Dashboard';
it('check component', () => {
const div = document.createElement('div');
ReactDOM.render(<Dashboard />, div);
});
it('check sum function', () => {
expect(sum(12, 12)).toEqual(24);
});
But the second test and sum has failed, because the test function could not find sum function ...
How can I export component and that contain method ?
Thanks
If you want test a function, that doesn't depend on a component you can use static modifier:
import React from 'react'
class Dashboard extends React.Component {
constructor(props) {
super(props)
}
static sum(one, two) {
return one + two
}
render() {
return(
<div>
<h1>{Dashboard.sum(12, 14)}</h1>
</div>
)
}
}
export default Dashboard
it('check component', () => {
const div = document.createElement('div');
ReactDOM.render(<Dashboard />, div);
});
it('check sum function', () => {
expect(Dashboard.sum(12, 12)).toEqual(24);
});
In most cases it isn't necessary to test react-component methods separately.
Another way to solve you problem is move sum to separate module. Then you can add unit tests to this module.
I’m trying to understand why my jest/enzyme tests are failing. I have a component that I use the compose function from redux in, structured as following:
class MyComponent extends Component {
//code here
}
export default compose(
connect(mapStateToProps),
)(MyComponent)
In my jest test, I do this:
Import { MyComponent } from ‘app/MyComponent’;
describe(‘<MyComponent />’, () => {
let component;
beforeEach(() => {
props = {
id: ‘23423’
}
component = shallow(<MyComponent {…props} />);
}
it(‘Loads correctly’, () => {
expect(component.state(‘isLoading’)).toEqual(true);
expect(component.find(‘InnerComponent’).length).toBe(1);
}
However, I get errors like "Cannot read property 'state' of undefined". I understand that using shallow rendering doesn't give me the exact structure that I need, but I'm not sure what else to try to get the right structure. I tried shallow-rendering the wrapped component and then finding the unwrapped component within it, like so, component = shallow(<MyComponent {...props} />).find('MyComponent').shallow();, with no luck. Any other suggestions would be appreciated.
`
Usually you want to test the component and not the integration of the component with redux:
class MyComponent extends Component {
//code here
}
export { MyComponent } // export the component
export default compose(
connect(mapStateToProps),
)(MyComponent)
Also on your test you would import the named export import { MyComponent } from '...' instead of importing the default: import MyComponent from '..'
import { MyComponent } from ‘app/MyComponent’;
describe(‘<MyComponent />’, () => {
let component;
beforeEach(() => {
props = {
id: ‘23423’
}
component = shallow(<MyComponent {…props} />);
}
it(‘Loads correctly’, () => {
expect(component.state(‘isLoading’)).toEqual(true);
expect(component.find(‘InnerComponent’).length).toBe(1);
}
}
If you want to test component interactions with your redux store you need to wrap your component with a <Provider />
import { MyComponent } from ‘app/MyComponent’;
import { Provider } from 'react-redux'
describe(‘<MyComponent />’, () => {
let component;
beforeEach(() => {
props = {
id: ‘23423’
}
component = shallow(<Provider><MyComponent {…props} /></Provider>);
}
You should definitely read the testing section of the redux documentation