@johngw/stream
Version:
Reactive programming tools using the WHATWG Streams API.
113 lines (98 loc) • 2.99 kB
text/typescript
import { ForkableStream } from '@johngw/stream/sinks/ForkableStream'
import { fromCollection } from '@johngw/stream/sources/fromCollection'
import { write } from '@johngw/stream/sinks/write'
import { interval } from '@johngw/stream/sources/interval'
import { tap } from '@johngw/stream/transformers/tap'
import { timeout } from '@johngw/stream-common'
let forkable: ForkableStream<number>
let fn: jest.Mock<void, [number]>
let readable: ReadableStream<number>
beforeEach(() => {
forkable = new ForkableStream()
fn = jest.fn()
readable = fromCollection([1, 2, 3, 4, 5])
})
test('fork before piping', async () => {
const promise = forkable.fork().pipeTo(write(fn))
readable.pipeTo(forkable)
await promise
expect(fn).toHaveBeenCalledTimes(5)
})
test('fork after piping', async () => {
readable.pipeTo(forkable)
await forkable.fork().pipeTo(write(fn))
expect(fn).toHaveBeenCalledTimes(5)
})
test('multiple subscribers', async () => {
readable.pipeTo(forkable)
await Promise.all([
forkable.fork().pipeTo(write(fn)),
forkable.fork().pipeTo(write(fn)),
forkable.fork().pipeTo(write(fn)),
])
expect(fn).toHaveBeenCalledTimes(15)
})
test('finished property', async () => {
await readable.pipeTo(forkable)
expect(forkable.finished).toBe(true)
})
test('finished streams will immediately close forks', async () => {
await readable.pipeTo(forkable)
await forkable
.fork({
pull(controller) {
controller.enqueue(6)
},
})
.pipeTo(write(fn))
expect(fn).not.toHaveBeenCalled()
})
describe('aborting', () => {
let fn: jest.Mock<void, [Date]>
let forkable: ForkableStream<Date>
let abortController: AbortController
beforeEach(() => {
fn = jest.fn()
forkable = new ForkableStream<Date>()
abortController = new AbortController()
interval(5)
.pipeThrough(tap(fn))
.pipeTo(forkable, { signal: abortController.signal })
.catch(() => {
//
})
})
afterEach(async () => {
abortController.abort()
})
test('previously aborted streams will error new forks', async () => {
abortController.abort()
await timeout()
await expect(forkable.fork().pipeTo(write())).rejects.toThrow()
})
test('aborting an stream will error previous forks', async () => {
const fork = forkable.fork().pipeTo(write())
abortController.abort()
await expect(fork).rejects.toThrow()
})
test('should not affect upstream', async () => {
await expect(
forkable.fork().pipeTo(write(), { signal: AbortSignal.timeout(10) })
).rejects.toThrow()
await timeout(50)
expect(fn.mock.calls.length).toBeGreaterThanOrEqual(5)
})
test('will cancel the fork', async () => {
let cancelled = false
await expect(
forkable
.fork({
cancel() {
cancelled = true
},
})
.pipeTo(write(), { signal: AbortSignal.timeout(10) })
).rejects.toThrow()
expect(cancelled).toBe(true)
})
})