Skip to content

Commit

Permalink
test(resolutionContext): add test for baseUrl configuration (#1898)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcosta7 authored Nov 30, 2023
1 parent 8100e6d commit b440f12
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 30 deletions.
4 changes: 4 additions & 0 deletions src/core/handlers/RequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ export abstract class RequestHandler<

/**
* Test if this handler matches the given request.
*
* This method is not used internally but is exposed
* as a convenience method for consumers writing custom
* handlers.
*/
public async test(args: {
request: Request
Expand Down
134 changes: 105 additions & 29 deletions src/core/utils/handleRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { passthrough } from '../passthrough'
const options: RequiredDeep<SharedOptions> = {
onUnhandledRequest: vi.fn(),
}
const callbacks: Partial<Record<keyof HandleRequestOptions, any>> = {
const handleRequestOptions: Partial<Record<keyof HandleRequestOptions, any>> = {
onPassthroughResponse: vi.fn(),
onMockedResponse: vi.fn(),
}
Expand Down Expand Up @@ -65,7 +65,7 @@ test('returns undefined for a request with the "x-msw-intention" header equal to
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).toBeUndefined()
Expand All @@ -74,8 +74,11 @@ test('returns undefined for a request with the "x-msw-intention" header equal to
['request:end', { request, requestId }],
])
expect(options.onUnhandledRequest).not.toHaveBeenCalled()
expect(callbacks.onPassthroughResponse).toHaveBeenNthCalledWith(1, request)
expect(callbacks.onMockedResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).toHaveBeenNthCalledWith(
1,
request,
)
expect(handleRequestOptions.onMockedResponse).not.toHaveBeenCalled()
})

test('does not bypass a request with "x-msw-intention" header set to arbitrary value', async () => {
Expand All @@ -98,12 +101,12 @@ test('does not bypass a request with "x-msw-intention" header set to arbitrary v
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).not.toBeUndefined()
expect(options.onUnhandledRequest).not.toHaveBeenCalled()
expect(callbacks.onMockedResponse).toHaveBeenCalledTimes(1)
expect(handleRequestOptions.onMockedResponse).toHaveBeenCalledTimes(1)
})

test('reports request as unhandled when it has no matching request handlers', async () => {
Expand All @@ -119,7 +122,7 @@ test('reports request as unhandled when it has no matching request handlers', as
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).toBeUndefined()
Expand All @@ -132,8 +135,11 @@ test('reports request as unhandled when it has no matching request handlers', as
warning: expect.any(Function),
error: expect.any(Function),
})
expect(callbacks.onPassthroughResponse).toHaveBeenNthCalledWith(1, request)
expect(callbacks.onMockedResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).toHaveBeenNthCalledWith(
1,
request,
)
expect(handleRequestOptions.onMockedResponse).not.toHaveBeenCalled()
})

test('returns undefined on a request handler that returns no response', async () => {
Expand All @@ -154,7 +160,7 @@ test('returns undefined on a request handler that returns no response', async ()
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).toBeUndefined()
Expand All @@ -163,8 +169,11 @@ test('returns undefined on a request handler that returns no response', async ()
['request:end', { request, requestId }],
])
expect(options.onUnhandledRequest).not.toHaveBeenCalled()
expect(callbacks.onPassthroughResponse).toHaveBeenNthCalledWith(1, request)
expect(callbacks.onMockedResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).toHaveBeenNthCalledWith(
1,
request,
)
expect(handleRequestOptions.onMockedResponse).not.toHaveBeenCalled()

/**
* @note Returning undefined from a resolver no longer prints a warning.
Expand Down Expand Up @@ -199,7 +208,7 @@ test('returns the mocked response for a request with a matching request handler'
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).toEqual(mockedResponse)
Expand All @@ -208,11 +217,11 @@ test('returns the mocked response for a request with a matching request handler'
['request:match', { request, requestId }],
['request:end', { request, requestId }],
])
expect(callbacks.onPassthroughResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).not.toHaveBeenCalled()

expect(callbacks.onMockedResponse).toHaveBeenCalledTimes(1)
expect(handleRequestOptions.onMockedResponse).toHaveBeenCalledTimes(1)
const [mockedResponseParam, lookupResultParam] =
callbacks.onMockedResponse.mock.calls[0]
handleRequestOptions.onMockedResponse.mock.calls[0]

expect(mockedResponseParam.status).toBe(mockedResponse.status)
expect(mockedResponseParam.statusText).toBe(mockedResponse.statusText)
Expand Down Expand Up @@ -265,7 +274,7 @@ test('returns a transformed response if the "transformResponse" option is provid
options,
emitter,
{
...callbacks,
...handleRequestOptions,
transformResponse,
},
)
Expand All @@ -281,7 +290,7 @@ test('returns a transformed response if the "transformResponse" option is provid
['request:match', { request, requestId }],
['request:end', { request, requestId }],
])
expect(callbacks.onPassthroughResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).not.toHaveBeenCalled()

expect(transformResponse).toHaveBeenCalledTimes(1)
const [responseParam] = transformResponse.mock.calls[0]
Expand All @@ -292,9 +301,9 @@ test('returns a transformed response if the "transformResponse" option is provid
Object.fromEntries(mockedResponse.headers.entries()),
)

expect(callbacks.onMockedResponse).toHaveBeenCalledTimes(1)
expect(handleRequestOptions.onMockedResponse).toHaveBeenCalledTimes(1)
const [mockedResponseParam, lookupResultParam] =
callbacks.onMockedResponse.mock.calls[0]
handleRequestOptions.onMockedResponse.mock.calls[0]

expect(mockedResponseParam.status).toBe(finalResponse.status)
expect(mockedResponseParam.statusText).toBe(finalResponse.statusText)
Expand Down Expand Up @@ -330,7 +339,7 @@ it('returns undefined without warning on a passthrough request', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(result).toBeUndefined()
Expand All @@ -339,8 +348,11 @@ it('returns undefined without warning on a passthrough request', async () => {
['request:end', { request, requestId }],
])
expect(options.onUnhandledRequest).not.toHaveBeenCalled()
expect(callbacks.onPassthroughResponse).toHaveBeenNthCalledWith(1, request)
expect(callbacks.onMockedResponse).not.toHaveBeenCalled()
expect(handleRequestOptions.onPassthroughResponse).toHaveBeenNthCalledWith(
1,
request,
)
expect(handleRequestOptions.onMockedResponse).not.toHaveBeenCalled()
})

it('marks the first matching one-time handler as used', async () => {
Expand All @@ -366,7 +378,7 @@ it('marks the first matching one-time handler as used', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(await firstResult?.text()).toBe('One-time')
Expand All @@ -379,7 +391,7 @@ it('marks the first matching one-time handler as used', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(await secondResult?.text()).toBe('Another')
Expand Down Expand Up @@ -413,7 +425,7 @@ it('does not mark non-matching one-time handlers as used', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(await firstResult?.text()).toBe('Another')
Expand All @@ -426,7 +438,7 @@ it('does not mark non-matching one-time handlers as used', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

expect(await secondResult?.text()).toBe('One-time')
Expand Down Expand Up @@ -457,15 +469,15 @@ it('handles parallel requests with one-time handlers', async () => {
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)
const secondResultPromise = handleRequest(
request,
requestId,
handlers,
options,
emitter,
callbacks,
handleRequestOptions,
)

const firstResult = await firstResultPromise
Expand All @@ -476,3 +488,67 @@ it('handles parallel requests with one-time handlers', async () => {
expect(oneTimeHandler.isUsed).toBe(true)
expect(anotherHandler.isUsed).toBe(true)
})

describe('[Private] - resolutionContext - used for extensions', () => {
describe('#baseUrl', () => {
test('when defined, handle requests to that base url only defining pathnames in the handler', async () => {
const { emitter } = setup()

const baseUrl = 'http://this-base-url-works.com'
const handleRequestOptionsWithBaseUrl: HandleRequestOptions = {
...handleRequestOptions,
resolutionContext: { baseUrl },
}

const handler = http.get('/resource', () => {
return HttpResponse.text('Mocked response')
})

const handlers: Array<RequestHandler> = [handler]

const requestId = uuidv4()
const request = new Request(new URL('/resource', baseUrl))
const response = await handleRequest(
request,
requestId,
handlers,
options,
emitter,
handleRequestOptionsWithBaseUrl,
)

expect(await response?.text()).toBe('Mocked response')
})

test('when defined, do not handle requests to different base urls when defining pathnames in the handler', async () => {
const { emitter } = setup()

const baseUrl = 'http://this-base-url-works.com'
const handleRequestOptionsWithBaseUrl: HandleRequestOptions = {
...handleRequestOptions,
resolutionContext: { baseUrl },
}

const handler = http.get('/resource', () => {
return HttpResponse.text('Mocked response')
})

const handlers: Array<RequestHandler> = [handler]

const requestId = uuidv4()
const request = new Request(
new URL('/resource', `http://not-the-base-url.com`),
)
const response = await handleRequest(
request,
requestId,
handlers,
options,
emitter,
handleRequestOptionsWithBaseUrl,
)

expect(response).toBeUndefined()
})
})
})
9 changes: 8 additions & 1 deletion src/core/utils/handleRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ import { readResponseCookies } from './request/readResponseCookies'

export interface HandleRequestOptions {
/**
* Options for the response resolution process.
* `resolutionContext` is not part of the general public api
* but is exposed to aid in creating extensions like
* `@mswjs/http-middleware`.
*/
resolutionContext?: {
/**
* A base url to use when resolving relative urls.
* @note This is primarily used by the `@mswjs/http-middleware`
* to resolve relative urls in the context of the running server
*/
baseUrl?: string
}

Expand Down

0 comments on commit b440f12

Please sign in to comment.