Skip to content

Commit

Permalink
chore: adjust more things, add tests for RR
Browse files Browse the repository at this point in the history
Signed-off-by: Logan McAnsh <[email protected]>
  • Loading branch information
mcansh committed Nov 16, 2024
1 parent a30e9fb commit f568518
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 178 deletions.
329 changes: 183 additions & 146 deletions packages/remix-fastify/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ import type { FastifyReply, FastifyRequest } from "fastify";
import fastify from "fastify";
import { createRequest } from "node-mocks-http";
import {
createReadableStreamFromReadable,
createReadableStreamFromReadable as remixCreateReadableStreamFromReadable,
createRequestHandler as createRemixRequestHandler,
} from "@remix-run/node";
import "@remix-run/node/install";
import { createRequestHandler as createReactRouterRequestHandler } from "react-router";
import { createReadableStreamFromReadable as reactRouterCreateReadableStreamFromReadable } from "@react-router/node";
import type { MockedFunction } from "vitest";
import { afterAll, afterEach, describe, expect, it, vi } from "vitest";

import {
createRemixHeaders,
createRemixRequest,
createRequestHandler,
} from "../src/server";
import { createRemixRequest, createRequestHandler } from "../src/servers/remix";
import { createHeaders } from "../src/shared";

// We don't want to test that the remix server works here (that's what the
// playwright tests do), we just want to test the fastify adapter
Expand All @@ -27,9 +25,24 @@ vi.mock("@remix-run/node", async () => {
createRequestHandler: vi.fn(),
};
});
let mockedCreateRequestHandler = createRemixRequestHandler as MockedFunction<
typeof createRemixRequestHandler
>;
// We don't want to test that the remix server works here (that's what the
// playwright tests do), we just want to test the fastify adapter
vi.mock("react-router", async () => {
let original =
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
await vi.importActual<typeof import("react-router")>("react-router");
return {
...original,
createRequestHandler: vi.fn(),
};
});

let mockedRemixCreateRequestHandler =
createRemixRequestHandler as MockedFunction<typeof createRemixRequestHandler>;
let mockedReactRouterCreateRequestHandler =
createReactRouterRequestHandler as MockedFunction<
typeof createReactRouterRequestHandler
>;

function createApp() {
let app = fastify();
Expand All @@ -47,187 +60,211 @@ function createApp() {
return app;
}

describe("fastify createRequestHandler", () => {
describe("basic requests", () => {
afterEach(() => {
mockedCreateRequestHandler.mockReset();
});

afterAll(() => {
vi.restoreAllMocks();
});
function runTests(
name: string,
{
createReadableStreamFromReadable,
handler,
}: {
handler:
| typeof mockedRemixCreateRequestHandler
| typeof mockedReactRouterCreateRequestHandler;
createReadableStreamFromReadable:
| typeof remixCreateReadableStreamFromReadable
| typeof reactRouterCreateReadableStreamFromReadable;
},
) {
describe(`[${name}] fastify createRequestHandler`, () => {
describe(`[${name}] basic requests`, () => {
afterEach(() => {
handler.mockReset();
});

it("handles requests", async () => {
mockedCreateRequestHandler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
afterAll(() => {
vi.restoreAllMocks();
});

let app = createApp();
it(`[${name}] handles requests`, async () => {
handler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
});

let response = await app.inject("/foo/bar");
let app = createApp();

expect(response.body).toBe("URL: /foo/bar");
expect(response.statusCode).toBe(200);
});
let response = await app.inject("/foo/bar");

it("handles root // URLs", async () => {
mockedCreateRequestHandler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
expect(response.body).toBe("URL: /foo/bar");

Check failure on line 96 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles requests

AssertionError: expected '{"statusCode":500,"error":"Internal S…' to be 'URL: /foo/bar' // Object.is equality Expected: "URL: /foo/bar" Received: "{"statusCode":500,"error":"Internal Server Error","message":"handleRequest is not a function"}" ❯ __tests__/index.test.ts:96:31

Check failure on line 96 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles requests

AssertionError: expected '{"statusCode":500,"error":"Internal S…' to be 'URL: /foo/bar' // Object.is equality Expected: "URL: /foo/bar" Received: "{"statusCode":500,"error":"Internal Server Error","message":"handleRequest is not a function"}" ❯ __tests__/index.test.ts:96:31

Check failure on line 96 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles requests

AssertionError: expected '{"statusCode":500,"error":"Internal S…' to be 'URL: /foo/bar' // Object.is equality Expected: "URL: /foo/bar" Received: "{"statusCode":500,"error":"Internal Server Error","message":"handleRequest is not a function"}" ❯ __tests__/index.test.ts:96:31
expect(response.statusCode).toBe(200);
});

let app = createApp();
it(`[${name}] handles root // URLs`, async () => {
handler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
});

let response = await app.inject("//");
let app = createApp();

expect(response.statusCode).toBe(200);
expect(response.body).toBe("URL: //");
});
let response = await app.inject("//");

it("handles nested // URLs", async () => {
mockedCreateRequestHandler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
expect(response.statusCode).toBe(200);

Check failure on line 109 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles root // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:109:37

Check failure on line 109 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles root // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:109:37

Check failure on line 109 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles root // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:109:37
expect(response.body).toBe("URL: //");
});

let app = createApp();
it(`[${name}] handles nested // URLs`, async () => {
handler.mockImplementation(() => async (req) => {
return new Response(`URL: ${new URL(req.url).pathname}`);
});

let response = await app.inject("//foo//bar");
let app = createApp();

expect(response.statusCode).toBe(200);
expect(response.body).toBe("URL: //foo//bar");
});
let response = await app.inject("//foo//bar");

it("handles null body", async () => {
mockedCreateRequestHandler.mockImplementation(() => async () => {
return new Response(null);
expect(response.statusCode).toBe(200);

Check failure on line 122 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles nested // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:122:37

Check failure on line 122 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles nested // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:122:37

Check failure on line 122 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles nested // URLs

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:122:37
expect(response.body).toBe("URL: //foo//bar");
});

let app = createApp();
it(`[${name}] handles null body`, async () => {
handler.mockImplementation(() => async () => {
return new Response(null);
});

let response = await app.inject("/");
let app = createApp();

expect(response.statusCode).toBe(200);
});
let response = await app.inject("/");

// https://github.com/node-fetch/node-fetch/blob/4ae35388b078bddda238277142bf091898ce6fda/test/response.js#L142-L148
it("handles body as stream", async () => {
mockedCreateRequestHandler.mockImplementation(() => async () => {
let readable = Readable.from("hello world");
let stream = createReadableStreamFromReadable(readable);
return new Response(stream);
expect(response.statusCode).toBe(200);

Check failure on line 135 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles null body

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:135:37

Check failure on line 135 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles null body

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:135:37

Check failure on line 135 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles null body

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:135:37
});

let app = createApp();
let response = await app.inject("/");
// https://github.com/node-fetch/node-fetch/blob/4ae35388b078bddda238277142bf091898ce6fda/test/response.js#L142-L148
it(`[${name}] handles body as stream`, async () => {
handler.mockImplementation(() => async () => {
let readable = Readable.from("hello world");
let stream = createReadableStreamFromReadable(readable);
return new Response(stream);
});

expect(response.statusCode).toBe(200);
expect(response.body).toBe("hello world");
});
let app = createApp();
let response = await app.inject("/");

it("handles status codes", async () => {
mockedCreateRequestHandler.mockImplementation(() => async () => {
return new Response(null, { status: 204 });
expect(response.statusCode).toBe(200);

Check failure on line 149 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles body as stream

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:149:37

Check failure on line 149 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles body as stream

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:149:37

Check failure on line 149 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles body as stream

AssertionError: expected 500 to be 200 // Object.is equality - Expected + Received - 200 + 500 ❯ __tests__/index.test.ts:149:37
expect(response.body).toBe("hello world");
});

let app = createApp();
let response = await app.inject("/");
it(`[${name}] handles status codes`, async () => {
handler.mockImplementation(() => async () => {
return new Response(null, { status: 204 });
});

expect(response.statusCode).toBe(204);
});
let app = createApp();
let response = await app.inject("/");

it("sets headers", async () => {
mockedCreateRequestHandler.mockImplementation(() => async () => {
let headers = new Headers({ "X-Time-Of-Year": "most wonderful" });
headers.append(
"Set-Cookie",
expect(response.statusCode).toBe(204);

Check failure on line 161 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles status codes

AssertionError: expected 500 to be 204 // Object.is equality - Expected + Received - 204 + 500 ❯ __tests__/index.test.ts:161:37

Check failure on line 161 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles status codes

AssertionError: expected 500 to be 204 // Object.is equality - Expected + Received - 204 + 500 ❯ __tests__/index.test.ts:161:37

Check failure on line 161 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] handles status codes

AssertionError: expected 500 to be 204 // Object.is equality - Expected + Received - 204 + 500 ❯ __tests__/index.test.ts:161:37
});

it(`[${name}] sets headers`, async () => {
handler.mockImplementation(() => async () => {
let headers = new Headers({ "X-Time-Of-Year": "most wonderful" });
headers.append(
"Set-Cookie",
"first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax",
);
headers.append(
"Set-Cookie",
"second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax",
);
headers.append(
"Set-Cookie",
"third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax",
);
return new Response(null, { headers });
});

let app = createApp();
let response = await app.inject("/");

expect(response.headers["x-time-of-year"]).toBe("most wonderful");

Check failure on line 185 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / ubuntu-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] sets headers

AssertionError: expected undefined to be 'most wonderful' // Object.is equality - Expected: "most wonderful" + Received: undefined ❯ __tests__/index.test.ts:185:52

Check failure on line 185 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / macos-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] sets headers

AssertionError: expected undefined to be 'most wonderful' // Object.is equality - Expected: "most wonderful" + Received: undefined ❯ __tests__/index.test.ts:185:52

Check failure on line 185 in packages/remix-fastify/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / test / windows-latest | latest

__tests__/index.test.ts > [react-router] fastify createRequestHandler > [react-router] basic requests > [react-router] sets headers

AssertionError: expected undefined to be 'most wonderful' // Object.is equality - Expected: "most wonderful" + Received: undefined ❯ __tests__/index.test.ts:185:52
expect(response.headers["set-cookie"]).toEqual([
"first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax",
);
headers.append(
"Set-Cookie",
"second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax",
);
headers.append(
"Set-Cookie",
"third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax",
);
return new Response(null, { headers });
]);
});

let app = createApp();
let response = await app.inject("/");

expect(response.headers["x-time-of-year"]).toBe("most wonderful");
expect(response.headers["set-cookie"]).toEqual([
"first=one; Expires=0; Path=/; HttpOnly; Secure; SameSite=Lax",
"second=two; MaxAge=1209600; Path=/; HttpOnly; Secure; SameSite=Lax",
"third=three; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Path=/; HttpOnly; Secure; SameSite=Lax",
]);
});
});
});

describe("fastify createRemixHeaders", () => {
describe("creates fetch headers from fastify headers", () => {
it("handles empty headers", () => {
let headers = createRemixHeaders({});
expect(Array.from(headers.keys())).toHaveLength(0);
});
describe(`[${name}] fastify createHeaders`, () => {
describe(`[${name}] creates fetch headers from fastify headers`, () => {
it(`[${name}] handles empty headers`, () => {
let headers = createHeaders({});
expect(Array.from(headers.keys())).toHaveLength(0);
});

it("handles simple headers", () => {
let headers = createRemixHeaders({ "x-foo": "bar" });
expect(headers.get("x-foo")).toBe("bar");
});
it(`[${name}] handles simple headers`, () => {
let headers = createHeaders({ "x-foo": "bar" });
expect(headers.get("x-foo")).toBe("bar");
});

it("handles multiple headers", () => {
let headers = createRemixHeaders({ "x-foo": "bar", "x-bar": "baz" });
expect(headers.get("x-foo")).toBe("bar");
});
it(`[${name}] handles multiple headers`, () => {
let headers = createHeaders({ "x-foo": "bar", "x-bar": "baz" });
expect(headers.get("x-foo")).toBe("bar");
});

it("handles headers with multiple values", () => {
let headers = createRemixHeaders({ "x-foo": "bar, baz" });
expect(headers.get("x-foo")).toBe("bar, baz");
});
it(`[${name}] handles headers with multiple values`, () => {
let headers = createHeaders({ "x-foo": "bar, baz" });
expect(headers.get("x-foo")).toBe("bar, baz");
});

it("handles headers with multiple values and multiple headers", () => {
let headers = createRemixHeaders({ "x-foo": "bar, baz", "x-bar": "baz" });
expect(headers.get("x-foo")).toBe("bar, baz");
expect(headers.get("x-bar")).toBe("baz");
});
it(`[${name}] handles headers with multiple values and multiple headers`, () => {
let headers = createHeaders({ "x-foo": "bar, baz", "x-bar": "baz" });
expect(headers.get("x-foo")).toBe("bar, baz");
expect(headers.get("x-bar")).toBe("baz");
});

it("handles multiple set-cookie headers", () => {
let headers = createRemixHeaders({
"set-cookie": [
"__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax",
"__other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax",
],
it(`[${name}] handles multiple set-cookie headers`, () => {
let headers = createHeaders({
"set-cookie": [
"__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax",
"__other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax",
],
});

expect(headers.get("set-cookie")).toBe(
"__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax, __other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax",
);
});
});
});

expect(headers.get("set-cookie")).toBe(
"__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax, __other=some_other_value; Path=/; Secure; HttpOnly; MaxAge=3600; SameSite=Lax",
describe("fastify createRemixRequest", () => {
it(`[${name}] creates a request with the correct headers`, async () => {
let fastifyRequest = createRequest({
url: "/foo/bar",
method: "GET",
protocol: "http",
hostname: "localhost:3000",
headers: {
"Cache-Control": "max-age=300, s-maxage=3600",
Host: "localhost:3000",
},
}) as unknown as FastifyRequest;

let fastifyReply = { raw: { on: vi.fn() } } as unknown as FastifyReply;

let request = createRemixRequest(fastifyRequest, fastifyReply);

expect(request.headers.get("cache-control")).toBe(
"max-age=300, s-maxage=3600",
);
expect(request.headers.get("host")).toBe("localhost:3000");
});
});
});
}

describe("fastify createRemixRequest", () => {
it("creates a request with the correct headers", async () => {
let fastifyRequest = createRequest({
url: "/foo/bar",
method: "GET",
protocol: "http",
hostname: "localhost:3000",
headers: {
"Cache-Control": "max-age=300, s-maxage=3600",
Host: "localhost:3000",
},
}) as unknown as FastifyRequest;

let fastifyReply = { raw: { on: vi.fn() } } as unknown as FastifyReply;

let request = createRemixRequest(fastifyRequest, fastifyReply);

expect(request.headers.get("cache-control")).toBe(
"max-age=300, s-maxage=3600",
);
expect(request.headers.get("host")).toBe("localhost:3000");
});
runTests("remix", {
handler: mockedRemixCreateRequestHandler,
createReadableStreamFromReadable: remixCreateReadableStreamFromReadable,
});
runTests("react-router", {
handler: mockedReactRouterCreateRequestHandler,
createReadableStreamFromReadable: reactRouterCreateReadableStreamFromReadable,
});
Loading

0 comments on commit f568518

Please sign in to comment.