Repository: wheresrhys/fetch-mock (js)

Issue:
Differentiate `0` and undefined value of `status` parameter
It's rare case, but common enough that `fetch` can return `0` number status. Current library version (12.0.1) doesn't support `0` number and treats this value as `undefined` which leads to return status `200`.

Example:
```ts
		fetchMock.mockGlobal().postOnce({
			...baseConfig,
			response: {
				status: 0,
				body: JSON.stringify({ hello: "world" })
			}
		});
```

will return:
```
    {
      [Symbol(realm)]: { settingsObject: {} },
      [Symbol(state)]: {
        aborted: false,
        rangeRequested: false,
        timingAllowPassed: false,
        requestIncludesCredentials: false,
        type: 'default',
        status: 200,
        timingInfo: null,
        cacheState: '',
        statusText: 'OK',
        headersList: HeadersList {
          cookies: null,
          [Symbol(headers map)]: [Map],
          [Symbol(headers map sorted)]: null
        },
        urlList: [],
        body: { stream: undefined, source: '{"hello":"world"}', length: 17 }
      },
      [Symbol(headers)]: HeadersList {
        cookies: null,
        [Symbol(headers map)]: Map(2) { 'content-length' => [Object], 'content-type' => [Object] },
        [Symbol(headers map sorted)]: null
      }
    }
```

Pull request description:
fix: allow sending responses with status 0
fixes #855 

Patch:
diff --git a/packages/fetch-mock/src/Route.ts b/packages/fetch-mock/src/Route.ts
index 85b65e9..ca9f823 100644
--- a/packages/fetch-mock/src/Route.ts
+++ b/packages/fetch-mock/src/Route.ts
@@ -89,6 +89,12 @@ function isBodyInit(body: BodyInit | object): body is BodyInit {
 }
 
 function sanitizeStatus(status?: number): number {
+	if (status === 0) {
+		// we do this here for now because we can't construct a Response with status 0
+		// we overwrite to 0 later in the proxy wrapper around teh response.
+		return 200;
+	}
+
 	if (!status) {
 		return 200;
 	}
diff --git a/packages/fetch-mock/src/Router.ts b/packages/fetch-mock/src/Router.ts
index be3af6c..bd5f866 100644
--- a/packages/fetch-mock/src/Router.ts
+++ b/packages/fetch-mock/src/Router.ts
@@ -70,7 +70,7 @@ function shouldSendAsObject(responseInput: RouteResponseData): boolean {
 	// TODO improve this... make it less hacky and magic
 	if (
 		responseConfigProps.some(
-			(prop) => (responseInput as RouteResponseConfig)[prop],
+			(prop) => prop in (responseInput as RouteResponseConfig),
 		)
 	) {
 		if (
@@ -268,6 +268,11 @@ export default class Router {
 						return false;
 					}
 				}
+
+				if (responseInput.status === 0) {
+					if (name === 'status') return 0;
+					if (name === 'statusText') return '';
+				}
 				// TODO fix these types properly
 				//@ts-expect-error TODO probably make use of generics here
 				if (typeof response[name] === 'function') {


Test patch:
diff --git a/packages/fetch-mock/src/__tests__/FetchMock/response-construction.test.js b/packages/fetch-mock/src/__tests__/FetchMock/response-construction.test.js
index 15fae2d..98f2426 100644
--- a/packages/fetch-mock/src/__tests__/FetchMock/response-construction.test.js
+++ b/packages/fetch-mock/src/__tests__/FetchMock/response-construction.test.js
@@ -27,6 +27,13 @@ describe('response construction', () => {
 				);
 			}
 		});
+
+		it('should be able to send status 0', async () => {
+			fm.route('*', { status: 0 });
+			const res = await fm.fetchHandler('http://a.com/');
+			expect(res.status).toEqual(0);
+			expect(res.statusText).toEqual('');
+		});
 	});
 
 	describe('string', () => {