Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions .github/workflows/test-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,12 @@ jobs:
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:artifact

- name: E2E Test (Playwright)
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:e2e

- name: Examples Test
if: steps.changes.outputs.changed == 'true'
run: |
pnpm run build:examples

- name: E2E Test (Playwright)
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:e2e

8 changes: 4 additions & 4 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ jobs:
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:artifact

- name: E2E Test (Playwright)
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:e2e

- name: Examples Test
if: steps.changes.outputs.changed == 'true'
run: pnpm run build:examples

- name: E2E Test (Playwright)
if: steps.changes.outputs.changed == 'true'
run: pnpm run test:e2e
26 changes: 26 additions & 0 deletions e2e/cases/examples-e2e/react-component/index.pw.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { dev } from '@e2e/helper/rsbuild';
import { expect, test } from '@playwright/test';

test('should render example "react-component" successfully', async ({
page,
}) => {
const rsbuild = await dev({
cwd: __dirname,
page,
});

const h2El = page.locator('h2');
await expect(h2El).toHaveText('Counter: 0');

const buttonEl = page.locator('#root button');

const [subtractEl, addEl] = await buttonEl.all();

await expect(h2El).toHaveText('Counter: 0');
addEl?.click();
await expect(h2El).toHaveText('Counter: 1');
subtractEl?.click();
await expect(h2El).toHaveText('Counter: 0');

await rsbuild.close();
});
5 changes: 5 additions & 0 deletions e2e/cases/examples-e2e/react-component/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "react-component-e2e",
"version": "1.0.0",
"private": true
}
6 changes: 6 additions & 0 deletions e2e/cases/examples-e2e/react-component/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';

export default defineConfig({
plugins: [pluginReact()],
});
9 changes: 9 additions & 0 deletions e2e/cases/examples-e2e/react-component/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Counter } from '@examples/react-component';

const App = () => (
<div>
<Counter />
</div>
);

export default App;
10 changes: 10 additions & 0 deletions e2e/cases/examples-e2e/react-component/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
15 changes: 15 additions & 0 deletions e2e/cases/examples-e2e/react-component/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "ES2020"],
"module": "ESNext",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"isolatedModules": true,
"resolveJsonModule": true,
"moduleResolution": "bundler",
"useDefineForClassFields": true
},
"include": ["src"]
}
6 changes: 5 additions & 1 deletion e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
"test": "playwright test --pass-with-no-tests"
},
"dependencies": {
"react": "^18.3.1"
"@examples/react-component": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@e2e/helper": "workspace:*",
"@playwright/test": "1.47.2",
"@rsbuild/core": "1.0.7",
"@rsbuild/plugin-react": "1.0.2",
"@rslib/core": "workspace:*",
"@rslib/tsconfig": "workspace:*",
"@types/fs-extra": "^11.0.4",
"@types/node": "~18.19.39",
"@types/react": "^18.3.9",
"@types/react-dom": "^18.3.0",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"path-serializer": "0.0.6",
Expand Down
4 changes: 4 additions & 0 deletions e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ import { defineConfig } from '@playwright/test';
export default defineConfig({
// Playwright test files with `.pw.` to distinguish from Vitest test files
testMatch: /.*pw.(test|spec).(js|ts|mjs)/,
// Retry on CI
retries: process.env.CI ? 3 : 0,
// Print line for each test being run in CI
reporter: 'list',
});
138 changes: 138 additions & 0 deletions e2e/scripts/rsbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* The following code is modified based on
* https://github.com/web-infra-dev/rsbuild/blob/c21e2130a285177b890fca543f70377b66d1ad73/e2e/scripts/shared.ts
*/
import net from 'node:net';
import type { Page } from '@playwright/test';
import type {
CreateRsbuildOptions,
RsbuildConfig,
RsbuildPlugins,
} from '@rsbuild/core';

const getHrefByEntryName = (entryName: string, port: number) => {
const htmlRoot = new URL(`http://localhost:${port}`);
const homeUrl = new URL(`${entryName}.html`, htmlRoot);

return homeUrl.href;
};

const gotoPage = async (
page: Page,
rsbuild: { port: number },
path = 'index',
) => {
const url = getHrefByEntryName(path, rsbuild.port);
return page.goto(url);
};

function isPortAvailable(port: number) {
try {
const server = net.createServer().listen(port);
return new Promise((resolve) => {
server.on('listening', () => {
server.close();
resolve(true);
});

server.on('error', () => {
resolve(false);
});
});
} catch (err) {
return false;
}
}

const portMap = new Map();
// Available port ranges: 1024 ~ 65535
// `10080` is not available in macOS CI, `> 50000` get 'permission denied' in Windows.
// so we use `15000` ~ `45000`.
async function getRandomPort(
defaultPort = Math.ceil(Math.random() * 30000) + 15000,
) {
let port = defaultPort;
while (true) {
if (!portMap.get(port) && (await isPortAvailable(port))) {
portMap.set(port, 1);
return port;
}
port++;
}
}

const updateConfigForTest = async (
originalConfig: RsbuildConfig,
cwd: string = process.cwd(),
) => {
const { loadConfig, mergeRsbuildConfig } = await import('@rsbuild/core');
const { content: loadedConfig } = await loadConfig({
cwd,
});

const baseConfig: RsbuildConfig = {
dev: {
progressBar: false,
},
server: {
// make port random to avoid conflict
port: await getRandomPort(),
printUrls: false,
},
performance: {
buildCache: false,
printFileSize: false,
},
};

return mergeRsbuildConfig(baseConfig, loadedConfig, originalConfig);
};

const createRsbuild = async (
rsbuildOptions: CreateRsbuildOptions,
plugins: RsbuildPlugins = [],
) => {
const { createRsbuild: createRsbuildInner } = await import('@rsbuild/core');

rsbuildOptions.rsbuildConfig ||= {};
rsbuildOptions.rsbuildConfig.plugins = [
...(rsbuildOptions.rsbuildConfig.plugins || []),
...(plugins || []),
];

const rsbuild = await createRsbuildInner(rsbuildOptions);
return rsbuild;
};

export async function dev({
plugins,
page,
...options
}: CreateRsbuildOptions & {
plugins?: RsbuildPlugins;
/**
* Playwright Page instance.
* This method will automatically goto the page.
*/
page?: Page;
}) {
process.env.NODE_ENV = 'development';

options.rsbuildConfig = await updateConfigForTest(
options.rsbuildConfig || {},
options.cwd,
);

const rsbuild = await createRsbuild(options, plugins);
const result = await rsbuild.startDevServer();

if (page) {
await gotoPage(page, result);
}

return {
...result,
instance: rsbuild,
close: async () => result.server.close(),
};
}
3 changes: 3 additions & 0 deletions examples/react-component/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "@examples/react-component",
"private": true,
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.mjs",
"types": "./dist/cjs/index.d.ts",
"scripts": {
"build": "rslib build"
},
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading