diff --git a/contributors.yml b/contributors.yml index 1105211f05..665eff4562 100644 --- a/contributors.yml +++ b/contributors.yml @@ -387,3 +387,4 @@ - yuleicul - zeromask1337 - zheng-chuang +- richardszalay \ No newline at end of file diff --git a/integration/bug-report-test.ts b/integration/bug-report-test.ts index 8be63c7fc2..fa9f6df347 100644 --- a/integration/bug-report-test.ts +++ b/integration/bug-report-test.ts @@ -64,27 +64,60 @@ test.beforeAll(async () => { // `createFixture` will make an app and run your tests against it. //////////////////////////////////////////////////////////////////////////// files: { - "app/routes/_index.tsx": js` - import { useLoaderData, Link } from "react-router"; + "app/routes/_layout.tsx": js` + import { Outlet } from "react-router"; - export function loader() { - return "pizza"; + function dummyApiCall() { + return new Promise((resolve, reject) => { + setTimeout(resolve, 1000) + }) + } + + // [WORKAROUND 1]: If the layout does not define a loader (by commenting this out), the process does not crash + export async function loader() { + await dummyApiCall(); + return {} } - export default function Index() { - let data = useLoaderData(); + export default function Layout() { return (
- {data} - Other Route + Layout +
) } `, - "app/routes/burgers.tsx": js` - export default function Index() { - return
cheeseburger
; + "app/routes/_layout._index.tsx": js` + import { Suspense } from "react"; + import { Await, useLoaderData } from "react-router"; + + function dummyApiCall() { + return new Promise((_, reject) => { + // [WORKAROUND 2]: If the index's loader takes longer to resolve (e.g. 1500) than the layout's the process does not crash + setTimeout(reject, 500) + }) + } + + export function loader() { + return { promise: dummyApiCall() } + } + + export default function Home() { + const { promise } = useLoaderData() + + return Loading}> + }>{() => } + + } + + function HomeSuccess() { + return
This is not expected because the promise was rejected
+ } + + function HomeError() { + return
Error, but the good kind!
} `, }, @@ -103,22 +136,10 @@ test.afterAll(() => { // add a good description for what you expect React Router to do 👇🏽 //////////////////////////////////////////////////////////////////////////////// -test("[description of what you expect it to do]", async ({ page }) => { - let app = new PlaywrightFixture(appFixture, page); - // You can test any request your app might get using `fixture`. +test("route renders suspense error when route loader rejects before layout loader completes", async ({ page }) => { let response = await fixture.requestDocument("/"); - expect(await response.text()).toMatch("pizza"); - - // If you need to test interactivity use the `app` - await app.goto("/"); - await app.clickLink("/burgers"); - await page.waitForSelector("text=cheeseburger"); - - // If you're not sure what's going on, you can "poke" the app, it'll - // automatically open up in your browser for 20 seconds, so be quick! + expect(await response.text()).toMatch("Error, but the good kind"); // await app.poke(20); - - // Go check out the other tests to see what else you can do. }); ////////////////////////////////////////////////////////////////////////////////