Skip to content

Commit

Permalink
Add integration tests for request structures (#4829)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Dec 13, 2022
1 parent c4957c1 commit 87a0d91
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .changeset/mighty-grapes-laugh.md
@@ -0,0 +1,6 @@
---
"@remix-run/server-runtime": patch
---

- Ensure `loader` `request`'s proxy headers on document `action` submissions
- Fix an issue where loader `request`'s reflected `method: "POST"` on document submissions
5 changes: 5 additions & 0 deletions .changeset/sharp-paws-nail.md
@@ -0,0 +1,5 @@
---
"@remix-run/server-runtime": patch
---

Fix error boundary tracking for multiple errors bubbling to the same boundary
40 changes: 39 additions & 1 deletion integration/catch-boundary-test.ts
Expand Up @@ -67,6 +67,9 @@ test.describe("CatchBoundary", () => {
<Link to="${HAS_BOUNDARY_LOADER}">
${HAS_BOUNDARY_LOADER}
</Link>
<Link to="${HAS_BOUNDARY_LOADER}/child">
${HAS_BOUNDARY_LOADER}/child
</Link>
<Link to="${NO_BOUNDARY_LOADER}">
${NO_BOUNDARY_LOADER}
</Link>
Expand Down Expand Up @@ -111,11 +114,27 @@ test.describe("CatchBoundary", () => {
`,

[`app/routes${HAS_BOUNDARY_LOADER}.jsx`]: js`
import { useCatch } from '@remix-run/react';
export function loader() {
throw new Response("", { status: 401 })
}
export function CatchBoundary() {
return <div id="boundary-loader">${OWN_BOUNDARY_TEXT}</div>
let caught = useCatch();
return (
<>
<div id="boundary-loader">${OWN_BOUNDARY_TEXT}</div>
<pre id="status">{caught.status}</pre>
</>
);
}
export default function Index() {
return <div/>
}
`,

[`app/routes${HAS_BOUNDARY_LOADER}/child.jsx`]: js`
export function loader() {
throw new Response("", { status: 404 })
}
export default function Index() {
return <div/>
Expand Down Expand Up @@ -292,4 +311,23 @@ test.describe("CatchBoundary", () => {
expect(await app.getHtml("#child-catch")).toMatch("400");
expect(await app.getHtml("#child-catch")).toMatch("Caught!");
});

test("prefers parent catch when child loader also bubbles, document request", async () => {
let res = await fixture.requestDocument(`${HAS_BOUNDARY_LOADER}/child`);
expect(res.status).toBe(401);
let text = await res.text();
expect(text).toMatch(OWN_BOUNDARY_TEXT);
expect(text).toMatch('<pre id="status">401</pre>');
});

test("prefers parent catch when child loader also bubbles, client transition", async ({
page,
}) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/");
await app.clickLink(`${HAS_BOUNDARY_LOADER}/child`);
await page.waitForSelector("#boundary-loader");
expect(await app.getHtml("#boundary-loader")).toMatch(OWN_BOUNDARY_TEXT);
expect(await app.getHtml("#status")).toMatch("401");
});
});
162 changes: 162 additions & 0 deletions integration/request-test.ts
@@ -0,0 +1,162 @@
import { test, expect } from "@playwright/test";

import { PlaywrightFixture } from "./helpers/playwright-fixture";
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.jsx": js`
import { json } from "@remix-run/node";
import { Form, useLoaderData, useActionData } from "@remix-run/react";
export async function loader({ request }) {
let text = (await request.text());
return json({
method: request.method,
url: request.url,
headers: Object.fromEntries(request.headers.entries()),
text,
});
}
export async function action({ request }) {
let text = (await request.text());
return json({
method: request.method,
url: request.url,
headers: Object.fromEntries(request.headers.entries()),
text,
});
}
export default function Index() {
let loaderData = useLoaderData();
let actionData = useActionData();
return (
<div>
<button id="set-cookie" onClick={() => {
document.cookie = 'cookie=nomnom; path=/';
}}>
Set Cookie
</button>
<Form method="get" reloadDocument>
<button type="submit" id="submit-get-ssr" name="type" value="ssr" />
</Form>
<Form method="get">
<button type="submit" id="submit-get-csr" name="type" value="csr" />
</Form>
<Form method="post" reloadDocument>
<button type="submit" id="submit-post-ssr" name="type" value="ssr" />
</Form>
<Form method="post">
<button type="submit" id="submit-post-csr" name="type" value="csr" />
</Form>
<pre id="loader-data">{JSON.stringify(loaderData)}</pre>
{actionData ?
<pre id="action-data">{JSON.stringify(actionData)}</pre> :
null}
</div>
)
}
`,
},
});

appFixture = await createAppFixture(fixture);
});

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

test("loader request on SSR GET requests", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/");
await app.clickElement("#set-cookie");

let loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual(undefined);
expect(loaderData.text).toEqual("");

await app.clickElement("#submit-get-ssr");

loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/\?type=ssr$/);
expect(loaderData.headers.cookie).toEqual("cookie=nomnom");
expect(loaderData.text).toEqual("");
});

test("loader request on CSR GET requests", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/");
await app.clickElement("#set-cookie");

let loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual(undefined);
expect(loaderData.text).toEqual("");

await app.clickElement("#submit-get-csr");

loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/\?type=csr$/);
expect(loaderData.headers.cookie).toEqual("cookie=nomnom");
expect(loaderData.text).toEqual("");
});

test("action + loader requests SSR POST requests", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/");
await app.clickElement("#set-cookie");

let loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual(undefined);
expect(loaderData.text).toEqual("");

await app.clickElement("#submit-post-ssr");

let actionData = JSON.parse(await page.locator("#action-data").innerHTML());
expect(actionData.method).toEqual("POST");
expect(actionData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(actionData.headers.cookie).toEqual("cookie=nomnom");
expect(actionData.text).toEqual("type=ssr");

loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual("cookie=nomnom");
expect(loaderData.text).toEqual("");
});

test("action + loader requests on CSR POST requests", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/");
await app.clickElement("#set-cookie");

let loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual(undefined);
expect(loaderData.text).toEqual("");

await app.clickElement("#submit-post-csr");

let actionData = JSON.parse(await page.locator("#action-data").innerHTML());
expect(actionData.method).toEqual("POST");
expect(actionData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(actionData.headers.cookie).toEqual("cookie=nomnom");
expect(actionData.text).toEqual("type=csr");

loaderData = JSON.parse(await page.locator("#loader-data").innerHTML());
expect(loaderData.method).toEqual("GET");
expect(loaderData.url).toMatch(/^http:\/\/localhost:\d+\/$/);
expect(loaderData.headers.cookie).toEqual("cookie=nomnom");
expect(loaderData.text).toEqual("");
});
4 changes: 2 additions & 2 deletions packages/remix-react/package.json
Expand Up @@ -16,8 +16,8 @@
"typings": "dist/index.d.ts",
"module": "dist/esm/index.js",
"dependencies": {
"@remix-run/router": "1.0.5",
"react-router-dom": "6.4.5"
"@remix-run/router": "1.1.0-pre.0",
"react-router-dom": "6.5.0-pre.0"
},
"devDependencies": {
"@remix-run/server-runtime": "1.8.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/remix-server-runtime/package.json
Expand Up @@ -16,7 +16,7 @@
"typings": "dist/index.d.ts",
"module": "dist/esm/index.js",
"dependencies": {
"@remix-run/router": "1.0.5",
"@remix-run/router": "1.1.0-pre.0",
"@types/cookie": "^0.4.0",
"@web3-storage/multipart-parser": "^1.0.0",
"cookie": "^0.4.1",
Expand Down
27 changes: 16 additions & 11 deletions yarn.lock
Expand Up @@ -2174,6 +2174,11 @@
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.0.5.tgz#d5c65626add4c3c185a89aa5bd38b1e42daec075"
integrity sha512-my0Mycd+jruq/1lQuO5LBB6WTlL/e8DTCYWp44DfMTDcXz8DcTlgF0ISaLsGewt+ctHN+yA8xMq3q/N7uWJPug==

"@remix-run/router@1.1.0-pre.0":
version "1.1.0-pre.0"
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.1.0-pre.0.tgz#c33db6bd13c6d3847f73f618008ebecdaec237c7"
integrity sha512-FFa1aGAYUZm+PdOO2a7r/4gxLqSIOq1Qav3g6wwRgWj28PNyO7CjdUNER4O4DSKVVyob21mhZHvTe25z+2xnZw==

"@remix-run/web-blob@^3.0.3", "@remix-run/web-blob@^3.0.4":
version "3.0.4"
resolved "https://registry.npmjs.org/@remix-run/web-blob/-/web-blob-3.0.4.tgz"
Expand Down Expand Up @@ -10722,20 +10727,20 @@ react-is@^17.0.1:
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==

react-router-dom@6.4.5:
version "6.4.5"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.5.tgz#4fdb12efef4f3848c693a76afbeaed1f6ca02047"
integrity sha512-a7HsgikBR0wNfroBHcZUCd9+mLRqZS8R5U1Z1mzLWxFXEkUT3vR1XXmSIVoVpxVX8Bar0nQYYYc9Yipq8dWwAA==
react-router-dom@6.5.0-pre.0:
version "6.5.0-pre.0"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.5.0-pre.0.tgz#73dc3861f43b1bc83a854bd5d3d3ab4d7beb1710"
integrity sha512-Hq8lhsAqLH4LDewj6OeDCiEel5RP6El1DsxohxwgOctt+xq4Q6kGiiuVnLA+eHl2wXFCEF8ZSK/kOddGKfLWYA==
dependencies:
"@remix-run/router" "1.0.5"
react-router "6.4.5"
"@remix-run/router" "1.1.0-pre.0"
react-router "6.5.0-pre.0"

react-router@6.4.5:
version "6.4.5"
resolved "https://registry.npmjs.org/react-router/-/react-router-6.4.5.tgz#73f382af2c8b9a86d74e761a7c5fc3ce7cb0024d"
integrity sha512-1RQJ8bM70YEumHIlNUYc6mFfUDoWa5EgPDenK/fq0bxD8DYpQUi/S6Zoft+9DBrh2xmtg92N5HMAJgGWDhKJ5Q==
react-router@6.5.0-pre.0:
version "6.5.0-pre.0"
resolved "https://registry.npmjs.org/react-router/-/react-router-6.5.0-pre.0.tgz#513b2fe858736443082a33a7a9d2f728b2bd7fe4"
integrity sha512-JqRGYSGzySjcqVMkgCa+1i3zvXiH2IHUfEPac71sJn5ArH5tvR5GmraWUn+D5t7Yzq2dz11is4u2SzHiT0pGdg==
dependencies:
"@remix-run/router" "1.0.5"
"@remix-run/router" "1.1.0-pre.0"

react@^18.2.0:
version "18.2.0"
Expand Down

0 comments on commit 87a0d91

Please sign in to comment.