Skip to content

Commit

Permalink
Add failing test for workspace route library
Browse files Browse the repository at this point in the history
Adds workspace routes fixture and a failing test
  • Loading branch information
wilcoxmd committed Feb 11, 2025
1 parent f9f4a27 commit 74fed50
Show file tree
Hide file tree
Showing 17 changed files with 344 additions and 264 deletions.
45 changes: 45 additions & 0 deletions integration/helpers/filesystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import fse from "fs-extra";
import stripIndent from "strip-indent";
import path from "node:path";
import url from "node:url";

const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const root = path.resolve(__dirname, "../..");
const TMP_DIR = path.join(root, ".tmp/integration");

export async function writeTestFiles(
files: Record<string, string> | undefined,
dir: string
) {
await Promise.all(
Object.keys(files ?? {}).map(async (filename) => {
let filePath = path.join(dir, filename);
await fse.ensureDir(path.dirname(filePath));
let file = files![filename];

await fse.writeFile(filePath, stripIndent(file));
})
);
}

export async function getAllFilesInDir(dirPath: string): Promise<string[]> {
const entries = await fse.promises.readdir(dirPath, { withFileTypes: true });
const files = await Promise.all(
entries.map((entry) => {
const resolvedPath = path.resolve(dirPath, entry.name);
if (entry.isDirectory()) {
return getAllFilesInDir(resolvedPath);
} else {
return [resolvedPath];
}
})
);
return files.flat();
}

export async function createTestDirectory() {
let folderName = `rr-${Math.random().toString(32).slice(2)}`;
let testDir = path.join(TMP_DIR, folderName);
await fse.ensureDir(testDir);
return testDir;
}
48 changes: 35 additions & 13 deletions integration/helpers/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import url from "node:url";
import { createRequire } from "node:module";
import { platform } from "node:os";
import fse from "fs-extra";
import stripIndent from "strip-indent";
import waitOn from "wait-on";
import getPort from "get-port";
import shell from "shelljs";
Expand All @@ -15,13 +14,12 @@ import dedent from "dedent";
import type { Page } from "@playwright/test";
import { test as base, expect } from "@playwright/test";
import type { Config } from "@react-router/dev/config";
import { createTestDirectory, writeTestFiles } from "./filesystem";

const require = createRequire(import.meta.url);

const reactRouterBin = "node_modules/@react-router/dev/bin.js";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const root = path.resolve(__dirname, "../..");
const TMP_DIR = path.join(root, ".tmp/integration");

export const reactRouterConfig = ({
ssr,
Expand Down Expand Up @@ -157,26 +155,50 @@ export async function createProject(
files: Record<string, string> = {},
templateName: TemplateName = "vite-5-template"
) {
let projectName = `rr-${Math.random().toString(32).slice(2)}`;
let projectDir = path.join(TMP_DIR, projectName);
await fse.ensureDir(projectDir);
let projectDir = await createTestDirectory();

// base template
let templateDir = path.resolve(__dirname, templateName);
await fse.copy(templateDir, projectDir, { errorOnExist: true });

// user-defined files
await Promise.all(
Object.entries(files).map(async ([filename, contents]) => {
let filepath = path.join(projectDir, filename);
await fse.ensureDir(path.dirname(filepath));
await fse.writeFile(filepath, stripIndent(contents));
})
);
await writeTestFiles(files, projectDir);

return projectDir;
}

type WorkspaceFileCreatorFn = (
libDir: string,
appDir: string
) => { appFiles?: Record<string, string>; libFiles?: Record<string, string> };

export async function createWorkspaceProject(files: WorkspaceFileCreatorFn) {
const workspaceDir = await createTestDirectory();

const workspaceTemplateDir = path.resolve(
__dirname,
"workspace-routes-template"
);
await fse.copy(workspaceTemplateDir, workspaceDir, { errorOnExist: true });

const appProjectDir = path.resolve(workspaceDir, "apps", "test-app");
const libProjectDir = path.resolve(workspaceDir, "libs", "test-route-library");

const userFiles = files(libProjectDir, appProjectDir);
if (userFiles.libFiles) {
await writeTestFiles(userFiles.libFiles, libProjectDir);
}
if (userFiles.appFiles) {
await writeTestFiles(userFiles.appFiles, appProjectDir);
}

return {
appProjectDir,
libProjectDir,
workspaceDir,
};
}

// Avoid "Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env
// being set" in vite-ecosystem-ci which breaks empty stderr assertions. To fix
// this we always ensure that only NO_COLOR is set after spreading process.env.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules

/.cache
/build
.env
.react-router
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";

export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export default flatRoutes() satisfies RouteConfig;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { MetaFunction } from "react-router";

export const meta: MetaFunction = () => {
return [
{ title: "New React Router App" },
{ name: "description", content: "Welcome to React Router!" },
];
};

export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
<h1>Welcome to React Router</h1>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="@react-router/node" />
/// <reference types="vite/client" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "integration-workspace-test-app-template",
"version": "0.0.0",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "react-router dev",
"build": "react-router build",
"start": "react-router-serve ./build/server/index.js",
"typecheck": "react-router typegen && tsc"
},
"dependencies": {
"@react-router/express": "workspace:*",
"@react-router/node": "workspace:*",
"@react-router/serve": "workspace:*",
"@vanilla-extract/css": "^1.10.0",
"@vanilla-extract/vite-plugin": "^3.9.2",
"express": "^4.19.2",
"isbot": "^5.1.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "workspace:*",
"test-route-library": "workspace:*",
"serialize-javascript": "^6.0.1"
},
"devDependencies": {
"@react-router/dev": "workspace:*",
"@react-router/fs-routes": "workspace:*",
"@react-router/remix-routes-option-adapter": "workspace:*",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"eslint": "^8.38.0",
"typescript": "^5.1.6",
"vite": "^6.0.0",
"vite-env-only": "^3.0.1",
"vite-tsconfig-paths": "^4.2.1"
},
"engines": {
"node": ">=20.0.0"
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"include": [
"env.d.ts",
"**/*.ts",
"**/*.tsx",
".react-router/types/**/*.d.ts"
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"verbatimModuleSyntax": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
"noEmit": true,
"rootDirs": [".", ".react-router/types/"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
plugins: [reactRouter(), tsconfigPaths()],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function sum(a: number, b: number): number;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function sum(a, b) {
return a + b;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "test-route-library",
"type": "module",
"private": true,
"exports": {
".": "./index.js"
},
"peerDependencies": {
"react": "^18.2.0",
"@react-router/dev": "workspace:*"
}
}
41 changes: 40 additions & 1 deletion integration/typegen-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { expect, test } from "@playwright/test";
import dedent from "dedent";
import fse from "fs-extra";

import { createProject } from "./helpers/vite";
import {
createProject,
createWorkspaceProject,
} from "./helpers/vite";
import { getAllFilesInDir } from "./helpers/filesystem";

const tsx = dedent;

Expand Down Expand Up @@ -362,4 +366,39 @@ test.describe("typegen", () => {
expect(proc.stderr.toString()).toBe("");
expect(proc.status).toBe(0);
});

test("route files from workspace packages", async () => {
const { appProjectDir } = await createWorkspaceProject((libDir) => ({
appFiles: {
"app/routes.ts": tsx`
import type { RouteConfig } from "@react-router/dev/routes";
export default [
{ path: 'lib-route', file: "${libDir}/my-route.jsx" }
] satisfies RouteConfig;
`,
},
libFiles: {
"my-route.jsx": tsx`
export default function MyRoute() {
return <h1>My Route</h1>;
}
`,
},
}));

const proc = typecheck(appProjectDir);

expect(proc.stdout.toString()).toBe("");
expect(proc.stderr.toString()).toBe("");
expect(proc.status).toBe(0);

// Expect that the route library's typing is not generated into the app project
const files = await getAllFilesInDir(appProjectDir);
const appProjectFiles = files.filter(
(name) => !name.includes("node_modules")
);
expect(
appProjectFiles.some((name) => name.includes("my-route"))
).toBeFalsy();
});
});
Loading

0 comments on commit 74fed50

Please sign in to comment.