mirror of
https://github.com/hanzoai/msw.git
synced 2026-09-24 17:00:34 +00:00
136 lines
3.5 KiB
TypeScript
136 lines
3.5 KiB
TypeScript
// @vitest-environment node
|
|
import https from 'node:https'
|
|
import { HttpResponse, http, delay } from 'msw'
|
|
import { setupServer } from 'msw/node'
|
|
|
|
interface CustomMatchers<R = unknown> {
|
|
toRoughlyEqual: (actual: number, deviation: number) => R
|
|
}
|
|
|
|
declare module 'vitest' {
|
|
interface Matchers<T = any> extends CustomMatchers<T> {}
|
|
}
|
|
|
|
expect.extend({
|
|
/**
|
|
* Asserts a given actual number to roughly equal to the expected number,
|
|
* taking the maximum allowed delta `deviation` into account.
|
|
*/
|
|
toRoughlyEqual(actual, expected, deviation) {
|
|
const diff = Math.abs(actual - expected)
|
|
const passes = diff <= deviation
|
|
|
|
if (passes) {
|
|
return {
|
|
pass: true,
|
|
message: () =>
|
|
`expected ${actual} not to be roughly equal to ${expected} (deviation: ${deviation})`,
|
|
}
|
|
}
|
|
|
|
return {
|
|
pass: false,
|
|
message: () =>
|
|
`expected ${actual} to be roughly equal to ${expected} (deviation: ${deviation})`,
|
|
}
|
|
},
|
|
})
|
|
|
|
const encoder = new TextEncoder()
|
|
const server = setupServer()
|
|
|
|
beforeAll(() => {
|
|
server.listen()
|
|
})
|
|
|
|
afterEach(() => {
|
|
server.resetHandlers()
|
|
})
|
|
|
|
afterAll(() => {
|
|
server.close()
|
|
})
|
|
|
|
test('responds with a ReadableStream', async () => {
|
|
server.use(
|
|
http.get('https://api.example.com/stream', () => {
|
|
const stream = new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue(encoder.encode('hello'))
|
|
controller.enqueue(encoder.encode('world'))
|
|
controller.close()
|
|
},
|
|
})
|
|
|
|
return new HttpResponse(stream, {
|
|
headers: {
|
|
'Content-Type': 'text/event-stream',
|
|
},
|
|
})
|
|
}),
|
|
)
|
|
|
|
const response = await fetch('https://api.example.com/stream')
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(response.statusText).toBe('OK')
|
|
expect(response.body).toBeInstanceOf(ReadableStream)
|
|
expect(response.body!.locked).toBe(false)
|
|
|
|
expect(await response.text()).toBe('helloworld')
|
|
})
|
|
|
|
test('supports delays when enqueuing chunks', async () => {
|
|
server.use(
|
|
http.get('https://api.example.com/stream', () => {
|
|
const stream = new ReadableStream({
|
|
async start(controller) {
|
|
controller.enqueue(encoder.encode('first'))
|
|
await delay(250)
|
|
|
|
controller.enqueue(encoder.encode('second'))
|
|
await delay(250)
|
|
|
|
controller.enqueue(encoder.encode('third'))
|
|
await delay(250)
|
|
controller.close()
|
|
},
|
|
})
|
|
|
|
return new HttpResponse(stream, {
|
|
headers: {
|
|
'Content-Type': 'text/event-stream',
|
|
},
|
|
})
|
|
}),
|
|
)
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
const request = https.get('https://api.example.com/stream', (response) => {
|
|
const chunks: Array<{ buffer: Buffer; timestamp: number }> = []
|
|
|
|
response.on('data', (data) => {
|
|
chunks.push({
|
|
buffer: Buffer.from(data),
|
|
timestamp: performance.now(),
|
|
})
|
|
})
|
|
|
|
response.once('end', () => {
|
|
const textChunks = chunks.map((chunk) => chunk.buffer.toString('utf8'))
|
|
expect(textChunks).toEqual(['first', 'second', 'third'])
|
|
|
|
// Ensure that the chunks were sent over time,
|
|
// respecting the delay set in the mocked stream.
|
|
const chunkTimings = chunks.map((chunk) => chunk.timestamp)
|
|
expect(chunkTimings[1] - chunkTimings[0]).toRoughlyEqual(250, 50)
|
|
expect(chunkTimings[2] - chunkTimings[1]).toRoughlyEqual(250, 50)
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
|
|
request.on('error', (error) => reject(error))
|
|
})
|
|
})
|