36 lines
1.7 KiB
TypeScript
36 lines
1.7 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
|
|
// Keep a response open; the browser test controls sample delivery independently of HTTP routes.
|
|
export async function installOpenLiveStream(page: Page, path: string, sample: unknown, sendImmediately = true) {
|
|
await page.clock.install()
|
|
await page.addInitScript(({ path, sample, sendImmediately }) => {
|
|
const originalFetch = window.fetch.bind(window)
|
|
window.fetch = async (input, init) => {
|
|
const url = new URL(input instanceof Request ? input.url : String(input), location.href)
|
|
if (url.pathname !== path) return originalFetch(input, init)
|
|
const stream = new ReadableStream<Uint8Array>({
|
|
start(controller) {
|
|
const encode = (value: string) => new TextEncoder().encode(value)
|
|
const send = () => {
|
|
// A comment may precede an event; CRLF delimiters may cross chunks.
|
|
controller.enqueue(encode(': heartbeat\r\nevent: sample\r\ndata: ' + JSON.stringify(sample) + '\r\n\r'))
|
|
controller.enqueue(encode('\n'))
|
|
}
|
|
const heartbeat = () => controller.enqueue(encode(': heartbeat\r\n\r\n'))
|
|
Object.assign(window, { sendLiveSample: send, sendLiveHeartbeat: heartbeat })
|
|
if (sendImmediately) send()
|
|
},
|
|
})
|
|
return new Response(stream, { headers: { 'Content-Type': 'text/event-stream' } })
|
|
}
|
|
}, { path, sample, sendImmediately })
|
|
}
|
|
|
|
export async function resumeLiveStream(page: Page) {
|
|
await page.evaluate(() => (window as unknown as { sendLiveSample: () => void }).sendLiveSample())
|
|
}
|
|
|
|
export async function sendLiveHeartbeat(page: Page) {
|
|
await page.evaluate(() => (window as unknown as { sendLiveHeartbeat: () => void }).sendLiveHeartbeat())
|
|
}
|