I have a component like this:
component.js
import React from "react";
import PropTypes from "prop-types";
const Test = ({ text }) => (
<div>
{text.split("\n").map((item, key) => {
return (
<span key={key}>
{item}
<br />
</span>
);
})}
</div>
);
Test.propTypes = {
text: PropTypes.string.isRequired
};
export default Test;
How do i write component test for this react component using enzyme? I am new to react and enzyme. Any help will really appreciable.
This could be a test using mocha:
import {shallow} from 'enzyme'
import assert from 'assert'
import Test from './Test'
describe('component Test', () => {
it('should show a span for each line of "text" prop', () => {
const text = `foo
bar
`
const wrapper = shallow(<Test text={text} />)
const spans = wrapper.find('span')
assert.equal(spans.length, 2)
assert.equal(spans.at(0).text(), 'foo')
assert.equal(spans.at(1).text(). 'bar')
})
it('should throw if "text" prop is not provided', () => {
assert.throws(() => {
shallow(<Text />)
})
})
})
Here is shamelessly taken example of testing dom using enzyme + jest (from jest web site):
// __tests__/CheckboxWithLabel-test.js
import React from 'react';
import {shallow} from 'enzyme';
import CheckboxWithLabel from '../CheckboxWithLabel';
test('CheckboxWithLabel changes the text after click', () => {
// Render a checkbox with label in the document
const checkbox = shallow(
<CheckboxWithLabel labelOn="On" labelOff="Off" />
);
expect(checkbox.text()).toEqual('Off');
checkbox.find('input').simulate('change');
expect(checkbox.text()).toEqual('On');
});
I recommend you to go though the link I gave - it contains nice examples of testing react components using Jest + Enzyme.
Related
I have written test case for the post.js to find 3 p tag but it's throwing an error. How do I properly test this component?
Post.js
import React from 'react';
import './Post.css';
const Post = (props) => {
const displayPosts = (props) => {
const { posts } = props;
if ( posts.length > 0 ){
return(
posts.map( (post) => {
return(
<div className = "Post">
<p className = "name"> <b>Name :</b> {post.name}</p>
<p className = "email"> <b> Email :</b> {post.email}</p>
<p className = "body"> <b> Body :</b> {post.body}</p>
</div>
)
})
)
}
}
return (
<div className = "Posts">
{ displayPosts(props) }
</div>
)
}
export default Post;
Post.test.js
import React from "react";
import Adapter from "enzyme-adapter-react-16";
import { shallow, configure } from "enzyme";
import Post from "./Post";
configure({ adapter: new Adapter() });
describe("Post", () => {
it("includes three paragraphs", () => {
const wrapper = shallow(<Post />);
expect(wrapper.find("p")).toHaveLength(3);
});
});
I'm new to testing myself. However, at a quick glance your testing from a shallow perspective while your 'p' tags are actually rendered/nested deeper (in your 'displayPosts' component) than where you are testing. I would bet that if you console.log the wrapper object in your test code you would see a single div logged.
From the enzyme docs: "Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components."
I have a component with an input like this:
const myComponent = () => {
return (
<h2>My component</h2>
<input type="text" value="initial"/>
)
}
export default MyComponent;
I am trying to test value change in this component using Enzyme and Jest like below.
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from '../src/MyComponent';
describe('MyComponent', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<MyComponent />);
});
it('changes the input', () => {
wrapper.find('input').simulate('change', {target: {value: 'new value' }});
expect(wrapper.find('input').prop('value')).toBe('new value');
});
});
The problem is that the value is still ''. I have tried to do wapper.update() or wrapper.setProps({}) but the value does not change. What's wrong ??
The problem was that I wasn't changing the value. My component should de like the following code:
import {React, useState} from 'react';
const myComponent = () => {
const [value, setValue[ = useState('');
return (
<h2>My component</h2>
<input type="text" value={value} />
)
}
export default MyComponent;
It's My first Nextjs project with SSR.
When Integrating Enzyme For Reactjs UI Testing. it could not run due to "React' refers to a UMD global, but the current file is a module. Consider adding an import instead."
but it's works when i am using normal Reactjs Component(Functional or Class). Anyone Please give suggestions.
SandBox Link - https://codesandbox.io/s/currying-moon-gdk09
Full code From GitHub - https://github.com/Rizz13/nextJs-with-Enzyme
to run testing Use "npm test"
pages/Index.tsx
import Head from 'next/head'
import Link from 'next/link'
import { GetStaticProps } from 'next'
export default function Home({
allPostsData
}: {
allPostsData: {
title: string
id: string
}[]
}) {
return (
<>
<Head>
<title>Sample Page</title>
</Head>
<section className="icon-stars">
<p>[Your Self Introduction]</p>
<p>
(This is a sample website - you’ll be building a site like...)
</p>
</section>
<section>
<h2>Blog</h2>
<ul>
{allPostsData.map(({ id, title }) => (
<li key={id}>
<Link href="#">
<a>{title}</a>
</Link>
<br />
</li>
))}
</ul>
</section>
</>
)
}
export const getStaticProps: GetStaticProps = async () => {
const allPostsData = [{id: 0, title:"Sample1"}, {id: 1, title:"Sample2"}]
return {
props: {
allPostsData
}
}
}
_tests_/Index.tsx
import * as React from 'react'
import { expect as expect1 } from 'chai';
import IndexPage from '../pages/index'
import {/*mount,*/ shallow} from 'enzyme'
const setUp1 = (data) => {
return shallow(<IndexPage {...data} />);
}
let wrapper;
describe('props Check', () => {
beforeEach(() => {
wrapper = setUp1({});
});
it('should render an `.icon-stars`', () => {
expect1(wrapper.find('.icon-stars')).to.have.length(1);
});
});
When I using the Above Code Testing could not run due to below Error.
tests/Index.tsx
import * as React from 'react'
import { expect as expect1 } from 'chai';
import IndexPage from '../pages/index'
import {/*mount,*/ shallow} from 'enzyme'
const setUp1 = (data) => {
return shallow(<IndexPage {...data} />);
}
let wrapper;
describe('props Check', () => {
beforeEach(() => {
wrapper = setUp1(allPostsData={[]});
});
it('should render an `.icon-stars`', () => {
expect1(wrapper.find('.icon-stars')).to.have.length(1);
});
});
You have to pass props inside the testing component & use
import * as React from 'react'
In pages/Index.tsx for rendering react components
Im a bit new to the react ecosytem. Im having a weird behaviour with passing tests.
Im using CRA, prop-types and react-test-library.
Here is my component:
import React from 'react';
import PropTypes from 'prop-types';
export default function Navbar({
Logo, MenuItems, className,
}) {
return (
<nav aria-label="navigation bar" className={className}>
{Logo}
<div>
{ MenuItems.map((MenuItem) => MenuItem) }
</div>
</nav>
);
}
Navbar.defaultProps = {
className: '',
};
Navbar.propTypes = {
className: PropTypes.string,
Logo: PropTypes.node.isRequired,
MenuItems: PropTypes.arrayOf(PropTypes.node).isRequired,
};
I want to test that prop-types complains when params are not receiving the right type.
import React from 'react';
import { render } from '#testing-library/react';
import Navbar from './Navbar';
describe('<Navbar />', () => {
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => {});
});
beforeEach(() => {
console.error.mockClear();
});
afterAll(() => {
console.error.mockRestore();
});
it('renders', () => {
render(<Navbar
Logo={<p data-test="logo">My logo</p>}
MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">english</p>,
]}
/>);
expect(console.error).not.toHaveBeenCalled();
});
it('errors to console when Logo is missing', () => {
render(<Navbar MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">English</p>,
]}
/>);
expect(console.error).toHaveBeenCalled();
});
it('does not error to console when Logo is missing', () => {
render(<Navbar MenuItems={[
<p key="spanish">Spanish</p>,
<p key="english">English</p>,
]}
/>);
expect(console.error).toHaveBeenCalled();
});
});
My thinking is that Im not resetting properly the mocks, they have some state that it is not clear or something similar.
What am i missing?
PropTypes.checkPropTypes(...) only console.errors a given message once. To reset the error warning cache in tests, call PropTypes.resetWarningCache()
Source
Try invoke resetWarningCache in your beforeEach hooks
import PropTypes from 'prop-types';
beforeEach(() => {
PropTypes.resetWarningCache()
});
How would i be able to unit-test onChange method on this component.
Comment.js
import React from "react";
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
const Comment = (props) => (
<div>
<form onSubmit={props.onSubmit}>
<TextField
type="text"
id="outlined-multiline-static"
label="Write A Comment"
multiline
name="comment_body"
value={props.commentBody}
rows="10"
fullWidth
margin="normal"
variant="outlined"
onChange={props.commentChange}
/>
{/* <Button type="submit" variant="outlined" component="span" color="primary">
Post A Comment
</Button> */}
<button type="submit" variant="outlined" component="span" color="primary">
Write a Comment
</button>
</form>
</div>
)
export default Comment;
This is my attempt to unit test the onChange component, getting a
Method “simulate” is meant to be run on 1 node. 0 found instead
around this line
const component = shallow(<Comment commentChange={onChangeMock} commentBody={'test'} />)
component.find('input').simulate('change');
Comment.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import { shallow } from 'enzyme';
import Comment from './Comment';
describe('Should render <Comment/> component', () => {
it('Should render form', () => {
const wrapper = shallow(<Comment/>)
// wrapper.find('Form').at(0)
expect(wrapper.find("form")).toHaveLength(1); // checks if there is a form.
})
it('Should render button', () => {
const wrapper = shallow(<Comment/>)
expect(wrapper.find('button')).toHaveLength(1);
})
it('should check for onChange method', () => {
// const wrapper = shallow(<Comment onChange={}/>)
const onChangeMock = jest.fn();
// const event = {
// preventDefualt(){},
// target: {
// value: 'testing'
// }
// }
const component = shallow(<Comment commentChange={onChangeMock} commentBody={'test'} />)
component.find('input').simulate('change');
expect(onChangeMock).toBeCalledWith('test')
})
})
The Comment component is being passed in another component like this:
ImageContainer.js
state = {
isComment: false,
comment_body: ""
}
handleCommentChange = (e) => {
this.setState({
comment_body: e.target.value
})
}
commentSubmit = (event, id) => {
event.preventDefault();
console.log(this.state.comment_body); // doesn't get console.log
// note that commentBody is being used for the req.body as well so its called by req.body.commentBody
const commentBody = this.state.comment_body
const data = {
commentBody,
id
}
this.props.postComment(data);
this.setState({
comment_body: ''
})
}
<Comment onSubmit={(e) => this.commentSubmit(e, img.id)}
commentBody={this.state.comment_body }
commentChange={this.handleCommentChange}/>
The reason you are having the error is because when you call component.find('input') it returns an array of matched components, so what you want to do is
component.find('input').at(0).simulate('change')
However, there is another way you can test this, which is my preferred method.
component.find('input').at(0).props().onChange()
Below is the correct way to do the test with both methods
import React from "react";
import Enzyme, { shallow } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import Comment from "./Comment";
import TextField from "#material-ui/core/TextField";
Enzyme.configure({ adapter: new Adapter() });
describe("Should render <Comment/> component", () => {
it("should check for onChange method (1)", () => {
// const wrapper = shallow(<Comment onChange={}/>)
const onChangeMock = jest.fn();
const component = shallow(
<Comment commentChange={onChangeMock} commentBody={"test"} />
);
component
.find(TextField)
.at(0)
.simulate("change", "test");
expect(onChangeMock).toBeCalledWith("test");
});
it("should check for onChange method (2)", () => {
// const wrapper = shallow(<Comment onChange={}/>)
const onChangeMock = jest.fn();
const component = shallow(
<Comment commentChange={onChangeMock} commentBody={"test"} />
);
component
.find(TextField)
.at(0)
.props()
.onChange();
expect(onChangeMock).toBeCalled();
});
});
For this particular test it will be better if you just use toBeCalled rather than toBeCalledWith. There is no need to test the value it is called with.