Testing prop drilling with Enzyme - javascript

I want to write an integration test to assert that a when a parent component drills certain values or properties to a child component, that component receives said values and renders them properly. Below I have two component examples and an example test. Of course, the test is not accurate, but I'm wondering how I can use enzyme to accomplish this? Thanks!
sampleComponent.js:
import React from 'react';
const SampleComponent = () => (
<div test-attr="div">
<SampleChildComponent title="Sample title" />
</div>
);
export default SampleComponent;
sampleChildComponent.js:
import React from 'react';
const SampleChildComponent = ({ title }) => <h3 test-attr="h">{title}</h3>;
export default SampleChildComponent;
sampleComponent.test.js:
import React from 'react';
import { shallow } from 'enzyme';
import SampleComponent from './sampleComponent';
import SampleChildComponent from './sampleChildComponent';
test('renders component without errors', () => {
const wrapper = shallow(<SampleComponent />);
const childWrapper = shallow(<SampleChildComponent />);
expect(childWrapper.text()).toEqual('sample title');
});

To render child components you should use mount instead of shallow:
import { mount } from 'enzyme'
import React from 'react'
import SampleChildComponent from './sampleChildComponent'
import SampleComponent from './sampleComponent'
test('renders component without errors', () => {
const wrapper = mount(<SampleComponent />)
expect(wrapper.find(SampleChildComponent).text()).toEqual('sample title')
})

Related

Simple React button test fails

Im using jest to test a simple button in React and it keeps failing. My latest iteration complains about render. I'm new to testing and I've been at it for a while and cannot figure this out. What am I missing here?
Here's my App.js
function clickMe() {
alert("Hello")
}
function App() {
return (
<div className="App">
<button id="btn" onClick={clickMe}>Click Me!!</button>
</div>
)
}
export default App;
Here's my App.test.js
import React from 'react'
import {render} from 'react-dom'
import App from './App'
test("Click", () => {
const {container} = render(<App />)
const button = getByTestId(container, 'btn')
fireEvent.click(button)
})
You can simulate some events with the enzyme library
For this first install this by npm, then import that
import {shallow} from 'enzyme';
After using this structure to simulate a click on a bottom
Create a wrapper
let wrapper = shallow(<App />);
beforeEach( ()=>{
wrapper = shallow(<CounterApp />);
});
This creates a simulation of render components and gives you the capacity to simulate events, this method is working in my project counterApp
test('Click', ()=>{
wrapper.find('button').at(0).simulate('click');
expect(//The action of your botton).toBe(//the result expected);
});
Not exactly the same but something like this also worked
import { shallow } from 'enzyme'
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import App from './App'
configure({ adapter: new Adapter() })
it('renders the link inside the output area', () => {
const output = shallow(<App />)
expect(output.find('div').find('button').length).toEqual(1)
})

React multiple import one module caching re-use

I am using Centrifugo websocket server. I need to connect to Centrifugo and store connection instance for future usage from from multiple components.
Will it be the good way to create this kind of export from ./socket.js? Will centrifuge.connect() and centrifuge.setToken('') be executed if I gonna import ./socket.js module muitiple times?
./socket.js
const Centrifuge = require('centrifuge');
const centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket');
centrifuge.setToken('');
centrifuge.connect();
export default {
socket: centrifuge,
};
./App.jsx
import React from 'react';
import { socket } from '../socket'; // first import
import SomeComponent from './components/SomeComponent';
import SomeSecondComponent from './components/SomeSecondComponent';
export default () => (
<>
<SomeComponent />
<SomeSecondComponent />
</>
)
./components/SomeComponent.jsx
import React from 'react';
import { socket } from '../socket'; // second import
export default () => <>...</>;
./components/SomeSecondComponent.jsx
import React from 'react';
import { socket } from '../socket'; // third import
export default () => <>...</>;
What would it be the best way to make instance and reuse it?
If you want to use a single instance only, it's better to import it in one place only. Best to import in the parent component and pass it as props to the children.
So your app.jsx would become:
import React from 'react';
import { socket } from '../socket'; // first import
import SomeComponent from './components/SomeComponent';
import SomeSecondComponent from './components/SomeSecondComponent';
export default () => (
<>
<SomeComponent socket={socket} />
<SomeSecondComponent socket={socket} />
</>
)
Now socket will be available as the props in both the components.
For eg. In ./components/SomeComponent.jsx
import React from 'react';
export default ({socket}) => <>...</>;

Unit testing of the updated component in react using jest and enzyme

I am trying to write the testing file for the following code.
with my present code
import React from 'react';
import renderer from 'react-test-renderer';
// import { mount } from 'enzyme';
import LazyToastMessage from '../LazyToastMessage';
import IntlHelper from "test/util/Mount";
import nls from "src/nls/homepageHeader.json";
describe('the suspended toast message component renders correctly', () => {
const mountWithNLS = new IntlHelper(nls);
it('LazyToastMessage fallback', () => {
const mockHandler = jest.fn();
const wrapper = renderer.create(mountWithNLS.mountWithIntl(
<LazyToastMessage
state
message="test message"
iconType="success"
handleToasterStateChange={mockHandler}
/>)
)
expect(wrapper.toJSON()).toMatchSnapshot();
})
});
The result of the snapshot is giving as null. How can I test the updated component and take its snapshot?
The Lazy component is the following:
import React, {lazy, Suspense} from "react";
import {IAppProps} from 'src/js/components/misc/ToastMessage'
const LazyToastMessage = lazy(() =>
import(/* webpackChunkName: "toast-message" */ "./ToastMessage"),
);
export default function(props: IAppProps) {
return (
<Suspense fallback={null}>
<LazyToastMessage {...props} />
</Suspense>
);
}
To test it properly, you have to wrap your lazily loaded component in Suspense in test.
First, in your component:
export const LazyToastMessage = ...
Then, in your test:
import SuspendedLazyToastMesssage, {LazyToastMessage} from '../LazyToastMessage';
.
.
.
const wrapper = renderer.create(mountIthNLS(mountWithIntl(
<Suspense fallback=null>
<SuspendedLazyToastMessage/>
</Suspense>
));
await LazyToastMessage;
expect(wrapper.toJSON()).toMatchSnapshot();
Or something like that, but you get the idea...

How to use jest.mock in React

Is there a way to use jest.mock's in React? For example, say I want to re-use a component (e.g. Storybook) but want to mock an import / implementation detail for that original React component. Is this possible, and if so, how? Thanks!
sampleComponent.js:
import React from 'react';
import sampleFn from './sampleFn';
const SampleComponent = () => <h1>{sampleFn()}</h1>; // expected output: 'Hello World'
export default SampleComponent;
sampleMockComponent.js:
import React from 'react';
import SampleMockComponent from './sampleComponent';
jest.mock('./sampleFn');
const SampleMockComponent = () => <SampleComponent />; // expected output: 'Testing Mock'
sampleFn.js:
export default () => 'Hello World';
__mocks__/sampleFn.js:
export default () => 'Testing Mock';
If you want to mock for reasons that are not for testing.
I would not suggest you use jest mocks.
Go for a dependency injection pattern.
import React from 'react';
import sampleFn from './sampleFn';
// Unless sample is supplied, sampleFn will be used by default
const SampleComponent = () => {
const { sample = sampleFn } = props;
return <h1>{sample()}</h1>;
}
export default SampleComponent;

Testing - React stateless components, spying on component methods using sinon

Problem:
I am trying to test the click function of a React stateless component in ES6. However, when using sinon to spy on the handleClick function I get the response...
TypeError: Cannot read property 'goToFullCart' of undefined
I have tried a few other methods. Some of them seem to work when the component is a Class component but all methods seem to fail when using a stateless functional component as follows...
The code:
import React from 'react'
import PropTypes from 'prop-types'
import SVG from '../../../../static/svg/Svg';
import Svgs from '../../../../static/svg/SvgTemplates';
const TestComponent = ({order, router}) => {
const handleClick = (event) => {
event.stopPropagation()
router.push(`/order/${order.orderId}/cart`);
}
return (
<button className="preview-bar" onClick={handleClick}>
<p>Button Content</p>
</button>
)
}
TestComponent.propTypes = {
order: PropTypes.object.isRequired,
router: PropTypes.object.isRequired,
}
export default TestComponent
export { TestComponent }
import React from 'react';
import { shallow, mount } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import TestComponent from "./TestComponent"
let wrapper, props;
describe('<TestComponent /> component unit tests', () => {
describe('when the minimized cart is clicked', () => {
beforeEach(function() {
props = {
}
wrapper = shallow((<TestComponent {...props} />))
});
it('should have a goToFullCart method', () => {
const spy = sinon.spy(TestComponent.prototype, 'handleClick');
expect(spy).to.equal(true)
});
});
});
I am at a loss as to how to spy on the handleClick method to check when the button is clicked.
Thanks for the help and discussion. Feel free to ask for any clarification if anything is not clear.
Cheers
A stateless component is basically a function. Good practice not to create another function inside this because it will create a closure, if you wanted to create methods inside component create stateful component rather
Instead of testing handleClick, you can test route is changed or not
import React from 'react';
import {shallow} from 'enzyme';
test('should call handleClick method when button got clicked', () => {
window.location.assign = mock;
wrapper .find('button').simulate('click');
expect(window.location.assign).toHaveBeenCalled(1);
});
Hope this help you!

Categories