我将尝试分解您的测试,以便您了解发生了什么以及您做错了什么。真的很抱歉,但我不会使用jasmine-marbles库,而是编写测试的首选方式(我还建议您避免使用 jasmine-marbles 库)。
当转换为普通的旧弹珠(不使用 jasmine-marbles 库)时,您的测试如下所示:
import { mergeMap, map } from 'rxjs/operators';
import { TestScheduler } from 'rxjs/testing';
describe('mergeMap', () => {
let testScheduler: TestScheduler;
beforeEach(() => {
testScheduler = new TestScheduler(someMatcher);
});
it('should maps to inner observable and flattens', () => {
testScheduler.run(({ cold, expectObservable }) => {
const values = { a: 'hello', b: 'world', x: 'hello world' };
const obs1 = cold('-a---a| ', values);
const obs2 = cold('-b-b-b-| ', values);
const expected = ' --x-xxxx-x-|';
const result = obs1.pipe(mergeMap(x => obs2.pipe(map(y => x + ' ' + y))));
expectObservable(result).toBe(expected, values);
});
});
});
而这个测试失败了。原因如下:您希望您的测试在第 2、4、5、6、7、9 帧发射,并在第 11 帧完成发射。但是,实际发射发生在第 2、4、6、6、8 帧, 10 帧和第 12 帧完整。现在,为了能够直观地理解为什么以及如何发生这种情况,我将编写一个带有几个评论的测试,我将以不同的方式对齐它们,以便您更好地填充发生的事情:
const obs1 = cold('-a---a| ', values);
const obs2 = cold(' -b-b-b-| ', values);
// -b-b-b-|
const expected = ' --x-xxxx-x-| ';
// frames: 0123456789012
基本上,在 中mergeMap
,您将返回obs2
源 observable 何时发出的实例。在这种情况下,源是obs1
。当它在第1a
帧mergeMap
发出第一个值(obs2
obs2
a
obs2
类似地,当obs1
发出第二个值时,在第 5 帧,发生另一个订阅,obs2
并且由于obs2
是cold
可观察的,另一个生产者被实例化,因此另一个流开始流动。这就是为什么我添加了一条评论来指示第二次订阅何时obs2
发生。它从第 5 帧开始,就在第二帧a
从obs1
. 同样,来自第二个订阅的排放obs2
是到达消费者的排放。
因此,结合这一点,我们得出了预期帧应该在哪里的结论:
-b-b-b-| emits at frames: 2, 4 and 6 and a complete at frame 8
-b-b-b-| emits at frames: 6, 8 and 10 and a complete at frame 12
0123456789012
基于此,最终的发射发生在第 2、4、6、6、8 和 10 帧,而完整的发射发生在第 12 帧。这种设置的问题是不可能显示在两个或更多排放量在同一框架内。
也就是说,第 8 帧的发射与第 6 帧的两个发射太接近了。原因是在同一帧发生的发射()
在大理石图中用括号分组,而括号在某种程度上隐藏了一些发射。这是你的情况:
-b-b-b-|
-b-b-b-|
--x-x-(xx)x-| // brackets start at frame 6 and represent grouped emissions which all happen at frame 6
0123456666012 // the frames 7, 8 and 9 are "hidden"
第 7、8 和 9 帧是隐藏的,无法表示,因此这些帧的排放量无论如何都无法显示在大理石图中。而且,由于第 8 帧的发射丢失了,因此您无法为该预期发射创建适当的大理石图。
为了使该测试通过,您可以在第6 帧进一步a
从obs1
一帧发出第二个。现在,您的测试可能如下所示(它现在应该通过):
testScheduler.run(({ cold, expectObservable }) => {
const values = { a: 'hello', b: 'world', x: 'hello world' };
const obs1 = cold('-a----a| ', values);
const obs2 = cold(' -b-b-b-| ', values);
// -b-b-b-|
const expected = ' --x-x-xx-x-x-|';
const result = obs1.pipe(mergeMap(x => obs2.pipe(map(y => x + ' ' + y))));
expectObservable(result).toBe(expected, values);
});