Skip to content

Commit

Permalink
Upgrade msw to next (2.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
IanVS committed Jun 12, 2024
1 parent 36fbe40 commit ddf4cba
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 114 deletions.
116 changes: 74 additions & 42 deletions lib/msw-config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import {
rest,
RestHandler,
setupWorker,
type RestRequest,
type SetupWorkerApi,
MockedRequest,
} from 'msw';
import { http, HttpHandler, HttpResponse, delay } from 'msw';
import { setupWorker, type SetupWorker } from 'msw/browser';
import PassthroughRegistry from './passthrough-registry';
import type { Server } from 'miragejs';
import type { Request } from 'miragejs';
import type { HTTPVerb, RouteHandler, ServerConfig } from 'miragejs/server';
import type { AnyFactories, AnyModels, AnyRegistry } from 'miragejs/-types';

Expand Down Expand Up @@ -43,7 +37,7 @@ type MirageServer = {
rawHandler?: RawHandler,
customizedCode?: ResponseCode,
options?: unknown
) => (request: RestRequest) => ResponseData | PromiseLike<ResponseData>;
) => (request: Request) => ResponseData | PromiseLike<ResponseData>;

shouldLog: () => boolean;

Expand Down Expand Up @@ -127,17 +121,17 @@ export default class MswConfig {

timing?: number;

msw?: SetupWorkerApi;
msw?: SetupWorker;

mirageServer?: MirageServer;

// TODO: infer models and factories
mirageConfig?: ServerConfig<AnyModels, AnyFactories>;

handlers: RestHandler[] = [];
handlers: HttpHandler[] = [];

private passthroughs;
private passthroughChecks: ((req: MockedRequest) => boolean)[] = [];
private passthroughChecks: ((req: globalThis.Request) => boolean)[] = [];

get?: BaseHandler;
post?: BaseHandler;
Expand Down Expand Up @@ -188,35 +182,72 @@ export default class MswConfig {
options
);
let fullPath = this._getFullPath(path);
let mswHandler = rest[verb](fullPath, async (req, res, ctx) => {
let mswHandler = http[verb](fullPath, async ({ request, params }) => {
let queryParams: Record<string, string | string[]> = {};
req.url.searchParams.forEach((value, key) => {
let newValue: string | string[] = value;
if (key.includes('[]')) {
key = key.replace('[]', '');
newValue = [...(queryParams[key] || []), value];
const reqUrl = new URL(request.url);
for (const [paramKey, paramValue] of reqUrl.searchParams.entries()) {
let newValue: string | string[] = paramValue;
let newKey = paramKey;
if (newKey.includes('[]')) {
newKey = newKey.replace('[]', '');
newValue = [...(queryParams[newKey] || []), paramValue];
}
queryParams[key] = newValue;
});
let request = Object.assign(req, {
requestBody:
typeof req.body === 'string'
? req.body
: JSON.stringify(req.body),
queryParams: queryParams,
queryParams[newKey] = newValue;
}

// Determine how to process a request body
let requestBody: string = '';
const contentType =
request.headers?.get('content-type')?.toLowerCase() || '';
const hasJsonContent = contentType.includes('json');
if (hasJsonContent) {
requestBody = JSON.stringify(await request.json());
} else {
// This will parse multipart as text, which I think will work? Should be tested
requestBody = await request.text();
}
const requestHeaders: Record<string, string> = {};
request.headers.forEach((v, k) => {
requestHeaders[k.toLowerCase()] = v;
});
let [code, headers, response] = await handler(request);
if (code === 204) {

let req: Request = {
requestBody,
// @ts-expect-error this is fixed in an unreleased version of miragejs
queryParams,
requestHeaders,
// @ts-expect-error params can be an array, but mirage doesn't expect that
params,
};

let [status, headers, responseBody] = await handler(req);

if (status === 204) {
// MirageJS Incorrectly sets the body to "" on a 204.
response = undefined;
responseBody = undefined;
}

const init = {
status,
headers,
};

// Delay the response if needed
if (this.timing) {
await delay(this.timing);
}

// Return the correct type of response based on the `accept` header
const accept = request.headers?.get('accept')?.toLowerCase() || '';
if (accept.includes('json')) {
return HttpResponse.json(responseBody, init);
} else if (accept.includes('text')) {
return HttpResponse.text(responseBody, init);
} else {
throw new Error(
`Mirage-msw: Only json and text responses are supported at this time. Please open an issue requesting support for ${accept}.`
);
}
return res(ctx.status(code), ctx.delay(this.timing), (res) => {
res.body = response;
Object.entries(headers || {}).forEach(([key, value]) => {
res.headers.set(key, value);
});
return res;
});
});
if (this.msw) {
this.msw.use(mswHandler);
Expand Down Expand Up @@ -454,7 +485,8 @@ export default class MswConfig {
quiet: !logging,
onUnhandledRequest: (req) => {
const verb = req.method.toUpperCase();
const path = req.url.pathname;
const requestUrl = new URL(req.url);
const path = requestUrl.pathname;

// Check passthrough functions
let shouldPassthrough = this.passthroughChecks.some(
Expand All @@ -463,15 +495,15 @@ export default class MswConfig {

// Also check other passthroughs
const recognized = this.passthroughs
.retrieve(req.url.host)
.retrieve(requestUrl.host)
?.get(verb)
?.recognize(path);
const match = recognized?.[0];

if (shouldPassthrough || match) {
if (this.mirageServer?.shouldLog()) {
console.log(
`Mirage: Passthrough request for ${verb} ${req.url.href}`
`Mirage: Passthrough request for ${verb} ${requestUrl.href}`
);
}
// @ts-expect-error this seems to be an issue in msw types
Expand All @@ -480,7 +512,7 @@ export default class MswConfig {

// Log a warning for any requests for resources that aren't static assets of the page itself
else if (
req.url.host !== window.location.host &&
requestUrl.host !== window.location.host &&
this.mirageServer?.shouldLog()
) {
let namespaceError = '';
Expand All @@ -490,7 +522,7 @@ export default class MswConfig {
namespaceError = `The existing namespace is ${this.namespace}`;
}
console.warn(
`Mirage: Your app tried to ${verb} '${req.url.href}', but there was no route defined to handle this request. Add a passthrough or define a route for this endpoint in your routes() config.\nDid you forget to define a namespace? ${namespaceError}`
`Mirage: Your app tried to ${verb} '${requestUrl.href}', but there was no route defined to handle this request. Add a passthrough or define a route for this endpoint in your routes() config.\nDid you forget to define a namespace? ${namespaceError}`
);
}
},
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"devDependencies": {
"@tsconfig/recommended": "^1.0.2",
"miragejs": "^0.1.47",
"msw": "^0.39.2",
"msw": "0.0.0-fetch.rc-19",
"prettier": "^3.0.1",
"tsup": "^7.2.0",
"typescript": "^5.1.6"
Expand All @@ -43,7 +43,7 @@
},
"peerDependancies": {
"miragejs": "~0.1.43",
"msw": "^0.39.2"
"msw": "^0.0.0-fetch.rc-16"
},
"author": "Brian Gantzler",
"license": "MIT",
Expand Down
Loading

0 comments on commit ddf4cba

Please sign in to comment.