bun
bun copied to clipboard
Support `msw`
What is the problem this feature would solve?
use msw
in bun has some problem, after some exploration, find node:http
is not fully implemented in Bun.
with this code
import axios from 'axios';
import { setupServer } from 'msw/node'
const server = setupServer(...[])
server.listen({
onUnhandledRequest: 'warn',
});
axios.get('https://swapi.dev/api/people/?page=2')
.then(function (response) {
// handle success
console.log(response.data.results.length);
})
.catch(function (error) {
// handle error
console.log(error?.message);
});
and dependencies:
{
"dependencies": {
"axios": "^1.4.0",
"msw": "^1.2.3"
}
}
output in Node:
[MSW] Warning: captured a request without a matching request handler:
• GET https://swapi.dev:8001/api/people/
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
Request failed with status code 400
output in Bun
Cannot call a class constructor without |new|
and first two of error stack is
TypeError: Cannot call a class constructor without |new|
at ClientRequest (node:http:884:26)
What is the feature you are proposing to solve the problem?
fully implement node:http
to support msw
What alternatives have you considered?
No response
Thank you for reporting this.
Our node:http
module is basically complete but it looks like some exports are missing (but implemented) and aside from that we have been getting a few bug reports with it lately.
I'm currently working on porting all of the node:http
tests from Node and working through the bugs now and hopefully we can get full compatibility with node:http
and node:https
(or close to it) within the next few days or so.
Thank you for reporting this.
Our
node:http
module is basically complete but it looks like some exports are missing (but implemented) and aside from that we have been getting a few bug reports with it lately.I'm currently working on porting all of the
node:http
tests from Node and working through the bugs now and hopefully we can get full compatibility withnode:http
andnode:https
(or close to it) within the next few days or so.
Sorry to bother, do we have trouble in porting node:http?
@Jarred-Sumner sorry to bother, can you have a look at this problem, which broke msw
in bun:test
Current output in bun:
➜ bun index.ts
🚀 ~ http: {
Agent: [class Agent],
Server: [class Server],
createServer: [Function],
ServerResponse: [class ServerResponse],
IncomingMessage: [class IncomingMessage],
request: [Function],
get: [Function],
maxHeaderSize: 16384,
validateHeaderName: [Function],
validateHeaderValue: [Function],
setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
globalAgent: { /* Removed for comparison to Node */ },
ClientRequest: [class ClientRequest],
OutgoingMessage: [class OutgoingMessage]
}
Node is here
{
_connectionListener: [Function: connectionListener],
Agent: [Function: Agent] { defaultMaxSockets: Infinity },
ClientRequest: [Function: ClientRequest],
IncomingMessage: [Function: IncomingMessage],
OutgoingMessage: [Function: OutgoingMessage],
Server: [Function: Server],
ServerResponse: [Function: ServerResponse],
createServer: [Function: createServer],
validateHeaderName: [Function: __node_internal_],
validateHeaderValue: [Function: __node_internal_],
get: [Function: get],
request: [Function: request],
maxHeaderSize: [Getter],
globalAgent: [Getter/Setter]
}
So the discrepancy is now that only Bun has: setMaxIdleHTTPParsers
and only Node has _connectionListener
, and that the types are somewhat different like maxHeaderSize
is a 16384
in bun and a [Getter] in Node.
The ticket here is specifically about ClientRequest
and msw
, which now is in Bun, so @xxleyi, can you verify that this works now? You can change the title to something more specific, like Support msw
or ClientRequest not in node:http
, and close it if it is working.
The ticket here is specifically about
ClientRequest
andmsw
, which now is in Bun, so @xxleyi, can you verify that this works now? You can change the title to something more specific, likeSupport msw
orClientRequest not in node:http
, and close it if it is working.
Original issue has been fixed, but Support msw
still not works, I will change title to something more specific
Issue in MSW repo:
- https://github.com/mswjs/msw/issues/1718
Some additional information about node.http module compatibility in BUN https://github.com/mswjs/interceptors/issues/418#issuecomment-1722383706
Hey, folks. So from the report in https://github.com/mswjs/interceptors/issues/418#issuecomment-1722383706, it appears that this is no longer an issue with MSW 2.0. I highly encourage you updating and letting me know whether the same cannot call without new
error persists on that version. Thanks.
Hey, I try with a minimal repo like this
import { HttpResponse, http } from 'msw';
import { setupServer } from 'msw/node'
const handlers = [
http.get("https://bun.sh", () => {
return HttpResponse.json({ "test": "a" })
})
]
export const server = setupServer(...handlers)
server.listen({
onUnhandledRequest: "warn"
})
const response = await fetch("https://bun.sh");
const html = await response.text(); // HTML string
And give this error:
61 | }, getEventListeners = function(emitter, type) {
62 | if (emitter instanceof EventTarget)
63 | throwNotImplemented("getEventListeners with an EventTarget", 2678);
64 | return emitter.listeners(type);
65 |
66 | }, setMaxListeners = function(n, ...eventTargets) {
^
TypeError: undefined is not a function
at node:events:66:58
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:60:10
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:18:4
at new Promise (:1:20)
at __async (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:2:9)
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/chunk-YQGTMMOZ.mjs:50:10
at emitAsync (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/chunk-YQGTMMOZ.mjs:44:25)
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:62:34
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:61:53
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@open-draft/until/lib/index.mjs:4:23
139 | }
140 | };
141 | var FetchInterceptor = _FetchInterceptor;
142 | FetchInterceptor.symbol = Symbol("fetch");
143 | function createNetworkError(cause) {
144 | return Object.assign(new TypeError("Failed to fetch"), {
^
TypeError: Failed to fetch
at createNetworkError (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:144:23)
at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:84:30
The undefined is not a function is a console log of the error in the /node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:84:30
The error is inside the bun implementation of setMaxListeners
.
If I comment that function the library works like a charm
Thanks to
@Nisgrak's tips
Hey, I try with a minimal repo like this
import { HttpResponse, http } from 'msw'; import { setupServer } from 'msw/node' const handlers = [ http.get("https://bun.sh", () => { return HttpResponse.json({ "test": "a" }) }) ] export const server = setupServer(...handlers) server.listen({ onUnhandledRequest: "warn" }) const response = await fetch("https://bun.sh"); const html = await response.text(); // HTML string
And give this error:
61 | }, getEventListeners = function(emitter, type) { 62 | if (emitter instanceof EventTarget) 63 | throwNotImplemented("getEventListeners with an EventTarget", 2678); 64 | return emitter.listeners(type); 65 | 66 | }, setMaxListeners = function(n, ...eventTargets) { ^ TypeError: undefined is not a function at node:events:66:58 at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:60:10 at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:18:4 at new Promise (:1:20) at __async (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/msw/lib/node/index.mjs:2:9) at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/chunk-YQGTMMOZ.mjs:50:10 at emitAsync (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/chunk-YQGTMMOZ.mjs:44:25) at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:62:34 at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:61:53 at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@open-draft/until/lib/index.mjs:4:23 139 | } 140 | }; 141 | var FetchInterceptor = _FetchInterceptor; 142 | FetchInterceptor.symbol = Symbol("fetch"); 143 | function createNetworkError(cause) { 144 | return Object.assign(new TypeError("Failed to fetch"), { ^ TypeError: Failed to fetch at createNetworkError (/Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:144:23) at /Users/enekorg/Proyectos/test/test-bun-msw/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:84:30
The undefined is not a function is a console log of the error in the /node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs:84:30
The error is inside the bun implementation of
setMaxListeners
.If I comment that function the library works like a charm
Here is the workaround(currently in Bun v1.0.18):
import { expect, test, describe, mock } from "bun:test"
// fix
mock.module("events", () => {
return {
setMaxListeners: () => {},
}
})
import { HttpResponse, http } from 'msw';
import { setupServer } from 'msw/node'
const handlers = [
http.get("https://bun.sh", () => {
return HttpResponse.json({ "test": "a" })
})
]
export const server = setupServer(...handlers)
server.listen({
onUnhandledRequest: "warn"
})
const response = await fetch("https://bun.sh");
const html = await response.text(); // HTML string
Does it only work with fetch()
? I have the same example bellow, using Axios for the request, and it’s throwing an error:
import axios from "axios";
import { HttpResponse, http } from "msw";
import { setupServer } from "msw/node";
const axiosInstance = axios.create();
const handlers = [
http.get("https://bun.sh", () => {
return HttpResponse.json({ test: "a" });
}),
];
export const server = setupServer(...handlers);
server.listen({
onUnhandledRequest: "warn",
});
// this works fine
// const response = await fetch("https://bun.sh");
// const html = response.json();
// but with axios, it doesn't
const response = await axiosInstance.get("https://bun.sh");
const html = response.data;
bun test v1.0.26 (c75e768a)
src/Sample.test.ts:
432 | total: totalResponseBodyLength
433 | });
434 | };
435 | if (response.body) {
436 | this.logger.info("mocked response has body, streaming...");
437 | const reader = response.body.getReader();
^
TypeError: response.body.getReader is not a function. (In 'response.body.getReader()', 'response.body.getReader' is undefined)
at respondWith (/Users/joeldaros/corteva/msw-2-issue/node_modules/@mswjs/interceptors/lib/node/chunk-IZG42TWK.mjs:437:22)
Does it only work with
fetch()
? I have the same example bellow, using Axios for the request, and it’s throwing an error:import axios from "axios"; import { HttpResponse, http } from "msw"; import { setupServer } from "msw/node"; const axiosInstance = axios.create(); const handlers = [ http.get("https://bun.sh", () => { return HttpResponse.json({ test: "a" }); }), ]; export const server = setupServer(...handlers); server.listen({ onUnhandledRequest: "warn", }); // this works fine // const response = await fetch("https://bun.sh"); // const html = response.json(); // but with axios, it doesn't const response = await axiosInstance.get("https://bun.sh"); const html = response.data;
bun test v1.0.26 (c75e768a) src/Sample.test.ts: 432 | total: totalResponseBodyLength 433 | }); 434 | }; 435 | if (response.body) { 436 | this.logger.info("mocked response has body, streaming..."); 437 | const reader = response.body.getReader(); ^ TypeError: response.body.getReader is not a function. (In 'response.body.getReader()', 'response.body.getReader' is undefined) at respondWith (/Users/joeldaros/corteva/msw-2-issue/node_modules/@mswjs/interceptors/lib/node/chunk-IZG42TWK.mjs:437:22)
I too facing the same issue. @joel-daros were you able to fix this issue?
too facing the same issue. @joel-daros were you able to fix this issue?
Nope. Maybe @kettanaito can help to identify if it’s a MSW or Bun issue.
too facing the same issue. @joel-daros were you able to fix this issue?
Nope. Maybe @kettanaito can help to identify if it’s a MSW or Bun issue.
Adding below snippet in jest configuration worked for me.
const { Blob, File } = require('node:buffer')
const { fetch, Headers, FormData, Request, Response } = require('undici')
Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Blob: { value: Blob },
File: { value: File },
Headers: { value: Headers },
FormData: { value: FormData },
Request: { value: Request },
Response: { value: Response },
})
@joel-daros, I can help indeed, with this issue any other issues: MSW works without problems in Node.js. Every exception you encounter while using it with Bun is Bun's issue related to Node.js compatibility (it can also be your misconfigured environment, like @kishores05 has pointed out, so first ensure MSW works in your environment).
Is there any progress on this?
A heads-up on this, in the near future MSW will migrate to a new architecture for request interception in Node.js (see https://github.com/mswjs/interceptors/pull/515). That architecture will rely on net.Socket
and HttpAgent
instead of http.ClientRequest
. If anyone from the Bun team is looking into this issue, consider looking at the compatibility with net.Socket
in Node.js as the first step.
The new algorithm also relies on
HTTPParser
which is not a public API in Node.js but is distributed regardless in thenode:_http_common
built-in module. Bun has to implement both that module and theHTTPParser
class in order for MSW to work in Bun.
Does this still reproduce for you? using Bun 1.1.8 this works for me.
Does this still reproduce for you? using Bun 1.1.8 this works for me.
yeah, still reproduce for me. did you try with the code demo i provide?
update: with msw v2 lastest version(2.3.0), the code demo works, however, if i put a real handler, still has issues:
import axios from 'axios';
import { http, passthrough, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
const server = setupServer(...[
http.get('https://swapi.dev/api/people/', () => {
// return passthrough()
return HttpResponse.json({ results: [{}, {}] })
}),
])
server.listen({
onUnhandledRequest: 'warn',
});
axios.get('https://swapi.dev/api/people/?page=2')
.then(function (response) {
// handle success
console.log(response.data.results.length);
})
.catch(function (error) {
// handle error
console.log(error?.message);
});
with output:
485 | writableFinished: { value: true },
486 | writableEnded: { value: true }
487 | });
488 | this.emit("finish");
489 | const { status, statusText, headers, body } = mockedResponse;
490 | this.response.statusCode = status;
^
TypeError: Attempted to assign to readonly property.
A heads-up on this, in the near future MSW will migrate to a new architecture for request interception in Node.js (see mswjs/interceptors#515). That architecture will rely on
net.Socket
andHttpAgent
instead ofhttp.ClientRequest
. If anyone from the Bun team is looking into this issue, consider looking at the compatibility withnet.Socket
in Node.js as the first step.The new algorithm also relies on
HTTPParser
which is not a public API in Node.js but is distributed regardless in thenode:_http_common
built-in module. Bun has to implement both that module and theHTTPParser
class in order for MSW to work in Bun.
Looks like msw 2.4.4 is now using the HTTPParser
which Bun doesn't currently seem to support (I'm on 1.1.27). Is there a Bun version that does, or should this issue be reopened?
looks like https://github.com/oven-sh/bun/issues/13072 is already open
Can confirm we've migrated to use built-in HTTP parser in Node.js since v2.4.4. If you wish to run MSW in Bun, Bun has to implement that parser. It may be tricky since it's technically an internal built-in _http_common
.