react-intl 与 react-testing-library 给出了无效的钩子调用错误

Posted

技术标签:

【中文标题】react-intl 与 react-testing-library 给出了无效的钩子调用错误【英文标题】:react-intl with react-testing-library gives Invalid hook call error 【发布时间】:2020-05-12 17:42:27 【问题描述】:

在我们的项目中,我们使用react-intl 进行国际化。我们使用jest 作为测试框架,我们决定将我们的单元测试实用程序库从酶移到react-testing-library。但是现在,由于没有浅渲染,我必须自己在测试中提供<IntlProvider ... />,没有问题。但即使我这样做,当测试终端说Invalid hook call. Hooks can only be called inside of the body of a function component 但当我在本地运行项目时,没有错误只是按预期正常运行。 P.S 在测试中,Apollo 提供者正常工作。

FirstNameFor.test.tsx

import  IntlProvider  from 'react-intl';
import  createMockClient  from 'mock-apollo-client';
import  ApolloProvider as ApolloProviderHooks  from '@apollo/react-hooks';
import  ApolloProvider  from 'react-apollo';

const wrapper = (mockProps, mockClient) => 
  return (
    <ApolloProvider client=mockClient>
      <ApolloProviderHooks client=mockClient>
        <IntlProvider locale="en">
          <FirstNameForm
            handleNext=mockProps.handleNext
            onboardingState=mockProps.onboardingState
            setHelpContent=mockProps.setHelpContent
            updateOnboardingState=mockProps.updateOnboardingState
          />
        </IntlProvider>
      </ApolloProviderHooks>
    </ApolloProvider>
  );
;

describe('FirstNameForm Container', () => 
  afterEach(() => 
    jest.clearAllMocks();
    cleanup();
  );

  it('should match snapshot', () => 
    // Arrange
    const mockProps = 
      handleNext: jest.fn(),
      onboardingState: ,
      setHelpContent: jest.fn(),
      updateOnboardingState: jest.fn(),
    ;
    const mockClient = createMockClient();

    // Act
    const component = render(wrapper(mockProps, mockClient));

    // Assert
    expect(component).toMatchSnapshot();
  );
);

FirstNameForm.tsx

export const FirstNameForm: React.FC<StepContentProps> = props => 
  const [showMessageMutation] = useShowMessageMutation();
  const intl = useIntl();

  const formik = useFormik<FirstNameFormValues>(
   ...,
  );

  return <FirstNameFormComponent formik=formik intl=intl />;
;

终端截图

package.json


  "private": true,
  "proxy": "http://localhost:5000",
  "version": "0.1.57",
  "scripts": 
    "dev": "yarn graphql:generate && SKIP_PREFLIGHT_CHECK=true react-app-rewired start",
    "build": "SKIP_PREFLIGHT_CHECK=true react-app-rewired build",
    "testonly": "SKIP_PREFLIGHT_CHECK=true react-app-rewired test --env=jsdom",
    "coverage": "SKIP_PREFLIGHT_CHECK=true react-app-rewired test --env=jsdom --coverage",
  ,
  "jest": 
    "coveragePathIgnorePatterns": [
      "/node_modules/",
      "src/types/",
      "src/config/analytics/mp.d.ts",
      "src/config/analytics/ua.d.ts"
    ],
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ]
  ,
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "resolutions": 
    "@types/react": "16.8.17"
  ,
  "dependencies": 
    "@apollo/react-hooks": "3.1.3",
    "animated-scroll-to": "1.2.2",
    "apollo-cache": "1.3.2",
    "apollo-cache-inmemory": "1.6.3",
    "apollo-client": "2.6.3",
    "apollo-link": "1.2.12",
    "apollo-link-context": "1.0.18",
    "apollo-link-error": "1.1.11",
    "apollo-link-http": "1.5.15",
    "apollo-link-ws": "1.0.18",
    "apollo-utilities": "1.3.2",
    "big.js": "5.2.2",
    "copy-to-clipboard": "3.2.0",
    "core-js": "3.0.1",
    "date-fns": "1.30.1",
    "downloadjs": "1.4.7",
    "formik": "2.1.1",
    "graphql": "14.3.0",
    "graphql-subscriptions": "1.1.0",
    "graphql-tag": "2.10.1",
    "graphql-tools": "4.0.4",
    "history": "4.9.0",
    "intl": "1.2.5",
    "js-cookie": "2.2.0",
    "lodash": "4.17.11",
    "owasp-password-strength-test": "1.3.0",
    "qrcode.react": "0.9.3",
    "query-string": "6.5.0",
    "react": "16.8.6",
    "react-apollo": "3.1.3",
    "react-dom": "16.8.6",
    "react-google-recaptcha": "1.1.0",
    "react-intl": "3.1.8",
    "react-router-dom": "5.1.0",
    "recompose": "0.30.0",
    "regenerator-runtime": "0.13.2",
    "subscriptions-transport-ws": "0.9.16",
    "validator": "10.11.0",
    "victory": "34.0.0",
    "yup": "0.27.0"
  ,
  "devDependencies": 
    "@apollo/react-testing": "3.1.3",
    "@babel/cli": "7.4.4",
    "@babel/core": "7.4.4",
    "@babel/preset-env": "7.4.4",
    "@graphql-codegen/add": "1.8.1",
    "@graphql-codegen/cli": "1.8.1",
    "@graphql-codegen/fragment-matcher": "1.8.1",
    "@graphql-codegen/typescript": "1.8.1",
    "@graphql-codegen/typescript-operations": "1.8.1",
    "@graphql-codegen/typescript-react-apollo": "1.8.1",
    "@testing-library/react": "10.0.4",
    "@testing-library/jest-dom": "5.8.0",
    "@types/testing-library__react": "10.0.1",
    "@types/big.js": "4.0.5",
    "@types/downloadjs": "1.4.1",
    "@types/enzyme": "3.10.5",
    "@types/graphql": "14.2.0",
    "@types/js-cookie": "2.2.2",
    "@types/node": "12.0.0",
    "@types/owasp-password-strength-test": "1.3.0",
    "@types/prop-types": "15.7.1",
    "@types/qrcode.react": "0.8.2",
    "@types/query-string": "6.3.0",
    "@types/react": "16.8.17",
    "@types/react-dom": "16.8.4",
    "@types/react-google-recaptcha": "1.0.0",
    "@types/react-router-dom": "5.1.0",
    "@types/react-test-renderer": "16.9.0",
    "@types/recompose": "0.30.6",
    "@types/validator": "10.11.0",
    "@types/victory": "33.1.0",
    "@types/ws": "6.0.1",
    "@types/yup": "0.26.13",
    "babel-loader": "8.0.6",
    "enzyme": "3.11.0",
    "enzyme-adapter-react-16": "1.15.2",
    "enzyme-to-json": "3.4.4",
    "jest-canvas-mock": "2.2.0",
    "jest-localstorage-mock": "2.4.0",
    "merge-graphql-schemas": "1.5.8",
    "npm-run-all": "4.1.5",
    "patch-package": "6.1.2",
    "postinstall-postinstall": "2.0.0",
    "react-app-rewired": "2.1.3",
    "react-scripts": "3.3.0",
    "react-test-renderer": "16.8.6",
    "source-map-explorer": "1.8.0",
    "ts-jest": "25.3.1",
    "ts-node": "8.1.0",
    "typescript": "3.5.3"
  

【问题讨论】:

我认为这可能与github.com/formatjs/formatjs/issues/1477有关。 你能给我们看看你的 package.json 吗?你检查过你是否在某个地方有重复的 react 版本吗? 分享你的 package.json 这个错误很棘手:|,你捆绑你的测试吗? 我使用coverage 命令运行测试,但是是的,这很棘手。我将在一个新项目上测试这个场景,看看是否会出现同样的错误,然后我会相应地更新这个问题。 【参考方案1】:

错误来自 React 本身,很可能与 react-intl 无关。

很有可能您有多个 React 实例发生冲突,出于某种原因,仅在测试环境中发生。我怀疑这可能与react-app-rewired 有关,但不确定。

official help doc 中的步骤应该有助于揭示重复的 React 是否是问题的根源。

如果是这个原因,这里有一些来自社区的***解决方案:

修改您的 webpack 配置以解析 react 别名 (discussion)
  resolve: 
    alias: 
        react: path.resolve('./node_modules/react'),
      
  ,
修改您的 webpack 配置以将 react 设置为外部 (PR example)
  externals: 
    react: 'react'
  
或这些其他杂项之一approaches

【讨论】:

以上是关于react-intl 与 react-testing-library 给出了无效的钩子调用错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 React-intl 的 Redux-form 字段级验证和错误翻译

用酶测试 react-intl 组件

尝试导入错误:“addLocaleData”未从“react-intl”导出

为 react/react-intl 动态导入语言 json 文件

非组件的 React-intl

react-intl 实现 React 国际化多语言