Шутка внезапно сломалась после того, как смоделировал другой модуль - PullRequest
0 голосов
/ 31 октября 2018

Я создаю приложение React Native с помощью TypeScript. Я использую Jest и Enzyme для своих юнит-тестов.

Я недавно добавил сканер QRCode в свое приложение, используя этот пакет . Это зависит от этой камеры . После добавления пакета и после того, как я закончил писать тесты (мы делаем TDD) для нового компонента, который использует этот сканер, я внезапно заметил, что некоторые тесты были неудачными:

● Test suite failed to run

    TypeError: Cannot read property 'Aspect' of undefined

      at Object.<anonymous> (node_modules/react-native-camera/src/Camera.js:386:113)
      at Object.<anonymous> (node_modules/react-native-camera/src/index.js:1:413)
      at Object.<anonymous> (node_modules/react-native-qrcode-scanner/index.js:19:26)

Ну, как обычно, я погуглил ошибку и нашел два исправления.

  1. Проверяйте камеру в каждом тесте, который выдает эту ошибку следующим образом:

    jest.mock("react-native-camera", () => "Camera");
    
  2. Макет модуля камеры на уровне проекта __mocks__/ папка, подобная этой:

    const Camera = {}
    export default Camera;
    

Когда я сделал это, ошибка об «Аспекте» правильно исчезла. Но теперь Jest начал жаловаться на import во всех тестах с участием узловых модулей.

● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /Users/my/folders/node_modules/react-navigation-stack/dist/navigators/createContainedStackNavigator.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { createNavigationContainer } from 'react-navigation';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token import

       9 | import ScannerScreen from "../screens/Scanner";
      10 |
    > 11 | const HomeStack = createStackNavigator({ HomeScreen });
         |                   ^
      12 | const ScannerStack = createStackNavigator({ ScannerScreen });
      13 |
      14 | const MainDrawer = createDrawerNavigator({ HomeStack, ScannerStack });

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
      at Object.get createStackNavigator [as createStackNavigator] (node_modules/react-navigation-stack/dist/index.js:8:12)
      at Object.get createStackNavigator [as createStackNavigator] (node_modules/react-navigation/src/react-navigation.js:29:45)
      at Object.<anonymous> (app/navigation/Navigator.ts:11:19)

Первая странная вещь об этом - , чего раньше не было! То есть до того, как я добавил этот макет и пакет сканера QR-кодов с его зависимостью (реагировать-нативная камера) ) все тесты работали нормально! Преобразование импорта не было проблемой для Jest.

Хорошо, я снова гуглил и обнаружил, что некоторые люди смогли это исправить, используя "transform-ignore-patterns".

Вот конфиги, которые я пробовал:

transformIgnorePatterns: [
  "<rootDir>/node_modules/react-native/.+"
]

"transformIgnorePatterns": [
  "node_modules/(?!react-native|react-navigation)/"
],

Ни один из этих двух не сработал. В результате тесты заняли от 20 секунд (когда я тестировал только один компонент) или несколько минут (когда я запустил все тесты одновременно с npm test) до того, как они начались. И тогда они сразу же потерпят неудачу с:

 FAIL  app/components/LoginForm/LoginForm.test.tsx
  ● Test suite failed to run

    The component for route 'LoginScreen' must be a React component. For example:

    import MyScreen from './MyScreen';
    ...
    LoginScreen: MyScreen,
    }

    You can also use a navigator:

    import MyNavigator from './MyNavigator';
    ...
    LoginScreen: MyNavigator,
    }

      14 | const MainDrawer = createDrawerNavigator({ HomeStack, ScannerStack });
      15 |
    > 16 | const RootSwitch = createSwitchNavigator(
         |                    ^
      17 |   { MainDrawer, LoadingScreen, LoginScreen },
      18 |   { initialRouteName: "LoadingScreen" }
      19 | );

      at node_modules/react-navigation/src/routers/validateRouteConfigMap.js:24:13
          at Array.forEach (<anonymous>)
      at validateRouteConfigMap (node_modules/react-navigation/src/routers/validateRouteConfigMap.js:14:14)
      at _default (node_modules/react-navigation/src/routers/SwitchRouter.js:22:39)
      at createSwitchNavigator (node_modules/react-navigation/src/navigators/createSwitchNavigator.js:7:42)
      at Object.SwitchNavigator (node_modules/react-navigation/src/navigators/createContainedSwitchNavigator.js:5:54)
      at Object.<anonymous> (app/navigation/Navigator.ts:16:20)

Что происходит? Почему Джест внезапно сломан? Импорт работал нормально, пока не пришел react-native-camera.

Добавлена ​​информация:

Вот мои конфигурационные файлы.

package.json

"jest": {
  "preset": "react-native",
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
    "^.+\\.tsx?$": "ts-jest"
  },
  "globals": {
    "ts-jest": {
      "tsConfigFile": "tsconfig.jest.json"
    }
  },
  "transformIgnorePatterns": [
    "node_modules/(?!react-native|react-navigation)/"
  ],
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js",
    "jsx",
    "json",
    "node"
  ],
  "modulePaths": [
    "<rootDir>"
  ],
  "setupFiles": [
    "./tests/setup.js"
  ]
}

tsconfig.jest.json

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "jsx": "react",
    "module": "commonjs"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "react-native",
    "lib": ["es2017"],
    "moduleResolution": "node",
    "noEmit": true,
    "strict": true,
    "strictPropertyInitialization": false,
    "target": "esnext"
  },
  "exclude": ["node_modules"]
}

tests/setup.js

import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { NativeModules } from "react-native";

jest.mock("react-native-device-info", () => {
  return {
    getDeviceName: jest.fn(() => "device name"),
    getBrand: jest.fn(() => "android"),
    getDeviceId: jest.fn(() => "device-id-123")
  };
});
NativeModules.ReactLocalization = {
  language: "en"
};
global.fetch = require("jest-fetch-mock"); // eslint-disable-line no-undef
Enzyme.configure({ adapter: new Adapter() });
...