ohos-playwright 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/cli.mjs +27 -1
- package/dist/setup.mjs +22 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,6 +46,15 @@ export default defineConfig(withOpenHarmony({ /* your config */ }))
|
|
|
46
46
|
| `OHOS_PW_HDC` | `/data/service/hnp/bin/hdc` |
|
|
47
47
|
| `OHOS_PW_AUTO_CONNECT` | auto (set `0` to skip device auto-connect) |
|
|
48
48
|
| `OHOS_PW_INFO_PATH` | `<tmpdir>/ohos-playwright-cdp.json` |
|
|
49
|
+
| `OHOS_PW_UI_HOST` | `0.0.0.0` — used when `--ui` is passed without `--ui-host` on an OHOS device |
|
|
50
|
+
| `OHOS_PW_UI_PORT` | `8765` — used when `--ui` is passed without `--ui-port` on an OHOS device |
|
|
51
|
+
|
|
52
|
+
### `--ui` and `--debug` on an OHOS device
|
|
53
|
+
|
|
54
|
+
Playwright's bundled Chromium cannot exec inside the OHOS app sandbox, which breaks the local windows that `--ui` and `--debug` normally open.
|
|
55
|
+
|
|
56
|
+
- **`--ui`** auto-injects `--ui-host=0.0.0.0 --ui-port=8765` when run on OHOS, so the UI server starts as HTTP-only. Open `http://<device-ip>:8765` in any browser on your LAN.
|
|
57
|
+
- **`--debug`** has no equivalent escape hatch; running it on OHOS exits with guidance. Use `await page.pause()` inside a test, or run `--debug` from a host (Linux/macOS/Windows) connected to the device via hdc.
|
|
49
58
|
|
|
50
59
|
## Compatibility
|
|
51
60
|
|
package/dist/cli.mjs
CHANGED
|
@@ -35,7 +35,33 @@ if (!existsSync(resolve(pkgRoot, 'package.json'))) {
|
|
|
35
35
|
const playwrightCli = resolve(pkgRoot, 'cli.js');
|
|
36
36
|
// Node 24 has native TypeScript support; register.mts is resolved directly.
|
|
37
37
|
const register = resolve(import.meta.dirname, 'register.mjs');
|
|
38
|
-
const
|
|
38
|
+
const argv = process.argv.slice(2);
|
|
39
|
+
// On OpenHarmony, Playwright's bundled Chromium cannot exec inside the app
|
|
40
|
+
// sandbox (unsigned ELF). Two of Playwright's CLI modes try to launch it:
|
|
41
|
+
// --ui : opens a Chromium window to host the UI app
|
|
42
|
+
// --debug : opens a Chromium window for the Inspector (via PWDEBUG=1)
|
|
43
|
+
// For --ui, Playwright skips the local Chromium when --ui-host or --ui-port
|
|
44
|
+
// is provided (runner/index.js: runUIMode). Inject defaults so users don't
|
|
45
|
+
// need to remember the flags. For --debug, no such escape hatch exists —
|
|
46
|
+
// fail fast with guidance.
|
|
47
|
+
if (process.platform === 'openharmony') {
|
|
48
|
+
const hasFlag = (name) => argv.some((a) => a === name || a.startsWith(name + '='));
|
|
49
|
+
if (hasFlag('--debug')) {
|
|
50
|
+
console.error('[ohos-playwright] --debug is not supported on OpenHarmony.\n' +
|
|
51
|
+
' Playwright Inspector launches a bundled Chromium that the OHOS app sandbox cannot exec.\n' +
|
|
52
|
+
' Alternatives:\n' +
|
|
53
|
+
' 1) Use `await page.pause()` inside a test for step-through inspection.\n' +
|
|
54
|
+
' 2) Run `ohos-playwright test --debug` from a host (Linux/macOS/Windows) connected to the device via hdc.');
|
|
55
|
+
process.exit(2);
|
|
56
|
+
}
|
|
57
|
+
if (hasFlag('--ui') && !hasFlag('--ui-host') && !hasFlag('--ui-port')) {
|
|
58
|
+
const host = process.env.OHOS_PW_UI_HOST ?? '0.0.0.0';
|
|
59
|
+
const port = process.env.OHOS_PW_UI_PORT ?? '8765';
|
|
60
|
+
argv.push(`--ui-host=${host}`, `--ui-port=${port}`);
|
|
61
|
+
console.error(`[ohos-playwright] UI server bound to ${host}:${port} — open http://<device-ip>:${port} in any browser. Override with OHOS_PW_UI_HOST / OHOS_PW_UI_PORT.`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const child = spawn(process.execPath, ['--import', register, playwrightCli, ...argv], { stdio: 'inherit' });
|
|
39
65
|
child.on('exit', (code, signal) => {
|
|
40
66
|
if (signal)
|
|
41
67
|
process.kill(process.pid, signal);
|
package/dist/setup.mjs
CHANGED
|
@@ -8,6 +8,16 @@ import { INFO_PATH } from "./info-path.mjs";
|
|
|
8
8
|
const HDC = process.env.OHOS_PW_HDC ?? '/data/service/hnp/bin/hdc';
|
|
9
9
|
const BUNDLE = process.env.OHOS_PW_BUNDLE ?? 'com.huawei.hmos.browser';
|
|
10
10
|
const LAUNCH_URL = process.env.OHOS_PW_LAUNCH_URL ?? 'about:blank';
|
|
11
|
+
// 校验环境变量,防止通过 hdc shell 注入恶意命令。
|
|
12
|
+
// BUNDLE 必须是点分隔的 Android 风格包名;LAUNCH_URL 必须是合法 URL。
|
|
13
|
+
const SAFE_BUNDLE_RE = /^[a-zA-Z][a-zA-Z0-9.]*$/;
|
|
14
|
+
const SAFE_URL_RE = /^[a-z][a-z0-9+.-]*:(?:\/\/)?\S+$/i;
|
|
15
|
+
if (!SAFE_BUNDLE_RE.test(BUNDLE) || BUNDLE.length > 256) {
|
|
16
|
+
throw new Error(`[ohos-playwright] OHOS_PW_BUNDLE "${BUNDLE}" 不是合法的包名(期望: com.example.app)`);
|
|
17
|
+
}
|
|
18
|
+
if (!SAFE_URL_RE.test(LAUNCH_URL) || LAUNCH_URL.length > 2048) {
|
|
19
|
+
throw new Error(`[ohos-playwright] OHOS_PW_LAUNCH_URL "${LAUNCH_URL}" 不是合法的 URL`);
|
|
20
|
+
}
|
|
11
21
|
const HDC_OPTS = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] };
|
|
12
22
|
function hdc(args, opts) {
|
|
13
23
|
return String(execFileSync(HDC, args, { ...HDC_OPTS, ...opts })).trim();
|
|
@@ -39,6 +49,10 @@ function fetchDeviceState() {
|
|
|
39
49
|
}
|
|
40
50
|
export function findBrowserPid() {
|
|
41
51
|
const { ps } = fetchDeviceState();
|
|
52
|
+
// Match the main process only: its cmdline equals BUNDLE exactly.
|
|
53
|
+
// Child processes like "com.huawei.hmos.browser:render" / ":gpu" must be
|
|
54
|
+
// excluded — the DevTools abstract socket only exists on the main process,
|
|
55
|
+
// so picking a child PID leads to socket-not-found errors downstream.
|
|
42
56
|
for (const line of ps.split('\n')) {
|
|
43
57
|
const t = line.trim();
|
|
44
58
|
if (!t)
|
|
@@ -46,7 +60,7 @@ export function findBrowserPid() {
|
|
|
46
60
|
const s = t.indexOf(' ');
|
|
47
61
|
if (s === -1)
|
|
48
62
|
continue;
|
|
49
|
-
if (t.slice(s + 1).
|
|
63
|
+
if (t.slice(s + 1).trim() === BUNDLE) {
|
|
50
64
|
const pid = parseInt(t.slice(0, s), 10);
|
|
51
65
|
if (!Number.isNaN(pid))
|
|
52
66
|
return pid;
|
|
@@ -204,7 +218,13 @@ export default async function globalSetup() {
|
|
|
204
218
|
const probe = await probeCdp(port);
|
|
205
219
|
if (!probe.ok)
|
|
206
220
|
throw new Error(`CDP probe failed: ${probe.err || probe.body}`);
|
|
207
|
-
|
|
221
|
+
let info;
|
|
222
|
+
try {
|
|
223
|
+
info = JSON.parse(probe.body);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
throw new Error(`CDP response is not valid JSON (body preview: ${probe.body?.slice(0, 300) ?? '(empty)'})`);
|
|
227
|
+
}
|
|
208
228
|
console.log(`[ohos-playwright] CDP ready: ${info.Browser}`);
|
|
209
229
|
mkdirSync(dirname(INFO_PATH), { recursive: true });
|
|
210
230
|
writeFileSync(INFO_PATH, JSON.stringify({ port, pid, socket, endpoint: `http://127.0.0.1:${port}` }, null, 2));
|