fix(logger-plugin): support ipv6 host and handle undefined protocol/host#1215
fix(logger-plugin): support ipv6 host and handle undefined protocol/host#1215
Conversation
📝 WalkthroughWalkthroughAdds a safe URL-construction utility with IPv6 bracket handling and fallbacks for missing protocol/host, and updates the logger plugin to use it; adds unit and E2E tests (msw, nock) and updates dev dependencies and changelog. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
src/utils/create-url.ts (1)
1-1: Usenode:urlto match the rest of the codebase.
src/plugins/default/logger-plugin.ts(and others) use thenode:prefix; aligning here keeps imports consistent and makes the built-in module unambiguous.♻️ Proposed change
-import { URL } from 'url'; +import { URL } from 'node:url';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/create-url.ts` at line 1, The import for the URL constructor is using 'url' but the project standard is to use the Node built-in prefix; update the import in src/utils/create-url.ts to import URL from 'node:url' instead of 'url' so it matches other modules (e.g., logger-plugin) and avoids ambiguity when locating the built-in URL symbol.test/unit/utils/create-url.spec.ts (1)
47-50: Move this test out of the "happy paths" group.It asserts a
toThrow()outcome and documents pass-through bracket behavior — better suited to the "edge cases" describe block (e.g., a newedge cases — already-bracketed IPv6group) for accurate grouping.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/unit/utils/create-url.spec.ts` around lines 47 - 50, The test asserting createUrl({ protocol: 'http:', host: '[::1]', port: '9000' }) throws (checking double-bracketing/pass-through behavior) should be relocated out of the "happy paths" describe and into an "edge cases" describe block (e.g., "edge cases — already-bracketed IPv6") to reflect its expected-to-throw behavior; update the surrounding describe/it grouping so the test still uses the same it(...) title but resides under the new edge-case describe to keep test organization clear.src/plugins/default/logger-plugin.ts (1)
56-62: Use the configuredloggerinstead ofconsole.errorin the catch fallback.
loggeris already in scope (Line 23) and is used elsewhere in this plugin (e.g., Line 33). Routing this error throughconsole.errorbypasses any customloggerprovided via theloggeroption, so consumers (e.g., webpack-dev-server, browser-sync) won’t see this diagnostic in their normal pipeline.♻️ Proposed refactor
} catch (err) { // should not error. keeping fallback just in case - console.error('[HPM] Unexpected error while creating target URL', err); + logger.error('[HPM] Unexpected error while creating target URL %o', err); // fallback to old implementation (less correct - without port) target = new URL(options.target as URL); target.pathname = proxyRes.req.path; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/plugins/default/logger-plugin.ts` around lines 56 - 62, Replace the console.error call inside the catch block that handles target URL creation with the configured logger: use the existing logger variable to log the error (e.g., logger.error or appropriate logger method) and include the error object and context message; keep the fallback creation of target via new URL(options.target as URL) and setting target.pathname = proxyRes.req.path unchanged. Ensure you update the log invocation within the catch in the function that constructs the target URL so it uses logger instead of console.test/e2e/msw.spec.ts (1)
17-27: Align with MSW's recommended lifecycle pattern for better efficiency.MSW's documented best practice uses
server.listen()inbeforeAll,server.resetHandlers()inafterEach, andserver.close()inafterAll. The current setup starts and stops the interceptor per test, which adds unnecessary overhead. The handlers are correctly reset between tests, so behavior is unaffected—this is purely an optimization.♻️ Proposed refactor
-import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; @@ - beforeEach(() => { - // Supertest sends local loopback requests to the in-memory app; bypass those. - server.listen({ onUnhandledRequest: 'bypass' }); - }); - - afterEach(() => { - server.resetHandlers(); - server.close(); - }); + beforeAll(() => { + // Supertest sends local loopback requests to the in-memory app; bypass those. + server.listen({ onUnhandledRequest: 'bypass' }); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + afterAll(() => { + server.close(); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/e2e/msw.spec.ts` around lines 17 - 27, The MSW lifecycle is inefficient: change the test setup to call setupServer() as now but move server.listen({ onUnhandledRequest: 'bypass' }) from beforeEach into a beforeAll, keep server.resetHandlers() in afterEach, and move server.close() from afterEach into an afterAll; update the test hooks referencing the server instance (setupServer, server.listen, server.resetHandlers, server.close) accordingly so the interceptor starts once before the suite and stops once after the suite while still resetting handlers between tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/plugins/default/logger-plugin.ts`:
- Around line 56-62: Replace the console.error call inside the catch block that
handles target URL creation with the configured logger: use the existing logger
variable to log the error (e.g., logger.error or appropriate logger method) and
include the error object and context message; keep the fallback creation of
target via new URL(options.target as URL) and setting target.pathname =
proxyRes.req.path unchanged. Ensure you update the log invocation within the
catch in the function that constructs the target URL so it uses logger instead
of console.
In `@src/utils/create-url.ts`:
- Line 1: The import for the URL constructor is using 'url' but the project
standard is to use the Node built-in prefix; update the import in
src/utils/create-url.ts to import URL from 'node:url' instead of 'url' so it
matches other modules (e.g., logger-plugin) and avoids ambiguity when locating
the built-in URL symbol.
In `@test/e2e/msw.spec.ts`:
- Around line 17-27: The MSW lifecycle is inefficient: change the test setup to
call setupServer() as now but move server.listen({ onUnhandledRequest: 'bypass'
}) from beforeEach into a beforeAll, keep server.resetHandlers() in afterEach,
and move server.close() from afterEach into an afterAll; update the test hooks
referencing the server instance (setupServer, server.listen,
server.resetHandlers, server.close) accordingly so the interceptor starts once
before the suite and stops once after the suite while still resetting handlers
between tests.
In `@test/unit/utils/create-url.spec.ts`:
- Around line 47-50: The test asserting createUrl({ protocol: 'http:', host:
'[::1]', port: '9000' }) throws (checking double-bracketing/pass-through
behavior) should be relocated out of the "happy paths" describe and into an
"edge cases" describe block (e.g., "edge cases — already-bracketed IPv6") to
reflect its expected-to-throw behavior; update the surrounding describe/it
grouping so the test still uses the same it(...) title but resides under the new
edge-case describe to keep test organization clear.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: db951e2f-1262-45c1-91f6-7ce98e023efc
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (7)
CHANGELOG.mdpackage.jsonsrc/plugins/default/logger-plugin.tssrc/utils/create-url.tstest/e2e/msw.spec.tstest/e2e/nock.spec.tstest/unit/utils/create-url.spec.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
test/e2e/msw.spec.ts (2)
125-153: Router test mirrors nock parity well; consider also asserting[HPM]log here.Since
#1056specifically targets therouter(notarget) code path in the logger, assertingconsole.infowas called with the expected[HPM] ... -> http://localhost:45679/api/router [200]line in this test would directly cover the regression that motivated the PR. Currently only the GET test asserts logging; the router branch — which is the one#1056calls out — is verified only via response body.♻️ Suggested addition
it('supports router to re-target specific requests', async () => { + await using consoleInfoSpy = await vi.spyOn(console, 'info'); + server.use( http.get(`${alternateTarget}/api/router`, () => { return new HttpResponse('routed target', { status: 200 }); }), http.get(`${target}/api/default`, () => { return new HttpResponse('default target', { status: 200 }); }), ); const agent = request( createApp( createProxyMiddleware({ pathFilter: '/api', // Keep msw-based e2e stable and aligned with nock e2e transport path. followRedirects: true, + logger: console, router(req) { return req.url === '/api/router' ? alternateTarget : target; }, }), ), ); const routedResponse = await agent.get('/api/router').expect(200); const defaultResponse = await agent.get('/api/default').expect(200); expect(routedResponse.text).toBe('routed target'); expect(defaultResponse.text).toBe('default target'); + expect(consoleInfoSpy).toHaveBeenCalledWith( + '[HPM] GET /api/router -> http://localhost:45679/api/router [200]', + ); + expect(consoleInfoSpy).toHaveBeenCalledWith( + '[HPM] GET /api/default -> http://localhost:45678/api/default [200]', + ); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/e2e/msw.spec.ts` around lines 125 - 153, Add an assertion that the logger emitted the HPM routing line by spying on console.info around the router request: before calling agent.get('/api/router') create a spy (e.g., const consoleSpy = jest.spyOn(console, 'info').mockImplementation(() => {})), perform the routed request via routedResponse = await agent.get('/api/router').expect(200), then expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[HPM]'), expect.stringContaining('-> http://localhost:45679/api/router'), expect.stringContaining('[200]')) (or use a single expect.stringMatching regex that matches the full log line), and finally restore the spy with consoleSpy.mockRestore(); reference the createProxyMiddleware({ router }) usage and the routedResponse/agent variables to locate where to insert the spy and assertion.
17-27: Refactor MSW lifecycle to follow the recommendedbeforeAll/afterAllpattern.The current code calls
server.listen()inbeforeEachandserver.close()inafterEach, which reinstalls MSW interceptors for every test. MSW's documented pattern is to calllisten()once inbeforeAll,resetHandlers()inafterEach, andclose()once inafterAll. This eliminates unnecessary setup/teardown overhead per test.Suggested refactor
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; @@ - beforeEach(() => { - // Supertest sends local loopback requests to the in-memory app; bypass those. - server.listen({ onUnhandledRequest: 'bypass' }); - }); - - afterEach(() => { - server.resetHandlers(); - server.close(); - }); + // Supertest sends local loopback requests to the in-memory app; bypass those. + beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })); + afterEach(() => server.resetHandlers()); + afterAll(() => server.close());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/e2e/msw.spec.ts` around lines 17 - 27, Move MSW server lifecycle from per-test to suite-level: call setupServer() remains, replace beforeEach/afterEach listen/close usage with beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })) and afterAll(() => server.close()), and keep afterEach(() => server.resetHandlers()) to reset per-test handlers; update functions referenced: server, setupServer, beforeEach, afterEach, beforeAll, afterAll, server.listen, server.resetHandlers, server.close.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@test/e2e/msw.spec.ts`:
- Around line 125-153: Add an assertion that the logger emitted the HPM routing
line by spying on console.info around the router request: before calling
agent.get('/api/router') create a spy (e.g., const consoleSpy =
jest.spyOn(console, 'info').mockImplementation(() => {})), perform the routed
request via routedResponse = await agent.get('/api/router').expect(200), then
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[HPM]'),
expect.stringContaining('-> http://localhost:45679/api/router'),
expect.stringContaining('[200]')) (or use a single expect.stringMatching regex
that matches the full log line), and finally restore the spy with
consoleSpy.mockRestore(); reference the createProxyMiddleware({ router }) usage
and the routedResponse/agent variables to locate where to insert the spy and
assertion.
- Around line 17-27: Move MSW server lifecycle from per-test to suite-level:
call setupServer() remains, replace beforeEach/afterEach listen/close usage with
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })) and afterAll(()
=> server.close()), and keep afterEach(() => server.resetHandlers()) to reset
per-test handlers; update functions referenced: server, setupServer, beforeEach,
afterEach, beforeAll, afterAll, server.listen, server.resetHandlers,
server.close.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7128c6c6-081c-4d29-ad4c-73621b3f0ed4
📒 Files selected for processing (2)
test/e2e/msw.spec.tstest/e2e/nock.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- test/e2e/nock.spec.ts
Improve
logger-pluginfixed: #1035
fixed: #1056
Summary by CodeRabbit
New Features
Bug Fixes
Tests