Where to mount and unmount inside an Enzyme describe function? - javascript

I'm trying to get the hang of testing components in a React project. I have a single test file on a single component so far, and I'm trying to prepare this file as a test suite with multiple tests in it.
import React from 'react';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import HamburgerIcon from './HamburgerIcon';
Enzyme.configure({ adapter: new Adapter() });
describe('<HamburgerIcon />', () => {
const hamburgerIcon = mount(<HamburgerIcon showOverlay={showOverlay} />);
it('displays on mobile', () => {
...
...
});
it('has class .open after click', () => {
...
...
});
hamburgerIcon.unmount();
});
I've removed the guts of the two tests, but basically the two tests are wrapped inside of a describe function, and I'm trying to mount the component once and unmount the component once in an effort to keep things DRY (don't repeat yourself).
I've placed the mount before the two it functions, thinking that mounting the component before running tests makes logical sense.
I placed the unmount after the two test functions, which causes the error:
Method “simulate” is meant to be run on 1 node. 0 found instead.
I think this is happening because the component is unmounting before the tests are actually run.
If I mount and unmount in both tests, like this...
describe('<HamburgerIcon />', () => {
it('displays on mobile', () => {
const hamburgerIcon = mount(<HamburgerIcon showOverlay={showOverlay} />);
...
...
hamburgerIcon.unmount();
});
it('has class .open after click', () => {
const hamburgerIcon = mount(<HamburgerIcon showOverlay={showOverlay} />);
...
...
hamburgerIcon.unmount();
});
});
...the tests pass.
This seems excessive, though. What if my test suite has ten test functions it? Should I be mounting and unmounting like this for every single test?

You can use beforeEach and afterEach functions to set-up and clear your test.
afterEach(() => {
//do the unmounting and other stuff here
//this will be called after each test case
});
beforeEach(() => {
//do the mounting and setting up the test case here
//this will be called before each test case
});

Related

Testing fails because the prop was not rendered yet

I'm trying to write a test that searches a rendered Dom element, but it is rendered with useEffect, so the test fails because it's rendered a bit later.
for example:
const [isTrue, setIsTrue] = useState(false);
useEffect(() => {
setIsTrue(!isTrue);
}, []);
<div>
{isTrue && <div className="test">test</div>}
</div>
when the dom renders the div with the className="test" is not rendered only after useEffect is, but I have a test called:
test("test", () => {
expect(wrapper.find(".test").first().text()).toEqual("test");
});
and it fails because it only sees the first render, how can I change the test so it will see the rendered div post useEffect?
EDIT:
I tried using act but it still doesn't work
import { act } from "react-dom/test-utils";
import { mount } from "enzyme";
act(() => {
component = mount(<App />);
});
I've had this problem before, I believe you need to use the update method of your mounted wrapper:
https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/update.html
So your test would look something like this:
test("test", () => {
wrapper.update();
expect(wrapper.find(".test").first().text()).toEqual("test");
});

jest/enzyme test: this.props.showOverlay is not a function

I have a small test that simulates a click (hoping to do more with the test, but this is where I'm stuck so far):
import React from 'react';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import HamburgerIcon from './HamburgerIcon';
Enzyme.configure({ adapter: new Adapter() });
test('hamburger icon changes class and state on click', () => {
const wrapper = mount(<HamburgerIcon />);
const hamburgerIcon = wrapper.find('div#mobile-nav');
hamburgerIcon.simulate('click');
});
When running this test, I get the error:
TypeError: this.props.showOverlay is not a function
After doing some reading, I've realized that this isn't working because the simulated click calls a function that is two levels up from the component that is being tested (HamburgerIcon).
When I first tried to run this, I was using Enzyme's shallow, and I since changed it to mount thinking that this would give the test access to the showOverlay function, but I was wrong.
Then I read that this might be a good use case for a mock function, and I tried to start implementing this:
...
const showOverlay = jest.fn();
// how to set this.props.ShowOverlay to the const above??
test('has div with class .closed', () => {
const wrapper = mount(<HamburgerIcon />);
const hamburgerIcon = wrapper.find('div#mobile-nav');
hamburgerIcon.simulate('click');
});
This is where I am sort of lost -- I'm not sure if mock functions are the right direction here, and I'm also not sure how the syntax of setting up the mock function will work.
Continue with shallow if you're just unit testing a single component. If this component is nested and you're testing against child nodes, then you'll mount the parent.
That said, you're on the right track for using a mock function. Simply pass it into the component like so:
<HamburgerIcon showOverlay={showOverlay} />
For example:
const showOverlay = jest.fn();
test('shows an overlay', () => {
const wrapper = mount(<HamburgerIcon showOverlay={showOverlay} />);
const hamburgerIcon = wrapper.find('div#mobile-nav');
hamburgerIcon.simulate('click');
expect(showOverlay).toHaveBeenCalled();
});
If you have multiple props, then I like to do something more declarative:
// define props here if you want an easy way check if they've been
// called (since we're defining at the top-level, all tests have access
// to this function)
const showOverlay = jest.fn();
// then include them in an "initialProps" object (you can also just define
// them within this object as well, but you'll have to use
// "initialProps.nameOfFunction" to check if they're called -- kind of
// repetitive if you have a lot of props that you're checking against)
const initialProps = {
showOverlay,
someOtherFunction: jest.fn()
}
// use the spread syntax to pass all the props in the "initialProps" object
// to the component
test('shows an overlay', () => {
const wrapper = mount(<HamburgerIcon { ...initialProps } />);
const hamburgerIcon = wrapper.find('div#mobile-nav');
hamburgerIcon.simulate('click');
expect(showOverlay).toHaveBeenCalled(); // here we can just use the mock function name
expect(initialProps.someOtherFunction).toHaveBeenCalledTimes(0); // here we'll have to use "initialProps.property" because it has been scoped to the object
});

Which unit test set up is correct? Are both tests checking if the function is right and working correctly?

I just started doing some unit testing for React JS - using Jest / enzyme.
I would like to know which test (format) is more useful and correct to use for future tests. These are 2 different tests that I'm working on it at the moment.
Unit test 1 : I was writing most of my tests based on this set up
import React from 'react';
import Enzyme from 'enzyme';
import { shallow} from 'enzyme';
import EditWorkflow from './EditWorkflow';
import Adapter from 'enzyme-adapter-react-15';
//render must import shallow = method to show object structure
//Unit Test V
Enzyme.configure({ adapter: new Adapter() })
describe ('<Workflow />', () => {
it( 'renders 1 <Workflow /> Component', () => {
const Component = shallow(<EditWorkflow name= "workflow"/>);
expect(Component).toHaveLength(1);
});
describe('It renders props correctly', () => {
const Component = shallow(<EditWorkflow name= "workflow"/>);
expect(Component.instance().props.name).toBe('workflow');
})
});
**Unit test 2
Different way to write an unit test****
import React from 'react';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
import { Login } from './App';
import renderer from 'react-test-renderer';
Enzyme.configure({adapter: new Adapter()});
let wrapper;
let defaultProps = {
getSessionContext: jest.fn(),
checkSession: jest.fn(),
}
let mockCheckSession;
describe('Login', () => {
beforeEach(() => {
mockCheckSession = jest.fn(()=>{return true})
defaultProps = {
getSessionContext: jest.fn(),
checkSession: mockCheckSession,
}
})
it('should render "authorizing..." if theres no session ', () => {
mockCheckSession = jest.fn(()=>{return false})
defaultProps.checkSession = mockCheckSession;
const tree = renderer
.create(<Login {...defaultProps} />)
.toJSON();
expect(tree).toMatchSnapshot();
})
it('should render null if there is a session ', () => {
mockCheckSession = jest.fn(()=>{return true})
defaultProps.checkSession = mockCheckSession;
const tree = renderer
.create(<Login {...defaultProps}/>)
.toJSON();
expect(tree).toMatchSnapshot();
})
})
Since you're not providing the full code, it's hard to help you with your current component. Here are some general tips:
One of the goals of writing (good) unit tests for your React components, is to make sure your component behaves and renders as you want it to do. What I usually do, in this part there is no right or wrong, is start reading the render function from top to bottom and take note of each logical part.
Example #1:
Simply test if the className is set on the right element.
class Screen extends Component {
render() {
return (
<div className={this.props.className}>
<h1>My screen</h1>
</div>
);
}
}
it('should set the className on the first div', () => {
const wrapper = shallow(<Screen className="screen" />);
expect(wrapper.hasClass('screen')).toBeTruthy();
});
Example #2:
If the component renders a part conditionally, you want to test both cases.
class Screen extends Component {
render() {
return (
<div className={this.props.className}>
<h1>My screen</h1>
{this.props.subheading ? <h4>{this.props.subheading}</h4> : null}
</div>
);
}
}
it('should not render the subheading when not given by prop', () => {
const wrapper = shallow(<Screen />);
expect(wrapper.find('h4').exists()).toBeFalsy();
});
it('should render the subheading when given by prop', () => {
const wrapper = shallow(<Screen subheading="My custom subheading!" />);
expect(wrapper.find('h4').exists()).toBeTruthy();
expect(wrapper.find('h4').text()).toEqual('My custom subheading!');
});
I can give some more examples, but I think you'll get the idea.

Using Jest and Enzyme, how do I test a function passed in through props?

Using Jest and Enzyme, how can I test if this.props.functionToTest was run?
class TestComponent extends Component {
static propTypes = {
functionToTest: PropTypes.func
}
componentDidMount() {
this.props.functionToTest()
}
}
In Jest, I've tried creating mockProps and passing them in when mounting the component.
let props = {
functionToTest = jest.fn(() => {});
}
beforeEach(() => {
const wrapper = mount(<TestComponent {...props} />
}
A console.log in the componentDidMount function shows functionToTest as undefined. Obviously passing in the props during mount isn't working.
Question 1: How can I pass in mock props that will show in the componentDidMount function?
Question 2: Once that function is available, how do I gain access to the function so I can use spyOn or something similar to test if the function was run?
I don't know your exact setup, but this is how I would do that:
Mock the function with jest.fn() like you did
Pass mock to the component being mounted (like apparently you did)
Check whether it was run with expect(...).toBeCalled() or .toHaveBeenCalled() (varies between different Jest versions)
.
let props = {
functionToTest: jest.fn() // You don't need to define the implementation if it's empty
};
beforeEach(() => {
const wrapper = mount(<TestComponent {...props} />
}
// In the test code:
it('does something', () => {
expect(props.functionToTest).toBeCalled();
// OR... depending on your version of Jest
expect(props.functionToTest).toHaveBeenCalled();
});
The problem ended up being that TestComponent was only being exported within the Redux wrapper. Adding an export at the class level and destructuring it in the Jest test import, along with the solution Henrick posted above fixed it.

Testing React PropTypes with sinon

As an example I used Make React PropType warnings throw errors with enzyme.js + sinon.js + mocha.js.
I have a React component with one required prop:
class Pagination extends Component {
render() {
return (
... render some stuff
);
}
}
Pagination.propTypes = {
total: PropTypes.number.isRequired
};
And this is test for it:
describe('(Component) Pagination', () => {
before(() => {
sinon.stub(console, 'error', (warning) => { throw new Error(warning) })
})
after(() => { console.error.restore() })
it('render fails without props', () => {
shallow(<Pagination />);
});
it('render fails without props2', () => {
shallow(<Pagination />);
});
});
After running that tests first one crashes, but second - not. Tests are similar.
I think that the problem is that React throws warning messages only once.
How to avoid this?
I want to have 2 tests: one that will be crashed when no props is set, and second works fine with props.
You can find a workaround here:
Pagination.displayName = Math.random().toString();
You were apparently right that it is because of the same component, and if you do this before each test, then it tricks it. Just a hack, but it works. Apparently no better way.
P.S. I did it in beforeEach to not write it in each test myself.
P.P.S. random is not most reliable, since you can get the same name and it will fail, a guid or whatever can be used if it's not good enough, it's just an example.

Categories

Resources