From 79ae8424f8d183c063ce9d4584ee24359af9e4e8 Mon Sep 17 00:00:00 2001 From: Artem Zakharchenko Date: Thu, 9 Jan 2025 19:05:01 +0100 Subject: [PATCH] test: add warn/error/bypass `onUnhandledRequest` tests --- src/node/index.ts | 2 +- .../on-unhandled-request-bypass.test.ts | 107 ++++++++++++++++++ .../on-unhandled-request-error.test.ts | 100 ++++++++++++++++ .../on-unhandled-request-warn.test.ts | 105 +++++++++++++++++ .../msw-api/setup-remote-server/use.app.js | 5 + .../node/msw-api/setup-remote-server/utils.ts | 8 +- 6 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 test/node/msw-api/setup-remote-server/on-unhandled-request-bypass.test.ts create mode 100644 test/node/msw-api/setup-remote-server/on-unhandled-request-error.test.ts create mode 100644 test/node/msw-api/setup-remote-server/on-unhandled-request-warn.test.ts diff --git a/src/node/index.ts b/src/node/index.ts index df0fcff78..363da30a6 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,4 +1,4 @@ -export type { SetupServer } from './glossary' +export type { SetupServer, ListenOptions } from './glossary' export { SetupServerApi } from './SetupServerApi' export { setupServer } from './setupServer' export { diff --git a/test/node/msw-api/setup-remote-server/on-unhandled-request-bypass.test.ts b/test/node/msw-api/setup-remote-server/on-unhandled-request-bypass.test.ts new file mode 100644 index 000000000..7775fe54d --- /dev/null +++ b/test/node/msw-api/setup-remote-server/on-unhandled-request-bypass.test.ts @@ -0,0 +1,107 @@ +// @vitest-environment node +import { http } from 'msw' +import { setupRemoteServer } from 'msw/node' +import { spawnTestApp } from './utils' + +const remote = setupRemoteServer() + +beforeAll(async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + await remote.listen({ + onUnhandledRequest: 'bypass', + }) +}) + +afterEach(() => { + remote.resetHandlers() +}) + +afterAll(async () => { + await remote.close() +}) + +it( + 'does not error on the request not handled here and there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js'), { + onUnhandledRequest: 'bypass', + }) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/unhandled', + }, + }) + + const unhandledErrorPromise = vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + + • GET http://localhost/unhandled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledErrorPromise).rejects.toThrow() + expect(console.error).not.toHaveBeenCalled() + }), +) + +it( + 'does not error on the request handled here', + remote.boundary(async () => { + remote.use( + http.get('http://localhost/handled', () => { + return new Response('handled') + }), + ) + + await using testApp = await spawnTestApp(require.resolve('./use.app.js'), { + onUnhandledRequest: 'bypass', + }) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/handled', + }, + }) + + const unhandledErrorPromise = vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + +• GET http://localhost/handled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledErrorPromise).rejects.toThrow() + expect(console.error).not.toHaveBeenCalled() + }), +) + +it( + 'does not error on the request handled there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js'), { + onUnhandledRequest: 'bypass', + }) + + await fetch(new URL('/resource', testApp.url)) + + const unhandledErrorPromise = vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + +• GET https://example.com/resource + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledErrorPromise).rejects.toThrow() + expect(console.error).not.toHaveBeenCalled() + }), +) diff --git a/test/node/msw-api/setup-remote-server/on-unhandled-request-error.test.ts b/test/node/msw-api/setup-remote-server/on-unhandled-request-error.test.ts new file mode 100644 index 000000000..a266465a6 --- /dev/null +++ b/test/node/msw-api/setup-remote-server/on-unhandled-request-error.test.ts @@ -0,0 +1,100 @@ +// @vitest-environment node +import { http } from 'msw' +import { setupRemoteServer } from 'msw/node' +import { spawnTestApp } from './utils' + +const remote = setupRemoteServer() + +beforeAll(async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + await remote.listen({ + onUnhandledRequest: 'error', + }) +}) + +afterEach(() => { + vi.clearAllMocks() + remote.resetHandlers() +}) + +afterAll(async () => { + vi.restoreAllMocks() + await remote.close() +}) + +it( + 'errors on the request not handled here and there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/unhandled', + }, + }) + + await vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + + • GET http://localhost/unhandled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + }), +) + +it( + 'does not error on the request handled here', + remote.boundary(async () => { + remote.use( + http.get('http://localhost/handled', () => { + return new Response('handled') + }), + ) + + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/handled', + }, + }) + + const unhandledErrorPromise = vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + +• GET http://localhost/handled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledErrorPromise).rejects.toThrow() + expect(console.error).not.toHaveBeenCalled() + }), +) + +it( + 'does not error on the request handled there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/resource', testApp.url)) + + const unhandledErrorPromise = vi.waitFor(() => { + expect(console.error).toHaveBeenCalledWith(`\ +[MSW] Error: intercepted a request without a matching request handler: + +• GET https://example.com/resource + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledErrorPromise).rejects.toThrow() + expect(console.error).not.toHaveBeenCalled() + }), +) diff --git a/test/node/msw-api/setup-remote-server/on-unhandled-request-warn.test.ts b/test/node/msw-api/setup-remote-server/on-unhandled-request-warn.test.ts new file mode 100644 index 000000000..c7502e597 --- /dev/null +++ b/test/node/msw-api/setup-remote-server/on-unhandled-request-warn.test.ts @@ -0,0 +1,105 @@ +// @vitest-environment node +import { http } from 'msw' +import { setupRemoteServer } from 'msw/node' +import { spawnTestApp } from './utils' + +const remote = setupRemoteServer() + +beforeAll(async () => { + /** + * @note Console warnings from the app's context are forwarded + * as `console.error`. Ignore those for this test. + */ + vi.spyOn(console, 'error').mockImplementation(() => {}) + vi.spyOn(console, 'warn').mockImplementation(() => {}) + await remote.listen({ + onUnhandledRequest: 'warn', + }) +}) + +afterEach(() => { + vi.clearAllMocks() + remote.resetHandlers() +}) + +afterAll(async () => { + vi.restoreAllMocks() + await remote.close() +}) + +it( + 'warns on the request not handled here and there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/unhandled', + }, + }) + + await vi.waitFor(() => { + expect(console.warn).toHaveBeenCalledWith(`\ +[MSW] Warning: intercepted a request without a matching request handler: + + • GET http://localhost/unhandled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + }), +) + +it( + 'does not warn on the request handled here', + remote.boundary(async () => { + remote.use( + http.get('http://localhost/handled', () => { + return new Response('handled') + }), + ) + + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/proxy', testApp.url), { + headers: { + location: 'http://localhost/handled', + }, + }) + + const unhandledWarningPromise = vi.waitFor(() => { + expect(console.warn).toHaveBeenCalledWith(`\ +[MSW] Warning: intercepted a request without a matching request handler: + +• GET http://localhost/handled + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledWarningPromise).rejects.toThrow() + expect(console.warn).not.toHaveBeenCalled() + }), +) + +it( + 'does not warn on the request handled there', + remote.boundary(async () => { + await using testApp = await spawnTestApp(require.resolve('./use.app.js')) + + await fetch(new URL('/resource', testApp.url)) + + const unhandledWarningPromise = vi.waitFor(() => { + expect(console.warn).toHaveBeenCalledWith(`\ +[MSW] Warning: intercepted a request without a matching request handler: + +• GET https://example.com/resource + +If you still wish to intercept this unhandled request, please create a request handler for it. +Read more: https://mswjs.io/docs/getting-started/mocks`) + }) + + await expect(unhandledWarningPromise).rejects.toThrow() + expect(console.warn).not.toHaveBeenCalled() + }), +) diff --git a/test/node/msw-api/setup-remote-server/use.app.js b/test/node/msw-api/setup-remote-server/use.app.js index d74266fca..ee623085d 100644 --- a/test/node/msw-api/setup-remote-server/use.app.js +++ b/test/node/msw-api/setup-remote-server/use.app.js @@ -3,6 +3,8 @@ const express = require('express') const { http, HttpResponse } = require('msw') const { setupServer } = require('msw/node') +const { SETUP_SERVER_LISTEN_OPTIONS } = process.env + // Enable API mocking as usual. const server = setupServer( http.get('https://example.com/resource', () => { @@ -11,6 +13,9 @@ const server = setupServer( ) server.listen({ + ...(SETUP_SERVER_LISTEN_OPTIONS + ? JSON.parse(SETUP_SERVER_LISTEN_OPTIONS) + : {}), remote: { enabled: true, }, diff --git a/test/node/msw-api/setup-remote-server/utils.ts b/test/node/msw-api/setup-remote-server/utils.ts index 1be18d239..6f975e484 100644 --- a/test/node/msw-api/setup-remote-server/utils.ts +++ b/test/node/msw-api/setup-remote-server/utils.ts @@ -1,9 +1,12 @@ import { invariant } from 'outvariant' import { ChildProcess, spawn } from 'child_process' import { DeferredPromise } from '@open-draft/deferred-promise' -import { getRemoteEnvironment } from 'msw/node' +import { type ListenOptions, getRemoteEnvironment } from 'msw/node' -export async function spawnTestApp(appSourcePath: string) { +export async function spawnTestApp( + appSourcePath: string, + listenOptions: Partial = {}, +) { let url: string | undefined const spawnPromise = new DeferredPromise().then((resolvedUrl) => { url = resolvedUrl @@ -18,6 +21,7 @@ export async function spawnTestApp(appSourcePath: string) { env: { ...process.env, ...getRemoteEnvironment(), + SETUP_SERVER_LISTEN_OPTIONS: JSON.stringify(listenOptions), }, })