开玩笑不处理来自RxJS的subscription()中的Expect()的错误

时间:2018-12-18 04:32:53

标签: rxjs jestjs rxjs6

我一直在尝试让Jest与RxJS一起使用,并且遇到Jest无法从订阅回调内部传播错误的麻烦。

这是我尝试过的不起作用的示例测试:

import {of} from 'rxjs';

test('should fail', () => {
  of(false).subscribe(val => {
    expect(val).toBe(true);
  });
});

上面的测试应该失败,但是可以通过。我到处搜寻,找到以下解决方案:

这建议您开玩笑地使用“ done”语法来解决此问题。虽然使用“完成”回调确实会使上述测试失败,但是这种方法存在很多问题:

非描述性错误

测试失败,因为subcribe()中的“ expect”调用引发了错误,导致从未调用过“ done()”。然后测试超时,等待完成。因此,它没有传播“期望”错误,而是引起超时错误,这意味着在Expect子句中失败的每个测试都将显示超时错误,而不是失败的“期望”调用的实际错误消息。

测试需要更长的时间才能失败

由于所有测试均由于超时错误而失败,这意味着每个测试需要5秒钟才能失败(5秒钟后异步测试超时)。这可以大大增加测试运行的时间

做事使用不佳

done回调旨在支持异步用例进行测试。但是rxjs不一定是异步的。我上面内联的代码实际上是同步运行的。例如,以下测试将通过:

import {of} from 'rxjs';

test('should pass', () => {
  let didRunSynchronously = false;
  of(true).subscribe(() => {
    didRunSynchronously = true;
  });
  expect(didRunSynchronously).toBe(true);
});

不得不使用异步语义来解决同步测试的问题似乎很奇怪。

想知道是否有人提出了一个很好的在rxjs中进行测试的解决方案,这会导致expect调用正确地由测试库处理。

谢谢!

package.json中的相关依赖项:

 "dependencies": {
    "@babel/polyfill": "^7.0.0",
    "classnames": "^2.2.6",
    "history": "^4.7.2",
    "json-stringify-pretty-compact": "^1.2.0",
    "minimist": "^1.2.0",
    "normalize.css": "^8.0.0",
    "nullthrows": "^1.1.0",
    "react": "^16.5.2",
    "react-dom": "^16.5.2",
    "react-router-dom": "^4.3.1",
    "rxjs": "^6.3.3",
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/plugin-proposal-class-properties": "^7.1.0",
    "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
    "@babel/preset-env": "^7.1.0",
    "@babel/preset-flow": "^7.0.0",
    "@babel/preset-react": "^7.0.0",
    "babel-core": "^7.0.0-bridge.0",
    "babel-env": "^2.4.1",
    "babel-eslint": "^10.0.1",
    "babel-jest": "^23.6.0",
    "babel-loader": "^8.0.4",
    "copy-webpack-plugin": "^4.5.3",
    "css-loader": "^1.0.0",
    "eslint": "^5.9.0",
    "eslint-plugin-flowtype": "^3.2.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-react": "^7.11.1",
    "eslint-watch": "^4.0.2",
    "flow-bin": "^0.83.0",
    "html-webpack-plugin": "^3.2.0",
    "jest": "^23.6.0",
    "prettier": "^1.15.3",
    "style-loader": "^0.23.1",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  }

.babelrc文件

{
  "plugins": [
    "module:@babel/plugin-proposal-class-properties",
    "module:@babel/plugin-proposal-object-rest-spread"
  ],
  "presets": [
    ["module:@babel/preset-env", { "targets": { "node": "6.10" } }],
    "module:@babel/preset-flow"
  ]
}

2 个答案:

答案 0 :(得分:2)

即使我在这个主题上晚了几年,这可能会帮助其他不熟悉测试异步代码的人。 例如,请参考 https://jestjs.io/docs/asynchronous 并在订阅结束时使用 done() 回调。 如果不执行这个回调,因为之前的错误,测试会按预期失败。

it('should fetch the right data', done => {
  fetchData().subscribe(data => {
    expect(data).toBe('expected data');
    done();
  });
});

答案 1 :(得分:1)

找出问题所在!将此留给遇到类似问题的任何人。 RxJS和Jest正常工作并正确传播错误。问题是我在测试脚本中添加了“ jest.useFakeTimers”调用。由于某种原因,这导致错误无法在测试中正确传播。我需要添加“ jest.runAllTimers”以获取引发的错误。这是完整的测试脚本,已正确实施:

import {of} from 'rxjs';

jest.useFakeTimers();

test('should fail', () => {
  of(false).subscribe(val => {
    expect(val).toBe(true);
  });
  jest.runAllTimers();
});

如果不需要模拟计时器,则无需添加它们。我以为假计时器是一个问题有点奇怪,即使我可以验证代码是否被同步调用。如果有人对为什么会发生这种情况的实现细节有更深入的了解,我将不胜感激。