ohos-playwright 0.2.7 → 0.2.8
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/dist/fixture.mjs +3 -14
- package/dist/setup.d.mts +1 -0
- package/dist/setup.mjs +77 -2
- package/package.json +1 -1
package/dist/fixture.mjs
CHANGED
|
@@ -12,20 +12,9 @@ export const test = base.extend({
|
|
|
12
12
|
},
|
|
13
13
|
{ scope: 'worker' },
|
|
14
14
|
],
|
|
15
|
-
context: async ({ browser }, use
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (baseURL) {
|
|
19
|
-
try {
|
|
20
|
-
const opts = ctx._options;
|
|
21
|
-
if (opts && typeof opts === 'object')
|
|
22
|
-
opts.baseURL = baseURL;
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
console.warn(`[ohos-playwright] Failed to inject baseURL: ${e instanceof Error ? e.message : e}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
await use(ctx);
|
|
15
|
+
context: async ({ browser }, use) => {
|
|
16
|
+
// baseURL 通过 page fixture 重写 page.goto 实现;不再触碰 BrowserContext 私有字段 _options。
|
|
17
|
+
await use(browser.contexts()[0]);
|
|
29
18
|
},
|
|
30
19
|
page: async ({ context }, use, testInfo) => {
|
|
31
20
|
const pages = context.pages();
|
package/dist/setup.d.mts
CHANGED
|
@@ -8,6 +8,7 @@ export declare function findBrowserPid(): number | null;
|
|
|
8
8
|
export declare function hasDeviceConnected(): boolean;
|
|
9
9
|
export declare function discoverDevices(): string[];
|
|
10
10
|
export declare function tryLocalDevice(): boolean;
|
|
11
|
+
export declare function ensureHdcKey(): boolean;
|
|
11
12
|
export declare function ensureDeviceConnected(): Promise<void>;
|
|
12
13
|
export default function globalSetup(): Promise<void>;
|
|
13
14
|
export {};
|
package/dist/setup.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { writeFileSync, mkdirSync, existsSync, copyFileSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, join } from 'node:path';
|
|
3
4
|
import { createServer } from 'node:net';
|
|
4
5
|
import { dirname } from 'node:path';
|
|
5
6
|
import { createInterface } from 'node:readline';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { generateKeyPairSync } from 'node:crypto';
|
|
6
9
|
import http from 'node:http';
|
|
7
10
|
import { INFO_PATH } from "./info-path.mjs";
|
|
8
11
|
const HDC = process.env.OHOS_PW_HDC ?? '/data/service/hnp/bin/hdc';
|
|
@@ -18,6 +21,15 @@ if (!SAFE_BUNDLE_RE.test(BUNDLE) || BUNDLE.length > 256) {
|
|
|
18
21
|
if (!SAFE_URL_RE.test(LAUNCH_URL) || LAUNCH_URL.length > 2048) {
|
|
19
22
|
throw new Error(`[ohos-playwright] OHOS_PW_LAUNCH_URL "${LAUNCH_URL}" 不是合法的 URL`);
|
|
20
23
|
}
|
|
24
|
+
if (!isAbsolute(HDC) || !existsSync(HDC)) {
|
|
25
|
+
throw new Error(`[ohos-playwright] OHOS_PW_HDC "${HDC}" 不是有效的可执行文件路径(需绝对路径且文件存在)`);
|
|
26
|
+
}
|
|
27
|
+
// HarmonyOS host 提示:系统自带 hdc 与本机设备 hdcd 协议匹配;
|
|
28
|
+
// 其他 hdc(如 OHOS SDK 3.x)连本机设备会握手失败。
|
|
29
|
+
const SYSTEM_HDC_ON_HARMONY = '/data/service/hnp/bin/hdc';
|
|
30
|
+
if (existsSync(SYSTEM_HDC_ON_HARMONY) && HDC !== SYSTEM_HDC_ON_HARMONY) {
|
|
31
|
+
console.warn(`[ohos-playwright] 注意:当前 OHOS_PW_HDC="${HDC}",但系统自带 ${SYSTEM_HDC_ON_HARMONY} 才能与本机 HarmonyOS 设备通信;如握手失败请改用系统 hdc。`);
|
|
32
|
+
}
|
|
21
33
|
const HDC_OPTS = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] };
|
|
22
34
|
function hdc(args, opts) {
|
|
23
35
|
return String(execFileSync(HDC, args, { ...HDC_OPTS, ...opts })).trim();
|
|
@@ -126,9 +138,11 @@ export function discoverDevices() {
|
|
|
126
138
|
}
|
|
127
139
|
return out.split('\n').map(s => s.trim()).filter(s => IP_PORT_RE.test(s));
|
|
128
140
|
}
|
|
141
|
+
// 已连接时 hdc tconn 返回 "Target is connected, repeat operation",也视作成功。
|
|
129
142
|
function tconn(addr) {
|
|
130
143
|
try {
|
|
131
|
-
|
|
144
|
+
const out = hdc(['tconn', addr], { timeout: 10000 });
|
|
145
|
+
return out.includes('Connect OK') || out.includes('repeat operation');
|
|
132
146
|
}
|
|
133
147
|
catch {
|
|
134
148
|
return false;
|
|
@@ -166,9 +180,70 @@ export function tryLocalDevice() {
|
|
|
166
180
|
catch { }
|
|
167
181
|
return false;
|
|
168
182
|
}
|
|
183
|
+
// HarmonyOS host 自愈:缺 hdc key 时自动生成 RSA-3072,并重启本机 hdc server。
|
|
184
|
+
// 仅在 host 看似 HarmonyOS 时触发(/data/service/hnp/bin/hdc 存在);最多 1 次。
|
|
185
|
+
const HARMONY_HDC_PATH = '/data/service/hnp/bin/hdc';
|
|
186
|
+
const HARMONY_KEY_DIR = join(homedir(), '.harmony');
|
|
187
|
+
let selfHealAttempted = false;
|
|
188
|
+
function isHarmonyHost() { return existsSync(HARMONY_HDC_PATH); }
|
|
189
|
+
export function ensureHdcKey() {
|
|
190
|
+
const priv = join(HARMONY_KEY_DIR, 'hdckey');
|
|
191
|
+
const pub = join(HARMONY_KEY_DIR, 'hdckey.pub');
|
|
192
|
+
if (existsSync(priv) && existsSync(pub))
|
|
193
|
+
return false;
|
|
194
|
+
mkdirSync(HARMONY_KEY_DIR, { recursive: true });
|
|
195
|
+
for (const f of [priv, pub]) {
|
|
196
|
+
if (existsSync(f)) {
|
|
197
|
+
try {
|
|
198
|
+
copyFileSync(f, f + '.bak');
|
|
199
|
+
}
|
|
200
|
+
catch { }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const { privateKey, publicKey } = generateKeyPairSync('rsa', {
|
|
204
|
+
modulusLength: 3072,
|
|
205
|
+
privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
|
|
206
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
207
|
+
});
|
|
208
|
+
writeFileSync(priv, privateKey, { mode: 0o600 });
|
|
209
|
+
writeFileSync(pub, publicKey, { mode: 0o644 });
|
|
210
|
+
console.warn(`[ohos-playwright] generated RSA-3072 hdc key at ${priv} (设备首次连接需 UI 授权)`);
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
async function restartHdcServer() {
|
|
214
|
+
try {
|
|
215
|
+
hdc(['kill']);
|
|
216
|
+
}
|
|
217
|
+
catch { }
|
|
218
|
+
await sleep(500);
|
|
219
|
+
try {
|
|
220
|
+
hdc(['start']);
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
console.warn(`[ohos-playwright] hdc start failed: ${e instanceof Error ? e.message : e}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function selfHealHdc() {
|
|
227
|
+
if (selfHealAttempted)
|
|
228
|
+
return;
|
|
229
|
+
selfHealAttempted = true;
|
|
230
|
+
if (process.env.OHOS_PW_AUTO_HEAL === '0')
|
|
231
|
+
return;
|
|
232
|
+
if (!isHarmonyHost())
|
|
233
|
+
return;
|
|
234
|
+
console.log('[ohos-playwright] self-heal: 检查 hdc key 与重启本机 hdc server...');
|
|
235
|
+
const keyChanged = ensureHdcKey();
|
|
236
|
+
await restartHdcServer();
|
|
237
|
+
await sleep(keyChanged ? 1500 : 500);
|
|
238
|
+
}
|
|
169
239
|
export async function ensureDeviceConnected() {
|
|
170
240
|
if (process.env.OHOS_PW_AUTO_CONNECT === '0')
|
|
171
241
|
return;
|
|
242
|
+
if (hasDeviceConnected())
|
|
243
|
+
return;
|
|
244
|
+
if (tryLocalDevice())
|
|
245
|
+
return;
|
|
246
|
+
await selfHealHdc();
|
|
172
247
|
if (hasDeviceConnected())
|
|
173
248
|
return;
|
|
174
249
|
if (tryLocalDevice())
|