0

I'm using injectIntl in my react functional component to achieve the localization. I'm using enzyme/jest to do the unit test. I've copied the intl-test-helper file, but got error: " TypeError: intlProvider.getChildContext is not a function "

I've tried other suggestions from stackflow: 1. remove mock file --- which I don't have mock file 2. use const { IntlProvider } = jest.requireActual("react-intl"); to force it use the actual one , not mock --- not working.

the react component is: WarningModal.jsx:

import { FormattedMessage, injectIntl } from "react-intl";
.......

const WarningModal = ({
  .........
  ...props
}) => {
  ........

export default injectIntl(WarningModal);

the intlTestHelper.js file is :

 * Components using the react-intl module require access to the intl context.
 * This is not available when mounting single components in Enzyme.
 * These helper functions aim to address that and wrap a valid,
 * English-locale intl context around them.
 */

import React from "react";
import { IntlProvider, intlShape } from "react-intl";
import { mount, shallow } from "enzyme"; // eslint-disable-line import/no-extraneous-dependencies

/** Create the IntlProvider to retrieve context for wrapping around. */
function createIntlContext(messages, locale) {
  const { IntlProvider } = jest.requireActual("react-intl");
  const intlProvider = new IntlProvider({ messages, locale }, {});
  const { intl } = intlProvider.getChildContext();
  return intl;
}

/** When using React-Intl `injectIntl` on components, props.intl is required. */
function nodeWithIntlProp(node, messages = {}, locale = "en") {
  return React.cloneElement(node, {
    intl: createIntlContext(messages, locale)
  });
}

/**
 * Create a shadow renderer that wraps a node with Intl provider context.
 * @param {ReactComponent} node - Any React Component
 * @param {Object} context
 * @param {Object} messages - A map with keys (id) and messages (value)
 * @param {string} locale - Locale string
 */
export function shallowWithIntl(
  node,
  { context } = {},
  messages = {},
  locale = "en"
) {
  return shallow(nodeWithIntlProp(node), {
    context: Object.assign({}, context, {
      intl: createIntlContext(messages, locale)
    })
  });
}

/**
 * Mount the node with Intl provider context.
 * @param {Component} node - Any React Component
 * @param {Object} context
 * @param {Object} messages - A map with keys (id) and messages (value)
 * @param {string} locale - Locale string
 */
export function mountWithIntl(
  node,
  { context, childContextTypes } = {},
  messages = {},
  locale = "en"
) {
  return mount(nodeWithIntlProp(node), {
    context: Object.assign({}, context, {
      intl: createIntlContext(messages, locale)
    }),
    childContextTypes: Object.assign({}, { intl: intlShape }, childContextTypes)
  });
}

here how I use it to test:

import React from "react";
import { _WM as WarningModal } from "../components/WarningModal";
// import { shallow } from "enzyme";
import { mountWithIntl } from "../utils/intlTestHelper.js";

describe("<WarningModal />", () => {
  const props = {
    discardChanges: jest.fn(),
    saveChanges: jest.fn(),
    closeWarningModal: jest.fn(),
    intl: { formatMessage: jest.fn() }
  };

  it("should have heading", () => {
    const wrapper = mountWithIntl(<WarningModal {...props} />);
    expect(wrapper.find(".confirm-title")).toBeTruthy();
  });
});

error:

 ● <WarningModal /> › should have heading

    TypeError: intlProvider.getChildContext is not a function

      14 |   const { IntlProvider } = jest.requireActual("react-intl");
      15 |   const intlProvider = new IntlProvider({ messages, locale }, {});
    > 16 |   const { intl } = intlProvider.getChildContext();
         |                                 ^
      17 |   return intl;
      18 | }
      19 | 

      at getChildContext (src/utils/intlTestHelper.js:16:33)
      at createIntlContext (src/utils/intlTestHelper.js:23:11)
      at nodeWithIntlProp (src/utils/intlTestHelper.js:60:16)
      at Object.<anonymous> (src/tests/WarningModal.spec.js:29:21)

please shine some lights on this. Thank you.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Lei
  • 11
  • 1
  • 3
  • updated the test file to :https://github.com/formatjs/react-intl/blob/master/docs/Testing-with-React-Intl.md#-advanced-uses-injectintl; it works. – Lei Jan 15 '20 at 06:40

2 Answers2

0

In later versions of react-intl getChildContext has been deprecated and may generate this error. You can use the following instead:

import { createIntl } from 'react-intl';

const intl = createIntl({ locale: "en",
    messages: {
        message1: "Hello world"
    }
});
JoeTidee
  • 24,754
  • 25
  • 104
  • 149
  • While this code may answer the question, providing additional context regarding *how* and/or *why* it solves the problem would improve the answer's long-term value. – Sven Eberth Jul 07 '21 at 23:04
0

React-Intl has replaced IntlProvider.getChildContext, with the createIntl for testing purpose, while migrating V2 to V3.

We've removed IntlProvider.getChildContext for testing and now you can use createIntl to create a standalone intl object outside of React and use that for testing purposes. See Testing with React Intl for more details

Here is the Link

So the working code for this is

For resolving this error, you have to create custom shallow component. Like as

    import { createIntl } from 'react-intl';

    const LocalLanguage  = {
       french:{},
       arabic:{},
       english:{}
    }
    const lang = getCurrentLanguage('en', LocalLanguage);
    const intl  = createIntl({ locale: 'en', lang }, {});

    export const shallowWithIntl = (node) => {
        return shallow(nodeWithIntlProp(node), { context: { intl } });
    }

If this not helps, then you can define the following function, in your helper file.

    const messages = require('./Lang/en.json') // en.json 
    const defaultLocale = 'en'

    const locale = defaultLocale

    export const intl = (component) => {
         return (
             <IntlProvider
                 locale={locale}
                 messages={messages}
             >
                 {React.cloneElement(component)}
             </IntlProvider>
         );
    }

And use it in your test files as below

    const wrapper = mount(intl(<MobileRechargeComponent />));
vineet tanwar
  • 329
  • 2
  • 9