I have the following onClick function
onClickFunction= index => () => {
this.setState({ activeIndex: index });
}
Which is used in the following function
getPersons= (persons) => persons
.map((person, index) => (
<StyledComponentHeader
key...
...
onClick={this.onClickFunction(index)}
>
<Styled2
...
>
{person.name}
</Styled2>
</StyledComponentHeader>
))
in my unit test I need to test the onClickFunction. currently I have something like this
const component= (
<StyledComponent
persons={persons}
/>);
describe('...', () => {
beforeEach(() => {
wrapper = shallow(component);
});
it('testing name', () => {
expect(wrapper).toMatchSnapshot();
expect(wrapper.state().activeIndex).toEqual(0);
wrapper.instance().onClickFunction(1);
expect(wrapper.state().activeIndex).toEqual(1);
});
it returns saying that the above last except should be 0. What is the correct way to test this function?
Since onClickFunction does not change the state, but returns a function which if called then changes the state, the logical way would be to test it with
wrapper.instance().onClickFunction(1)();
(notice the added () at the end to invoke the returned function)
Related
I have a react table component that looks like this:
<DataTableBodyV2>
{
workGroups.order.map((rowKey, index) => {
const rowData = workGroups.items[rowKey];
return (
<DataTableRowV2
rowIndex={index + 2}
key={`${rowKey}x`}
id={`${rowKey}x`}
expandButtonLabel="expand-markets"
expanded={rowData.expanded}
>
{
workGroups.columns.map((column) => (
<DataTableCellV2
id={`resultTableRow${column}`}
key={column}
onClick={(event) => onRowClick(event, rowKey)} // TODO edit popup!!
>
{rowData[column]}
</DataTableCellV2>
))
}
<DataTableExpandableContentV2>
<ul>
<div id="markets">Markets</div>
<div id="markets">
{
rowData.marketList.map((mkt) => (
<li>{mkt.marketId}</li>
))
}
</div>
</ul>
</DataTableExpandableContentV2>
</DataTableRowV2>
);
})
}
</DataTableBodyV2>
Every cell in the table has an onClick function that sets a few pieces of state that allow a modal with another data table to render on the screen.
The OnRowClick function sets a selectId. that is used to key into my WorkGroups object and render the associated markets attached to a workgroup in the second table component. The OnRowClick function looks like:
const onRowClick = (event, key) => {
setSelectedId(key);
const row = workGroups.items[key];
setWorkgroupId(row.workGroupID);
setWorkgroupName(row.workGroupName);
setWorkgroupStatus(row.status);
setShowEditWorkgroup(true);
};
And the second component looks like:
<DataTableBodyV2>
{
workGroups.items[selectedId].marketList.map((marketObject, index) => {
console.log('XX', workGroups.items[selectedId]);
// const rowData = workGroupsDisplay.marketList[index]; // TODO
// const rowData = marketObject; // TODO working on
return (
<DataTableRowV2
key={`${marketObject.workgroupId}-${marketObject.marketId}`}
id={`${marketObject.workgroupId}-${marketObject.marketId}-${index}`}
// checked={workGroups.items[selectedWorkgroupId].checked}
checked={workGroups.items[selectedId].marketList[index].checked}
checkboxLabel={marketObject.workgroupId}
>
{
// table.columns.map((column) => (
tableEditDataColumns.items.map((column) => (
<DataTableCellV2
id={`editWGTableRow${column}`}
key={column}
>
{`${marketObject.marketId}: ${marketObject.marketName}`}
</DataTableCellV2>
))
}
</DataTableRowV2>
);
})
}
</DataTableBodyV2>
I have written the following enzyme unit test to test these components
it('edit workgroup - model success/default', async () => {
const renderedModule = mount(<SetupSubmissionsWorkgroup {...props} />);
await act(() => new Promise((resolve) => {
setImmediate(() => {
resolve();
});
}));
renderedModule.update(); expect(renderedModule.find('#resultTable').at(0).length).toEqual(1);
renderedModule.find('#resultTableRowworkGroupID').at(0).props().onClick({}, '001001');
await act(() => new Promise((resolve) => {
setImmediate(() => {
resolve();
resolve();
});
}));
renderedModule.update();
expect(renderedModule.find('#editModal').at(0).length).toEqual(1);
Interestingly, the test passes when the onRowClick function looks like this with the setSelectId line first
const onRowClick = (event, key) => {
setSelectedId(key);
const row = workGroups.items[key];
setWorkgroupId(row.workGroupID);
setWorkgroupName(row.workGroupName);
setWorkgroupStatus(row.status);
setShowEditWorkgroup(true);
};
But fails with when the onRowClick function looks like this with the setSelectId line last
const onRowClick = (event, key) => {
const row = workGroups.items[key];
setWorkgroupId(row.workGroupID);
setWorkgroupName(row.workGroupName);
setWorkgroupStatus(row.status);
setShowEditWorkgroup(true);
setSelectedId(key);
};
The error the test gives happens during the rendering of the second component and is below:
TypeError: Cannot read properties of undefined (reading 'marketList')
826 | <DataTableBodyV2>
827 | {
> 828 | workGroups.items[selectedId].marketList.map((marketObject, index) => {
Could someone please explain why this might be happening?
I am using function component where is there is a arrow function.
const handleOnConfig = (cfg) => {
const layout = { ...config };
setConfig(layout);
};
Now, I want to write unit test for that function.
So, I did following in my test file. I used
beforeEach(() => {
let props = {user:user}
view = shallow(<Views {...props} />).instance();
});
test('should call config change call back', () => {
const handleOnConfig = jest.spyOn(view,'handleOnConfig').mockImplementation(() => config);
expect(handleOnConfig).toHaveBeenCalledTimes(1);
});
But, this test case gives error:
TypeError: Cannot read property 'handleOnConfig' of null
Any help would greatly appreciated
Edit:
Views component
const Views = forwardRef(({ user, id }, ref) => {
useEffect(() => {
handleOnConfig();
}, []);
return (
<div>
<Component
user={user}
id={id}
name='Component'
/>
</div>
);
})
export default Views;
Not a problem with spyOn() directly: your view variable is null.
Try using .dive() in the return from shadow():
beforeEach(() => {
let props = {user:user}
view = shallow(<Views {...props} />).dive().instance(); // <-- added .dive()
});
I am trying to test the onClick but they are not being called using props:
here is part of the file.js
handleSystemClick = () => {
// var message = All unsaved changes will be lost.`
confirmAlert({
title: 'Confirm Navigation',
message: ' All unsaved changes will be lost.',
childrenElement: () => <div></div>,
confirmLabel: 'Confirm',
cancelLabel: 'Cancel',
onConfirm: () => {this.setState({ toSystemEntitlments: true})},
onCancel: () => {},
})
}
handleCancelClick = () => {
window.history.back();
}
here is render method of file.js
render()
return(
<div className='add-edit-button' id= 'test1' onClick={() => {this.handleSystemClick()}}>System</div>
<div className='add-edit-button' onClick={() => {this.handleCancelClick()}}>Cancel</div>
<div className='add-edit-button' onClick={() => {this.handleSave()}}>Save</div>
</div>
I have seen some examples here on stackoverflow and I tried to apply the following:
// jest mock functions (mocks this.props.func)
// defining this.props
const baseProps = {
describe(' FunctionalEntitlement Test', () => {
let wrapper;
let tree;
beforeEach(() => wrapper = shallow(<BrowserRouter><Component {...baseProps} /></BrowserRouter>));
it("should call handlesave function on button click", () => {
// Reset info from possible previous calls of these mock functions:
baseProps.handleSave.mockClear();
wrapper.setProps({
});
wrapper.setState({ getINITIAL_STATE:""
});
wrapper.find('.add-edit-button').at(0).simulate("click");
expect(baseProps.handleSave).toHaveBeenCalled();
expect(toJson(wrapper)).toMatchSnapshot();
});
Also How could I apply the same method for the first 2 clicks based on file.js
Thank you for the help
If you want to use shallow there is a way to get the shallow wrapper of one of the children using the dive method. If you have to wrap your components with BrowserRouter frequently on the test, maybe it's worth it to have a helper method for this like:
function shallowWithBrowserRouter(component) {
return shallow(<BrowserRouter>{component}</BrowserRouter>).childAt(0).dive();
}
Able to work something out but how could I improve the following answer.
Switched shallow to Mount in order to render children components
it("should call button click 3 times", () => {
// Reset info from possible previous calls of these mock functions:
wrapper.setProps({
});
wrapper.setState({
});
wrapper.find('.add-edit-button').at(0).simulate("click");
wrapper.find('.add-edit-button').at(1).simulate("click");
wrapper.find('.add-edit-button').at(2).simulate("click");
expect(toJson(wrapper)).toMatchSnapshot();
});
Good afternoon,
I have a component file structured like that globally :
class Component ...
render(){
const {array} = this.props
{!array.includes(value) ?
(<View ...props
id="myComponent"/>
....
</View>) :
(<View ...props
id="myOtherComponent"/>
....
</View>)
}
}
And in my test file, i'm doing the stuff like that :
describe('Testing Component', () => {
test('conditional rendering', () => {
const wrapper = shallow(<Component array={[value]}/>);
expect(wrapper.find(n => n.prop('id') === "myOtherComponent").exists(true))
});
});
But even if I modify the props sent for the array, it always returned me true... What's the keyword to check that the nested component is actually verified and rendered...
I think the error is in your expect argument.
I would use the findWhere function instead of find;
The exists method should not receive a parameter in this
case, as it only receives Enzyme's Selectors and not booleans (you can read more about it here);
Add a toBeTruthy call to the expect line.
Here's a similar situation to yours that we have a test for and it works just fine:
it('tests name', () => {
const mockComponent = shallow(<Component {...props} />);
const textNode = mockComponent.findWhere(n => n.text() === props.name);
expect(textNode.exists()).toBeTruthy();
});
So your test would end up looking like this:
describe('Testing Component', () => {
test('conditional rendering', () => {
const wrapper = shallow(<Component array={[value]}/>);
const node = wrapper.findWhere(n => n.prop('id') === 'myOtherComponent');
expect(node.exists()).toBeTruthy();
});
});
Say I have the following component:
export class ExampleComponent extends Component {
exampleMethod1 = () => {
console.log('in example 1')
}
exampleMethod2 = () => {
console.log('in example 2')
this.exampleMethod1()
}
render() {
return (
<TouchableOpacity id='touchable' onPress={exampleMethod2}><Text>Touchable</Text></TouchableOpacity>
)
}
}
This works exactly how you would expect. The button appears, and can be pressed. Both methods fire, and console log their text.
I now try to test this with jest:
describe('example tests', () => {
let wrapper
beforeEach(() => {
wrapper = shallow(<ExampleComponent/>)
})
it('this test fails. Interestingly both messages still print', () => {
const instance = wrapper.instance()
instance.exampleMethod2 = jest.fn()
wrapper.find('#touchable').simulate('press')
//wrapper.update() uncommenting this line has no effect.
expect(instance.exampleMethod2.mock.calls.length).toBe(1)
})
it('this test passes. Only the first message prints', () => {
const instance = wrapper.instnace()
instance.exampleMethod1 = jest.fn()
wrapper.find('#touchable').simulate('press')
expect(instance.exampleMethod1.mock.calls.length).toBe(1)
})
})
As annotated, the first test fails, and the original message prints, as if I had never mocked out the method. This happens irrespectively of whether wrapper.update() is run or not.
Interestingly, if we replace the onPress with a seemingly identical arrow function like so:
onPress={() => {exampleMethod2()}}
The test suddenly passes. This whole thing suggest some weird this binding shenanigans (I think?). Any explanation as to what is going on would be much appreciated!
If you want to test custom methods on component's prototype object, you should use mount function from enzyme and use spyOn to mock and trace the call to that method.
export class ExampleComponent extends Component {
exampleMethod1 = () => {
console.log('in example 1');
this.setState({ example1: true });
}
exampleMethod2 = () => {
console.log('in example 2')
this.exampleMethod1()
}
render() {
return (
<TouchableOpacity id='touchable' onPress={exampleMethod2}><Text>Touchable</Text></TouchableOpacity>
)
}
}
describe('example tests', () => {
let wrapper
beforeEach(() => {
wrapper = mount(<ExampleComponent/>)
})
afterAll(() => { wrapper = null; })
it('some desc here', () => {
const instance = wrapper.instance();
spyOn(instance, 'exampleMethod1').and.callThrough();
expect(instance.setState).toHaveBeenCalled();
});
})