From 496154da7e76007977d0c5e937a79e0fc55ae34b Mon Sep 17 00:00:00 2001 From: Artem Zakharchenko Date: Wed, 22 Jun 2022 17:17:45 +0200 Subject: [PATCH] fix: apply response delay conditionally (#1300) * fix(handleRequest): apply response delay conditionally * test: add integration test for delay in node --- src/node/createSetupServer.ts | 36 +++++++------ src/utils/handleRequest.ts | 34 ++++++------ test/msw-api/context/delay.node.test.ts | 72 +++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 34 deletions(-) create mode 100644 test/msw-api/context/delay.node.test.ts diff --git a/src/node/createSetupServer.ts b/src/node/createSetupServer.ts index 35060985b..f57680dc9 100644 --- a/src/node/createSetupServer.ts +++ b/src/node/createSetupServer.ts @@ -67,24 +67,30 @@ export function createSetupServer( interceptor.on('request', async function setupServerListener(request) { const mockedRequest = parseIsomorphicRequest(request) - const response = await handleRequest( - mockedRequest, - currentHandlers, - resolvedOptions, - emitter, - { - transformResponse(response) { - return { - status: response.status, - statusText: response.statusText, - headers: response.headers.all(), - body: response.body, - } - }, + const response = await handleRequest< + MockedInterceptedResponse & { delay?: number } + >(mockedRequest, currentHandlers, resolvedOptions, emitter, { + transformResponse(response) { + return { + status: response.status, + statusText: response.statusText, + headers: response.headers.all(), + body: response.body, + delay: response.delay, + } }, - ) + }) if (response) { + // Delay Node.js responses in the listener so that + // the response lookup logic is not concerned with responding + // in any way. The same delay is implemented in the worker. + if (response.delay) { + await new Promise((resolve) => { + setTimeout(resolve, response.delay) + }) + } + request.respondWith(response) } diff --git a/src/utils/handleRequest.ts b/src/utils/handleRequest.ts index 3952aeadf..2877e428e 100644 --- a/src/utils/handleRequest.ts +++ b/src/utils/handleRequest.ts @@ -125,27 +125,23 @@ Expected response resolver to return a mocked response Object, but got %s. The o emitter.emit('request:match', request) - return new Promise((resolve) => { - const requiredLookupResult = - lookupResult as RequiredDeep + const requiredLookupResult = + lookupResult as RequiredDeep - const transformedResponse = - handleRequestOptions?.transformResponse?.(response) || - (response as any as ResponseType) + const transformedResponse = + handleRequestOptions?.transformResponse?.(response) || + (response as any as ResponseType) - handleRequestOptions?.onMockedResponse?.( - transformedResponse, - requiredLookupResult, - ) + handleRequestOptions?.onMockedResponse?.( + transformedResponse, + requiredLookupResult, + ) - setTimeout(() => { - handleRequestOptions?.onMockedResponseSent?.( - transformedResponse, - requiredLookupResult, - ) - emitter.emit('request:end', request) + handleRequestOptions?.onMockedResponseSent?.( + transformedResponse, + requiredLookupResult, + ) + emitter.emit('request:end', request) - resolve(transformedResponse as ResponseType) - }, response.delay ?? 0) - }) + return transformedResponse } diff --git a/test/msw-api/context/delay.node.test.ts b/test/msw-api/context/delay.node.test.ts new file mode 100644 index 000000000..279e8fbc2 --- /dev/null +++ b/test/msw-api/context/delay.node.test.ts @@ -0,0 +1,72 @@ +/** + * @jest-environment node + */ +import fetch from 'node-fetch' +import { rest } from 'msw' +import { setupServer } from 'msw/node' +import { performance } from 'perf_hooks' + +const server = setupServer() + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +async function makeRequest(url: string) { + const requestStart = performance.now() + const res = await fetch(url) + const requestEnd = performance.now() + const responseTime = requestEnd - requestStart + + return { res, responseTime } +} + +test('uses explicit server response time', async () => { + server.use( + rest.get('http://localhost/user', (req, res, ctx) => { + return res(ctx.delay(500), ctx.text('john')) + }), + ) + + const { res, responseTime } = await makeRequest('http://localhost/user') + + expect(responseTime).toBeGreaterThanOrEqual(500) + expect(await res.text()).toBe('john') +}) + +test('uses realistic server response time when no duration is provided', async () => { + server.use( + rest.get('http://localhost/user', (req, res, ctx) => { + return res(ctx.delay(), ctx.text('john')) + }), + ) + + const { res, responseTime } = await makeRequest('http://localhost/user') + + // Realistic server response time in Node.js is set to 5ms. + expect(responseTime).toBeGreaterThan(5) + expect(responseTime).toBeLessThan(100) + expect(await res.text()).toBe('john') +}) + +test('uses realistic server response time when "real" mode is provided', async () => { + server.use( + rest.get('http://localhost/user', (req, res, ctx) => { + return res(ctx.delay('real'), ctx.text('john')) + }), + ) + + const { res, responseTime } = await makeRequest('http://localhost/user') + + // Realistic server response time in Node.js is set to 5ms. + expect(responseTime).toBeGreaterThan(5) + expect(await res.text()).toBe('john') +})