File size: 3,210 Bytes
1f21206 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | import { describe, it, expect, beforeEach } from 'bun:test'
import { MessageBuffer } from '../message-buffer.js'
describe('MessageBuffer', () => {
it('accumulates text and flushes on complete', async () => {
const flushed: Array<{ text: string; isComplete: boolean }> = []
const buf = new MessageBuffer(
(text, isComplete) => { flushed.push({ text, isComplete }) },
500, // 500ms interval
1000, // 1000 char threshold
)
buf.append('Hello ')
buf.append('World')
await buf.complete()
expect(flushed.length).toBeGreaterThanOrEqual(1)
const allText = flushed.map((f) => f.text).join('')
expect(allText).toBe('Hello World')
// Last flush should be marked complete
expect(flushed[flushed.length - 1]!.isComplete).toBe(true)
})
it('flushes when character threshold is reached', async () => {
const flushed: string[] = []
const buf = new MessageBuffer(
(text) => { flushed.push(text) },
10000, // very long interval (won't trigger)
10, // 10 char threshold
)
buf.append('12345678901') // 11 chars > threshold
// Wait for microtask
await new Promise((r) => setTimeout(r, 10))
expect(flushed.length).toBeGreaterThanOrEqual(1)
buf.reset()
})
it('flushes on timer interval', async () => {
const flushed: string[] = []
const buf = new MessageBuffer(
(text) => { flushed.push(text) },
50, // 50ms interval
1000,
)
buf.append('hi')
// Wait for timer
await new Promise((r) => setTimeout(r, 80))
expect(flushed).toContain('hi')
buf.reset()
})
it('does not flush empty buffer on complete', async () => {
const flushed: string[] = []
const buf = new MessageBuffer(
(text) => { flushed.push(text) },
)
await buf.complete()
expect(flushed.length).toBe(0)
})
it('waits for an in-flight flush before complete resolves', async () => {
let releaseFlush!: () => void
let flushStarted = false
const flushed: Array<{ text: string; isComplete: boolean }> = []
const buf = new MessageBuffer(
async (text, isComplete) => {
flushStarted = true
flushed.push({ text, isComplete })
await new Promise<void>((resolve) => {
releaseFlush = resolve
})
},
10000,
3,
)
buf.append('abcd')
await new Promise((resolve) => setTimeout(resolve, 0))
expect(flushStarted).toBe(true)
let completeResolved = false
const completing = buf.complete().then(() => {
completeResolved = true
})
await new Promise((resolve) => setTimeout(resolve, 0))
expect(completeResolved).toBe(false)
releaseFlush()
await completing
expect(completeResolved).toBe(true)
expect(flushed).toEqual([{ text: 'abcd', isComplete: false }])
})
it('resets properly between messages', async () => {
const flushed: string[] = []
const buf = new MessageBuffer(
(text) => { flushed.push(text) },
500,
1000,
)
buf.append('first')
buf.reset()
buf.append('second')
await buf.complete()
const allText = flushed.map((f) => f).join('')
expect(allText).toBe('second')
})
})
|