Skip to content

Commit

Permalink
feat(remix-node): replace extended classes for NodeRequest & `NodeR…
Browse files Browse the repository at this point in the history
…esponse` with interface type casts (#7109)

Co-authored-by: Michaël De Boey <[email protected]>
Co-authored-by: Michaël De Boey <[email protected]>
  • Loading branch information
jacob-ebey and MichaelDeBoey authored Aug 9, 2023
1 parent b788f34 commit 9543712
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/global-fetch-instanceof.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/node": patch
---

ensures fetch() return is instanceof global Response by removing extended classes for NodeRequest and NodeResponse in favor of custom interface type cast.
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
- jaydiablo
- jca41
- jdeniau
- jeeyoungk
- JeffBeltran
- jenseng
- jeremyjfleming
Expand Down
39 changes: 39 additions & 0 deletions integration/fetch-globals-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { test, expect } from "@playwright/test";

import type { Fixture, AppFixture } from "./helpers/create-fixture";
import { createAppFixture, createFixture, js } from "./helpers/create-fixture";

let fixture: Fixture;
let appFixture: AppFixture;

test.beforeAll(async () => {
fixture = await createFixture({
files: {
"app/routes/_index.tsx": js`
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader() {
const resp = await fetch('https://reqres.in/api/users?page=2');
return (resp instanceof Response) ? 'is an instance of global Response' : 'is not an instance of global Response';
}
export default function Index() {
let data = useLoaderData();
return (
<div>
{data}
</div>
)
}
`,
},
});

appFixture = await createAppFixture(fixture);
});

test.afterAll(async () => appFixture.close());

test("returned variable from fetch() should be instance of global Response", async () => {
let response = await fixture.requestDocument("/");
expect(await response.text()).toMatch("is an instance of global Response");
});
22 changes: 21 additions & 1 deletion packages/remix-node/__tests__/fetch-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { ReadableStream } from "@remix-run/web-stream";
import {
Request as WebRequest,
Response as WebResponse,
} from "@remix-run/web-fetch";

import { Request } from "../fetch";
import { Request, Response } from "../fetch";

let test = {
source: [
Expand Down Expand Up @@ -111,6 +115,22 @@ describe("Request", () => {
expect(file.size).toBe(1023);

expect(cloned instanceof Request).toBeTruthy();
expect(cloned instanceof WebRequest).toBeTruthy();
});

it("instanceOf", async () => {
let nodeReq = new Request("http://example.com");
let webReq = new WebRequest("http://example.com");
let nodeRes = new Response("http://example.com");
let webRes = new WebResponse("http://example.com");
expect(nodeReq instanceof Request).toBeTruthy();
expect(nodeReq instanceof WebRequest).toBeTruthy();
expect(webReq instanceof Request).toBeTruthy();
expect(webReq instanceof WebRequest).toBeTruthy();
expect(nodeRes instanceof Response).toBeTruthy();
expect(nodeRes instanceof WebResponse).toBeTruthy();
expect(webRes instanceof Response).toBeTruthy();
expect(webRes instanceof WebResponse).toBeTruthy();
});
});

Expand Down
34 changes: 16 additions & 18 deletions packages/remix-node/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { FormData } from "@remix-run/web-fetch";
export { File, Blob } from "@remix-run/web-file";

type NodeHeadersInit = ConstructorParameters<typeof WebHeaders>[0];
type NodeResponseInfo = ConstructorParameters<typeof WebResponse>[0];
type NodeResponseInit = NonNullable<
ConstructorParameters<typeof WebResponse>[1]
>;
Expand All @@ -31,30 +32,27 @@ export type {
NodeResponseInit as ResponseInit,
};

class NodeRequest extends WebRequest {
constructor(info: NodeRequestInfo, init?: NodeRequestInit) {
super(info, init as RequestInit);
}
interface NodeRequest extends WebRequest {
get headers(): WebHeaders;

public get headers(): WebHeaders {
return super.headers as WebHeaders;
}

public clone(): NodeRequest {
return new NodeRequest(this);
}
clone(): NodeRequest;
}

class NodeResponse extends WebResponse {
public get headers(): WebHeaders {
return super.headers as WebHeaders;
}
interface NodeResponse extends WebResponse {
get headers(): WebHeaders;

public clone(): NodeResponse {
return super.clone() as NodeResponse;
}
clone(): NodeResponse;
}

const NodeRequest = WebRequest as new (
info: NodeRequestInfo,
init?: NodeRequestInit
) => NodeRequest;
const NodeResponse = WebResponse as unknown as new (
info: NodeResponseInfo,
init?: NodeResponseInit
) => NodeResponse;

export {
WebHeaders as Headers,
NodeRequest as Request,
Expand Down

0 comments on commit 9543712

Please sign in to comment.