Почему при использовании Jest / Enzyme при использовании насмешек используютEffect, почему `import * as React from 'реагирует' 'работает, а обычный импорт - нет? - PullRequest
0 голосов
/ 21 марта 2020

Я тестировал react-redux useSelector с поверхностным монтажом фермента с использованием метода насмешки spyOn от Jest. Мой коллега указал, что я не использовал какую-то форму ReactRedux.useSelector() в своих компонентах, поэтому он был озадачен тем, почему макеты работают; он прочитал из поста Уилла Окельманна-Вагнера Shallow Testing Hooks с ферментом , что это было требованием для useEffect. Публикация гласит:

Единственное предостережение: если вы import React, { useEffect } from 'react' в соответствии с рекомендациями документа, вы не собираетесь импортировать свою поддельную функцию, и ваш тест все равно будет неудачным , Но если вы просто используете React.useEffect в своем компоненте, все будет работать нормально.

Я, будучи в замешательстве относительно того, почему возникли расхождения, клонировал репо Уилла и проверил его дальше. Это действительно не сработало, за исключением того, что я заметил, что у react-redux нет экспорта по умолчанию, поэтому мне пришлось импортировать его как import * as ReactRedux from 'react-redux'. Поэтому я попробовал то же самое в моем тестовом файле с React: import * as React from 'react' и вот! Макеты работают отлично, и мне не нужно менять ни один из моих компонентов! Я полагаю, что благодаря счастливой случайности react-redux заставил меня использовать метод импорта * as obj.

Мой вопрос, однако, почему не они оба работают? Я попытался распечатать оба метода импорта объекта React, и единственные различия были у этого метода импорта * as obj было дополнительное свойство default, которое было просто копией исходного объекта React.

Более того, состояние документации Jest:

jest.spyOn (object, methodName)

Создает фиктивную функцию, аналогичную jest.fn, но также отслеживает вызовы object[methodName].

Хорошо. Это означает, что пока метод useEffect находится внутри объекта React, он действительно будет издеваться над useEffect. Ну, React из import React ... содержит содержит useEffect, так почему же Jest не может шпионить за ним?

Ниже представлены две распечатки двух React объектов в зависимости от метода импорта:

import React from 'react' и import React, { useEffect } from 'react'

React:  {
  Children: {
    map: [Function: mapChildren],
    forEach: [Function: forEachChildren],
    count: [Function: countChildren],
    toArray: [Function: toArray],
    only: [Function: onlyChild]
  },
  Component: [Function: Component],
  Fragment: Symbol(react.fragment),
  Profiler: Symbol(react.profiler),
  PureComponent: [Function: PureComponent],
  StrictMode: Symbol(react.strict_mode),
  Suspense: Symbol(react.suspense),
  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
    ReactCurrentDispatcher: { current: null },
    ReactCurrentBatchConfig: { suspense: null },
    ReactCurrentOwner: { current: null },
    IsSomeRendererActing: { current: false },
    assign: [Function: assign],
    ReactDebugCurrentFrame: { getCurrentStack: null, getStackAddendum: [Function] },
    ReactComponentTreeHook: {}
  },
  cloneElement: [Function: cloneElementWithValidation],
  createContext: [Function: createContext],
  createElement: [Function: createElementWithValidation],
  createFactory: [Function: createFactoryWithValidation],
  createRef: [Function: createRef],
  forwardRef: [Function: forwardRef],
  isValidElement: [Function: isValidElement],
  lazy: [Function: lazy],
  memo: [Function: memo],
  useCallback: [Function: useCallback],
  useContext: [Function: useContext],
  useDebugValue: [Function: useDebugValue],
  useEffect: [Function: useEffect],
  useImperativeHandle: [Function: useImperativeHandle],
  useLayoutEffect: [Function: useLayoutEffect],
  useMemo: [Function: useMemo],
  useReducer: [Function: useReducer],
  useRef: [Function: useRef],
  useState: [Function: useState],
  version: '16.13.1'
}

import * as React from 'react'

React:  {
  Children: {
    map: [Function: mapChildren],
    forEach: [Function: forEachChildren],
    count: [Function: countChildren],
    toArray: [Function: toArray],
    only: [Function: onlyChild]
  },
  Component: [Function: Component],
  Fragment: Symbol(react.fragment),
  Profiler: Symbol(react.profiler),
  PureComponent: [Function: PureComponent],
  StrictMode: Symbol(react.strict_mode),
  Suspense: Symbol(react.suspense),
  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
    ReactCurrentDispatcher: { current: null },
    ReactCurrentBatchConfig: { suspense: null },
    ReactCurrentOwner: { current: null },
    IsSomeRendererActing: { current: false },
    assign: [Function: assign],
    ReactDebugCurrentFrame: { getCurrentStack: null, getStackAddendum: [Function] },
    ReactComponentTreeHook: {}
  },
  cloneElement: [Function: cloneElementWithValidation],
  createContext: [Function: createContext],
  createElement: [Function: createElementWithValidation],
  createFactory: [Function: createFactoryWithValidation],
  createRef: [Function: createRef],
  forwardRef: [Function: forwardRef],
  isValidElement: [Function: isValidElement],
  lazy: [Function: lazy],
  memo: [Function: memo],
  useCallback: [Function: useCallback],
  useContext: [Function: useContext],
  useDebugValue: [Function: useDebugValue],
  useEffect: [Function: useEffect],
  useImperativeHandle: [Function: useImperativeHandle],
  useLayoutEffect: [Function: useLayoutEffect],
  useMemo: [Function: useMemo],
  useReducer: [Function: useReducer],
  useRef: [Function: useRef],
  useState: [Function: useState],
  version: '16.13.1',
  default: { // This is where the differences begin
    Children: {
      map: [Function: mapChildren],
      forEach: [Function: forEachChildren],
      count: [Function: countChildren],
      toArray: [Function: toArray],
      only: [Function: onlyChild]
    },
    Component: [Function: Component],
    Fragment: Symbol(react.fragment),
    Profiler: Symbol(react.profiler),
    PureComponent: [Function: PureComponent],
    StrictMode: Symbol(react.strict_mode),
    Suspense: Symbol(react.suspense),
    __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
      ReactCurrentDispatcher: [Object],
      ReactCurrentBatchConfig: [Object],
      ReactCurrentOwner: [Object],
      IsSomeRendererActing: [Object],
      assign: [Function: assign],
      ReactDebugCurrentFrame: [Object],
      ReactComponentTreeHook: {}
    },
    cloneElement: [Function: cloneElementWithValidation],
    createContext: [Function: createContext],
    createElement: [Function: createElementWithValidation],
    createFactory: [Function: createFactoryWithValidation],
    createRef: [Function: createRef],
    forwardRef: [Function: forwardRef],
    isValidElement: [Function: isValidElement],
    lazy: [Function: lazy],
    memo: [Function: memo],
    useCallback: [Function: useCallback],
    useContext: [Function: useContext],
    useDebugValue: [Function: useDebugValue],
    useEffect: [Function: useEffect],
    useImperativeHandle: [Function: useImperativeHandle],
    useLayoutEffect: [Function: useLayoutEffect],
    useMemo: [Function: useMemo],
    useReducer: [Function: useReducer],
    useRef: [Function: useRef],
    useState: [Function: useState],
    version: '16.13.1'
  }
}
...