UNPKG

rxjs-mergemap-array

Version:

An RxJS map operator that takes an observable of arrays as input and emits arrays where each element represents emissions from the projected observable.

304 lines (280 loc) 6.87 kB
import {concat, firstValueFrom, of, Subject, timer} from 'rxjs' import {delay, toArray} from 'rxjs/operators' import {describe, expect, it} from 'vitest' import {mergeMapArray} from './mergeMapArray' describe('mergeMapArray()', () => { it('works with an empty array as input', async () => { const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray(() => timer(1000)), toArray(), ) const promise = firstValueFrom(observable) subject.next([]) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [], ] `) }) it('orders the output array based on the input array', async () => { const one = {id: 1} const two = {id: 2} const three = {id: 3} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray((item) => concat(of(`id=${item.id} #1`), of(`id=${item.id} #2`).pipe(delay(20))), ), toArray(), ) const promise = firstValueFrom(observable) subject.next([one, two, three]) subject.next([three, two, one]) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", "id=2 #1", "id=3 #1", ], [ "id=3 #1", "id=2 #1", "id=1 #2", ], [ "id=3 #1", "id=2 #2", "id=1 #2", ], [ "id=3 #2", "id=2 #2", "id=1 #2", ], ] `) }) it("stops the inner observable when it's source value is removed from the input array", async () => { const one = {id: 1} const two = {id: 2} const three = {id: 3} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray((item) => concat(of(`id=${item.id} #1`), of(`id=${item.id} #2`).pipe(delay(20))), ), toArray(), ) const promise = firstValueFrom(observable) subject.next([one, two, three]) subject.next([one, two]) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", "id=2 #1", "id=3 #1", ], [ "id=1 #1", "id=2 #1", ], [ "id=1 #2", "id=2 #1", ], [ "id=1 #2", "id=2 #2", ], ] `) }) it('works with duplicate elements', async () => { const one = {id: 1} const two = {id: 2} const three = {id: 3} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray((item) => { return concat(of(`id=${item.id} #1`), of(`id=${item.id} #2`).pipe(delay(20))) }), toArray(), ) const promise = firstValueFrom(observable) subject.next([one, two, three, one, two, three]) subject.next([one, two]) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", "id=2 #1", "id=3 #1", "id=1 #1", "id=2 #1", "id=3 #1", ], [ "id=1 #1", "id=2 #1", ], [ "id=1 #2", "id=2 #1", ], [ "id=1 #2", "id=2 #2", ], ] `) }) it('works with multiple emissions', async () => { const one = {id: 1} const two = {id: 2} const three = {id: 3} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray((item) => { return concat(of(`id=${item.id} #1`), of(`id=${item.id} #2`).pipe(delay(20))) }), toArray(), ) const promise = firstValueFrom(observable) subject.next([one, two, one, two]) subject.next([one]) subject.next([one, two, three]) subject.next([one, three]) subject.next([one, two]) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", "id=2 #1", "id=1 #1", "id=2 #1", ], [ "id=1 #1", ], [ "id=1 #1", "id=2 #1", "id=3 #1", ], [ "id=1 #1", "id=3 #1", ], [ "id=1 #1", "id=3 #1", ], [ "id=1 #1", "id=2 #1", ], [ "id=1 #1", "id=2 #1", ], [ "id=1 #2", "id=2 #1", ], [ "id=1 #2", "id=2 #2", ], ] `) }) it('supports custom isEqual', async () => { const one = {id: 1} const anotherone = {id: 1} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray( (item) => { return concat( of(`id=${item.id} #1`), of(`id=${item.id} #2`).pipe(delay(20)), of(`id=${item.id} #3`).pipe(delay(100)), ) }, (a, b) => a.id === b.id, ), toArray(), ) const promise = firstValueFrom(observable) subject.next([anotherone]) subject.next([one]) subject.next([anotherone, one]) await new Promise((resolve) => setTimeout(resolve, 100)) subject.next([anotherone]) await new Promise((resolve) => setTimeout(resolve, 100)) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", ], [ "id=1 #2", "id=1 #2", ], [ "id=1 #3", ], ] `) }) }) it('waits for all mapped values to emit', async () => { const one = {id: 1} const anotherone = {id: 2} const third = {id: 3} const subject = new Subject<{id: number}[]>() const observable = subject.asObservable().pipe( mergeMapArray((item) => item.id === 2 ? of(`id=${item.id} #1`).pipe(delay(20)) : item.id === 3 ? of(`id=${item.id} #1`).pipe(delay(20)) : of(`id=${item.id} #1`), ), toArray(), ) const promise = firstValueFrom(observable) subject.next([one, anotherone]) subject.next([one]) await new Promise((resolve) => setTimeout(resolve, 100)) subject.next([one, anotherone]) await new Promise((resolve) => setTimeout(resolve, 100)) subject.next([one, anotherone, third]) await new Promise((resolve) => setTimeout(resolve, 100)) subject.complete() expect(await promise).toMatchInlineSnapshot(` [ [ "id=1 #1", ], [ "id=1 #1", "id=2 #1", ], [ "id=1 #1", "id=2 #1", "id=3 #1", ], ] `) })