React Native JEST TDD - Cannot read property 'getByText' of undefined - reactjs

I have a inssue, with tdd. I want to call a event byText and i cant do that because i get this error in my component.
TypeError: Cannot read property 'getByText' of undefined
this is my component:
const createSubject = props => {
render(
<AnnoucementItem
{...defaultProps}
{...props}
/>
);
};
and this is my test file:
import React from 'react';
import { render, fireEvent } from 'react-native-testing-library';
import Enzyme, { shallow } from 'enzyme';
import { useDispatch } from 'react-redux';
import i18n from '../../../../src/i18n';
import AnnoucementItem from '../../../../src/screens/Profile/AnnouncementList/AnnouncementItem';
jest.mock('react-redux');
let { onEdit, toggleVisibility, onDelete } = jest.fn();
describe('<AnnoucementItem />', () => {
const defaultProps = {
navigation: {},
item: {
id: 'annoucement id',
user_id: 'id do usuario',
is_published: true,
images: {
0: {
secure_url: genericurl',
},
},
address: {
city: 'Pelotas',
state: 'RS',
number: '990',
street: 'Rua Doutor Francisco Ferreira Veloso',
neighbourhood: 'Py Crespo',
},
values: {
other: '4.32',
total: '4422.33',
},
positive_ratings: '2',
negative_ratings: '1',
onEdit: onEdit,
toggleVisibility: toggleVisibility,
onDelete: onDelete,
},
toggleVisibility: () => {},
onDelete: () => {},
onEdit: () => {},
numberOfLikes: 3,
SwitchOption: {
switchValue: false,
},
userId: () => {},
isFetching: () => {},
shouldUpdate: () => {},
userAnnouncements: () => {},
formVisibility: () => {},
error: () => {},
fetchUserAnnouncements: () => {},
deleteAnnouncement: () => {},
fillFormAnnouncement: () => {},
changeAnnouncementVisibility: () => {},
};
const createSubject = props => {
render(
<AnnoucementItem
{...defaultProps}
{...props}
/>
);
};
describe('AnnoucementItem component', () => {
it('should delete annoucement', () => {
const { getByText, getByTextId } = createSubject();
fireEvent.CallDelete(getByTextId('DeleteButton'), 'deleteAnnouncement');
fireEvent.press(getByText(i18n.t('profile.announcementList.announcementItem.deleteAnnouncementAlert')));
const {
requestDeleteAnnouncement,
successDeleteAnnouncement,
announcementId,
} = jest.fn();
useDispatch.mockReturnValue(
requestDeleteAnnouncement,
successDeleteAnnouncement,
announcementId);
expect(AnnoucementItem.prototype.onDelete.calledOnce).toBe(true);
expect(requestDeleteAnnouncement).toHaveBeenCalledWith({
actionTypes: 'REQUEST_DELETE_ANNOUNCEMENT',
});
expect(successDeleteAnnouncement).toHaveBeenCalledWith({
actionTypes: 'SUCCESS_DELETE_ANNOUNCEMENT',
dispatch: { deletedId: announcementId },
});
});
});
it('should go to edit annoucement', () => {
const { getByText, getByTextId } = createSubject();
fireEvent.CallEdit(getByTextId('EditButton'), 'EditAnnouncement');
fireEvent.press(getByText(i18n.t('profile.announcementList.announcementItem.editAnnouncement')));
const editAnnouncement = jest.fn();
const navigation = { navigate: jest.fn() };
useDispatch.mockReturnValue(editAnnouncement);
expect(editAnnouncement).toHaveBeenCalledWith({
navigation: { navigation },
});
});
it('should count interested peoples in my annoucement', () => {
const { getByText, item } = createSubject();
const interested = getByText(item.positive_ratings + item.negative_ratings);
expect(interested).toBeTruthy();
});
it('should switch visibleAnnoucement', () => {
});
});
the question is, how can i get a element ByText?

In your test update
const createSubject = props => {
render(
<AnnoucementItem
{...defaultProps}
{...props}
/>
);
};
to
const createSubject = props => {
return render(
<AnnoucementItem
{...defaultProps}
{...props}
/>
);
};
Since createSubject is a function you need to return something from that function in order to use its output.

Related

React testing library fimding multiple nodes in the DOM

I am writing tests for my component using react testing library and I am using nested describe blocks for separating tests
const dummyData1 = Array.from({ length: 10 }).map((obj, i) => ({title: "Test" + i,
value: "Test" + i,
key: "Test" + i,
}));
describe("Custom Select", () => {
describe("Single", () => {
afterAll(() => {
cleanup();
});
const loadMore = jest.fn();
const onChange = jest.fn();
loadMore.mockResolvedValueOnce(dummyData2);
const { queryByTestId, getByText, getAllByText, container } = render(
<MultiSelect
data={[{ title: "Test", key: "Test", value: "Test" }, ...dummyData1]}
value="Test"
loadMoreData={loadMore}
onChange={onChange}
/>
);
const selectWrapper = queryByTestId("multi-select-wrapper");
it("Renders successfully -- Single", () => {
expect(selectWrapper).toBeTruthy();
});
it("Value rendered -- Single", () => {
expect(getByText("Test")).toBeInTheDocument();
});
it("Options rendered -- Single", async () => {
act(() => {
fireEvent.click(selectWrapper);
});
const elements = getAllByText("Test");
expect(elements).toHaveLength(1);
});
it("Load More called -- Single", async () => {
act(() => {
fireEvent.click(selectWrapper);
});
const menuEl = container.querySelector(".multi-select-menu");
act(() => {
fireEvent.scroll(menuEl, { target: { scrollY: 700 } });
});
await waitFor(
() => {
expect(loadMore).toBeCalled();
},
{ timeout: 500 }
);
});
it("onChange called -- Single", async () => {
act(() => {
fireEvent.click(selectWrapper);
});
const menuItem = getByText("Test0");
act(() => {
fireEvent.click(menuItem);
});
await waitFor(
() => {
expect(onChange).toHaveBeenCalledWith("Test0");
},
{ timeout: 500 }
);
});
it("Load More called on search -- Single", async () => {
const input = container.querySelector(".multi-select-input");
act(() => {
fireEvent.change(input, { target: { value: "TT" } });
});
await waitFor(
() => {
expect(loadMore).toBeCalledTimes(1);
},
{ timeout: 500 }
);
});
});
describe("Multiple", () => {
beforeAll(() => {
cleanup();
});
const loadMore = jest.fn();
const onChange = jest.fn();
loadMore.mockResolvedValueOnce(dummyData2);
const { queryByTestId, getByText, getAllByText, container } = render(
<MultiSelect
data={[{ title: "Test", key: "Test", value: "Test" }, ...dummyData1]}
value={["Test"]}
loadMoreData={loadMore}
onChange={onChange}
multiple
showCheckboxes
/>
);
const selectWrapper = queryByTestId("multi-select-wrapper");
it("Renders successfully", () => {
expect(selectWrapper).toBeTruthy();
});
it("Value rendered", () => {
expect(getByText("Test")).toBeInTheDocument();
});
});
});
I am getting this error on running the tests. The tests run perfectly if I use them separately. I dont want to render in each test individually but the nested describe is not working
TestingLibraryElementError: Found multiple elements by: [data-testid="multi-select-wrapper"]

Unit Testing with Mocha,Enzyme dispatched functions in functional components which uses React Hooks + Redux

I am trying to test a dispatch from 'mapDispatchToProps' defined with a functional component which uses useEffect() hook and the function is called there.
export const MyComponent = (props) => {
useEffect(() => {
// Anything in here is fired on component mount.
props.registerInStore(props.id, false);
return () => {
// Anything in here is fired on component unmount.
props.resetInStore(props.id);
};
}, []);
const handleOnClick = () => {
props.toggle(props.id);
};
return (
<div >
{!props.isOpen ? (
<button
onClick={handleOnClick}>
Open
</button>
) : (
<button
onClick={handleOnClick}>
close
</button>
)}
</div>
);
};
const mapDispatchToProps = (dispatch) => ({
registerInStore(id, isOpen) {
dispatch(registerInStore(id, isOpen));
},
resetInStore(id) {
dispatch(resetInStore(id));
}
});
export default connect(null, mapDispatchToProps)(MyComponent);
In my unit tests with Mocha and enzyme i also want to test the dispatches inside 'mapDispatchToProps', what i did below does not seem to work :
describe('<MyComponent/>', () => {
let store = mockStore({
toggles: [
{
id: 10,
isOpen: true
}
]
}
});
const options = {
context: {store},
childContextTypes: {store: PropTypes.object.isRequired},
lifecycleExperimental: true
};
const setup = (inputProps = {}) => {
const props = {
id: 10,
isOpen: false,
registerInStore: expect.createSpy(),
resetInStore: expect.createSpy(),
toggle: expect.createSpy(),
...inputProps
};
const wrapper = mount(<MyComponent {...props} />, options);
return {
props,
wrapper
};
};
afterEach(() => {
expect.restoreSpies();
});
it('should dispatch', async () => {
const {wrapper}=setup();
await store.dispatch(wrapper.prop('registerInStore')(10,false));
/* i tried the commented way too instead of directly dispatching*/
// wrapper.prop('registerInStore')(10,false);
//await new Promise((resolve) => setTimeout(resolve, 50));
const expectedActions = [{type: 'REGISTER_IN_STORE', id: 10, isOpen: false}];
expect(store.getActions()).toEqual(expectedActions);
});
the store.getActions() is returning an empty array, i am new to React Hooks and testing, what am i doing wrong, any other solutions?.
Thanks in Advance.
worked by removing the spies e.g:-
const setup = (inputProps = {}) => {
const props = {
id: 10,
isOpen: false,
registerInStore:()=>null,
resetInStore: ()=>null,
toggle: ()=>null,
...inputProps
};
const wrapper = mount(<MyComponent {...props} />, options);
return {
props,
wrapper
};
};

Fail to mock a function of react component props [duplicate]

I have a component called NamespaceMenu below.
export class NamespaceMenu extends Component {
// omit some code here
refreshNamespace = (e) => {
e.stopPropagation()
this.setState({
...this.initialState,
isRefreshing: true,
})
fetchNamespaces()
}
// omit some code here
}
function mapDispatchToProps(dispatch) {
return {
fetchNamespaces: bindActionCreators(getNameSpaces, dispatch),
}
const mapStateToProps = (state, ownProps) => {
return {
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NamespaceMenu)
I write a UT for this component
/* eslint-disable react/jsx-props-no-spreading */
import React from 'react'
import renderer from 'react-test-renderer'
import thunk from 'redux-thunk'
import configureMockStore from 'redux-mock-store'
import { Provider } from 'react-redux'
import NamespaceMenu from '../index'
jest.mock('#lib/TextSearchHighlight', () => () => <div>TextSearchHighlight</div>)
jest.mock('lib/Button', () => () => <div>Button</div>)
jest.mock('../SearchBox', () => () => <div>SearchBox</div>)
jest.mock('../../../../LoadingWaitbox', () => () => <div>LoadingWaitBox</div>)
jest.mock('../../../../../InformationWithDetails', () => () => <div>InformationWithDetails</div>)
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
const namespaces = [
{
id: 'id1',
name: 'ns1',
shouldDisplay: true,
},
{
id: 'id2',
name: 'ns2',
shouldDisplay: false,
},
]
describe('NamespaceMenu/index.js', () => {
let store
let component
let instance
let props
let mockCleanHandler
let mockLoadSelectedDataSources
beforeEach(() => {
mockCleanHandler = jest.fn()
mockLoadSelectedDataSources = jest.fn()
props = {
cleanHandler: mockCleanHandler,
visible: true,
dbRoleId: 'dbRoleId1',
}
store = mockStore({
dbRoleId: namespaces,
})
component = renderer.create(
<Provider store={store}>
<NamespaceMenu {...props} />
</Provider>
)
instance = component.root.children[0].children[0].instance
instance.props = {
...instance.props,
expandDbRole: jest.fn(),
setNamespaceDisplayState: jest.fn(),
loadSelectedDataSources: mockLoadSelectedDataSources,
}
})
// UT code A
it('when calling refreshNamespace', () => {
const mockFetchNamespaces = jest.fn()
// without the code below
// instance.setState = jest.fn()
instance.props = {
...instance.props,
fetchNamespaces: mockFetchNamespaces,
}
instance.refreshNamespace()
expect(mockFetchNamespaces.mock.calls.length).toEqual(1)
})
})
There is an error:
TypeError: Cannot read property 'getNameSpaces' of undefined
This error is thrown from the implemention code of fetchNamespaces.
Yes, the code fails to mock fetchNamespaces
The I change the code a little.
I mock the setState. It works!
// UT code B
it('when calling refreshNamespace', () => {
const mockFetchNamespaces = jest.fn()
// The line below is added. Yes, I mock the `setState`
instance.setState = jest.fn()
instance.props = {
...instance.props,
fetchNamespaces: mockFetchNamespaces,
}
instance.refreshNamespace()
expect(mockFetchNamespaces.mock.calls.length).toEqual(1)
})
Why UT code A fails and UT code B passes?
It seems that setState is the key to the question.

How to mock React stateless currying function using Jest & Enzyme

I have this stateless React component:
...
const Providers = ({ onSelectFeedProvider, ... }) => {
const handleSelectFeedProvider = value => e => {
e.preventDefault();
onSelectFeedProvider({ target: { value } });
};
return {
<Row onClick={handleSelectFeedProvider(1)}>
...
</Row>
}
}
And the test:
import Row from 'components/Common/Row';
import Providers from './index';
jest.mock('components/Common/Row', () => 'Row');
let onSelectFeedProviderSpy = jest.fn();
let onSelectProviderSpy = jest.fn();
const initialProps = {
feedProvider: 0,
onSelectFeedProvider: () => onSelectFeedProviderSpy(),
selectedProvider: undefined,
onSelectProvider: () => onSelectProviderSpy()
};
const mockComponent = props => {
const finalProps = { ...initialProps, ...props };
return <Providers {...finalProps} />;
};
it('should call correctly', () => {
const wrapper = shallow(mockComponent());
wrapper.find(Row).simulate('click', 'what do I have to do here');
expect(onSelect).toHaveBeenCalledTimes(1);
});
How can I do to call the method correctly and pass the coverage? I think have tried all the possibilities. Any thoughts?
You don't have many options in this, one approach is to have onSelect injectable
const Component = ({onSelect}) => {
const handleSelect = value => e => {
e.preventDefault()
onSelect && onSelect({ target: { value } })
}
return <Row onClick={handleSelect(1)} />
}
Test
it('should call correctly', () => {
const spy = jest.fn()
const wrapper = shallow(mockComponent({onSelectProvider: spy}));
wrapper.find(Row).simulate('click', 'what do I have to do here');
expect(spy).toHaveBeenCalledTimes(1);
});

How to stub window.print function with sinon

My Code:
printOrder() {
setTimeout(() => {
window.print();
}, 0);
}
render() {
const { orderDetails, messageTexts, preferences, isLoading, imagePath, featureFlags } = this.props;
const error = get(orderDetails, 'errorCode', '');
return (
<Layout disableWhiteBG><span className={cx('printOrder')}><button className={cx('printOrders')} onClick={e => this.printOrder(e)}><Icon iconType="svg" width="45px" height="45px" viewBox="0 0 45 45" name="print" /></button></span>}
</span>
</Layout>);
}
My test cases
const printOrder = sinon.spy();
const TokenProvider = {
get: TokenProviderGetStub,
logout: TokenProviderLogoutStub,
};
const Cookie = {
load: CookieLoadStub,
};
const Constants = {
...constants,
classic_yoda_combination: true,
};
const User = {
isUserLoggedIn: isUserLoggedInStub,
};
const OrderDetailsScreen = proxyquireStrict('./OrderDetails.jsx', {
'yoda-site-components/lib/helpers/TokenProvider/TokenProvider': TokenProvider,
'yoda-core-components/lib/helpers/Cookies/Cookies': Cookie,
'yoda-site-components/lib/helpers/User/User': User,
'yoda-site-components/lib/components/Layout/Layout': reactStubWithChild('Layout'),
'../../../components/OrderDetails/OrderDetails': reactStubWithChild('OrderDetails'),
'../../../common/redirect': redirectStub,
'../../../common/constant': Constants,
'react-router': {
browserHistory: {
push: pushStub,
},
},
});
describe('Test cases for print Order', () => {
describe('printOrders in DesktopScreen', () => {
before(() => {
wrapper = shallow(
<OrderDetailsScreen {...props} />,
);
wrapper.find('.printOrders').simulate('click');
});
after(() => {
wrapper.unmount();
printOrder.reset();
});
it('Should call the printOrder button', () => {
expect(printOrder.calledOnce).to.be.true;
});
});
describe('printOrders in MobileScreen', () => {
before(() => {
wrapper = shallow(
<OrderDetailsScreen {...props} deviceType={{ isDesktop: false, isMobile: true }} />,
);
wrapper.find('.printOrders').simulate('click');
});
after(() => {
wrapper.unmount();
printOrder.reset();
});
it('Should call the printOrder button', () => {
expect(printOrder.calledOnce).to.be.true;
});
});
});
My question is how do I spy window.print with sinon?

Resources