Skip to content

Commit

Permalink
Make sinon work
Browse files Browse the repository at this point in the history
  • Loading branch information
fzaninotto committed Jun 6, 2024
1 parent e980758 commit d77bafa
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 70 deletions.
49 changes: 13 additions & 36 deletions example/sinon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,19 @@ export const initializeSinon = () => {
baseUrl: 'http://localhost:3000',
data,
loggingEnabled: true,
});

restServer.addMiddleware(withDelay(300));
restServer.addMiddleware(async (request, context, next) => {
if (request.requestHeaders.Authorization === undefined) {
return {
status: 401,
headers: {},
};
}

return next(request, context);
});

restServer.addMiddleware(async (request, context, next) => {
if (context.collection === 'books' && request.method === 'POST') {
if (
restServer.database.getCount(context.collection, {
filter: {
title: context.requestBody?.title,
},
}) > 0
) {
return {
status: 400,
headers: {},
body: {
errors: {
title: 'An article with this title already exists. The title must be unique.',
},
},
};
}
}

return next(request, context);
middlewares: [
withDelay(300),
async (context, next) => {
if (!context.headers?.get('Authorization')) {
return {
status: 401,
headers: {},
};
}
return next(context);
},
// FIXME: add validation middleware
],
});

// use sinon.js to monkey-patch XmlHttpRequest
Expand Down
6 changes: 1 addition & 5 deletions src/BaseServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
FakeRestContext,
CollectionItem,
QueryFunction,
NormalizedRequest,
} from './types.js';

export class BaseServer {
Expand Down Expand Up @@ -396,8 +397,3 @@ export type BaseServerOptions = DatabaseOptions & {
defaultQuery?: QueryFunction;
middlewares?: Array<Middleware>;
};

export type NormalizedRequest = Pick<
FakeRestContext,
'url' | 'method' | 'params' | 'requestBody' | 'headers'
>;
4 changes: 2 additions & 2 deletions src/adapters/FetchMockServer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BaseServer } from '../BaseServer.js';
import { parseQueryString } from '../parseQueryString.js';
import type { BaseServerOptions, NormalizedRequest } from '../BaseServer.js';
import type { BaseResponse, APIServer } from '../types.js';
import type { BaseServerOptions } from '../BaseServer.js';
import type { BaseResponse, APIServer, NormalizedRequest } from '../types.js';
import type { MockResponseObject } from 'fetch-mock';

export class FetchMockServer {
Expand Down
4 changes: 2 additions & 2 deletions src/adapters/MswServer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { http, HttpResponse } from 'msw';
import { BaseServer } from '../BaseServer.js';
import type { BaseServerOptions, NormalizedRequest } from '../BaseServer.js';
import type { APIServer } from '../types.js';
import type { BaseServerOptions } from '../BaseServer.js';
import type { APIServer, NormalizedRequest } from '../types.js';

export class MswServer {
server: APIServer;
Expand Down
51 changes: 26 additions & 25 deletions src/adapters/SinonServer.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import type { SinonFakeXMLHttpRequest } from 'sinon';
import {
type BaseResponse,
BaseServer,
type BaseServerOptions,
} from '../BaseServer.js';
import { BaseServer, type BaseServerOptions } from '../BaseServer.js';
import { parseQueryString } from '../parseQueryString.js';
import type { BaseResponse, APIServer, NormalizedRequest } from '../types.js';

export class SinonServer extends BaseServer<
SinonFakeXMLHttpRequest,
SinonFakeRestResponse
> {
export class SinonServer {
loggingEnabled = false;
server: APIServer;

constructor({
loggingEnabled = false,
server,
...options
}: SinonServerOptions = {}) {
super(options);
this.server = server || new BaseServer(options);
this.loggingEnabled = loggingEnabled;
}

toggleLogging() {
this.loggingEnabled = !this.loggingEnabled;
getHandler() {
return (request: SinonFakeXMLHttpRequest) => {
// This is an internal property of SinonFakeXMLHttpRequest but we have to set it to 4 to
// suppress sinon's synchronous processing (which would result in HTTP 404). This allows us
// to handle the request asynchronously.
// See https://github.com/sinonjs/sinon/issues/637
// @ts-expect-error
request.readyState = 4;
const normalizedRequest = this.getNormalizedRequest(request);
this.server
.handle(normalizedRequest)
.then((response) => this.respond(response, request));
// Let Sinon know we've handled the request
return true;
};
}

async getNormalizedRequest(request: SinonFakeXMLHttpRequest) {
getNormalizedRequest(request: SinonFakeXMLHttpRequest): NormalizedRequest {
const req: Request | SinonFakeXMLHttpRequest =
typeof request === 'string' ? new Request(request) : request;

Expand All @@ -45,6 +54,7 @@ export class SinonServer extends BaseServer<

return {
url: req.url,
headers: new Headers(request.requestHeaders),
params,
requestBody,
method: req.method,
Expand Down Expand Up @@ -135,18 +145,8 @@ export class SinonServer extends BaseServer<
}
}

getHandler() {
return (request: SinonFakeXMLHttpRequest) => {
// This is an internal property of SinonFakeXMLHttpRequest but we have to set it to 4 to
// suppress sinon's synchronous processing (which would result in HTTP 404). This allows us
// to handle the request asynchronously.
// See https://github.com/sinonjs/sinon/issues/637
// @ts-expect-error
request.readyState = 4;
this.handle(request);
// Let Sinon know we've handled the request
return true;
};
toggleLogging() {
this.loggingEnabled = !this.loggingEnabled;
}
}

Expand All @@ -167,5 +167,6 @@ export type SinonFakeRestResponse = {
};

export type SinonServerOptions = BaseServerOptions & {
server?: APIServer;
loggingEnabled?: boolean;
};
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export type FakeRestContext = {
params: { [key: string]: any };
};

export type NormalizedRequest = Pick<
FakeRestContext,
'url' | 'method' | 'params' | 'requestBody' | 'headers'
>;

export type APIServer = {
baseUrl?: string;
handle: (context: FakeRestContext) => Promise<BaseResponse>;
Expand Down

0 comments on commit d77bafa

Please sign in to comment.