Skip to content
Open
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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,8 @@ jobs:
- name: Build project
run: pnpm run build

- name: Verify report template asset
run: pnpm run verify:report-template

- name: Run tests
run: pnpm run test
3 changes: 0 additions & 3 deletions .github/workflows/studio-headless-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ jobs:
- name: Build Studio
run: npx nx run-many --target=build --projects=studio,@midscene/report

- name: Re-inject report template into @midscene/core dist
run: node apps/report/scripts/inject-report-template.mjs

- name: Run Studio startup smoke test
run: xvfb-run -a --server-args="-screen 0 1920x1080x24" pnpm --dir apps/studio run test:smoke
env:
Expand Down
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ cd apps/playground && pnpm run dev
cd apps/chrome-extension && pnpm run dev
```

### `REPLACE_ME_WITH_REPORT_HTML` error in the report file
### Missing report template errors

`apps/report` is not standalone at runtime. Its built `index.html` template is
injected back into `packages/core/dist` during build. If report UI changes do
not show up, or you see `REPLACE_ME_WITH_REPORT_HTML` in the report file, the
template injection is usually stale. Rebuild the entire workspace without Nx
cache to fix it:
synced into `packages/core/dist/report-template/index.html` during build. If
report UI changes do not show up, or the runtime says the Midscene report
template is missing, rebuild the entire workspace without Nx cache to refresh
the synced template:

```sh
# Rebuild the entire project without cache
Expand Down
14 changes: 14 additions & 0 deletions apps/android-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,19 @@
"@types/react-dom": "^18.3.1",
"less": "^4.2.0",
"typescript": "^5.8.3"
},
"nx": {
"targets": {
"build": {
"dependsOn": [
"^build",
{
"projects": ["@midscene/report"],
"target": "build",
"params": "ignore"
}
]
}
}
}
}
4 changes: 4 additions & 0 deletions apps/android-playground/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { pluginWorkspaceDev } from 'rsbuild-plugin-workspace-dev';
import { version as playgroundVersion } from '../../packages/playground/package.json';
import {
commonIgnoreWarnings,
createCoreReportTemplateReplacementPlugin,
createPlaygroundCopyPlugin,
} from '../../scripts/rsbuild-utils.ts';

Expand Down Expand Up @@ -63,6 +64,9 @@ export default defineConfig({
pluginNodePolyfill(),
pluginLess(),
pluginSvgr(),
createCoreReportTemplateReplacementPlugin({
appDir: __dirname,
}),
createPlaygroundCopyPlugin(
path.join(__dirname, 'dist'),
path.join(__dirname, '../../packages/android-playground/static'),
Expand Down
15 changes: 14 additions & 1 deletion apps/chrome-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"@midscene/core": "workspace:*",
"@midscene/playground": "workspace:*",
"@midscene/recorder": "workspace:*",
"@midscene/report": "workspace:*",
"@midscene/shared": "workspace:*",
"@midscene/visualizer": "workspace:*",
"@midscene/web": "workspace:*",
Expand Down Expand Up @@ -53,5 +52,19 @@
"typescript": "^5.8.3",
"vitest": "3.0.5",
"web-ext": "9.0.0"
},
"nx": {
"targets": {
"build": {
"dependsOn": [
"^build",
{
"projects": ["@midscene/report"],
"target": "build",
"params": "ignore"
}
]
}
}
}
}
8 changes: 7 additions & 1 deletion apps/chrome-extension/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { pluginSvgr } from '@rsbuild/plugin-svgr';
import { pluginTypeCheck } from '@rsbuild/plugin-type-check';
import { pluginWorkspaceDev } from 'rsbuild-plugin-workspace-dev';
import { version } from '../../packages/visualizer/package.json';
import { commonIgnoreWarnings } from '../../scripts/rsbuild-utils.ts';
import {
commonIgnoreWarnings,
createCoreReportTemplateReplacementPlugin,
} from '../../scripts/rsbuild-utils.ts';

export default defineConfig({
tools: {
Expand Down Expand Up @@ -119,6 +122,9 @@ export default defineConfig({
pluginNodePolyfill(),
pluginLess(),
pluginSvgr(),
createCoreReportTemplateReplacementPlugin({
appDir: __dirname,
}),
pluginTypeCheck(),
pluginWorkspaceDev({
projects: {
Expand Down
14 changes: 14 additions & 0 deletions apps/computer-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,19 @@
"@types/react-dom": "^18.3.1",
"less": "^4.2.0",
"typescript": "^5.8.3"
},
"nx": {
"targets": {
"build": {
"dependsOn": [
"^build",
{
"projects": ["@midscene/report"],
"target": "build",
"params": "ignore"
}
]
}
}
}
}
4 changes: 4 additions & 0 deletions apps/computer-playground/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { pluginWorkspaceDev } from 'rsbuild-plugin-workspace-dev';
import { version as playgroundVersion } from '../../packages/playground/package.json';
import {
commonIgnoreWarnings,
createCoreReportTemplateReplacementPlugin,
createPlaygroundCopyPlugin,
} from '../../scripts/rsbuild-utils.ts';

Expand Down Expand Up @@ -63,6 +64,9 @@ export default defineConfig({
pluginNodePolyfill(),
pluginLess(),
pluginSvgr(),
createCoreReportTemplateReplacementPlugin({
appDir: __dirname,
}),
createPlaygroundCopyPlugin(
path.join(__dirname, 'dist'),
path.join(__dirname, '../../packages/computer-playground/static'),
Expand Down
14 changes: 14 additions & 0 deletions apps/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,19 @@
"rsbuild-plugin-workspace-dev": "0.0.1",
"tsx": "^4.19.2",
"typescript": "^5.8.3"
},
"nx": {
"targets": {
"build": {
"dependsOn": [
"^build",
{
"projects": ["@midscene/report"],
"target": "build",
"params": "ignore"
}
]
}
}
}
}
4 changes: 4 additions & 0 deletions apps/playground/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { pluginWorkspaceDev } from 'rsbuild-plugin-workspace-dev';
import { version as playgroundVersion } from '../../packages/playground/package.json';
import {
commonIgnoreWarnings,
createCoreReportTemplateReplacementPlugin,
createPlaygroundCopyPlugin,
} from '../../scripts/rsbuild-utils.ts';

Expand All @@ -23,6 +24,9 @@ export default defineConfig({
pluginLess(),
pluginNodePolyfill(),
pluginSvgr(),
createCoreReportTemplateReplacementPlugin({
appDir: __dirname,
}),
createPlaygroundCopyPlugin(
path.join(__dirname, 'dist'),
path.join(__dirname, '../../packages/playground/static'),
Expand Down
10 changes: 10 additions & 0 deletions apps/report/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
"generate-demo": "node scripts/generate-demo-report.mjs",
"e2e": "node scripts/generate-demo-report.mjs && node ../../packages/cli/bin/midscene ./e2e/"
},
"nx": {
"targets": {
"build": {
"outputs": [
"{projectRoot}/dist",
"{workspaceRoot}/packages/core/dist/report-template"
]
}
}
},
"dependencies": {
"@ant-design/icons": "^5.3.1",
"@midscene/core": "workspace:*",
Expand Down
105 changes: 20 additions & 85 deletions apps/report/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import assert from 'node:assert';
import fs from 'node:fs';
import path from 'node:path';
import { defineConfig } from '@rsbuild/core';
Expand All @@ -8,7 +7,10 @@ import { pluginReact } from '@rsbuild/plugin-react';
import { pluginSvgr } from '@rsbuild/plugin-svgr';
import { pluginTypeCheck } from '@rsbuild/plugin-type-check';
import { pluginWorkspaceDev } from 'rsbuild-plugin-workspace-dev';
import { commonIgnoreWarnings } from '../../scripts/rsbuild-utils.ts';
import {
commonIgnoreWarnings,
createReportTemplateSyncPlugin,
} from '../../scripts/rsbuild-utils.ts';

// Read all JSON files from test-data directory
const testDataDir = path.join(__dirname, 'test-data');
Expand All @@ -24,88 +26,17 @@ const allTestData = jsonFiles.map((file) => {
};
});

// put back the report template to the core package
// this is a workaround for the circular dependency issue
// ERROR: This repository uses pkg in bundler mode. It is necessary to declare @midscene/report in the dependency; otherwise, it may cause packaging order issues and thus lead to the failure of report injection
const copyReportTemplate = () => ({
name: 'copy-report-template',
setup(api: {
onAfterBuild: (arg0: ({ compiler }: { compiler: any }) => void) => void;
}) {
api.onAfterBuild(({ compiler }) => {
const magicString = 'REPLACE_ME_WITH_REPORT_HTML';
const replacedMark = '/*REPORT_HTML_REPLACED*/';
const regExpForReplace = /\/\*REPORT_HTML_REPLACED\*\/.*/;

// read the template file
const srcPath = path.join(__dirname, 'dist', 'index.html');
const tplFileContent = fs
.readFileSync(srcPath, 'utf-8')
.replaceAll(magicString, '');
assert(
!tplFileContent.includes(magicString),
'magic string should not be in the template file',
);
const finalContent = `${replacedMark}${JSON.stringify(tplFileContent)}`;

// find the core package
const corePkgDir = path.join(__dirname, '..', '..', 'packages', 'core');
const corePkgJson = JSON.parse(
fs.readFileSync(path.join(corePkgDir, 'package.json'), 'utf-8'),
);
assert(
corePkgJson.name === '@midscene/core',
'core package name is not @midscene/core',
);
const corePkgDistDir = path.join(corePkgDir, 'dist');

// traverse all .js files and inject (or update) the template
const jsFiles = fs.readdirSync(corePkgDistDir, { recursive: true });
let replacedCount = 0;
for (const file of jsFiles) {
if (
typeof file === 'string' &&
(file.endsWith('.js') || file.endsWith('.mjs'))
) {
const filePath = path.join(corePkgDistDir, file.toString());
const fileContent = fs.readFileSync(filePath, 'utf-8');
if (fileContent.includes(replacedMark)) {
assert(
regExpForReplace.test(fileContent),
'a replaced mark is found but cannot match',
);

const replacedContent = fileContent.replace(
regExpForReplace,
() => finalContent,
);
fs.writeFileSync(filePath, replacedContent);
replacedCount++;
console.log(`Template updated in file ${filePath}`);
} else if (fileContent.includes(magicString)) {
const magicStringCount = (
fileContent.match(new RegExp(magicString, 'g')) || []
).length;
assert(
magicStringCount === 1,
'magic string shows more than once in the file, cannot process',
);
const replacedContent = fileContent.replace(
`'${magicString}'`,
() => finalContent, // there are some $- code in the tpl, so we have to use a function as the second argument
);
fs.writeFileSync(filePath, replacedContent);
replacedCount++;
console.log(`Template injected into ${filePath}`);
}
}
}
if (replacedCount === 0) {
throw new Error('No html template found in the core package');
}
});
},
});
const reportTemplatePath = path.join(__dirname, 'dist', 'index.html');
const coreReportTemplatePath = path.join(
__dirname,
'..',
'..',
'packages',
'core',
'dist',
'report-template',
'index.html',
);

export default defineConfig({
html: {
Expand Down Expand Up @@ -163,7 +94,11 @@ export default defineConfig({
pluginLess(),
pluginNodePolyfill(),
pluginSvgr(),
copyReportTemplate(),
createReportTemplateSyncPlugin({
srcPath: reportTemplatePath,
destPath: coreReportTemplatePath,
pluginName: 'sync-report-template-to-core',
}),
pluginTypeCheck(),
pluginWorkspaceDev({
projects: {
Expand Down
Loading
Loading