使用 TypeScript 和 JestJS 测试无效的函数参数

fea*_*e86 7 typescript jestjs

我一直在用 typescript 创建一个节点应用程序,我正在使用 jest 来编写单元测试。

我的问题:我无法真正编写模拟无效函数参数类型的单元测试,因为 typescript 无法编译。我的意思是打字稿意识到我试图在这些函数中放入错误的数据很好,但到目前为止我理解 ts 的方式是,它只在编译时有效。在运行时不会对参数类型进行任何检查。

所以我仍然需要开玩笑地测试我的 IO 依赖函数的正确行为,对吗?

我以为我会写一个 xyz.spec。js并为该特定测试保留所有接口和类型。但是后来我收到了一个关于模块导入的笑话。我猜是因为它不是 ts 文件。

我是否必须更改我的 jest 或 ts 设置才能使其正常工作?

这是测试和错误的屏幕截图:

在此处输入图片说明

这是我的 package.json:

{
  "name": "state",
  "version": "0.0.0",
  "files": [
    "build"
  ],
  "main": "build/index",
  "types": "build/index",
  "scripts": {
    "clean": "rimraf build && rimraf coverage",
    "format": "prettier --write \"{src,__tests__}/**/*.ts\" --single-quote --trailing-comma es5",
    "lint": "tslint --force --format verbose \"src/**/*.ts\"",
    "prepublishOnly": "npm run build",
    "start": "node ./build/index.js",
    "prebuild": "npm run clean && npm run format && npm run lint && echo Using TypeScript && tsc --version",
    "build": "tsc --pretty",
    "build:watch": "nodemon --legacy-watch src/index.ts",
    "test": "jest --no-cache",
    "test:watch": "jest --no-cache --watch",
    "coverage": "jest --no-cache --coverage"
  },
  "dependencies": {
    "mongoose": "^5.6.0"
  },
  "devDependencies": {
    "@types/jest": "^24.0.13",
    "@types/mongoose": "^5.5.6",
    "@types/node": "^10.14.7",
    "coveralls": "^3.0.2",
    "jest": "^24.8.0",
    "nodemon": "^1.19.0",
    "prettier": "^1.14.3",
    "rimraf": "^2.6.2",
    "ts-jest": "^24.0.2",
    "ts-node": "^8.1.0",
    "tslint": "^5.11.0",
    "tslint-config-prettier": "^1.15.0",
    "typescript": "^3.1.1"
  },
  "engines": {
    "node": ">=10.0.0"
  },
  "jest": {
    "preset": "ts-jest"
  }
}
Run Code Online (Sandbox Code Playgroud)

这里是我的 tsconfig.json:

{
  "compilerOptions": {
    "declaration": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "lib": ["esnext"],
    "target": "es2015",
    "outDir": "./<%= buildpath %>",
    "removeComments": true,
    "inlineSourceMap": true,
    "inlineSources": true,
    "preserveConstEnums": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"]
}
Run Code Online (Sandbox Code Playgroud)

最好的问候

mag*_*ker 7

您可以as any在测试的参数中使用。这样你就可以添加“错误”的类型并用它测试你的代码。假设您想测试someFunction()需要某种 Prop 对象的函数,例如

interface Prop {
    id: number;
    type: string;
}

function someFunction(props: Prop): void {
    // ... do some stuff
}
Run Code Online (Sandbox Code Playgroud)

那么您的测试可能如下所示:

interface Prop {
    id: number;
    type: string;
}

function someFunction(props: Prop): void {
    // ... do some stuff
}
Run Code Online (Sandbox Code Playgroud)

您还可以查看 Type Guards,以进行运行时类型检查:http : //www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types

it('should not accept the wrong argument type', () => {
    const props = { id: 123 };
    const testSomeFunction = () => {
        someFunction(props as any);
    };
    expect(testSomeFunction).toThrow();
});
Run Code Online (Sandbox Code Playgroud)


daz*_*daz 7

这就是@ts-expect-error的用途。它告诉打字稿抑制以下错误,以便您可以编写否则无法编译的测试。与 @ts-ignore 不同,如果以下语句实际上没有产生错误,它也会生成错误。这是一个例子:

class NotANumberError extends Error {
  constructor(msg: string) {
    super(msg);
    this.name = 'NotANumberError';
  }
}

function acceptsNumber(x: number): void {
  if (typeof x !== 'number') {
    throw new NotANumberError(`expected number, received ${x}`);
  }
}

describe('acceptsNumber', () => {
  it('throws NotANumberError when called with string', () => {
    // @ts-expect-error test passing invalid string argument
    expect(() => acceptsNumber('hello')).toThrow(NotANumberError);
  });
});
Run Code Online (Sandbox Code Playgroud)

通常acceptsNumber('hello')不会编译,但该错误被上面的注释抑制@ts-expect-error,即使类型不匹配,我们也可以运行和测试代码。


fea*_*e86 -2

它最终为我解决的是允许 js 用于打字稿。所以我的新 tsconfig.json 看起来像这样:

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "lib": ["esnext"],
    "target": "es2015",
    "outDir": "./build",
    "removeComments": true,
    "inlineSourceMap": true,
    "inlineSources": true,
    "preserveConstEnums": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "allowJs": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"]
}
Run Code Online (Sandbox Code Playgroud)