Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy changes from RR 6.26.2 and Remix 2.12.0 to dev #11958

Merged
merged 21 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bde5a43
Add unit test for Remix GH issue 8298 (#11916)
brophdawg11 Aug 21, 2024
3908497
Preserve pending view transitions through a router revalidation call …
brophdawg11 Aug 22, 2024
5ff506e
fix: Wait for restore url navigation to complete before proceeding (#…
brophdawg11 Aug 27, 2024
8140a5f
Preserve view transitions through navigation redirects (#11925)
brophdawg11 Aug 29, 2024
7aa8f2d
unstable_dataStrategy refactor for better single fetch support (RR PR…
brophdawg11 Sep 4, 2024
45347e4
Change content type on single fetch requests (Remix PR 9889)
brophdawg11 Sep 5, 2024
53bd531
Sort lazy route discovery manifest request params (Remix PR 9888)
brophdawg11 Sep 5, 2024
f8d9b24
Remove hydration URL check (Remix PR 9890)
brophdawg11 Sep 5, 2024
d6e9ef4
Clarify wording in default console warning (Remix PR 9899)
brophdawg11 Sep 5, 2024
c57f4a9
Add failing test for syncronous blocker.proceed calls (Remix PR 9914)
brophdawg11 Sep 5, 2024
a847ff4
handle cycles between manual chunks (Remix PR 9917)
brophdawg11 Sep 5, 2024
1a9cb19
Update/fix Single Fetch revalidation behavior (Remix PR 9938)
brophdawg11 Sep 5, 2024
0979dac
Fix issue with 304 response sin single fetch (Remix PR 9941)
brophdawg11 Sep 5, 2024
5fc1df8
Fix lint error
brophdawg11 Sep 5, 2024
0d95481
Fix tests
brophdawg11 Sep 5, 2024
b26d387
Cleaup tests
brophdawg11 Sep 5, 2024
2ac4955
Fix HDR for single fetch (Remix PR 9954)
brophdawg11 Sep 5, 2024
2fa484c
Support 304 responses on document requests (Remix PR 9955)
brophdawg11 Sep 6, 2024
c14fdb5
bump timeout on flaky windows test
brophdawg11 Sep 6, 2024
a84d9da
Align single fetch prefetching with new revalidation logic (Remix PR …
brophdawg11 Sep 6, 2024
60d66da
Dont migrate over changesets
brophdawg11 Sep 6, 2024
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
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- Armanio
- arnassavickas
- aroyan
- Artur-
- ashusnapx
- avipatel97
- awreese
Expand Down
113 changes: 113 additions & 0 deletions integration/blocking-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { test, expect } from "@playwright/test";

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

let fixture: Fixture;
let appFixture: AppFixture;

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

test("handles synchronous proceeding correctly", async ({ page }) => {
fixture = await createFixture({
files: {
"app/routes/_index.tsx": js`
import { Link } from "react-router";
export default function Component() {
return (
<div>
<h1 id="index">Index</h1>
<Link to="/a">/a</Link>
</div>
)
}
`,
"app/routes/a.tsx": js`
import { Link } from "react-router";
export default function Component() {
return (
<div>
<h1 id="a">A</h1>
<Link to="/b">/b</Link>
</div>
)
}
`,
"app/routes/b.tsx": js`
import * as React from "react";
import { Form, useAction, useBlocker } from "react-router";
export default function Component() {
return (
<div>
<h1 id="b">B</h1>
<ImportantForm />
</div>
)
}
function ImportantForm() {
let [value, setValue] = React.useState("");
let shouldBlock = React.useCallback<BlockerFunction>(
({ currentLocation, nextLocation }) =>
value !== "" && currentLocation.pathname !== nextLocation.pathname,
[value]
);
let blocker = useBlocker(shouldBlock);
// Reset the blocker if the user cleans the form
React.useEffect(() => {
if (blocker.state === "blocked") {
blocker.proceed();
}
}, [blocker]);
return (
<>
<p>
Is the form dirty?{" "}
{value !== "" ? (
<span style={{ color: "red" }}>Yes</span>
) : (
<span style={{ color: "green" }}>No</span>
)}
</p>
<Form method="post">
<label>
Enter some important data:
<input
name="data"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</label>
<button type="submit">Save</button>
</Form>
</>
);
}
`,
},
});

// This creates an interactive app using puppeteer.
appFixture = await createAppFixture(fixture);

let app = new PlaywrightFixture(appFixture, page);

await app.goto("/");
await app.clickLink("/a");
await page.waitForSelector("#a");
await app.clickLink("/b");
await page.waitForSelector("#b");
await page.getByLabel("Enter some important data:").fill("Hello Remix!");

// Going back should:
// - block
// - immediately call blocker.proceed() once we enter the blocked state
// - and land back one history entry (/a)
await page.goBack();
await page.waitForSelector("#a");
expect(await app.getHtml()).toContain("A");
});
2 changes: 1 addition & 1 deletion integration/error-boundary-v2-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ test.describe("ErrorBoundary", () => {
await waitForAndAssert(
page,
app,
"#child-error",
"#parent-error",
"Unable to decode turbo-stream response"
);
});
Expand Down
112 changes: 94 additions & 18 deletions integration/fog-of-war-test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { Request as PlaywrightRequest } from "@playwright/test";
import { test, expect } from "@playwright/test";

import {
Expand Down Expand Up @@ -710,9 +709,7 @@ test.describe("Fog of War", () => {
expect(await app.getHtml("#parent")).toMatch(`Parent`);
expect(await app.getHtml("#child2")).toMatch(`Child 2`);
expect(manifestRequests).toEqual([
expect.stringMatching(
/\/__manifest\?version=[a-z0-9]{8}&p=%2Fparent%2Fchild2/
),
expect.stringMatching(/\/__manifest\?p=%2Fparent%2Fchild2&version=/),
]);
});

Expand Down Expand Up @@ -780,7 +777,7 @@ test.describe("Fog of War", () => {
)
).toEqual(["root", "routes/_index", "routes/$slug"]);
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fsomething/),
expect.stringMatching(/\/__manifest\?p=%2Fsomething&version=/),
]);
manifestRequests = [];

Expand All @@ -794,7 +791,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#static");
expect(await app.getHtml("#static")).toMatch("Static");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fstatic/),
expect.stringMatching(/\/__manifest\?p=%2Fstatic&version=/),
]);
expect(
await page.evaluate(() =>
Expand Down Expand Up @@ -867,7 +864,7 @@ test.describe("Fog of War", () => {
)
).toEqual(["root", "routes/_index", "routes/$"]);
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fsomething/),
expect.stringMatching(/\/__manifest\?p=%2Fsomething&version=/),
]);
manifestRequests = [];

Expand All @@ -881,7 +878,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#static");
expect(await app.getHtml("#static")).toMatch("Static");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fstatic/),
expect.stringMatching(/\/__manifest\?p=%2Fstatic&version=/),
]);
expect(
await page.evaluate(() =>
Expand Down Expand Up @@ -953,7 +950,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#slug");
expect(await app.getHtml("#slug")).toMatch("Slug: a");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fa/),
expect.stringMatching(/\/__manifest\?p=%2Fa&version=/),
]);
manifestRequests = [];

Expand All @@ -974,7 +971,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#slug");
expect(await app.getHtml("#slug")).toMatch("Slug: b");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fb/),
expect.stringMatching(/\/__manifest\?p=%2Fb&version=/),
]);
});

Expand Down Expand Up @@ -1041,7 +1038,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#splat");
expect(await app.getHtml("#splat")).toMatch("Splat: a");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fa/),
expect.stringMatching(/\/__manifest\?p=%2Fa&version=/),
]);
manifestRequests = [];

Expand All @@ -1062,7 +1059,7 @@ test.describe("Fog of War", () => {
await page.waitForSelector("#splat");
expect(await app.getHtml("#splat")).toMatch("Splat: b/c");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fb%2Fc/),
expect.stringMatching(/\/__manifest\?p=%2Fb%2Fc&version=/),
]);
});

Expand Down Expand Up @@ -1134,17 +1131,15 @@ test.describe("Fog of War", () => {
await app.clickLink("/not/a/path");
await page.waitForSelector("#error");
expect(manifestRequests).toEqual([
expect.stringMatching(
/\/__manifest\?version=[a-z0-9]{8}&p=%2Fnot%2Fa%2Fpath/
),
expect.stringMatching(/\/__manifest\?p=%2Fnot%2Fa%2Fpath&version=/),
]);
manifestRequests = [];

// Go to a valid slug route
await app.clickLink("/something");
await page.waitForSelector("#slug");
expect(manifestRequests).toEqual([
expect.stringMatching(/\/__manifest\?version=[a-z0-9]{8}&p=%2Fsomething/),
expect.stringMatching(/\/__manifest\?p=%2Fsomething&version=/),
]);
manifestRequests = [];

Expand Down Expand Up @@ -1177,10 +1172,10 @@ test.describe("Fog of War", () => {
let appFixture = await createAppFixture(fixture);
let app = new PlaywrightFixture(appFixture, page);

let manifestRequests: PlaywrightRequest[] = [];
let manifestRequests: string[] = [];
page.on("request", (req) => {
if (req.url().includes("/__manifest")) {
manifestRequests.push(req);
manifestRequests.push(req.url());
}
});

Expand All @@ -1197,4 +1192,85 @@ test.describe("Fog of War", () => {
)
).toEqual(["root", "routes/_index", "routes/a"]);
});

test("includes a version query parameter as a cachebuster", async ({
page,
}) => {
let fixture = await createFixture({
files: {
...getFiles(),
"app/routes/_index.tsx": js`
import { Link } from "react-router";
export default function Index() {
return (
<>
<h1 id="index">Index</h1>
<Link to="/a">/a</Link>
<Link to="/b">/b</Link>
</>
);
}
`,
},
});
let appFixture = await createAppFixture(fixture);
let app = new PlaywrightFixture(appFixture, page);

let manifestRequests: string[] = [];
page.on("request", (req) => {
if (req.url().includes("/__manifest")) {
manifestRequests.push(req.url());
}
});

await app.goto("/", true);
await new Promise((resolve) => setTimeout(resolve, 250));
expect(manifestRequests).toEqual([
expect.stringMatching(
/\/__manifest\?p=%2F&p=%2Fa&p=%2Fb&version=[a-z0-9]{8}/
),
]);
});

test("sorts url parameters", async ({ page }) => {
let fixture = await createFixture({
files: {
...getFiles(),
"app/routes/_index.tsx": js`
import { Link } from "react-router";
export default function Index() {
return (
<>
<h1 id="index">Index</h1>
<Link to="/a">/a</Link>
<Link to="/c">/c</Link>
<Link to="/e">/e</Link>
<Link to="/g">/g</Link>
<Link to="/f">/f</Link>
<Link to="/d">/d</Link>
<Link to="/b">/b</Link>
</>
);
}
`,
},
});
let appFixture = await createAppFixture(fixture);
let app = new PlaywrightFixture(appFixture, page);

let manifestRequests: string[] = [];
page.on("request", (req) => {
if (req.url().includes("/__manifest")) {
manifestRequests.push(req.url());
}
});

await app.goto("/", true);
await new Promise((resolve) => setTimeout(resolve, 250));
expect(manifestRequests).toEqual([
expect.stringMatching(
/\/__manifest\?p=%2F&p=%2Fa&p=%2Fb&p=%2Fc&p=%2Fd&p=%2Fe&p=%2Ff&p=%2F/
),
]);
});
});
5 changes: 3 additions & 2 deletions integration/helpers/create-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,13 @@ export async function createFixture(init: FixtureInit, mode?: ServerMode) {
let url = new URL(href, "test://test");
let request = new Request(url.toString(), init);
let response = await handler(request);
let decoded = await decodeViaTurboStream(response.body!, global);
return {
status: response.status,
statusText: response.statusText,
headers: response.headers,
data: decoded.value,
data: response.body
? (await decodeViaTurboStream(response.body!, global)).value
: null,
};
};

Expand Down
2 changes: 1 addition & 1 deletion integration/root-route-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ test.describe("root route", () => {
// which should throw on the initial render _and_ the error render,
// resulting in us bubbling to the default error boundary and skipping
// our Layout component entirely to avoid a loop
lazy: new Promise((r) => setTimeout(() => r(null), 100)),
lazy: new Promise((r) => setTimeout(() => r(null), 500)),
};
}
export default function Root() {
Expand Down
Loading
Loading