-
-
Notifications
You must be signed in to change notification settings - Fork 130
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(MockHttpSocket): add "signal" tests (#559)
- Loading branch information
1 parent
e52851c
commit c362b39
Showing
1 changed file
with
119 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/** | ||
* @vitest-environment node | ||
*/ | ||
import { vi, it, expect, beforeAll, afterEach, afterAll } from 'vitest' | ||
import http from 'node:http' | ||
import { HttpServer } from '@open-draft/test-server/http' | ||
import { DeferredPromise } from '@open-draft/deferred-promise' | ||
import { ClientRequestInterceptor } from '../../../../src/interceptors/ClientRequest' | ||
import { sleep } from '../../../helpers' | ||
|
||
const httpServer = new HttpServer((app) => { | ||
app.get('/resource', async (req, res) => { | ||
await sleep(200) | ||
res.status(500).end() | ||
}) | ||
}) | ||
|
||
const interceptor = new ClientRequestInterceptor() | ||
|
||
beforeAll(async () => { | ||
interceptor.apply() | ||
await httpServer.listen() | ||
}) | ||
|
||
afterEach(() => { | ||
interceptor.removeAllListeners() | ||
}) | ||
|
||
afterAll(async () => { | ||
interceptor.dispose() | ||
await httpServer.close() | ||
}) | ||
|
||
it('respects the "signal" for a handled request', async () => { | ||
interceptor.on('request', ({ request }) => { | ||
request.respondWith(new Response('hello world')) | ||
}) | ||
|
||
const abortController = new AbortController() | ||
const request = http.get( | ||
httpServer.http.url('/resource'), | ||
{ | ||
signal: abortController.signal, | ||
}, | ||
() => { | ||
abortController.abort('abort reason') | ||
} | ||
) | ||
|
||
// Must listen to the "close" event instead of "abort". | ||
const requestClosePromise = new DeferredPromise<void>() | ||
request.on('close', () => requestClosePromise.resolve()) | ||
await requestClosePromise | ||
|
||
// ClientRequest doesn't expose the destroy reason. | ||
// It's kept in the kError symbol but we won't be going there. | ||
expect(request.destroyed).toBe(true) | ||
}) | ||
|
||
it('respects the "signal" for a bypassed request', async () => { | ||
const abortController = new AbortController() | ||
const request = http.get( | ||
httpServer.http.url('/resource'), | ||
{ | ||
signal: abortController.signal, | ||
}, | ||
() => { | ||
abortController.abort('abort reason') | ||
} | ||
) | ||
|
||
// Must listen to the "close" event instead of "abort". | ||
const requestClosePromise = new DeferredPromise<void>() | ||
request.on('close', () => requestClosePromise.resolve()) | ||
await requestClosePromise | ||
|
||
// ClientRequest doesn't expose the destroy reason. | ||
// It's kept in the kError symbol but we won't be going there. | ||
expect(request.destroyed).toBe(true) | ||
}) | ||
|
||
it('respects "AbortSignal.timeout()" for a handled request', async () => { | ||
interceptor.on('request', ({ request }) => { | ||
request.respondWith(new Response('hello world')) | ||
}) | ||
|
||
const timeoutListener = vi.fn() | ||
const request = http.get('http://localhost/resource', { | ||
signal: AbortSignal.timeout(10), | ||
}) | ||
request.on('timeout', timeoutListener) | ||
|
||
// Must listen to the "close" event instead of "abort". | ||
const requestClosePromise = new DeferredPromise<void>() | ||
request.on('close', () => requestClosePromise.resolve()) | ||
await requestClosePromise | ||
|
||
expect(request.destroyed).toBe(true) | ||
// "AbortSignal.timeout()" indicates that it will create a | ||
// timeout after which the request will be destroyed. It | ||
// doesn't actually mean the request will time out. | ||
expect(timeoutListener).not.toHaveBeenCalled() | ||
}) | ||
|
||
it('respects "AbortSignal.timeout()" for a bypassed request', async () => { | ||
const timeoutListener = vi.fn() | ||
const request = http.get(httpServer.http.url('/resource'), { | ||
signal: AbortSignal.timeout(10), | ||
}) | ||
request.on('timeout', timeoutListener) | ||
|
||
// Must listen to the "close" event instead of "abort". | ||
const requestClosePromise = new DeferredPromise<void>() | ||
request.on('close', () => requestClosePromise.resolve()) | ||
await requestClosePromise | ||
|
||
expect(request.destroyed).toBe(true) | ||
expect(timeoutListener).not.toHaveBeenCalled() | ||
}) |