Hi! I have problem with testing decorated by translate components. Just simple example:
import React, { PropTypes } from 'react';
import { translate } from 'react-i18next';
import ProductBadge from './ProductBadge';
const ProductBadgeNew = ({ product, t }) => (
product.is_label_new
? <ProductBadge text={t('vendor.badges.new')} status="sold" />
: <span />
);
export default translate(ProductBadgeNew);
First of all when we test components, we render them into document via:
import { renderIntoDocument } from 'react-addons-test-utils';
import ProductBadgeNew from '../../ProductBadgeNew';
describe('[Component] ProductBadgeNew', () => {
it('should render without errors when there aren\'t any props', () => {
const component = renderIntoDocument(
<ProductBadgeNew />
);
expect(component).to.be.an('object');
});
});
But we have been decorated ProductBadgeNew component with translate, and here component variable contains Translate component which decorates ProductBadgeNew. And I can't get props for my ProductBadgeNew.
I've found one interesting solution https://github.com/ghengeveld/redux/blob/a68768ff8d6a4fbe7b8f6a06a8cf9b99a54aefb0/docs/recipes/WritingTests.md#testing-decorated-react-components
The code after changes is:
import React, { PropTypes } from 'react';
import { translate } from 'react-i18next';
import ProductBadge from './ProductBadge';
export const ProductBadgeNew = ({ product, t }) => (
product.is_label_new
? <ProductBadge text={t('vendor.badges.new')} status="sold" />
: <span />
);
export default translate(ProductBadgeNew);
import { ProductBadgeNew } from '../../ProductBadgeNew';
describe('[Component] ProductBadgeNew', () => {
it('should render without errors when there aren\'t any props', () => {
const component = renderIntoDocument(
<ProductBadgeNew />
);
expect(component).to.be.an('object');
});
});
Now component variable contains our vanilla component without any decorations. BUT!:) Inside component we use t function which is passed via props and of course we don't have it now. How can I fix my testing workflow with your decorators? Thanks
pass in a mock for t function function t(key, options) { return key; };?
@jamuhl Do you mean?
import { ProductBadgeNew } from '../../ProductBadgeNew';
const mockT = (key, options) => (key);
describe('[Component] ProductBadgeNew', () => {
it('should render without errors when there aren\'t any props', () => {
const component = renderIntoDocument(
<ProductBadgeNew t={mockT} />
);
expect(component).to.be.an('object');
});
});
What if I have more complicated component which includes children decorated with translate as well?
we just decorate the outer components with the translated hoc...from there we pass the t function as prop to the inner components....not sure if that helps...
I thought that main sense of translate is connecting everywhere we need it and avoid passing over props?
matter of taste...personally i like to have inner components as pure as possible...but both work.
a better option for you would be to use something like mockery (https://github.com/mfncooper/mockery) to completely replace the import of translated hoc. so you replace that once and for all calls to that module.
not sure if mockery works for your usecase...but for sure there is some mock framework for that.
Thanks for your help!
Maybe I'm missing something but I'm having this error when trying to run the code in a test case:
TypeError: Cannot read property 'options' of undefined
at new Translate (node_modules/react-i18next/dist/commonjs/translate.js:59:46)
I'm using an undecorated component in my test, with a mock t function. But the translate HoC is still executed, and because I don't specify any i18n context or custon namespaces, it fails.
What's the proper way of doing it?
what we do for testing is:
export function MyComponent(props) { ... };
export default translated(MyComponent);
for test we import { MyComponent } from './MyComponent'; -> no hoc just pure component to test
Exactly what I do. But one of the import was wrong, that's why it was trying to build the translated component :)
Stumbled on this when dealing with the same issue. We found the easiest solution to be mocking the translate function of react-i18next:
jest.mock('react-i18next', () => ({
// this mock makes sure any components using the translate HoC receive the t function as a prop
translate: () => Component => props => <Component t={() => ''} {...props} />,
}));
This helps address @sergeylaptev 's comment about complex components with child components also using the HoC
@jamesvclements added your snipplet to the docs
Most helpful comment
Stumbled on this when dealing with the same issue. We found the easiest solution to be mocking the
translatefunction ofreact-i18next:This helps address @sergeylaptev 's comment about complex components with child components also using the HoC