Reputation: 3672
I'm trying to stub/spy the translation, not just mock it, and I can't seem to get it to trigger even in this most base case.
/**
* ComponentName.jsx
*/
import { useTranslation } from "react-i18next";
export default function ComponentName() {
const { t } = useTranslation();
return <div>t(`index:path`)</div>
}
/**
* ComponentName.test.jsx
*/
import { shallow } from "enzyme";
import ComponentName from "./ComponentName";
import { useTranslation } from "react-i18next";
jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: jest.fn(key => key) })
}));
it("calls the translation function", () => {
const wrapper = shallow(<ComponentName />);
expect(useTranslation().t).toHaveBeenCalled();
});
When I drop a console.log(t)
in the ComponentName.jsx file
, it correctly displays that it's a mocked function.
If I put t()
in the ComponentName.test.jsx
file, it passes.
Is there a way to stub this so that I can eventually tag it with toHaveBeenCalledWith
? Or am I relegated to doing contains("index:path")
on the component?
Edit: So, when I updated on @felixmosh's answer
/**
* ComponentName.test.jsx
*/
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
describe('<SomeComponent />', () => {
it('dispatches SORT_TABLE', () => {
const i18nextMock = {
t: jest.fn(key => key),
};
const enzymeWrapper = mount(
<I18nextProvider i18n={i18nextMock}>
<SomeComponent />
</I18nextProvider>
);
expect(i18nextmock.t).toHaveBeenCalled()
});
});
/**
* ComponentName.jsx
*/
import { useTranslation } from "react-i18next";
export default function ComponentName() {
const { t } = useTranslation();
return <div>t(`index:path`)</div>
}
It's the same issue. If t
was "a string"
instead of jest.fn()
, when i console.log t
in ComponentName.jsx
, I correctly get "a string"
, when I console.log t
as jest.fn(key => key)
, I correctly get a function.
But when I call it, I don't get it.
Is it possible that it's not the same instance that's being sent to I18nextProvider?
Upvotes: 4
Views: 6616
Reputation: 35553
2 Things that you should improve in your code:
useTransaltion
is a hook which requires context
, make sure you wrap you component with i18nextProvider
.shallow
with mount
.i18next
has a built-it support of tests.
In order to enable it use cimode
as the lng
when configuring your i18next
for tests.// i18nForTests.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
lng: 'cimode',
// ----- ^
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
interpolation: {
escapeValue: false, // not needed for react!!
},
resources: { en: { translations: {} } },
});
export default i18n;
// SomeComponent.test.js
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18nForTests';
describe('<SomeComponent />', () => {
it('dispatches SORT_TABLE', () => {
const enzymeWrapper = mount(
<I18nextProvider i18n={i18n}>
<SomeComponent />
</I18nextProvider>
);
enzymeWrapper.find('.sort').simulate('click');
expect(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');
});
});
Edit: Version with mocked I18next
// i18nextMock.js
export const i18nextMock = {
t: jest.fn(),
// Do the same for other i18next fields
};
// SomeComponent.test.js
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
import i18nextMock from '../i18nextMock';
describe('<SomeComponent />', () => {
it('dispatches SORT_TABLE', () => {
const enzymeWrapper = mount(
<I18nextProvider i18n={i18nextMock}>
<SomeComponent />
</I18nextProvider>
);
enzymeWrapper.find('.sort').simulate('click');
expect(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');
});
});
Upvotes: 4