使用Jest mock进行TS默认导入

时间:2017-10-09 13:48:47

标签: unit-testing typescript export default jest

我正在编写针对Jest和Typescript的react-native测试,但是当我模拟使用export defaultexport的模块时,我遇到了问题。

我的模拟是这样的:

// test.setup.js
jest.mock('react-native-text-input-mask', () => ({
  default: 'TextInputMask',
  mask: () => {},
  unmask: () => {},
}));

但是当测试运行时,我的代码中的jest无法使用default引起错误:

import React, { Component } from 'react'
import { } from 'react-native'
import TextInputMask, { mask } from 'react-native-text-input-mask'

console.log(TextInputMask) // {'default': 'TextInputMask', mask: [Function]}
console.log(mask) // [Function]

export default class Comp extends Component<> {
    constructor(props) {
        super(props)
    }

    render(): JSX.Element {
        return (
            <TextInputMask  // error in this line
                mask={'[0000]'}
            />
        )
    }
}

测试错误:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

如何使用default exportexport模拟模块?

我的开玩笑配置:

// package.json
"devDependencies": {
    "@types/fbemitter": "2.0.32",
    "@types/jest": "21.1.1",
    "@types/prop-types": "15.5.2",
    "@types/react": "16.0.9",
    "@types/react-intl": "2.3.2",
    "@types/react-native": "0.48.9",
    "@types/react-navigation": "1.0.20",
    "@types/react-redux": "5.0.9",
    "@types/react-test-renderer": "15.5.4",
    "@types/redux-immutable-state-invariant": "2.0.2",
    "@types/redux-mock-store": "0.0.11",
    "@types/redux-storage": "4.0.10",
    "babel-core": "6.26.0",
    "babel-jest": "21.2.0",
    "babel-plugin-jest-hoist": "21.2.0",
    "babel-plugin-module-resolver": "2.7.1",
    "babel-plugin-transform-decorators-legacy": "1.3.4",
    "babel-preset-react-native": "4.0.0",
    "chai": "4.1.2",
    "chai-as-promised": "7.1.1",
    "colors": "1.1.2",
    "commitizen": "2.9.6",
    "cz-conventional-changelog": "2.0.0",
    "enzyme": "3.0.0",
    "fbemitter": "2.1.1",
    "husky": "^0.14.3",
    "jest": "21.2.1",
    "jest-cli": "21.2.1",
    "jest-serializer-enzyme": "1.0.0",
    "mocha": "3.5.3",
    "plop": "1.9.0",
    "prettier": "1.7.3",
    "react-addons-test-utils": "15.6.2",
    "react-dom": "16.0.0",
    "react-native-debugger-open": "0.3.12",
    "react-test-renderer": "16.0.0",
    "redux-devtools-extension": "2.13.2",
    "redux-immutable-state-invariant": "2.1.0",
    "redux-mock-store": "1.3.0",
    "rimraf": "2.6.2",
    "selenium-webdriver": "3.5.0",
    "sinon": "4.0.0",
    "standard-version": "4.2.0",
    "ts-jest": "21.0.1",
    "tslint": "5.7.0",
    "tslint-config-prettier": "1.5.0",
    "tslint-react": "3.2.0",
    "typescript": "2.5.3",
    "wd": "1.4.1"
},
"jest": {
    "preset": "react-native",
    "collectCoverage": true,
    "collectCoverageFrom": [
        "src/**/*.{ts,tsx}",
        "!src/**/*.test.{ts,tsx}",
        "!src/**/*.d.ts",
        "!build/**",
        "!**/node_modules/**"
    ],
    "coverageDirectory": "coverage",
    "moduleDirectories": [
        "node_modules",
        "src"
    ],
    "moduleNameMapper": {
        "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__scripts__/assetsTransformer.js",
        "^@animations.+\\.(json)$": "<rootDir>/__scripts__/assetsTransformer.js"
    },
    "moduleFileExtensions": [
        "js",
        "jsx",
        "json",
        "ts",
        "tsx",
        "ios.ts",
        "android.ts"
    ],
    "modulePathIgnorePatterns": [
        "<rootDir>/build/"
    ],
    "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
    "setupFiles": [
        "./__scripts__/test-setup.js"
    ],
    "testPathIgnorePatterns": [
        "<rootDir>/build/",
        "<rootDir>/node_modules/"
    ],
    "transform": {
        "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
        "^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
    },
    "transformIgnorePatterns": [
        "node_modules/(?!react-native|tcomb-form-native|react-navigation|lottie-react-native|jail-monkey|redux-persist/es/storage)"
    ],
    "globals": {
        "ts-jest": {
            "useBabelrc": true
        }
    }
},

我的TS配置:

// tsconfig.json
{
    "compilerOptions": {
        "target": "es2015",
        "module": "es2015",
        "jsx": "react-native",
        "watch": true,
        "allowJs": true,
        "sourceMap": true,
        "preserveConstEnums": true,
        "removeComments": true,
        "lib": [
            "dom",
            "es2017"
        ],
        "diagnostics": false,
        "noImplicitAny": false,
        "noImplicitUseStrict": false,
        "strictNullChecks": false,
        "noImplicitThis": false,
        "moduleResolution": "node",
        "outDir": "./build",
        "rootDir": "./src",
        "sourceRoot": ".",
        "baseUrl": "./src",
        "typeRoots": [
            "./src/types"
        ],
        "paths": {
            "@assets/*": [
                "../assets/*"
            ],
            "@animations/*": [
                "../animations/*"
            ]
        },
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true
    },
    "types": [
        "react",
        "react-native",
        "jest"
    ],
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "index.android.js",
        "index.ios.js",
        "build",
        "app",
        "node_modules"
    ],
    "compileOnSave": true
}

1 个答案:

答案 0 :(得分:0)

我解决了这个问题,为组件创建了一个模拟器,如下所示:

// __mocks__/react-native-text-input-mask.tsx
import React from 'react'

class TextInputMask extends React.Component {
    render() {
        return null
    }
}

const mask = (mask: string, value: string, text: string => {} ) => {}
const unmask = (mask: string, masked: string, unmasked: string => {} ) => {}
const setMask = (node: any, mask: string) => {}

export { mask, unmask, setMask }
export default TextInputMask