Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/funny-shirts-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/router": patch
---

Changes to statis handler for incorporating into Remix"
204 changes: 159 additions & 45 deletions packages/router/__tests__/router-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,31 @@ describe("a router", () => {
]);
});

it("matches root pathless route", () => {
let t = setup({
routes: [{ id: "root", children: [{ path: "foo" }] }],
});

t.navigate("/not-found");
expect(t.router.state.errors).toEqual({
root: {
status: 404,
statusText: "Not Found",
data: null,
},
});
expect(t.router.state.matches).toMatchObject([
{
params: {},
pathname: "",
route: {
id: "root",
children: expect.any(Array),
},
},
]);
});

it("clears prior loader/action data", async () => {
let t = initializeTmTest();
expect(t.router.state.loaderData).toEqual({
Expand Down Expand Up @@ -3123,11 +3148,7 @@ describe("a router", () => {
formData: createFormData({ gosh: "dang" }),
});
expect(t.router.state.errors).toEqual({
child: new ErrorResponse(
405,
"Method Not Allowed",
"No action found for [/child]"
),
child: new ErrorResponse(405, "Method Not Allowed", ""),
});
expect(console.warn).toHaveBeenCalled();
spy.mockReset();
Expand Down Expand Up @@ -3180,11 +3201,7 @@ describe("a router", () => {
});
expect(t.router.state.actionData).toBe(null);
expect(t.router.state.errors).toEqual({
grandchild: new ErrorResponse(
405,
"Method Not Allowed",
"No action found for [/child/grandchild]"
),
grandchild: new ErrorResponse(405, "Method Not Allowed", ""),
});
});
});
Expand Down Expand Up @@ -6381,11 +6398,7 @@ describe("a router", () => {
});
expect(A.fetcher).toBe(IDLE_FETCHER);
expect(t.router.state.errors).toEqual({
root: new ErrorResponse(
405,
"Method Not Allowed",
"No action found for [/]"
),
root: new ErrorResponse(405, "Method Not Allowed", ""),
});
});

Expand Down Expand Up @@ -9620,6 +9633,23 @@ describe("a router", () => {
});
});

it("should support document load navigations with HEAD requests", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let context = await query(
createRequest("/parent/child", { method: "HEAD" })
);
expect(context).toMatchObject({
actionData: null,
loaderData: {
parent: "PARENT LOADER",
child: "CHILD LOADER",
},
errors: null,
location: { pathname: "/parent/child" },
matches: [{ route: { id: "parent" } }, { route: { id: "child" } }],
});
});

it("should support document load navigations returning responses", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let context = await query(createRequest("/parent/json"));
Expand Down Expand Up @@ -9676,6 +9706,39 @@ describe("a router", () => {
});
});

it("should support alternative submission methods", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let context;

let expected = {
actionData: {
child: "CHILD ACTION",
},
loaderData: {
parent: "PARENT LOADER",
child: "CHILD LOADER",
},
errors: null,
location: { pathname: "/parent/child" },
matches: [{ route: { id: "parent" } }, { route: { id: "child" } }],
};

context = await query(
createSubmitRequest("/parent/child", { method: "PUT" })
);
expect(context).toMatchObject(expected);

context = await query(
createSubmitRequest("/parent/child", { method: "PATCH" })
);
expect(context).toMatchObject(expected);

context = await query(
createSubmitRequest("/parent/child", { method: "DELETE" })
);
expect(context).toMatchObject(expected);
});

it("should support document submit navigations returning responses", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let context = await query(createSubmitRequest("/parent/json"));
Expand Down Expand Up @@ -9870,20 +9933,6 @@ describe("a router", () => {
expect(e).toMatchInlineSnapshot(`[Error: query() call aborted]`);
});

it("should not support HEAD requests", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let request = createRequest("/", { method: "head" });
let e;
try {
await query(request);
} catch (_e) {
e = _e;
}
expect(e).toMatchInlineSnapshot(
`[Error: query()/queryRoute() do not support HEAD requests]`
);
});

it("should require a signal on the request", async () => {
let { query } = createStaticHandler(SSR_ROUTES);
let request = createRequest("/", { signal: undefined });
Expand Down Expand Up @@ -9914,7 +9963,30 @@ describe("a router", () => {
root: {
status: 405,
statusText: "Method Not Allowed",
data: "No action found for [/]",
data: "",
},
},
matches: [{ route: { id: "root" } }],
});
});

it("should handle unsupported methods with a 405 error", async () => {
let { query } = createStaticHandler([
{
id: "root",
path: "/",
},
]);
let request = createRequest("/", { method: "OPTIONS" });
let context = await query(request);
expect(context).toMatchObject({
actionData: null,
loaderData: {},
errors: {
root: {
status: 405,
statusText: "Method Not Allowed",
data: null,
},
},
matches: [{ route: { id: "root" } }],
Expand Down Expand Up @@ -10300,6 +10372,14 @@ describe("a router", () => {
expect(data).toBe("CHILD LOADER");
});

it("should support HEAD requests", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES);
let data = await queryRoute(
createRequest("/parent", { method: "HEAD" })
);
expect(data).toBe("PARENT LOADER");
});

it("should support singular route load navigations (primitives)", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES);
let data;
Expand Down Expand Up @@ -10468,6 +10548,29 @@ describe("a router", () => {
expect(data).toBe("");
});

it("should support alternative submission methods", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES);
let data;

data = await queryRoute(
createSubmitRequest("/parent", { method: "PUT" }),
"parent"
);
expect(data).toBe("PARENT ACTION");

data = await queryRoute(
createSubmitRequest("/parent", { method: "PATCH" }),
"parent"
);
expect(data).toBe("PARENT ACTION");

data = await queryRoute(
createSubmitRequest("/parent", { method: "DELETE" }),
"parent"
);
expect(data).toBe("PARENT ACTION");
});

it("should support singular route submit navigations (Responses)", async () => {
/* eslint-disable jest/no-conditional-expect */
let T = setupFlexRouteTest();
Expand Down Expand Up @@ -10656,20 +10759,6 @@ describe("a router", () => {
expect(e).toMatchInlineSnapshot(`[Error: queryRoute() call aborted]`);
});

it("should not support HEAD requests", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES);
let request = createRequest("/", { method: "head" });
let e;
try {
await queryRoute(request, "index");
} catch (_e) {
e = _e;
}
expect(e).toMatchInlineSnapshot(
`[Error: query()/queryRoute() do not support HEAD requests]`
);
});

it("should require a signal on the request", async () => {
let { queryRoute } = createStaticHandler(SSR_ROUTES);
let request = createRequest("/", { signal: undefined });
Expand Down Expand Up @@ -10753,7 +10842,32 @@ describe("a router", () => {
expect(data.status).toBe(405);
expect(data.statusText).toBe("Method Not Allowed");
expect(data.headers.get("X-Remix-Router-Error")).toBe("yes");
expect(await data.text()).toBe("No action found for [/]");
expect(await data.text()).toBe("");
}
/* eslint-enable jest/no-conditional-expect */
});

it("should handle unsupported methods with a 405 Response", async () => {
/* eslint-disable jest/no-conditional-expect */
let { queryRoute } = createStaticHandler([
{
id: "root",
path: "/",
},
]);

try {
await queryRoute(
createSubmitRequest("/", { method: "OPTIONS" }),
"root"
);
expect(false).toBe(true);
} catch (data) {
expect(data instanceof Response).toBe(true);
expect(data.status).toBe(405);
expect(data.statusText).toBe("Method Not Allowed");
expect(data.headers.get("X-Remix-Router-Error")).toBe("yes");
expect(await data.text()).toBe("");
}
/* eslint-enable jest/no-conditional-expect */
});
Expand Down
Loading