ohos-playwright 0.5.0 → 0.5.2
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 +1 -1
- package/dist/fixture.d.mts +1 -0
- package/dist/fixture.mjs +103 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ The following Playwright APIs have been validated on ArkWeb / HarmonyOS 6.1 (Chr
|
|
|
56
56
|
| File upload | `page.setInputFiles()` — fires `change`, file content readable |
|
|
57
57
|
| Cookies | `context.addCookies()`, `context.cookies()`, `context.clearCookies()` |
|
|
58
58
|
| Dialog | `page.on('dialog')`, `dialog.accept()`, `dialog.dismiss()`, `dialog.message()`, `dialog.type()` |
|
|
59
|
-
| Popup | `context.waitForEvent('page')` + `window.open()` —
|
|
59
|
+
| Popup | `context.waitForEvent('page')` + `window.open()` — real Page with full API. Requires `PW_CHROMIUM_ATTACH_TO_OTHER=1`. Falls back to idle-tab proxy or minimal stub when Target.createTarget is unavailable. |
|
|
60
60
|
| Page events | `page.on('pageerror')`, `page.on('console')`, `page.on('download')` |
|
|
61
61
|
| Script / style injection | `page.addScriptTag({ content \| path \| type:'module' })`, `page.addStyleTag({ content })` |
|
|
62
62
|
| Init script | `page.addInitScript()` — function or string, persists across `goto()` navigations |
|
package/dist/fixture.d.mts
CHANGED
|
@@ -27,6 +27,7 @@ export interface StorageState {
|
|
|
27
27
|
export type PageCleanup = (opts?: {
|
|
28
28
|
navigateTo?: string;
|
|
29
29
|
}) => Promise<void>;
|
|
30
|
+
export declare function createPopupPage(context: BrowserContext, seedPage: Page, popupUrl: string): Promise<Page | null>;
|
|
30
31
|
export declare function installPageWrappers(page: Page, context: BrowserContext, baseURL: string | undefined): Promise<PageCleanup>;
|
|
31
32
|
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
|
|
32
33
|
emulateDevice: (descriptor: DeviceDescriptor) => Promise<void>;
|
package/dist/fixture.mjs
CHANGED
|
@@ -16,6 +16,64 @@ function readInfo() {
|
|
|
16
16
|
return JSON.parse(readFileSync(INFO_PATH, 'utf8'));
|
|
17
17
|
}
|
|
18
18
|
function readEndpoint() { return readInfo().endpoint; }
|
|
19
|
+
// Create a real Page in the default context via Target.createTarget.
|
|
20
|
+
// Returns the new page (already navigated to popupUrl) on success, or null
|
|
21
|
+
// to let the caller fall back to idle-tab proxy or stub.
|
|
22
|
+
//
|
|
23
|
+
// Precondition: PW_CHROMIUM_ATTACH_TO_OTHER=1 must be set, otherwise the new
|
|
24
|
+
// target created by ArkWeb will be type:'other' and Playwright won't pick
|
|
25
|
+
// it up into ctx.pages().
|
|
26
|
+
export async function createPopupPage(context, seedPage, popupUrl) {
|
|
27
|
+
let session = null;
|
|
28
|
+
try {
|
|
29
|
+
session = await context.newCDPSession(seedPage);
|
|
30
|
+
const r = await Promise.race([
|
|
31
|
+
session
|
|
32
|
+
.send('Target.createTarget', { url: 'about:blank' }),
|
|
33
|
+
new Promise((_, rej) => setTimeout(() => rej(new Error('createTarget timeout')), 3000)),
|
|
34
|
+
]);
|
|
35
|
+
if (!r.targetId)
|
|
36
|
+
return null;
|
|
37
|
+
// Poll ctx.pages() until Playwright picks up the new target (max 2s).
|
|
38
|
+
const pagesBefore = context.pages().length;
|
|
39
|
+
const deadline = Date.now() + 2000;
|
|
40
|
+
while (Date.now() < deadline) {
|
|
41
|
+
if (context.pages().length > pagesBefore)
|
|
42
|
+
break;
|
|
43
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
44
|
+
}
|
|
45
|
+
const allPages = context.pages();
|
|
46
|
+
if (allPages.length <= pagesBefore)
|
|
47
|
+
return null;
|
|
48
|
+
// Pick the newly-added page (any page not equal to seedPage, preferring
|
|
49
|
+
// about:blank which is the createTarget's initial URL).
|
|
50
|
+
const newPage = allPages.find((p) => p !== seedPage && p.url() === 'about:blank') ??
|
|
51
|
+
allPages.find((p) => p !== seedPage);
|
|
52
|
+
if (!newPage)
|
|
53
|
+
return null;
|
|
54
|
+
// Navigate to the popup URL (skip for about:blank which is already loaded).
|
|
55
|
+
// On navigation failure, close the tab and return null — otherwise a
|
|
56
|
+
// half-loaded popup tab (url stuck at about:blank) gets mistaken for the
|
|
57
|
+
// launchUrl tab by the next test's fixture-page selector.
|
|
58
|
+
if (popupUrl && popupUrl !== 'about:blank') {
|
|
59
|
+
try {
|
|
60
|
+
await newPage.goto(popupUrl, { timeout: 5000 });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
await newPage.close().catch(() => { });
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return newPage;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (session)
|
|
74
|
+
await session.detach().catch(() => { });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
19
77
|
export async function installPageWrappers(page, context, baseURL) {
|
|
20
78
|
const ctxEmit = context.emit.bind(context);
|
|
21
79
|
// connectOverCDP reuses an existing tab — Playwright has no record of its
|
|
@@ -38,10 +96,17 @@ export async function installPageWrappers(page, context, baseURL) {
|
|
|
38
96
|
finally {
|
|
39
97
|
await session.detach();
|
|
40
98
|
}
|
|
41
|
-
// Override
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
;
|
|
99
|
+
// Override goto: connectOverCDP creates the server-side context with no baseURL in
|
|
100
|
+
// its _options, so Playwright's internal Frame.goto cannot resolve relative paths —
|
|
101
|
+
// CDP rejects them as invalid. Resolve here before delegating to the real goto.
|
|
102
|
+
const savedGoto = page['goto'];
|
|
103
|
+
const origGoto = page.goto.bind(page);
|
|
104
|
+
page.goto = async (url, options) => {
|
|
105
|
+
if (baseURL && url && !url.includes('://') && !url.startsWith('about:') && !url.startsWith('data:')) {
|
|
106
|
+
url = new URL(url, baseURL).toString();
|
|
107
|
+
}
|
|
108
|
+
return origGoto(url, options);
|
|
109
|
+
};
|
|
45
110
|
page.goBack = async (options) => {
|
|
46
111
|
const timeout = options?.timeout ?? 30000;
|
|
47
112
|
const s = await page.context().newCDPSession(page);
|
|
@@ -136,14 +201,39 @@ export async function installPageWrappers(page, context, baseURL) {
|
|
|
136
201
|
return q;
|
|
137
202
|
});
|
|
138
203
|
for (const { url } of pending ?? []) {
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
204
|
+
// 1) Target.createTarget(首选)
|
|
205
|
+
let emitted = null;
|
|
206
|
+
try {
|
|
207
|
+
emitted = await createPopupPage(context, page, url || 'about:blank');
|
|
208
|
+
}
|
|
209
|
+
catch { }
|
|
210
|
+
// 2) Fallback A:默认 context 闲置 about:blank tab
|
|
211
|
+
if (!emitted) {
|
|
212
|
+
const idle = context
|
|
213
|
+
.pages()
|
|
214
|
+
.find((p) => p !== page && p.url() === 'about:blank');
|
|
215
|
+
if (idle) {
|
|
216
|
+
try {
|
|
217
|
+
if (url && url !== 'about:blank') {
|
|
218
|
+
await idle.goto(url, { timeout: 5000 });
|
|
219
|
+
}
|
|
220
|
+
emitted = idle;
|
|
221
|
+
}
|
|
222
|
+
catch { }
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 3) Fallback B:退回原 stub(保持兼容)
|
|
226
|
+
if (!emitted) {
|
|
227
|
+
const stub = {
|
|
228
|
+
waitForLoadState: async () => { },
|
|
229
|
+
url: () => url,
|
|
230
|
+
close: async () => { },
|
|
231
|
+
};
|
|
232
|
+
ctxEmit('page', stub);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
ctxEmit('page', emitted);
|
|
236
|
+
}
|
|
147
237
|
}
|
|
148
238
|
}
|
|
149
239
|
catch { }
|
|
@@ -165,6 +255,7 @@ export async function installPageWrappers(page, context, baseURL) {
|
|
|
165
255
|
clearInterval(popupPoller);
|
|
166
256
|
page.evaluate = savedEvaluate;
|
|
167
257
|
page.locator = savedLocator;
|
|
258
|
+
page.goto = savedGoto;
|
|
168
259
|
if (opts?.navigateTo) {
|
|
169
260
|
// Reset the shared tab to a neutral state — page.close() would terminate
|
|
170
261
|
// the ArkWeb DevTools socket so we navigate instead.
|