I'm trying to test one of my React components but receive the following error:
ReferenceError: wrapper is not defined
describe('TodaysHabits', () => {
let component;
beforeEach(() => {
wrapper = shallow( < TodayHabits / > );
});
test('it exists', () => {
expect(wrapper).toExist;
});
test('it contains an p tag', () => {
const p = wrapper.find('p');
expect(p.text()).toBe('this is display habits');
});
});
index.js
import React from 'react';
import moment from 'moment';
import './todayhabits.css';
class TodayHabits extends React.Component {
// This component will show the habits that the user has to complete this specific day
// To do this we need to make a api call to get all habits where they have the respective day as true in the sql
state = {
dailyHabits: [],
}
//for each habit, it will display a new habit component
//we need to pass a prop to each habit component containing that habit's id and title
displayHabits () {
return <p>this is display habits</p>
}
render() {
return (
<div id='dailyHabits'>
{ moment().format('dddd') }, <br/>
{ moment().format("Do MMMM YYYY") } <br/>
{this.displayHabits()}
<button onClick={() => { history.push(`/newHabit`) }}>Add a habit!</button>
</div>
)
}
}
export default TodayHabits;
I tried doing more research on fixing this error but it wasn't successful.
Can you try declaring wrapper as a variable?
You're not declaring the variable and directly assigning a value to it.
describe('TodaysHabits', () => {
let component;
let wrapper;
beforeEach(() => {
wrapper = shallow( < TodayHabits / > );
});
test('it exists', () => {
expect(wrapper).toExist;
});
test('it contains an p tag', () => {
const p = wrapper.find('p');
expect(p.text()).toBe('this is display habits');
});
});
Related
Hey guys I am facing issue while trying to add test case for onClick in MetaDetails.tsx file
utils.js
export const handlePrintLabelButtonClick = (
e,
rmaNumber,
labelUrl,
getReturnLabel
) => {
const rmaList = [];
e.preventDefault();
if (!labelUrl) {
// some logic
} else {
// some logic
}
};
PrintLabel.tsx
import { DefaultButton } from "some path";
import { AnchorWrapper, ButtonWrapper } from "./index.styles";
export const PrintLabelButton = ({
target,
url,
type,
text,
onClickHandle
}: PrintLabelButtonProps) => {
return (
<ButtonWrapper>
<AnchorWrapper
href={url}
target={target}
type={type}
>
<DefaultButton
tabIndex="0"
onClick={onClickHandle}
data-test="print-label-button"
>
{text}
</DefaultButton>
</AnchorWrapper>
</ButtonWrapper>
);
};
MetaDetails.tsx
// Some lines of code
import { PrintLabelButton } from "./printLabel";
import { handlePrintLabelButtonClick } from "utils";
export const OrderMetaDetails = () => {
// some logic
return(
//Some React code
{showPrintLabelButton && (
<PrintLabelButton
onClickHandle={e =>
handlePrintLabelButtonClick(e, rmaNumber, labelUrl, getLabel)
}
url={labelUrl}
target="_blank"
type="printLabel"
text={intl.formatMessage(messages.printLabelText)}
/>
)}
// Some React code
)
}
What I've tried
MetaDetails.test.tsx
test("Order Meta Details Print Label Click", () => {
const handlePrintLabelButtonClick = jest.fn();
const wrapper = mountWithIntl(
<OrderMetaDetails
getLabel={() => {}}
info={/*some data*/}
intl={/*intl*/ }
/>
);
const component = wrapper.find(`[data-test="print-label-button"]`).hostNodes();
component.simulate("click")
expect(handlePrintLabelButtonClick).toHaveBeenCalled();
});
Jest throws the following error
Error: expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
When running the test coverage, in the function coverage I see that the "handlePrintLabelButtonClick" in MetaDetails.tsx is shown as uncovered. I have tried other approaches as well but none worked. I am new to unit testing. Can someone please guide as to what is the correct approach.
Note 1: I am using react/#emotion
Note 2: I have commented or written text such as "some logic" since there are lots of unwanted lines.
Your source code still uses the original handlePrintLabelButtonClick function, not the mock function that you created in the test.
You need to mock the actual exported function, for example using jest.mock:
import { handlePrintLabelButtonClick } from './utils.js';
const mockHandlePrintLabelButtonClick = jest.fn();
// Mock the module.
jest.mock('./utils.js', () => {
handlePrintLabelButtonClick: mockHandlePrintLabelButtonClick
}
describe('something', () => {
test("Order Meta Details Print Label Click", () => {
const wrapper = mountWithIntl(
<OrderMetaDetails
getLabel={() => {}}
info={/*some data*/}
intl={/*intl*/ }
/>
);
const component = wrapper.find(`[data-test="print-label-button"]`).hostNodes();
component.simulate("click")
expect(mockHandlePrintLabelButtonClick).toHaveBeenCalled();
});
})
I'm new to React and to React unit testing. I have a component which loads some divs based on state set with useState. Inside useEffect, if a rejected promise is returned from a function then an error div should be shown instead. I want to test this scenario, but because initial state is set as error = false, the original divs are still shown instead.
My question is, how can I do this so that the test registers updated divs? I'm using Enzyme's mount(), but I've also tried it with shallow(). I've also verified that it's actually going into .catch() with some console.logs.
component:
export const Main = (props) => {
const [showLoadError, setShowLoadError] = useState(false);
const [loadError, setLoadError] = useState('');
React.useEffect(() => {
const { categories, actions } = props;
// retrieve categories from Db if they don't exist in state
if (categories.length === 0) {
actions.loadCategories().catch(err => {
setShowLoadError(true);
setLoadError(err.message);
})
} else {
setShowLoadError(false);
setLoadError('');
}
}, []);
return (
<>
{/* conditional show for error container if loading failed */}
{showLoadError &&
<div className="load-error">
Error loading categories. {loadError}
</div>
}
{/* conditional show for no Load error */}
{!showLoadError &&
<div className="grid-container grid-container--fit">
<div><CategoryContainer /></div>
<div><ItemContainer /></div>
<div><FileAssociationsContainer /></div>
</div>
}
</>
);
}
test:
import React from 'react';
import ConnectedApp, { Main } from './Main';
import { shallow, mount } from 'enzyme';
jest.mock("../category/CategoryContainer");
jest.mock("../item/ItemContainer");
jest.mock("../fileAssociations/FileAssociationsContainer");
describe("Main component", () => {
beforeEach(() => {
fetch.resetMocks()
});
test('should render error div after loadCategories fail', () => {
const categories = [];
const errMessage = {message: 'test error'}
const actions = {
loadCategories: jest.fn(() => {
return Promise.reject(errMessage);
})
};
const wrapper = mount(<Main categories={categories} actions={actions} />);
wrapper.setProps(); // rerenders
// expect there to be a load-error div
expect(wrapper.find('div').hasClass('load-error')).toBe(true)
// expect loadCategories to be called because component was passed in empty categories
expect(actions.loadCategories).toBeCalled();
});
});
I've tried wrapper.setProps(), wrapper.update() before my expects with no luck.
Additionally, this unit test gives a jest warning that An update to Main inside a test was not wrapped in act(...). This only happens if actions.loadCategories() returns a rejected promise. It does not do this when it returns a resolved promise. I've tried moving code into act() with no luck in removing the error, like such:
act(() => {
actions = {
loadCategories: jest.fn(() => {
return Promise.reject(errMessage);
})
};
wrapper = mount(<Main categories={categories} actions={actions} />);
wrapper.setProps(); // rerenders
});
Here my ReactJS' snippet:
const LoaderModal = dynamic(
() => import("~/modal/Loader/Loader"),
{ ssr: false }
)
export default class MyApp extends Component {
state={
displayLoader:false
}
componentDidMount(){
let specificChangeStart= Router.events.on('routeChangeStart', () => {
console.log("routeChangeStart")
this.setState({displayLoader:true})
})
let specificComplete = Router.events.on('routeChangeComplete', () => {
console.log("routeChangeComplete")
this.setState({displayLoader:false})
})
let specificError= Router.events.on('routeChangeError',() => {
console.log("routeChangeError")
this.setState({displayLoader:false})
})
}
render(){
let { Component, pageProps }=this.props
let {displayLoader}=this.state
return(
<LayoutContextProvider >
<Component {...pageProps}/>
{
displayLoader &&
<LoaderModal/>
}
</LayoutContextProvider>
)
}
}
I am using nextjs version 9.1.4.
As you can see the Router's events are stored in the componentDidMount() component lifecycle's stage. I have stored them in variable to make them specific from other declarations in my app. I have also tried without assigning them, the both method fail so far.
How can I make the Router works, is there a subtlety to be inform of here?
I am using React-Redux, in a connected component and I want to test if a particular component is rendered. In order for that component to render 2 things must be true:
ListUsers must be an empty array
The securityMode should be basic.
I have already defined the securityMode in my component Props, with no problem. But the ListUsers prop, is coming through redux.
function mapStateToProps(state) {
return {
securityMode: securityModeSelector(state),
usersList: state.users.list,
usersListFetching: state.users.listFetching
};
}
This is my component logic that should be tested:
renderNoResourceComponent = () => {
const { usersList, securityMode } = this.props;
const { selectedGroups } = this.state;
const filteredData = filterUserData(usersList, selectedGroups);
if (filteredData && filteredData.length === 0 && securityMode === 'BASIC') {
return (
<div className="center-block" data-test="no-resource-component">
<NoResource>
.............
</NoResource>
</div>
);
}
return null;
};
And this is the test I wrote:
describe('BASIC securityMode without Data', () => {
const props = {
securityMode: 'BASIC',
listUsers: () => {},
usersList: [] // This is the redux prop
};
it('should render NoResource component', () => {
const wrapper = shallow(<UsersOverviewScreen {...props} />);
const renderUsers = wrapper.find(`[data-test="no-resource-component"]`);
expect(renderUsers).toHaveLength(1);
});
});
But I get an error saying the userLists is not defined. How do I pass this redux prop so my component would pass. `I also need that prop for another set of tests, that needs data, which I need to mock.
Can someone guide me through this? Thank you..
What you want to do is export the component before its connocted to Redux and pass all the props it needs manually:
export class UsersOverviewScreen extends Component {
// ... your functions
render() {
return (
// ... your componont
);
}
}
function mapStateToProps(state) {
return {
securityMode: securityModeSelector(state),
usersList: state.users.list,
usersListFetching: state.users.listFetching
};
}
export default connect(mapStateToProps)(UsersOverviewScreen);
Now, in your tests you can import { UsersOverviewScreen } form 'path/to/UsersOverviewScreen';. You can create the props and pass it to the component like this:
const mockUsersLists = jest.fn(() => usersList || []);
const wrapper = shallow(<UsersOverviewScreen {...props} usersList={mockUsersLists} />);
I was wondering how I'm able to test the methods of my react components and include them in my Istanbul test coverage?
Edit: I'm using enzyme. Forgot to mention that.
For example, I have this component:
class SearchFormContainer extends Component {
static handleToggle = () => {
const filter = document.querySelector('.filter-container');
const root = document.getElementById('root');
if (filter.classList.contains('closed')) {
filter.classList.remove('closed');
filter.classList.add('opened');
root.classList.add('paused');
} else {
root.classList.remove('paused');
filter.classList.remove('opened');
filter.classList.add('closed');
}
};
updateQuantity = (e) => {
const { store } = this.props;
store.setQuantity(e.target.value);
}
updateStrength = (e) => {
const { store } = this.props;
store.setStrength(e.target.value);
}
updateCustomQuantity = (e) => {
const { store } = this.props;
let value = e.target.value || '';
if (!value) {
store.setPricingError('invalidquantity');
} else {
value = value.match(/\d+(\.)?(\d+)?/);
if (!value) {
value = '';
} else {
value = value[0];
}
if (parseFloat(value) <= 0) {
store.setPricingError('invalidquantity');
} else if (store.pricingError === 'invalidquantity') {
store.setPricingError(null);
}
}
store.setCustomQuantity(value);
}
render() {
const {
styleName,
openFilterLabel,
closeFilterLabel,
updateFilterLabel,
searchLabel,
quantityLabel,
strengthLabel,
zipLabel,
zipPlaceholder,
searchFormAnchor,
customQuantityPlaceholder,
store,
searchBar,
} = this.props;
const toggled = 'closed';
const { useCustomQuantity } = store;
let inputType = 'predefined';
if (useCustomQuantity) {
inputType = 'custom';
} else {
inputType = 'predefined';
}
const handleCustomInput = () => {
store.toggleUseCustomQuantity();
};
Here's a test I'm trying to run (note that I've assigned store and searchBar in the describe block.
it('calls upDateQuantity', () => {
sinon.spy(App.prototype, 'updateQuantity');
const updateQuantity = sinon.stub();
const component = shallow(<App
updateQuantity={updateQuantity}
store={store}
searchBar={searchBar}
openFilterLabel="Filter"
closeFilterLabel="Close"
updateFilterLabel="UPDATE"
searchLabel="Medication Name"
quantityLabel="Quantity"
strengthLabel="Strength"
zipLabel="ZIP code"
zipPlaceholder="11111"
searchFormAnchor="SearchForm"
name="search-field"
placeholder="Search drug name..."
customQuantityPlaceholder="Enter Custom Quantity"
/>);
component.find('#quantitySelector').simulate('click');
expect(App.updateQuantity.callCount).to.equal(1);
});
I'm not sure if this will even test the actual function, seems like it will just test to see if the event was fired? I'm getting the error:
TypeError: Attempted to wrap undefined property updateQuantity as function.
I'm not sure how to test certain methods above, such as handleToggle, updateQuantity, UpdateStrength, etc. My react testing skills are young, so any assistance is greatly appreciated. Thank you!
I would suggest using enzyme to render the react component within your test and proceed as follow. You can then test your component methods directly with:
const component = shallow(<MyComponent {...props} />)
component.instance().myMethod()
Or if you need to trigger an event on your component, you can do as follow:
import {shallow} from 'enzyme'
import ButtonControl from '../ButtonControl'
describe('ButtonControl component', () => {
it('handleClick', () => {
let onClickHandler = jest.fn()
let props = { handleClick: onClickHandler }
let component = shallow(<ButtonControl {...props} />)
component.find('button').first().props().onClick()
expect(onClickHandler).toHaveBeenCalled()
})
})
this test use jest plus code coverage. Enzyme is compatible with jasmine, it should be easy to adapt.