Jest test onClick for util function - javascript

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();
});
})

Related

Wrapper is not defined in Jest

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');
});
});

Enzyme mount wrapper is empty after simulate('click') in ReactApp

I'm trying to test a registration component that has a Vertical Stepper with Jest/Enzyme and I keep hitting a wall when trying to simulate the user clicking "Next" .
expected behavior is to do nothing if the "Required" input fields are empty, however after doing the .simulate('click') following assertions fail with not finding any html in the wrapper.
The component is passed through react-redux connect() so I don't know if that would be related.
UserRegistration.js
import React from 'react';
import { connect } from 'react-redux';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step;
import StepLabel from '#material-ui/core/StepLabel;
import StepContent from '#material-ui/core/StepContent'
class UserRegistration extends React.Component {
constructor(props){
this.state = {
activeStep: 0,
inputData: {},
...
}
}
getStepContent = () => {
switch(this.state.activeStep)
case '...':
return
(<>
<input test-data="firstName"/>
...
</>);
...
}
render () {
const steps = ['Personal Info', 'Corporate Details', ...]
return (
<Stepper activeStep={this.state.activeStep} orientation="vertical">
{steps.map((label, index) => {
return (
<Step key={index}/>
<StepLabel>{label}</StepLabel>
<StepContent>
{this.getStepContent()}
<button data-test="btn-next" onClick={() => this.goNext()}> NEXT </button>
<button onClick={() => this.goBack()}> BACK </button>
)
}
}
</Stepper>
)
}
}
const mapStateToProps = () => {...}
const mapDispatchToProps = () => {...}
export default connect(mapStateToProps, mapDispatchToProps)(UserRegistration)
UserRegistration.test.js
const wrapper = mount(
<Provider store={store}
<UserCreate/>
</Provider>
)
it('Confirm REQUIRED fields rendered', () => {
expect(wrapper.find("input[data-test='firstName']").length).toEqual(1);
// PASS
});
it('Check if still on same step clicked NEXT with no user data', () => {
wrapper.find("button[data-test='btn-next']").simulate('click');
expect(wrapper.find("input[data-test='firstName']").length).toEqual(1);
// Expected value to equal: 1, Received: 0
})
Same outcome regardless of the element I'm looking up.
Any suggestions will be greatly appreciated.
You need to update. So you would change it:
it('Check if still on same step clicked NEXT with no user data', () => {
wrapper.find("button[data-test='btn-next']").simulate('click');
// Add this line
wrapper.update();
const button = wrapper.find("input[data-test='firstName']");
expect(button.length).toEqual(1);
// Expected value to equal: 1, Received: 0
});
Then the test should work as you intend.

Custom hook function not being called in React

I am trying to call my fetchPlants function, but I cannot see to figure out why it is NOT being called.
/screens/RecipeScreen.js
import usePlants from '../hooks/usePlants';
// Call our custom hook
const [fetchPlants, plantResults] = usePlants();
// ...other code...
<RecipeSearch
recipeSearch={recipeSearch}
onRecipeSearchChange={setRecipeSearch}
onRecipeSearchSubmit={() => fetchPlants(recipeSearch)}
/>
/components/RecipeSearch.js
const RecipeSearch = ({
onRecipeSearchChange,
onRecipeSearchSubmit,
recipeSearch,
}) => {
return (
console.log(recipeSearch); // This prints out nicely...
<View>
<View>
<TextInput
placeholder='Find a plant...'
value={recipeSearch}
onChangeText={onRecipeSearchChange}
onEndEditing={onRecipeSearchSubmit}
/>
</View>
</View>
);
};
/hooks/usePlants.js
import { useState, useEffect } from 'react';
import plantsApi from '../api/plants';
export default () => {
const [plantResults, setPlantResults] = useState([]);
const fetchPlants = async searchTerm => {
console.log('searchTerm... HERE IS THE QUERY', searchTerm); // this never gets hit
try {
const response = await plantsApi.get('').then(response => {
console.log(response);
setPlantResults(response);
});
} catch (err) {
console.log(err);
}
};
return [fetchPlants, plantResults];
};
I initially thought that maybe I was calling fetchPlants() too early (before recipeSearch had any state), but I don't think so, because it is still able to console.log(searchRecipe) properly.
Update it was working ALL along. When I was testing it with the iOS simulator I needed to hit the "ENTER" key on my computer because I am using the React Native onEndEditing prop.

Jest test validate data prop

I am new to jest and wanted to learn basics of how the test is written. How to write a simple test that validates uri contains/returns value?
renderProfileImage () {
const apiUrl = 'site.com'
const profileImagePath = this.props.data.field_profile_image
if (profileImagePath !== '') {
return <Image
style={styles.profile}
source={this.state.imageLoading ? require('../img/profileImagePlaceholder.png') : { uri: `${apiUrl}${profileImagePath}` }}
onLoadEnd={(e) => this.setState({ imageLoading: false })}
/>
}
say this.props.data.field_profile_image returns /photo.png
Remember that "React elements are plain objects":
import * as React from 'react';
import renderer from 'react-test-renderer';
import { MyComponent } from './path-to-your-component';
describe('renderProfileImage', () => {
it('should set the correct uri', () => {
const comp = renderer.create(<MyComponent data={{
field_profile_image: '/path-to-the-image'
}}/>).root.instance;
// element is just an object representing an <Image>...
const element = comp.renderProfileImage();
// ...so check that element.props.source was set correctly
expect(element.props.source).toEqual({ uri: 'site.com/path-to-the-image' });
});
});

How do I test methods of React components and include them in my Istanbul coverage?

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.

Categories

Resources