How to find a component inside another component in jest? - reactjs

I want to find a component inside another component in Jest. After finding the component The length should be 1 but I am getting 0 length.
Test cases code is as follows -
beforeEach(() => {
wrapper = enzyme.mount(
<Rest
onApplyClick={mockOnApplyClick}
translateFn={mockTranslateFn}
someData={mockSomeData}
/>
);
});
and then we have test case -
it('Test case', () => {
let Button= wrapper.find(Button);
Button.simulate('click');
expect(wrapper.find(StyledPopover).prop('open')).toBe(true);
act(() => {
let newWrapper = wrapper
.find(<NewComponent {...props} myData={mockMyData[1]} />)
expect(newWrapper.length).toBe(1);
console.log(newWrapper.length, "newWrapper.length")
});
});
I am getting 0 length in console.log(newWrapper.length) But if we are passing let newWrapper = wrapper.find(NewComponent) Then I am getting length 1. So how to resolve this issue as I want to pass props to NewComponent so that I can find some other elements inside NewComponent.

Related

Unable to find an element with React testing library testing a ternary operator

In my React component <MyBlock /> I have the following conditional rendering:
So when variant="one" prop is passed it will return <Container /> component, when variant="two" is passed it will render <Scroller />.
{variant === 'one' ? (
<Container items={items} testId="container" />
) : (
<Scroller items={items} testId="scroller" />
)}
With React testing library I am testing this component:
it('should render the container correctly', () => {
const { getByTestId } = mount(<MyBlock data={MockData} variant="one" />);
expect(getByTestId('container')).toBeDefined();
});
This test pass and works fine.
Now I want to test the other variant:
it('should render the container correctly', () => {
const { getByTestId } = mount(<MyBlock data={MockData} variant="two" />);
expect(getByTestId('scroller')).toBeDefined();
});
But then I get:
Unable to find an element by: [data-testid="scroller"]
What's the issue here?
I figured out. I have to use queryByTestId instead of getByTestId:
it('should render the container correctly', () => {
const { queryByTestId } = mount();
expect(queryByTestId('scroller')).toBeDefined();
});
Now it's working fine for both.

Jest function call for functional component gives error on stimulate click

I have imported a table component in a different component file and I am passing props form the parent component.
TableWrapper.js
const handleRowClick = rowData => {
// function data
}
<TableRender onRowClick={handleRowClick} id={'AUDIT'} />
I am writing test cases for this kind of function as I want this function to be covered and pass the data to it rowData
testFile.js
import React from 'react';
import { shallow } from 'enzyme';
it('handle row click is called', () => {
const handleRowClick = jest.fn();
const wrapper = shallow(<TableWrapper {...props} onRowClick={handleRowClick} />);
const rowClickFunction = wrapper.find('.ra--audit-table__content');
rowClickFunction.simulate('handleRowClick');
expect(handleRowClick).toBeTruthy();
})
If I do this then it passes the test case but does not cover the function in coverage.
testFile.js
import React from 'react';
import { shallow } from 'enzyme';
it('handle row click is called', () => {
const handleRowClick = jest.fn();
const wrapper = shallow(<TableWrapper {...props} onRowClick={handleRowClick} />);
const rowClickFunction = wrapper.find('.ra--audit-table__content');
rowClickFunction.simulate('handleRowClick');
expect(rowClick).toHaveBeenCalledTimes(1);
})
If I do this change it gives me an error:-
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
I want this function to b covered.
Any Idea for this?
you are simulating wrong event. you should simulate click.
change:
const rowClickFunction = wrapper.find('.ra--audit-table__content');
rowClickFunction.simulate('handleRowClick');
to:
const elem = wrapper.find('.ra--audit-table__content');
elem.simulate('click');
(also make sure the clickable element has a .ra--audit-table__content class)
you are creating wrong component. you should create a TableRender, not TableWrapper.
change:
const wrapper = shallow(<TableWrapper {...props} onRowClick={handleRowClick} />);
to:
const wrapper = shallow(<TableRender onRowClick={handleRowClick} />);
Code (testFile.js) :
it('handle row click is called', () => {
const handleRowClick = jest.fn((i) => {console.log(`row ${i} clicked`)});
const wrapper = shallow(<TableRender onRowClick={handleRowClick} />);
const elem = wrapper.find('.ra--audit-table__content');
elem.simulate('click');
// expect(handleRowClick).toBeTruthy();
expect(handleRowClick).toHaveBeenCalledTimes(1);
})
Ps: i tested it and it works fine.

How to simulate a click on a Font Awesome Icon using Jest?

I'm testing through Jest and am trying to test the click on a Font Awesome Icon. I've tried different ways to find the 'node', but I get the error that "Method “simulate” is meant to be run on 1 node. 0 found instead." Any insight would be helpful.
The error I get when I try different inputs to component.find() is: Method “simulate” is meant to be run on 1 node. 0 found instead.
StringEditor
const clearInput = () => {
onRemove()
}
render (
...
<FontAwesomeIcon icon={['fal', 'times-circle']} className="clear-button"
onClick={clearInput} /> : null`
)
onRemove is a callback function.
it('should call clearInput thus onRemove', () =>{
const onRemove= jest.fn()
const component = mount(<StringEditor {...defaultProps} onRemove={onRemove} />)
component.find('<dont know what to put>').simulate('click')
expect(saveValueFn).toBeCalled()
})
Try this:
it('should call clearInput thus onRemove', () =>{
const onRemove= jest.fn()
const component = mount(<StringEditor {...defaultProps} onRemove={onRemove} />)
component.find({ className: "clear-button" }).simulate('click');
expect(clearInput).toHaveBeenCalled();
})
You can use the Object Property Selector: https://airbnb.io/enzyme/docs/api/selector.html#4-object-property-selector
Or a React Component Constructor: https://airbnb.io/enzyme/docs/api/selector.html#2-a-react-component-constructor

Jest/Enzyme Shallow testing RFC - not firing jest.fn()

I'm trying to test the onChange prop (and the value) of an input on an RFC. On the tests, trying to simulate the event doesn't fire the jest mock function.
The actual component is connected (with redux) but I'm exporting it also as an unconnected component so I can do a shallow unit test. I'm also using some react-spring hooks for animation.
I've also tried to mount instead of shallow the component but I still get the same problem.
MY Component
export const UnconnectedSearchInput: React.FC<INT.IInputProps> = ({ scrolled, getUserInputRequest }): JSX.Element => {
const [change, setChange] = useState<string>('')
const handleChange = (e: InputVal): void => {
setChange(e.target.value)
}
const handleKeyUp = (): void => {
getUserInputRequest(change)
}
return (
<animated.div
className="search-input"
data-test="component-search-input"
style={animateInputContainer}>
<animated.input
type="text"
name="search"
className="search-input__inp"
data-test="search-input"
style={animateInput}
onChange={handleChange}
onKeyUp={handleKeyUp}
value={change}
/>
</animated.div>
)
}
export default connect(null, { getUserInputRequest })(UnconnectedSearchInput);
My Tests
Here you can see the test that is failing. Commented out code is other things that I-ve tried so far without any luck.
describe('test input and dispatch action', () => {
let changeValueMock
let wrapper
const userInput = 'matrix'
beforeEach(() => {
changeValueMock = jest.fn()
const props = {
handleChange: changeValueMock
}
wrapper = shallow(<UnconnectedSearchInput {...props} />).dive()
// wrapper = mount(<UnconnectedSearchInput {...props} />)
})
test('should update input value', () => {
const input = findByTestAttr(wrapper, 'search-input').dive()
// const component = findByTestAttr(wrapper, 'search-input').last()
expect(input.name()).toBe('input')
expect(changeValueMock).not.toHaveBeenCalled()
input.props().onChange({ target: { value: userInput } }) // not geting called
// input.simulate('change', { target: { value: userInput } })
// used with mount
// act(() => {
// input.props().onChange({ target: { value: userInput } })
// })
// wrapper.update()
expect(changeValueMock).toBeCalledTimes(1)
// expect(input.prop('value')).toBe(userInput);
})
})
Test Error
Nothing too special here.
expect(jest.fn()).toBeCalledTimes(1)
Expected mock function to have been called one time, but it was called zero times.
71 | // wrapper.update()
72 |
> 73 | expect(changeValueMock).toBeCalledTimes(1)
Any help would be greatly appreciated since it's been 2 days now and I cn't figure this out.
you don't have to interact with component internals; instead better use public interface: props and render result
test('should update input value', () => {
expect(findByTestAttr(wrapper, 'search-input').dive().props().value).toEqual('');
findByTestAttr(wrapper, 'search-input').dive().props().onChange({ target: {value: '_test_'} });
expect(findByTestAttr(wrapper, 'search-input').dive().props().value).toEqual('_test_');
}
See you don't need to check if some internal method has been called, what's its name or argument. If you get what you need - and you require to have <input> with some expected value - it does not matter how it happened.
But if function is passed from the outside(through props) you will definitely want to verify if it's called at some expected case
test('should call getUserInputRequest prop on keyUp event', () => {
const getUserInputRequest = jest.fn();
const mockedEvent = { target: { key: 'A' } };
const = wrapper = shallow(<UnconnectedSearchInput getUserInputRequest={getUserInputRequest } />).dive()
findByTestAttr(wrapper, 'search-input').dive().props().onKeyUp(mockedEvent)
expect(getUserInputRequest).toHaveBeenCalledTimes(1);
expect(getUserInputRequest).toHaveBeenCalledWith(mockedEvent);
}
[UPD] seems like caching selector in interm variable like
const input = findByTestAttr(wrapper, 'search-input').dive();
input.props().onChange({ target: {value: '_test_'} });
expect(input.props().value).toEqual('_test_');
does not pass since input refers to stale old object where value does not update.
At enzyme's github I've been answered that it's expected behavior:
This is intended behavior in enzyme v3 - see https://github.com/airbnb/enzyme/blob/master/docs/guides/migration-from-2-to-3.md#calling-props-after-a-state-change.
So yes, exactly - everything must be re-found from the root if anything has changed.

How to unit test addTodo in redux app?

I am trying this example :
https://github.com/reactjs/redux/tree/master/examples/todomvc
Based in this solution I have created a unit test that looks like this:
it('should call addTodo if length of text is greater than 0', () => {
const props = {
addTodo: jest.fn()
}
let cb = shallow(<Header {...props} />)
expect(props.addTodo).not.toBeCalled()
cb.find('TodoTextInput').simulate("onSave",{text:"fsdhsd"});
//error starts here:
expect(props.addTodo).toBeCalled()
});
The result of this one is :
FAIL src/components/NewHeaderTest.spec.js
●
Header enzyme style › should call addTodo if length of text is greater than 0
expect(jest.fn()).toBeCalled()
Expected mock function to have been called.
at Object.it (src/components/NewHeaderTest.spec.js:46:27)
This is part of the component:
handleSave = text => {
console.log('handlesave');
if (text.length > 0) {
this.props.addTodo(text);
}
}
render = () => {
return (
<header className="header">
<TodoTextInput onSave={this.handleSave}>
</TodoTextInput>
</header>)
}
How can I fix the unittest or how to pass in an argument for the simulate statement: cb.find('TodoTextInput').simulate("onSave",{text:"fsdhsd"});

Resources