用 Jest 模拟 Observable - rxjs

MLy*_*yck 6 unit-testing mocking rxjs jestjs

我有一个来自另一个 Observable 的简单 Observable 管道,我想测试它。

const loginState$ = messageBusObservables.loginState$.pipe(
    startWith({ isLoggedIn: false })
    pluck('isLoggedIn'),
    distinctUntilChanged()
  )
Run Code Online (Sandbox Code Playgroud)

messageBusObservables 是一个可观察对象。其中 loginState$ 是一个 Observable。

在我的测试中,我认为我可以轻松地像这样模拟“./messageBus”模块:(模块的导入方式无关紧要,但首选导入)

import { of } from 'rxjs'
import './messageBus'
jest.mock('./messageBus', () => ({
  loginState$: of({ isLoggedIn: true }),
}))
Run Code Online (Sandbox Code Playgroud)

但是,Jest 抛出错误:

babel-plugin-jest-hoist:模块工厂jest.mock()不允许引用任何范围外的变量。无效的变量访问: of

我试过,把它放在一个jest.fn()我试过提取of({ isLoggedIn: true })到一个变量中。但是我总是从玩笑中得到同样的错误。

那么如何使用 Jest 模拟输入到我的 Observable 中呢?我会在使用 .merge、.zip 等的其他 observable 中遇到同样的问题。

它需要是一个真正的 observable,是我其他 observable 的输入。我只是想用类似的东西来模拟值,of()而不是模拟一个对象,上面有一个方法,返回一个带有 .pipe 方法等的对象(我不想模拟 Observable 的功能)。我想通过在我的单元测试中设置一个值来传递一个真正的 observable。

我还需要这些模拟是动态的。因此,来自 1 个断言的模拟可能与下一个断言中的模拟不同。(用 beforeEach 之类的东西清除它们)

编辑:

我还尝试使用 babel-plugin-rewire 来模拟这个模块,这在我模拟它的 *.test.js 文件中工作得很好。但在实际文件中,无论我将导出设置为使用 rewire,它总是作为原始 Observable 导入。

小智 11

您收到此消息的原因:

babel-plugin-jest-hoist:jest.mock() 的模块工厂不允许引用任何范围外的变量。无效的变量访问: of

是因为 jest 会自动提升对 jest.mock 的调用,以便它们在导入之前发生。

您有两种选择来解决此默认行为,简单的方法是使用未提升的 jest.doMock:

jest.doMock('./messageBus', () => ({
  loginState$: of({ isLoggedIn: true }),
}))
Run Code Online (Sandbox Code Playgroud)

或者,您可以在传递给 jest.mock 的模拟工厂中引用的所有变量的前缀为“mock”:

const mockMessageBus = {
  loginState$: of({ isLoggedIn: true }),
}
jest.doMock('./messageBus', () => mockMessageBus)
Run Code Online (Sandbox Code Playgroud)

(请注意,当 jest.mock 被调用时,您有责任确保工厂函数中引用的所有模拟变量都在范围内)