48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import { EventEmitter } from 'node:events'
|
|
import { Readable } from 'node:stream'
|
|
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { bridge } from '../src/http-bridge.ts'
|
|
|
|
describe('HTTP bridge abort', () => {
|
|
it('aborts a pending native picker request when the browser disconnects', async () => {
|
|
const body = JSON.stringify({
|
|
type: 'client-request', rpcId: 'picker-1', method: 'host.pickDirectory', payload: {},
|
|
})
|
|
const request = Readable.from([Buffer.from(body)]) as unknown as IncomingMessage
|
|
Object.assign(request, {
|
|
url: '/api/host.pickDirectory',
|
|
method: 'POST',
|
|
headers: { 'content-type': 'application/json' },
|
|
})
|
|
|
|
const response = Object.assign(new EventEmitter(), {
|
|
writableEnded: false,
|
|
writeHead() { return this },
|
|
write() { return true },
|
|
end() { this.writableEnded = true; return this },
|
|
}) as unknown as ServerResponse
|
|
|
|
let resolveStarted!: () => void
|
|
const started = new Promise<void>((resolve) => { resolveStarted = resolve })
|
|
let carrierSignal: AbortSignal | undefined
|
|
const pending = bridge(request, response, {
|
|
fetch: async (input) => {
|
|
const fetchRequest = input as Request
|
|
carrierSignal = fetchRequest.signal
|
|
resolveStarted()
|
|
if (!fetchRequest.signal.aborted) {
|
|
await new Promise<void>((resolve) => {
|
|
fetchRequest.signal.addEventListener('abort', () => { resolve() }, { once: true })
|
|
})
|
|
}
|
|
return Response.json({ aborted: fetchRequest.signal.aborted })
|
|
},
|
|
})
|
|
await started
|
|
response.emit('close')
|
|
await pending
|
|
expect(carrierSignal?.aborted).toBe(true)
|
|
})
|
|
})
|