Skip to content

Commit de3a3c6

Browse files
rmarscherdai-shi
andauthored
chore: create monorepo e2e spec (#1079)
This needs more work to figure out how to install dependencies in the test monorepo and link in the waku package in a way that closely matches the way it works with published npm packages. --------- Co-authored-by: Daishi Kato <[email protected]>
1 parent 52f7ad6 commit de3a3c6

17 files changed

+275
-4
lines changed

e2e/fixtures/monorepo/package.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "monorepo",
3+
"private": true,
4+
"workspaces": [
5+
"packages/*"
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "waku-project",
3+
"version": "0.0.0",
4+
"type": "module",
5+
"private": true,
6+
"scripts": {
7+
"dev": "waku dev",
8+
"build": "waku build",
9+
"start": "waku start"
10+
},
11+
"dependencies": {
12+
"react": "19.0.0",
13+
"react-dom": "19.0.0",
14+
"react-server-dom-webpack": "19.0.0"
15+
},
16+
"devDependencies": {
17+
"@types/react": "19.0.1",
18+
"@types/react-dom": "19.0.2",
19+
"autoprefixer": "10.4.20",
20+
"tailwindcss": "3.4.16",
21+
"typescript": "5.7.2"
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/** @type {import('postcss-load-config').Config} */
2+
export default {
3+
plugins: {
4+
tailwindcss: {},
5+
autoprefixer: {},
6+
},
7+
};
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use client';
2+
3+
import { useState } from 'react'; // eslint-disable-line import/no-unresolved
4+
5+
export const Counter = () => {
6+
const [count, setCount] = useState(0);
7+
8+
const handleIncrement = () => setCount((c) => c + 1);
9+
10+
return (
11+
<section className="border-blue-400 -mx-4 mt-4 rounded border border-dashed p-4">
12+
<div>Count: {count}</div>
13+
<button
14+
onClick={handleIncrement}
15+
className="rounded-sm bg-black px-2 py-0.5 text-sm text-white"
16+
>
17+
Increment
18+
</button>
19+
</section>
20+
);
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export const Footer = () => {
2+
return (
3+
<footer className="p-6 lg:fixed lg:bottom-0 lg:left-0">
4+
<div>
5+
visit{' '}
6+
<a
7+
href="https://waku.gg/"
8+
target="_blank"
9+
rel="noreferrer"
10+
className="mt-4 inline-block underline"
11+
>
12+
waku.gg
13+
</a>{' '}
14+
to learn more
15+
</div>
16+
</footer>
17+
);
18+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Link } from 'waku';
2+
3+
export const Header = () => {
4+
return (
5+
<header className="flex items-center gap-4 p-6 lg:fixed lg:left-0 lg:top-0">
6+
<h2 className="text-lg font-bold tracking-tight">
7+
<Link to="/">Waku starter</Link>
8+
</h2>
9+
</header>
10+
);
11+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import '../styles.css';
2+
3+
import type { ReactNode } from 'react';
4+
5+
import { Header } from '../components/header';
6+
import { Footer } from '../components/footer';
7+
8+
type RootLayoutProps = { children: ReactNode };
9+
10+
export default async function RootLayout({ children }: RootLayoutProps) {
11+
const data = await getData();
12+
13+
return (
14+
<div className="font-['Nunito']">
15+
<meta name="description" content={data.description} />
16+
<link rel="icon" type="image/png" href={data.icon} />
17+
<Header />
18+
<main className="m-6 flex items-center *:min-h-64 *:min-w-64 lg:m-0 lg:min-h-svh lg:justify-center">
19+
{children}
20+
</main>
21+
<Footer />
22+
</div>
23+
);
24+
}
25+
26+
const getData = async () => {
27+
const data = {
28+
description: 'An internet website!',
29+
icon: '/images/favicon.png',
30+
};
31+
32+
return data;
33+
};
34+
35+
export const getConfig = async () => {
36+
return {
37+
render: 'static',
38+
} as const;
39+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Link } from 'waku';
2+
3+
export default async function AboutPage() {
4+
const data = await getData();
5+
6+
return (
7+
<div>
8+
<title>{data.title}</title>
9+
<h1 className="text-4xl font-bold tracking-tight">{data.headline}</h1>
10+
<p>{data.body}</p>
11+
<Link to="/" className="mt-4 inline-block underline">
12+
Return home
13+
</Link>
14+
</div>
15+
);
16+
}
17+
18+
const getData = async () => {
19+
const data = {
20+
title: 'About',
21+
headline: 'About Waku',
22+
body: 'The minimal React framework',
23+
};
24+
25+
return data;
26+
};
27+
28+
export const getConfig = async () => {
29+
return {
30+
render: 'static',
31+
} as const;
32+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Link } from 'waku';
2+
3+
import { Counter } from '../components/counter';
4+
5+
export default async function HomePage() {
6+
const data = await getData();
7+
8+
return (
9+
<div>
10+
<title>{data.title}</title>
11+
<h1 className="text-4xl font-bold tracking-tight" data-testid="header">
12+
{data.headline}
13+
</h1>
14+
<p>{data.body}</p>
15+
<Counter />
16+
<Link to="/about" className="mt-4 inline-block underline">
17+
About page
18+
</Link>
19+
</div>
20+
);
21+
}
22+
23+
const getData = async () => {
24+
const data = {
25+
title: 'Waku',
26+
headline: 'Waku',
27+
body: 'Hello world!',
28+
};
29+
30+
return data;
31+
};
32+
33+
export const getConfig = async () => {
34+
return {
35+
render: 'static',
36+
} as const;
37+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,700;1,400;1,700&display=swap');
2+
@tailwind base;
3+
@tailwind components;
4+
@tailwind utilities;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('tailwindcss').Config} */
2+
export default {
3+
content: ['./src/**/*.{js,jsx,ts,tsx}'],
4+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"composite": true,
4+
"strict": true,
5+
"target": "esnext",
6+
"downlevelIteration": true,
7+
"esModuleInterop": true,
8+
"module": "esnext",
9+
"moduleResolution": "bundler",
10+
"skipLibCheck": true,
11+
"noUncheckedIndexedAccess": true,
12+
"exactOptionalPropertyTypes": true,
13+
"types": ["react/experimental"],
14+
"jsx": "react-jsx",
15+
"rootDir": "./src",
16+
"outDir": "./dist"
17+
}
18+
}

e2e/monorepo.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { test, prepareStandaloneSetup } from './utils.js';
4+
5+
const startApp = prepareStandaloneSetup('monorepo');
6+
7+
for (const mode of ['DEV', 'PRD'] as const) {
8+
for (const packageManager of ['npm', 'pnpm', 'yarn'] as const) {
9+
test.describe(`${packageManager} monorepo: ${mode}`, () => {
10+
let port: number;
11+
let stopApp: () => Promise<void>;
12+
test.beforeAll(async () => {
13+
({ port, stopApp } = await startApp(
14+
mode,
15+
packageManager,
16+
'packages/waku-project',
17+
));
18+
});
19+
test.afterAll(async () => {
20+
await stopApp();
21+
});
22+
23+
test('renders the home page', async ({ page }) => {
24+
await page.goto(`http://localhost:${port}`);
25+
await expect(page.getByTestId('header')).toHaveText('Waku');
26+
});
27+
});
28+
}
29+
}

e2e/utils.ts

+20-4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ export const prepareNormalSetup = (fixtureName: string) => {
138138
return startApp;
139139
};
140140

141+
const PACKAGE_INSTALL = {
142+
npm: (path: string) => `npm add ${path}`,
143+
pnpm: (path: string) => `pnpm add ${path}`,
144+
yarn: (path: string) => `yarn add ${path}`,
145+
} as const;
146+
141147
export const prepareStandaloneSetup = (fixtureName: string) => {
142148
const wakuDir = fileURLToPath(new URL('../packages/waku', import.meta.url));
143149
const { version } = createRequire(import.meta.url)(
@@ -151,7 +157,11 @@ export const prepareStandaloneSetup = (fixtureName: string) => {
151157
const tmpDir = process.env.TEMP_DIR || tmpdir();
152158
let standaloneDir: string | undefined;
153159
let built = false;
154-
const startApp = async (mode: 'DEV' | 'PRD' | 'STATIC') => {
160+
const startApp = async (
161+
mode: 'DEV' | 'PRD' | 'STATIC',
162+
packageManager: 'npm' | 'pnpm' | 'yarn' = 'npm',
163+
packageDir = '',
164+
) => {
155165
if (!standaloneDir) {
156166
standaloneDir = mkdtempSync(join(tmpDir, fixtureName));
157167
cpSync(fixtureDir, standaloneDir, {
@@ -164,16 +174,22 @@ export const prepareStandaloneSetup = (fixtureName: string) => {
164174
cwd: wakuDir,
165175
stdio: 'inherit',
166176
});
177+
const wakuPackageTgz = join(standaloneDir, `waku-${version}.tgz`);
178+
const installScript = PACKAGE_INSTALL[packageManager](wakuPackageTgz);
179+
execSync(installScript, { cwd: standaloneDir, stdio: 'inherit' });
167180
execSync(
168181
`npm install --force ${join(standaloneDir, `waku-${version}.tgz`)}`,
169182
{ cwd: standaloneDir, stdio: 'inherit' },
170183
);
171184
}
172185
if (mode !== 'DEV' && !built) {
173-
rmSync(`${standaloneDir}/dist`, { recursive: true, force: true });
186+
rmSync(`${join(standaloneDir, packageDir, 'dist')}`, {
187+
recursive: true,
188+
force: true,
189+
});
174190
execSync(
175191
`node ${join(standaloneDir, './node_modules/waku/dist/cli.js')} build`,
176-
{ cwd: standaloneDir },
192+
{ cwd: join(standaloneDir, packageDir) },
177193
);
178194
built = true;
179195
}
@@ -190,7 +206,7 @@ export const prepareStandaloneSetup = (fixtureName: string) => {
190206
cmd = `node ${join(standaloneDir, './node_modules/serve/build/main.js')} dist/public -p ${port}`;
191207
break;
192208
}
193-
const cp = exec(cmd, { cwd: standaloneDir });
209+
const cp = exec(cmd, { cwd: join(standaloneDir, packageDir) });
194210
debugChildProcess(cp, fileURLToPath(import.meta.url), [
195211
/ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time/,
196212
]);

pnpm-lock.yaml

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tsconfig.e2e.json

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
{
5252
"path": "./e2e/fixtures/hot-reload/tsconfig.json"
5353
},
54+
{
55+
"path": "./e2e/fixtures/monorepo/packages/waku-project/tsconfig.json"
56+
},
5457
{
5558
"path": "./e2e/fixtures/create-pages/tsconfig.json"
5659
}

0 commit comments

Comments
 (0)