|  | 
| 1 | 1 | import fs from "node:fs/promises"; | 
| 2 | 2 | 
 | 
|  | 3 | +import { expect } from "@playwright/test"; | 
| 3 | 4 | import tsx from "dedent"; | 
| 4 | 5 | import * as Path from "pathe"; | 
| 5 | 6 | 
 | 
| @@ -336,6 +337,57 @@ test.describe("typegen", () => { | 
| 336 | 337 |     await $("pnpm typecheck"); | 
| 337 | 338 |   }); | 
| 338 | 339 | 
 | 
|  | 340 | +  test("routes outside app dir", async ({ cwd, edit, $ }) => { | 
|  | 341 | +    // Create the subdirectories | 
|  | 342 | +    await fs.mkdir(Path.join(cwd, "app/router"), { recursive: true }); | 
|  | 343 | +    await fs.mkdir(Path.join(cwd, "app/pages"), { recursive: true }); | 
|  | 344 | +     | 
|  | 345 | +    await edit({ | 
|  | 346 | +      "react-router.config.ts": tsx` | 
|  | 347 | +        export default { | 
|  | 348 | +          appDirectory: "app/router", | 
|  | 349 | +        } | 
|  | 350 | +      `, | 
|  | 351 | +      "app/router/routes.ts": tsx` | 
|  | 352 | +        import { type RouteConfig, route } from "@react-router/dev/routes"; | 
|  | 353 | +
 | 
|  | 354 | +        export default [ | 
|  | 355 | +          route("products/:id", "../pages/product.tsx") | 
|  | 356 | +        ] satisfies RouteConfig; | 
|  | 357 | +      `, | 
|  | 358 | +      "app/router/root.tsx": tsx` | 
|  | 359 | +        import { Outlet } from "react-router"; | 
|  | 360 | +
 | 
|  | 361 | +        export default function Root() { | 
|  | 362 | +          return <Outlet />; | 
|  | 363 | +        } | 
|  | 364 | +      `, | 
|  | 365 | +      "app/pages/product.tsx": tsx` | 
|  | 366 | +        import type { Expect, Equal } from "../expect-type" | 
|  | 367 | +        import type { Route } from "./+types/product" | 
|  | 368 | +
 | 
|  | 369 | +        export function loader({ params }: Route.LoaderArgs) { | 
|  | 370 | +          type Test = Expect<Equal<typeof params, { id: string }>> | 
|  | 371 | +          return { planet: "world" } | 
|  | 372 | +        } | 
|  | 373 | +
 | 
|  | 374 | +        export default function Component({ loaderData }: Route.ComponentProps) { | 
|  | 375 | +          type Test = Expect<Equal<typeof loaderData.planet, string>> | 
|  | 376 | +          return <h1>Hello, {loaderData.planet}!</h1> | 
|  | 377 | +        } | 
|  | 378 | +      `, | 
|  | 379 | +    }); | 
|  | 380 | +    await $("pnpm typecheck"); | 
|  | 381 | + | 
|  | 382 | +    // Verify that the types file was generated in the correct location | 
|  | 383 | +    const annotationPath = Path.join( | 
|  | 384 | +      cwd, | 
|  | 385 | +      ".react-router/types/app/pages/+types/product.ts", | 
|  | 386 | +    ); | 
|  | 387 | +    const annotation = await fs.readFile(annotationPath, "utf8"); | 
|  | 388 | +    expect(annotation).toContain("export namespace Route"); | 
|  | 389 | +  }); | 
|  | 390 | + | 
| 339 | 391 |   test("matches", async ({ edit, $ }) => { | 
| 340 | 392 |     await edit({ | 
| 341 | 393 |       "app/routes.ts": tsx` | 
|  | 
0 commit comments