@ricsam/isolate 0.0.1 → 0.1.0
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/cjs/bridge/diagnostics.cjs +58 -0
- package/dist/cjs/bridge/diagnostics.cjs.map +10 -0
- package/dist/cjs/bridge/legacy-adapters.cjs +242 -0
- package/dist/cjs/bridge/legacy-adapters.cjs.map +10 -0
- package/dist/cjs/bridge/request-context.cjs +59 -0
- package/dist/cjs/bridge/request-context.cjs.map +10 -0
- package/dist/cjs/bridge/runtime-bindings.cjs +367 -0
- package/dist/cjs/bridge/runtime-bindings.cjs.map +10 -0
- package/dist/cjs/browser/browser-runtime.cjs +157 -0
- package/dist/cjs/browser/browser-runtime.cjs.map +10 -0
- package/dist/cjs/daemon.cjs +91 -0
- package/dist/cjs/daemon.cjs.map +10 -0
- package/dist/cjs/files/index.cjs +140 -0
- package/dist/cjs/files/index.cjs.map +10 -0
- package/dist/cjs/host/create-isolate-host.cjs +235 -0
- package/dist/cjs/host/create-isolate-host.cjs.map +10 -0
- package/dist/cjs/host/index.cjs +47 -0
- package/dist/cjs/host/index.cjs.map +10 -0
- package/dist/cjs/index.cjs +55 -0
- package/dist/cjs/index.cjs.map +10 -0
- package/dist/cjs/internal/client/connection.cjs +1919 -0
- package/dist/cjs/internal/client/connection.cjs.map +10 -0
- package/dist/cjs/internal/client/index.cjs +48 -0
- package/dist/cjs/internal/client/index.cjs.map +10 -0
- package/dist/cjs/internal/client/types.cjs +30 -0
- package/dist/cjs/internal/client/types.cjs.map +9 -0
- package/dist/cjs/internal/console/index.cjs +506 -0
- package/dist/cjs/internal/console/index.cjs.map +10 -0
- package/dist/cjs/internal/console/utils.cjs +70 -0
- package/dist/cjs/internal/console/utils.cjs.map +10 -0
- package/dist/cjs/internal/core/index.cjs +2745 -0
- package/dist/cjs/internal/core/index.cjs.map +10 -0
- package/dist/cjs/internal/crypto/index.cjs +470 -0
- package/dist/cjs/internal/crypto/index.cjs.map +10 -0
- package/dist/cjs/internal/daemon/callback-fs-handler.cjs +355 -0
- package/dist/cjs/internal/daemon/callback-fs-handler.cjs.map +10 -0
- package/dist/cjs/internal/daemon/connection.cjs +1952 -0
- package/dist/cjs/internal/daemon/connection.cjs.map +10 -0
- package/dist/cjs/internal/daemon/daemon.cjs +98 -0
- package/dist/cjs/internal/daemon/daemon.cjs.map +10 -0
- package/dist/cjs/internal/daemon/index.cjs +145 -0
- package/dist/cjs/internal/daemon/index.cjs.map +10 -0
- package/dist/cjs/internal/daemon/runtime-pool.cjs +106 -0
- package/dist/cjs/internal/daemon/runtime-pool.cjs.map +10 -0
- package/dist/cjs/internal/daemon/types.cjs +30 -0
- package/dist/cjs/internal/daemon/types.cjs.map +9 -0
- package/dist/cjs/internal/encoding/index.cjs +419 -0
- package/dist/cjs/internal/encoding/index.cjs.map +10 -0
- package/dist/cjs/internal/fetch/consistency/origins.cjs +598 -0
- package/dist/cjs/internal/fetch/consistency/origins.cjs.map +10 -0
- package/dist/cjs/internal/fetch/index.cjs +2640 -0
- package/dist/cjs/internal/fetch/index.cjs.map +10 -0
- package/dist/cjs/internal/fetch/stream-state.cjs +256 -0
- package/dist/cjs/internal/fetch/stream-state.cjs.map +10 -0
- package/dist/cjs/internal/fs/index.cjs +847 -0
- package/dist/cjs/internal/fs/index.cjs.map +10 -0
- package/dist/cjs/internal/fs/node-adapter.cjs +254 -0
- package/dist/cjs/internal/fs/node-adapter.cjs.map +10 -0
- package/dist/cjs/internal/module-loader/bundle.cjs +482 -0
- package/dist/cjs/internal/module-loader/bundle.cjs.map +10 -0
- package/dist/cjs/internal/module-loader/index.cjs +240 -0
- package/dist/cjs/internal/module-loader/index.cjs.map +10 -0
- package/dist/cjs/internal/module-loader/mappings.cjs +120 -0
- package/dist/cjs/internal/module-loader/mappings.cjs.map +10 -0
- package/dist/cjs/internal/module-loader/resolve.cjs +177 -0
- package/dist/cjs/internal/module-loader/resolve.cjs.map +10 -0
- package/dist/cjs/internal/module-loader/strip-types.cjs +236 -0
- package/dist/cjs/internal/module-loader/strip-types.cjs.map +10 -0
- package/dist/cjs/internal/path/index.cjs +503 -0
- package/dist/cjs/internal/path/index.cjs.map +10 -0
- package/dist/cjs/internal/playwright/client.cjs +49 -0
- package/dist/cjs/internal/playwright/client.cjs.map +10 -0
- package/dist/cjs/internal/playwright/handler.cjs +1416 -0
- package/dist/cjs/internal/playwright/handler.cjs.map +10 -0
- package/dist/cjs/internal/playwright/index.cjs +1289 -0
- package/dist/cjs/internal/playwright/index.cjs.map +10 -0
- package/dist/cjs/internal/playwright/types.cjs +47 -0
- package/dist/cjs/internal/playwright/types.cjs.map +10 -0
- package/dist/cjs/internal/protocol/codec.cjs +510 -0
- package/dist/cjs/internal/protocol/codec.cjs.map +10 -0
- package/dist/cjs/internal/protocol/framing.cjs +141 -0
- package/dist/cjs/internal/protocol/framing.cjs.map +10 -0
- package/dist/cjs/internal/protocol/index.cjs +110 -0
- package/dist/cjs/internal/protocol/index.cjs.map +10 -0
- package/dist/cjs/internal/protocol/marshalValue.cjs +518 -0
- package/dist/cjs/internal/protocol/marshalValue.cjs.map +10 -0
- package/dist/cjs/internal/protocol/serialization.cjs +109 -0
- package/dist/cjs/internal/protocol/serialization.cjs.map +10 -0
- package/dist/cjs/internal/protocol/types.cjs +181 -0
- package/dist/cjs/internal/protocol/types.cjs.map +10 -0
- package/dist/cjs/internal/runtime/index.cjs +1235 -0
- package/dist/cjs/internal/runtime/index.cjs.map +10 -0
- package/dist/cjs/internal/server/index.cjs +223 -0
- package/dist/cjs/internal/server/index.cjs.map +10 -0
- package/dist/cjs/internal/test-environment/index.cjs +1415 -0
- package/dist/cjs/internal/test-environment/index.cjs.map +10 -0
- package/dist/cjs/internal/timers/index.cjs +200 -0
- package/dist/cjs/internal/timers/index.cjs.map +10 -0
- package/dist/cjs/internal/transform/index.cjs +361 -0
- package/dist/cjs/internal/transform/index.cjs.map +10 -0
- package/dist/cjs/internal/typecheck/index.cjs +60 -0
- package/dist/cjs/internal/typecheck/index.cjs.map +10 -0
- package/dist/cjs/internal/typecheck/isolate-types.cjs +2614 -0
- package/dist/cjs/internal/typecheck/isolate-types.cjs.map +10 -0
- package/dist/cjs/internal/typecheck/typecheck.cjs +131 -0
- package/dist/cjs/internal/typecheck/typecheck.cjs.map +10 -0
- package/dist/cjs/modules/index.cjs +160 -0
- package/dist/cjs/modules/index.cjs.map +10 -0
- package/dist/cjs/package.json +5 -0
- package/dist/cjs/runtime/script-runtime.cjs +97 -0
- package/dist/cjs/runtime/script-runtime.cjs.map +10 -0
- package/dist/cjs/server/app-server.cjs +158 -0
- package/dist/cjs/server/app-server.cjs.map +10 -0
- package/dist/cjs/testing/integration-helpers.cjs +127 -0
- package/dist/cjs/testing/integration-helpers.cjs.map +10 -0
- package/dist/cjs/typecheck/index.cjs +96 -0
- package/dist/cjs/typecheck/index.cjs.map +10 -0
- package/dist/cjs/types.cjs +30 -0
- package/dist/cjs/types.cjs.map +9 -0
- package/dist/mjs/bridge/diagnostics.mjs +18 -0
- package/dist/mjs/bridge/diagnostics.mjs.map +10 -0
- package/dist/mjs/bridge/legacy-adapters.mjs +178 -0
- package/dist/mjs/bridge/legacy-adapters.mjs.map +10 -0
- package/dist/mjs/bridge/request-context.mjs +19 -0
- package/dist/mjs/bridge/request-context.mjs.map +10 -0
- package/dist/mjs/bridge/runtime-bindings.mjs +303 -0
- package/dist/mjs/bridge/runtime-bindings.mjs.map +10 -0
- package/dist/mjs/browser/browser-runtime.mjs +93 -0
- package/dist/mjs/browser/browser-runtime.mjs.map +10 -0
- package/dist/mjs/daemon.mjs +91 -0
- package/dist/mjs/daemon.mjs.map +10 -0
- package/dist/mjs/files/index.mjs +76 -0
- package/dist/mjs/files/index.mjs.map +10 -0
- package/dist/mjs/host/create-isolate-host.mjs +171 -0
- package/dist/mjs/host/create-isolate-host.mjs.map +10 -0
- package/dist/mjs/host/index.mjs +7 -0
- package/dist/mjs/host/index.mjs.map +10 -0
- package/dist/mjs/index.mjs +15 -0
- package/dist/mjs/index.mjs.map +10 -0
- package/dist/mjs/internal/client/connection.mjs +1872 -0
- package/dist/mjs/internal/client/connection.mjs.map +10 -0
- package/dist/mjs/internal/client/index.mjs +8 -0
- package/dist/mjs/internal/client/index.mjs.map +10 -0
- package/dist/mjs/internal/client/types.mjs +2 -0
- package/dist/mjs/internal/client/types.mjs.map +9 -0
- package/dist/mjs/internal/console/index.mjs +442 -0
- package/dist/mjs/internal/console/index.mjs.map +10 -0
- package/dist/mjs/internal/console/utils.mjs +30 -0
- package/dist/mjs/internal/console/utils.mjs.map +10 -0
- package/dist/mjs/internal/core/index.mjs +2681 -0
- package/dist/mjs/internal/core/index.mjs.map +10 -0
- package/dist/mjs/internal/crypto/index.mjs +406 -0
- package/dist/mjs/internal/crypto/index.mjs.map +10 -0
- package/dist/mjs/internal/daemon/callback-fs-handler.mjs +315 -0
- package/dist/mjs/internal/daemon/callback-fs-handler.mjs.map +10 -0
- package/dist/mjs/internal/daemon/connection.mjs +1931 -0
- package/dist/mjs/internal/daemon/connection.mjs.map +10 -0
- package/dist/mjs/internal/daemon/daemon.mjs +98 -0
- package/dist/mjs/internal/daemon/daemon.mjs.map +10 -0
- package/dist/mjs/internal/daemon/index.mjs +105 -0
- package/dist/mjs/internal/daemon/index.mjs.map +10 -0
- package/dist/mjs/internal/daemon/runtime-pool.mjs +66 -0
- package/dist/mjs/internal/daemon/runtime-pool.mjs.map +10 -0
- package/dist/mjs/internal/daemon/types.mjs +2 -0
- package/dist/mjs/internal/daemon/types.mjs.map +9 -0
- package/dist/mjs/internal/encoding/index.mjs +379 -0
- package/dist/mjs/internal/encoding/index.mjs.map +10 -0
- package/dist/mjs/internal/fetch/consistency/origins.mjs +558 -0
- package/dist/mjs/internal/fetch/consistency/origins.mjs.map +10 -0
- package/dist/mjs/internal/fetch/index.mjs +2580 -0
- package/dist/mjs/internal/fetch/index.mjs.map +10 -0
- package/dist/mjs/internal/fetch/stream-state.mjs +216 -0
- package/dist/mjs/internal/fetch/stream-state.mjs.map +10 -0
- package/dist/mjs/internal/fs/index.mjs +783 -0
- package/dist/mjs/internal/fs/index.mjs.map +10 -0
- package/dist/mjs/internal/fs/node-adapter.mjs +190 -0
- package/dist/mjs/internal/fs/node-adapter.mjs.map +10 -0
- package/dist/mjs/internal/module-loader/bundle.mjs +418 -0
- package/dist/mjs/internal/module-loader/bundle.mjs.map +10 -0
- package/dist/mjs/internal/module-loader/index.mjs +185 -0
- package/dist/mjs/internal/module-loader/index.mjs.map +10 -0
- package/dist/mjs/internal/module-loader/mappings.mjs +80 -0
- package/dist/mjs/internal/module-loader/mappings.mjs.map +10 -0
- package/dist/mjs/internal/module-loader/resolve.mjs +113 -0
- package/dist/mjs/internal/module-loader/resolve.mjs.map +10 -0
- package/dist/mjs/internal/module-loader/strip-types.mjs +172 -0
- package/dist/mjs/internal/module-loader/strip-types.mjs.map +10 -0
- package/dist/mjs/internal/path/index.mjs +463 -0
- package/dist/mjs/internal/path/index.mjs.map +10 -0
- package/dist/mjs/internal/playwright/client.mjs +13 -0
- package/dist/mjs/internal/playwright/client.mjs.map +10 -0
- package/dist/mjs/internal/playwright/handler.mjs +1378 -0
- package/dist/mjs/internal/playwright/handler.mjs.map +10 -0
- package/dist/mjs/internal/playwright/index.mjs +1234 -0
- package/dist/mjs/internal/playwright/index.mjs.map +10 -0
- package/dist/mjs/internal/playwright/types.mjs +7 -0
- package/dist/mjs/internal/playwright/types.mjs.map +10 -0
- package/dist/mjs/internal/protocol/codec.mjs +470 -0
- package/dist/mjs/internal/protocol/codec.mjs.map +10 -0
- package/dist/mjs/internal/protocol/framing.mjs +101 -0
- package/dist/mjs/internal/protocol/framing.mjs.map +10 -0
- package/dist/mjs/internal/protocol/index.mjs +98 -0
- package/dist/mjs/internal/protocol/index.mjs.map +10 -0
- package/dist/mjs/internal/protocol/marshalValue.mjs +494 -0
- package/dist/mjs/internal/protocol/marshalValue.mjs.map +10 -0
- package/dist/mjs/internal/protocol/serialization.mjs +69 -0
- package/dist/mjs/internal/protocol/serialization.mjs.map +10 -0
- package/dist/mjs/internal/protocol/types.mjs +141 -0
- package/dist/mjs/internal/protocol/types.mjs.map +10 -0
- package/dist/mjs/internal/runtime/index.mjs +1198 -0
- package/dist/mjs/internal/runtime/index.mjs.map +10 -0
- package/dist/mjs/internal/server/index.mjs +183 -0
- package/dist/mjs/internal/server/index.mjs.map +10 -0
- package/dist/mjs/internal/test-environment/index.mjs +1351 -0
- package/dist/mjs/internal/test-environment/index.mjs.map +10 -0
- package/dist/mjs/internal/timers/index.mjs +136 -0
- package/dist/mjs/internal/timers/index.mjs.map +10 -0
- package/dist/mjs/internal/transform/index.mjs +321 -0
- package/dist/mjs/internal/transform/index.mjs.map +10 -0
- package/dist/mjs/internal/typecheck/index.mjs +35 -0
- package/dist/mjs/internal/typecheck/index.mjs.map +10 -0
- package/dist/mjs/internal/typecheck/isolate-types.mjs +2574 -0
- package/dist/mjs/internal/typecheck/isolate-types.mjs.map +10 -0
- package/dist/mjs/internal/typecheck/typecheck.mjs +91 -0
- package/dist/mjs/internal/typecheck/typecheck.mjs.map +10 -0
- package/dist/mjs/modules/index.mjs +96 -0
- package/dist/mjs/modules/index.mjs.map +10 -0
- package/dist/mjs/package.json +5 -0
- package/dist/mjs/runtime/script-runtime.mjs +57 -0
- package/dist/mjs/runtime/script-runtime.mjs.map +10 -0
- package/dist/mjs/server/app-server.mjs +118 -0
- package/dist/mjs/server/app-server.mjs.map +10 -0
- package/dist/mjs/testing/integration-helpers.mjs +63 -0
- package/dist/mjs/testing/integration-helpers.mjs.map +10 -0
- package/dist/mjs/typecheck/index.mjs +56 -0
- package/dist/mjs/typecheck/index.mjs.map +10 -0
- package/dist/mjs/types.mjs +2 -0
- package/dist/mjs/types.mjs.map +9 -0
- package/dist/types/bridge/diagnostics.d.ts +12 -0
- package/dist/types/bridge/legacy-adapters.d.ts +14 -0
- package/dist/types/bridge/request-context.d.ts +10 -0
- package/dist/types/bridge/runtime-bindings.d.ts +14 -0
- package/dist/types/browser/browser-runtime.d.ts +3 -0
- package/dist/types/daemon.d.ts +2 -0
- package/dist/types/files/index.d.ts +5 -0
- package/dist/types/host/create-isolate-host.d.ts +2 -0
- package/dist/types/host/index.d.ts +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/internal/client/connection.d.ts +9 -0
- package/dist/types/internal/client/index.d.ts +8 -0
- package/dist/types/internal/client/types.d.ts +198 -0
- package/dist/types/internal/console/index.d.ts +108 -0
- package/dist/types/internal/console/utils.d.ts +27 -0
- package/dist/types/internal/core/index.d.ts +119 -0
- package/dist/types/internal/crypto/index.d.ts +18 -0
- package/dist/types/internal/daemon/callback-fs-handler.d.ts +28 -0
- package/dist/types/internal/daemon/connection.d.ts +9 -0
- package/dist/types/internal/daemon/daemon.d.ts +2 -0
- package/dist/types/internal/daemon/index.d.ts +14 -0
- package/dist/types/internal/daemon/runtime-pool.d.ts +16 -0
- package/dist/types/internal/daemon/types.d.ts +211 -0
- package/dist/types/internal/encoding/index.d.ts +21 -0
- package/dist/types/internal/fetch/consistency/origins.d.ts +179 -0
- package/dist/types/internal/fetch/index.d.ts +93 -0
- package/dist/types/internal/fetch/stream-state.d.ts +65 -0
- package/dist/types/internal/fs/index.d.ts +70 -0
- package/dist/types/internal/fs/node-adapter.d.ts +24 -0
- package/dist/types/internal/module-loader/bundle.d.ts +33 -0
- package/dist/types/internal/module-loader/index.d.ts +30 -0
- package/dist/types/internal/module-loader/mappings.d.ts +47 -0
- package/dist/types/internal/module-loader/resolve.d.ts +26 -0
- package/dist/types/internal/module-loader/strip-types.d.ts +19 -0
- package/dist/types/internal/path/index.d.ts +23 -0
- package/dist/types/internal/playwright/client.d.ts +7 -0
- package/dist/types/internal/playwright/handler.d.ts +44 -0
- package/dist/types/internal/playwright/index.d.ts +14 -0
- package/dist/types/internal/playwright/types.d.ts +145 -0
- package/dist/types/internal/protocol/codec.d.ts +242 -0
- package/dist/types/internal/protocol/framing.d.ts +89 -0
- package/dist/types/internal/protocol/index.d.ts +10 -0
- package/dist/types/internal/protocol/marshalValue.d.ts +79 -0
- package/dist/types/internal/protocol/serialization.d.ts +23 -0
- package/dist/types/internal/protocol/types.d.ts +996 -0
- package/dist/types/internal/runtime/index.d.ts +200 -0
- package/dist/types/internal/server/index.d.ts +42 -0
- package/dist/types/internal/test-environment/index.d.ts +112 -0
- package/dist/types/internal/timers/index.d.ts +22 -0
- package/dist/types/internal/transform/index.d.ts +36 -0
- package/dist/types/internal/typecheck/index.d.ts +7 -0
- package/dist/types/internal/typecheck/isolate-types.d.ts +94 -0
- package/dist/types/internal/typecheck/typecheck.d.ts +148 -0
- package/dist/types/modules/index.d.ts +2 -0
- package/dist/types/runtime/script-runtime.d.ts +6 -0
- package/dist/types/server/app-server.d.ts +3 -0
- package/dist/types/testing/integration-helpers.d.ts +9 -0
- package/dist/types/typecheck/index.d.ts +8 -0
- package/dist/types/types.d.ts +233 -0
- package/package.json +74 -6
- package/README.md +0 -45
|
@@ -0,0 +1,1234 @@
|
|
|
1
|
+
// packages/isolate/src/internal/playwright/index.ts
|
|
2
|
+
import ivm from "isolated-vm";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_PLAYWRIGHT_HANDLER_META
|
|
5
|
+
} from "./types.mjs";
|
|
6
|
+
import {
|
|
7
|
+
createPlaywrightHandler,
|
|
8
|
+
defaultPlaywrightHandler,
|
|
9
|
+
getDefaultPlaywrightHandlerMetadata
|
|
10
|
+
} from "./handler.mjs";
|
|
11
|
+
import {
|
|
12
|
+
createPlaywrightHandler as createPlaywrightHandler2,
|
|
13
|
+
getDefaultPlaywrightHandlerMetadata as getDefaultPlaywrightHandlerMetadata2
|
|
14
|
+
} from "./handler.mjs";
|
|
15
|
+
function wrapHandlerWithPredicateSupport(handler, evaluatePredicate, defaultTimeout) {
|
|
16
|
+
return async (op) => {
|
|
17
|
+
switch (op.type) {
|
|
18
|
+
case "waitForURLPredicate": {
|
|
19
|
+
const [predicateId, customTimeout, waitUntil] = op.args;
|
|
20
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
const pollInterval = 100;
|
|
23
|
+
while (true) {
|
|
24
|
+
const urlResult = await handler({ type: "url", args: [], pageId: op.pageId, contextId: op.contextId });
|
|
25
|
+
if (urlResult.ok) {
|
|
26
|
+
try {
|
|
27
|
+
if (evaluatePredicate(predicateId, urlResult.value)) {
|
|
28
|
+
return { ok: true };
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
const error = e;
|
|
32
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
36
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for URL` } };
|
|
37
|
+
}
|
|
38
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
case "waitForResponsePredicateFinish": {
|
|
42
|
+
const [initialListenerId, predicateId, customTimeout] = op.args;
|
|
43
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
44
|
+
const broadMatcher = { type: "regex", value: { $regex: ".*", $flags: "" } };
|
|
45
|
+
const startTime = Date.now();
|
|
46
|
+
let currentListenerId = initialListenerId;
|
|
47
|
+
while (true) {
|
|
48
|
+
const finishResult = await handler({
|
|
49
|
+
type: "waitForResponseFinish",
|
|
50
|
+
args: [currentListenerId],
|
|
51
|
+
pageId: op.pageId,
|
|
52
|
+
contextId: op.contextId
|
|
53
|
+
});
|
|
54
|
+
if (!finishResult.ok)
|
|
55
|
+
return finishResult;
|
|
56
|
+
const responseData = finishResult.value;
|
|
57
|
+
try {
|
|
58
|
+
const serialized = {
|
|
59
|
+
method: "",
|
|
60
|
+
headers: Object.entries(responseData.headers || {}),
|
|
61
|
+
url: responseData.url,
|
|
62
|
+
status: responseData.status,
|
|
63
|
+
statusText: responseData.statusText,
|
|
64
|
+
body: responseData.text || ""
|
|
65
|
+
};
|
|
66
|
+
if (evaluatePredicate(predicateId, serialized)) {
|
|
67
|
+
return finishResult;
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
const error = e;
|
|
71
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
72
|
+
}
|
|
73
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
74
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for response` } };
|
|
75
|
+
}
|
|
76
|
+
const remainingTimeout = effectiveTimeout > 0 ? Math.max(1, effectiveTimeout - (Date.now() - startTime)) : effectiveTimeout;
|
|
77
|
+
const nextStartResult = await handler({
|
|
78
|
+
type: "waitForResponseStart",
|
|
79
|
+
args: [broadMatcher, remainingTimeout],
|
|
80
|
+
pageId: op.pageId,
|
|
81
|
+
contextId: op.contextId
|
|
82
|
+
});
|
|
83
|
+
if (!nextStartResult.ok)
|
|
84
|
+
return nextStartResult;
|
|
85
|
+
currentListenerId = nextStartResult.value.listenerId;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
case "waitForRequestPredicateFinish": {
|
|
89
|
+
const [initialListenerId, predicateId, customTimeout] = op.args;
|
|
90
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
91
|
+
const broadMatcher = { type: "regex", value: { $regex: ".*", $flags: "" } };
|
|
92
|
+
const startTime = Date.now();
|
|
93
|
+
let currentListenerId = initialListenerId;
|
|
94
|
+
while (true) {
|
|
95
|
+
const finishResult = await handler({
|
|
96
|
+
type: "waitForRequestFinish",
|
|
97
|
+
args: [currentListenerId],
|
|
98
|
+
pageId: op.pageId,
|
|
99
|
+
contextId: op.contextId
|
|
100
|
+
});
|
|
101
|
+
if (!finishResult.ok)
|
|
102
|
+
return finishResult;
|
|
103
|
+
const requestData = finishResult.value;
|
|
104
|
+
try {
|
|
105
|
+
const serialized = {
|
|
106
|
+
method: requestData.method,
|
|
107
|
+
headers: Object.entries(requestData.headers || {}),
|
|
108
|
+
url: requestData.url,
|
|
109
|
+
body: requestData.postData || ""
|
|
110
|
+
};
|
|
111
|
+
if (evaluatePredicate(predicateId, serialized)) {
|
|
112
|
+
return finishResult;
|
|
113
|
+
}
|
|
114
|
+
} catch (e) {
|
|
115
|
+
const error = e;
|
|
116
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
117
|
+
}
|
|
118
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
119
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for request` } };
|
|
120
|
+
}
|
|
121
|
+
const remainingTimeout = effectiveTimeout > 0 ? Math.max(1, effectiveTimeout - (Date.now() - startTime)) : effectiveTimeout;
|
|
122
|
+
const nextStartResult = await handler({
|
|
123
|
+
type: "waitForRequestStart",
|
|
124
|
+
args: [broadMatcher, remainingTimeout],
|
|
125
|
+
pageId: op.pageId,
|
|
126
|
+
contextId: op.contextId
|
|
127
|
+
});
|
|
128
|
+
if (!nextStartResult.ok)
|
|
129
|
+
return nextStartResult;
|
|
130
|
+
currentListenerId = nextStartResult.value.listenerId;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
default:
|
|
134
|
+
return handler(op);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function setupPlaywright(context, options) {
|
|
139
|
+
const timeout = options.timeout ?? 30000;
|
|
140
|
+
const explicitPage = "page" in options ? options.page : undefined;
|
|
141
|
+
const handler = "handler" in options ? options.handler : undefined;
|
|
142
|
+
const handlerMetadata = handler ? getDefaultPlaywrightHandlerMetadata2(handler) : undefined;
|
|
143
|
+
const page = explicitPage ?? handlerMetadata?.page;
|
|
144
|
+
const createPage = "createPage" in options ? options.createPage : undefined;
|
|
145
|
+
const createContext = "createContext" in options ? options.createContext : undefined;
|
|
146
|
+
const readFile = "readFile" in options ? options.readFile : undefined;
|
|
147
|
+
const writeFile = "writeFile" in options ? options.writeFile : undefined;
|
|
148
|
+
if (!handler && !page) {
|
|
149
|
+
throw new Error("Either page or handler must be provided to setupPlaywright");
|
|
150
|
+
}
|
|
151
|
+
const browserConsoleLogs = [];
|
|
152
|
+
const pageErrors = [];
|
|
153
|
+
const networkRequests = [];
|
|
154
|
+
const networkResponses = [];
|
|
155
|
+
const requestFailures = [];
|
|
156
|
+
const global = context.global;
|
|
157
|
+
let requestHandler;
|
|
158
|
+
let responseHandler;
|
|
159
|
+
let requestFailedHandler;
|
|
160
|
+
let consoleHandler;
|
|
161
|
+
let pageErrorHandler;
|
|
162
|
+
if (page) {
|
|
163
|
+
const onEvent = "onEvent" in options ? options.onEvent : undefined;
|
|
164
|
+
const requestIds = new WeakMap;
|
|
165
|
+
let nextRequestId = 1;
|
|
166
|
+
const getRequestId = (request) => {
|
|
167
|
+
let requestId = requestIds.get(request);
|
|
168
|
+
if (!requestId) {
|
|
169
|
+
requestId = `req_${nextRequestId++}`;
|
|
170
|
+
requestIds.set(request, requestId);
|
|
171
|
+
}
|
|
172
|
+
return requestId;
|
|
173
|
+
};
|
|
174
|
+
const toLocation = (location) => {
|
|
175
|
+
if (!location || !location.url && location.lineNumber == null && location.columnNumber == null) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
url: location.url || undefined,
|
|
180
|
+
lineNumber: location.lineNumber != null ? location.lineNumber + 1 : undefined,
|
|
181
|
+
columnNumber: location.columnNumber != null ? location.columnNumber + 1 : undefined
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
requestHandler = (request) => {
|
|
185
|
+
const info = {
|
|
186
|
+
requestId: getRequestId(request),
|
|
187
|
+
url: request.url(),
|
|
188
|
+
method: request.method(),
|
|
189
|
+
headers: request.headers(),
|
|
190
|
+
postData: request.postData() ?? undefined,
|
|
191
|
+
resourceType: request.resourceType(),
|
|
192
|
+
timestamp: Date.now()
|
|
193
|
+
};
|
|
194
|
+
networkRequests.push(info);
|
|
195
|
+
if (onEvent) {
|
|
196
|
+
onEvent({
|
|
197
|
+
type: "networkRequest",
|
|
198
|
+
requestId: info.requestId,
|
|
199
|
+
url: info.url,
|
|
200
|
+
method: info.method,
|
|
201
|
+
headers: info.headers,
|
|
202
|
+
postData: info.postData,
|
|
203
|
+
resourceType: info.resourceType,
|
|
204
|
+
timestamp: info.timestamp
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
responseHandler = (response) => {
|
|
209
|
+
const request = response.request();
|
|
210
|
+
const info = {
|
|
211
|
+
requestId: getRequestId(request),
|
|
212
|
+
url: response.url(),
|
|
213
|
+
status: response.status(),
|
|
214
|
+
statusText: response.statusText(),
|
|
215
|
+
headers: response.headers(),
|
|
216
|
+
resourceType: request.resourceType(),
|
|
217
|
+
timestamp: Date.now()
|
|
218
|
+
};
|
|
219
|
+
networkResponses.push(info);
|
|
220
|
+
if (onEvent) {
|
|
221
|
+
onEvent({
|
|
222
|
+
type: "networkResponse",
|
|
223
|
+
requestId: info.requestId,
|
|
224
|
+
url: info.url,
|
|
225
|
+
status: info.status,
|
|
226
|
+
statusText: info.statusText,
|
|
227
|
+
headers: info.headers,
|
|
228
|
+
resourceType: info.resourceType,
|
|
229
|
+
timestamp: info.timestamp
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
requestFailedHandler = (request) => {
|
|
234
|
+
const info = {
|
|
235
|
+
requestId: getRequestId(request),
|
|
236
|
+
url: request.url(),
|
|
237
|
+
method: request.method(),
|
|
238
|
+
failureText: request.failure()?.errorText || "request failed",
|
|
239
|
+
resourceType: request.resourceType(),
|
|
240
|
+
timestamp: Date.now()
|
|
241
|
+
};
|
|
242
|
+
requestFailures.push(info);
|
|
243
|
+
if (onEvent) {
|
|
244
|
+
onEvent({
|
|
245
|
+
type: "requestFailure",
|
|
246
|
+
requestId: info.requestId,
|
|
247
|
+
url: info.url,
|
|
248
|
+
method: info.method,
|
|
249
|
+
failureText: info.failureText,
|
|
250
|
+
resourceType: info.resourceType,
|
|
251
|
+
timestamp: info.timestamp
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
consoleHandler = (msg) => {
|
|
256
|
+
const args = msg.args().map((arg) => String(arg));
|
|
257
|
+
const entry = {
|
|
258
|
+
level: msg.type(),
|
|
259
|
+
stdout: args.join(" "),
|
|
260
|
+
location: toLocation(msg.location()),
|
|
261
|
+
timestamp: Date.now()
|
|
262
|
+
};
|
|
263
|
+
browserConsoleLogs.push(entry);
|
|
264
|
+
if (onEvent) {
|
|
265
|
+
onEvent({
|
|
266
|
+
type: "browserConsoleLog",
|
|
267
|
+
level: entry.level,
|
|
268
|
+
stdout: entry.stdout,
|
|
269
|
+
location: entry.location,
|
|
270
|
+
timestamp: entry.timestamp
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if ("console" in options && options.console) {
|
|
274
|
+
const prefix = `[browser:${entry.level}]`;
|
|
275
|
+
console.log(prefix, entry.stdout);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
pageErrorHandler = (error) => {
|
|
279
|
+
const entry = {
|
|
280
|
+
name: error.name,
|
|
281
|
+
message: error.message,
|
|
282
|
+
stack: error.stack,
|
|
283
|
+
timestamp: Date.now()
|
|
284
|
+
};
|
|
285
|
+
pageErrors.push(entry);
|
|
286
|
+
if (onEvent) {
|
|
287
|
+
onEvent({
|
|
288
|
+
type: "pageError",
|
|
289
|
+
name: entry.name,
|
|
290
|
+
message: entry.message,
|
|
291
|
+
stack: entry.stack,
|
|
292
|
+
timestamp: entry.timestamp
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
page.on("request", requestHandler);
|
|
297
|
+
page.on("response", responseHandler);
|
|
298
|
+
page.on("requestfailed", requestFailedHandler);
|
|
299
|
+
page.on("console", consoleHandler);
|
|
300
|
+
page.on("pageerror", pageErrorHandler);
|
|
301
|
+
}
|
|
302
|
+
context.evalSync(`
|
|
303
|
+
(function() {
|
|
304
|
+
globalThis.__pw_invoke = async function(type, args, options) {
|
|
305
|
+
const op = JSON.stringify({ type, args, pageId: options?.pageId, contextId: options?.contextId });
|
|
306
|
+
const resultJson = await __Playwright_handler_ref.apply(
|
|
307
|
+
undefined,
|
|
308
|
+
[op],
|
|
309
|
+
{ result: { promise: true, copy: true } }
|
|
310
|
+
);
|
|
311
|
+
const result = JSON.parse(resultJson);
|
|
312
|
+
if (result.ok) {
|
|
313
|
+
return result.value;
|
|
314
|
+
}
|
|
315
|
+
const error = new Error(result.error.message);
|
|
316
|
+
error.name = result.error.name;
|
|
317
|
+
throw error;
|
|
318
|
+
};
|
|
319
|
+
})();
|
|
320
|
+
`);
|
|
321
|
+
context.evalSync(`
|
|
322
|
+
(function() {
|
|
323
|
+
const __pw_predicates = new Map();
|
|
324
|
+
let __pw_next_id = 0;
|
|
325
|
+
globalThis.__pw_register_predicate = function(fn) {
|
|
326
|
+
const id = __pw_next_id++;
|
|
327
|
+
__pw_predicates.set(id, fn);
|
|
328
|
+
return id;
|
|
329
|
+
};
|
|
330
|
+
globalThis.__pw_unregister_predicate = function(id) {
|
|
331
|
+
__pw_predicates.delete(id);
|
|
332
|
+
};
|
|
333
|
+
globalThis.__pw_evaluate_predicate = function(id, data) {
|
|
334
|
+
const fn = __pw_predicates.get(id);
|
|
335
|
+
if (!fn) throw new Error('Predicate not found: ' + id);
|
|
336
|
+
const result = fn(data);
|
|
337
|
+
if (result && typeof result === 'object' && typeof result.then === 'function') {
|
|
338
|
+
throw new Error('Async predicates are not supported. Use a synchronous predicate function.');
|
|
339
|
+
}
|
|
340
|
+
return !!result;
|
|
341
|
+
};
|
|
342
|
+
})();
|
|
343
|
+
`);
|
|
344
|
+
const evaluatePredicateRef = context.global.getSync("__pw_evaluate_predicate", { reference: true });
|
|
345
|
+
const evaluatePredicateFn = (predicateId, data) => {
|
|
346
|
+
return evaluatePredicateRef.applySync(undefined, [new ivm.ExternalCopy(predicateId).copyInto(), new ivm.ExternalCopy(data).copyInto()]);
|
|
347
|
+
};
|
|
348
|
+
let effectiveHandler;
|
|
349
|
+
if (handler && handlerMetadata?.page) {
|
|
350
|
+
effectiveHandler = createPlaywrightHandler2(handlerMetadata.page, {
|
|
351
|
+
...handlerMetadata.options,
|
|
352
|
+
evaluatePredicate: evaluatePredicateFn
|
|
353
|
+
});
|
|
354
|
+
} else if (handler) {
|
|
355
|
+
effectiveHandler = wrapHandlerWithPredicateSupport(handler, evaluatePredicateFn, timeout);
|
|
356
|
+
} else if (page) {
|
|
357
|
+
effectiveHandler = createPlaywrightHandler2(page, {
|
|
358
|
+
timeout,
|
|
359
|
+
readFile,
|
|
360
|
+
writeFile,
|
|
361
|
+
createPage,
|
|
362
|
+
createContext,
|
|
363
|
+
evaluatePredicate: evaluatePredicateFn
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
throw new Error("Either page or handler must be provided to setupPlaywright");
|
|
367
|
+
}
|
|
368
|
+
global.setSync("__Playwright_handler_ref", new ivm.Reference(async (opJson) => {
|
|
369
|
+
const op = JSON.parse(opJson);
|
|
370
|
+
const result = await effectiveHandler(op);
|
|
371
|
+
return JSON.stringify(result);
|
|
372
|
+
}));
|
|
373
|
+
context.evalSync(`
|
|
374
|
+
(function() {
|
|
375
|
+
// IsolatePage class - represents a page with a specific pageId
|
|
376
|
+
class IsolatePage {
|
|
377
|
+
#pageId; #contextId;
|
|
378
|
+
constructor(pageId, contextId) {
|
|
379
|
+
this.#pageId = pageId;
|
|
380
|
+
this.#contextId = contextId;
|
|
381
|
+
}
|
|
382
|
+
get __isPage() { return true; }
|
|
383
|
+
get __pageId() { return this.#pageId; }
|
|
384
|
+
get __contextId() { return this.#contextId; }
|
|
385
|
+
|
|
386
|
+
async goto(url, options) {
|
|
387
|
+
await __pw_invoke("goto", [url, options?.waitUntil || null], { pageId: this.#pageId });
|
|
388
|
+
}
|
|
389
|
+
async reload() {
|
|
390
|
+
await __pw_invoke("reload", [], { pageId: this.#pageId });
|
|
391
|
+
}
|
|
392
|
+
async url() { return __pw_invoke("url", [], { pageId: this.#pageId }); }
|
|
393
|
+
async title() { return __pw_invoke("title", [], { pageId: this.#pageId }); }
|
|
394
|
+
async content() { return __pw_invoke("content", [], { pageId: this.#pageId }); }
|
|
395
|
+
async waitForSelector(selector, options) {
|
|
396
|
+
return __pw_invoke("waitForSelector", [selector, options ? JSON.stringify(options) : null], { pageId: this.#pageId });
|
|
397
|
+
}
|
|
398
|
+
async waitForTimeout(ms) { return __pw_invoke("waitForTimeout", [ms], { pageId: this.#pageId }); }
|
|
399
|
+
async waitForLoadState(state) { return __pw_invoke("waitForLoadState", [state || null], { pageId: this.#pageId }); }
|
|
400
|
+
async evaluate(script, arg) {
|
|
401
|
+
const hasArg = arguments.length > 1;
|
|
402
|
+
if (hasArg) {
|
|
403
|
+
const serialized = typeof script === "function" ? script.toString() : script;
|
|
404
|
+
return __pw_invoke("evaluate", [serialized, arg], { pageId: this.#pageId });
|
|
405
|
+
}
|
|
406
|
+
const serialized = typeof script === "function" ? "(" + script.toString() + ")()" : script;
|
|
407
|
+
return __pw_invoke("evaluate", [serialized], { pageId: this.#pageId });
|
|
408
|
+
}
|
|
409
|
+
locator(selector) { return new Locator("css", selector, null, this.#pageId); }
|
|
410
|
+
getByRole(role, options) {
|
|
411
|
+
if (options) {
|
|
412
|
+
const serialized = { ...options };
|
|
413
|
+
const name = options.name;
|
|
414
|
+
if (name && typeof name === 'object' && typeof name.source === 'string' && typeof name.flags === 'string') {
|
|
415
|
+
serialized.name = { $regex: name.source, $flags: name.flags };
|
|
416
|
+
}
|
|
417
|
+
return new Locator("role", role, JSON.stringify(serialized), this.#pageId);
|
|
418
|
+
}
|
|
419
|
+
return new Locator("role", role, null, this.#pageId);
|
|
420
|
+
}
|
|
421
|
+
getByText(text) { return new Locator("text", text, null, this.#pageId); }
|
|
422
|
+
getByLabel(label) { return new Locator("label", label, null, this.#pageId); }
|
|
423
|
+
getByPlaceholder(p) { return new Locator("placeholder", p, null, this.#pageId); }
|
|
424
|
+
getByTestId(id) { return new Locator("testId", id, null, this.#pageId); }
|
|
425
|
+
getByAltText(alt) { return new Locator("altText", alt, null, this.#pageId); }
|
|
426
|
+
getByTitle(title) { return new Locator("title", title, null, this.#pageId); }
|
|
427
|
+
frameLocator(selector) {
|
|
428
|
+
const pageId = this.#pageId;
|
|
429
|
+
return {
|
|
430
|
+
locator(innerSelector) { return new Locator("frame", JSON.stringify([["css", selector, null], ["css", innerSelector, null]]), null, pageId); },
|
|
431
|
+
getByRole(role, options) { return new Locator("frame", JSON.stringify([["css", selector, null], ["role", role, options ? JSON.stringify(options) : null]]), null, pageId); },
|
|
432
|
+
getByText(text) { return new Locator("frame", JSON.stringify([["css", selector, null], ["text", text, null]]), null, pageId); },
|
|
433
|
+
getByLabel(label) { return new Locator("frame", JSON.stringify([["css", selector, null], ["label", label, null]]), null, pageId); },
|
|
434
|
+
getByPlaceholder(placeholder) { return new Locator("frame", JSON.stringify([["css", selector, null], ["placeholder", placeholder, null]]), null, pageId); },
|
|
435
|
+
getByTestId(testId) { return new Locator("frame", JSON.stringify([["css", selector, null], ["testId", testId, null]]), null, pageId); },
|
|
436
|
+
getByAltText(alt) { return new Locator("frame", JSON.stringify([["css", selector, null], ["altText", alt, null]]), null, pageId); },
|
|
437
|
+
getByTitle(title) { return new Locator("frame", JSON.stringify([["css", selector, null], ["title", title, null]]), null, pageId); },
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
async goBack(options) {
|
|
441
|
+
await __pw_invoke("goBack", [options?.waitUntil || null], { pageId: this.#pageId });
|
|
442
|
+
}
|
|
443
|
+
async goForward(options) {
|
|
444
|
+
await __pw_invoke("goForward", [options?.waitUntil || null], { pageId: this.#pageId });
|
|
445
|
+
}
|
|
446
|
+
async waitForURL(url, options) {
|
|
447
|
+
if (typeof url === 'function') {
|
|
448
|
+
const predicateId = __pw_register_predicate(url);
|
|
449
|
+
try {
|
|
450
|
+
await __pw_invoke("waitForURLPredicate", [predicateId, options?.timeout || null, options?.waitUntil || null], { pageId: this.#pageId });
|
|
451
|
+
} finally {
|
|
452
|
+
__pw_unregister_predicate(predicateId);
|
|
453
|
+
}
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
let serializedUrl;
|
|
457
|
+
if (typeof url === 'string') {
|
|
458
|
+
serializedUrl = { type: 'string', value: url };
|
|
459
|
+
} else if (url && typeof url === 'object' && typeof url.source === 'string' && typeof url.flags === 'string') {
|
|
460
|
+
serializedUrl = { type: 'regex', value: { $regex: url.source, $flags: url.flags } };
|
|
461
|
+
} else {
|
|
462
|
+
serializedUrl = url;
|
|
463
|
+
}
|
|
464
|
+
return __pw_invoke("waitForURL", [serializedUrl, options?.timeout || null, options?.waitUntil || null], { pageId: this.#pageId });
|
|
465
|
+
}
|
|
466
|
+
async waitForRequest(urlOrPredicate, options) {
|
|
467
|
+
if (typeof urlOrPredicate === 'function') {
|
|
468
|
+
const userPredicate = urlOrPredicate;
|
|
469
|
+
const wrappedPredicate = (data) => {
|
|
470
|
+
const requestLike = {
|
|
471
|
+
url: () => data.url,
|
|
472
|
+
method: () => data.method,
|
|
473
|
+
headers: () => Object.fromEntries(data.headers),
|
|
474
|
+
headersArray: () => data.headers.map(h => ({ name: h[0], value: h[1] })),
|
|
475
|
+
postData: () => data.body || null,
|
|
476
|
+
};
|
|
477
|
+
return userPredicate(requestLike);
|
|
478
|
+
};
|
|
479
|
+
const predicateId = __pw_register_predicate(wrappedPredicate);
|
|
480
|
+
const pageId = this.#pageId;
|
|
481
|
+
// Start listening immediately (before the user triggers the request)
|
|
482
|
+
const broadMatcher = { type: 'regex', value: { $regex: '.*', $flags: '' } };
|
|
483
|
+
const startResult = await __pw_invoke("waitForRequestStart", [broadMatcher, options?.timeout || null], { pageId });
|
|
484
|
+
const listenerId = startResult.listenerId;
|
|
485
|
+
try {
|
|
486
|
+
const r = await __pw_invoke("waitForRequestPredicateFinish", [listenerId, predicateId, options?.timeout || null], { pageId });
|
|
487
|
+
return { url: () => r.url, method: () => r.method, headers: () => r.headers, postData: () => r.postData };
|
|
488
|
+
} finally {
|
|
489
|
+
__pw_unregister_predicate(predicateId);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
let serializedMatcher;
|
|
493
|
+
if (typeof urlOrPredicate === 'string') {
|
|
494
|
+
serializedMatcher = { type: 'string', value: urlOrPredicate };
|
|
495
|
+
} else if (urlOrPredicate && typeof urlOrPredicate === 'object'
|
|
496
|
+
&& typeof urlOrPredicate.source === 'string'
|
|
497
|
+
&& typeof urlOrPredicate.flags === 'string') {
|
|
498
|
+
serializedMatcher = { type: 'regex', value: { $regex: urlOrPredicate.source, $flags: urlOrPredicate.flags } };
|
|
499
|
+
} else {
|
|
500
|
+
throw new Error('waitForRequest requires a URL string, RegExp, or predicate function');
|
|
501
|
+
}
|
|
502
|
+
const startResult = await __pw_invoke("waitForRequestStart", [serializedMatcher, options?.timeout || null], { pageId: this.#pageId });
|
|
503
|
+
const listenerId = startResult.listenerId;
|
|
504
|
+
const pageId = this.#pageId;
|
|
505
|
+
const r = await __pw_invoke("waitForRequestFinish", [listenerId], { pageId });
|
|
506
|
+
return { url: () => r.url, method: () => r.method, headers: () => r.headers, postData: () => r.postData };
|
|
507
|
+
}
|
|
508
|
+
async waitForResponse(urlOrPredicate, options) {
|
|
509
|
+
if (typeof urlOrPredicate === 'function') {
|
|
510
|
+
const userPredicate = urlOrPredicate;
|
|
511
|
+
const wrappedPredicate = (data) => {
|
|
512
|
+
const responseLike = {
|
|
513
|
+
url: () => data.url,
|
|
514
|
+
status: () => data.status,
|
|
515
|
+
statusText: () => data.statusText,
|
|
516
|
+
headers: () => Object.fromEntries(data.headers),
|
|
517
|
+
headersArray: () => data.headers.map(h => ({ name: h[0], value: h[1] })),
|
|
518
|
+
ok: () => data.status >= 200 && data.status < 300,
|
|
519
|
+
};
|
|
520
|
+
return userPredicate(responseLike);
|
|
521
|
+
};
|
|
522
|
+
const predicateId = __pw_register_predicate(wrappedPredicate);
|
|
523
|
+
const pageId = this.#pageId;
|
|
524
|
+
// Start listening immediately (before the user triggers the response)
|
|
525
|
+
const broadMatcher = { type: 'regex', value: { $regex: '.*', $flags: '' } };
|
|
526
|
+
const startResult = await __pw_invoke("waitForResponseStart", [broadMatcher, options?.timeout || null], { pageId });
|
|
527
|
+
const listenerId = startResult.listenerId;
|
|
528
|
+
try {
|
|
529
|
+
const r = await __pw_invoke("waitForResponsePredicateFinish", [listenerId, predicateId, options?.timeout || null], { pageId });
|
|
530
|
+
return {
|
|
531
|
+
url: () => r.url, status: () => r.status, statusText: () => r.statusText,
|
|
532
|
+
headers: () => r.headers, headersArray: () => r.headersArray,
|
|
533
|
+
ok: () => r.ok, json: async () => r.json, text: async () => r.text, body: async () => r.body,
|
|
534
|
+
};
|
|
535
|
+
} finally {
|
|
536
|
+
__pw_unregister_predicate(predicateId);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
let serializedMatcher;
|
|
540
|
+
if (typeof urlOrPredicate === 'string') {
|
|
541
|
+
serializedMatcher = { type: 'string', value: urlOrPredicate };
|
|
542
|
+
} else if (urlOrPredicate && typeof urlOrPredicate === 'object'
|
|
543
|
+
&& typeof urlOrPredicate.source === 'string'
|
|
544
|
+
&& typeof urlOrPredicate.flags === 'string') {
|
|
545
|
+
serializedMatcher = { type: 'regex', value: { $regex: urlOrPredicate.source, $flags: urlOrPredicate.flags } };
|
|
546
|
+
} else {
|
|
547
|
+
throw new Error('waitForResponse requires a URL string, RegExp, or predicate function');
|
|
548
|
+
}
|
|
549
|
+
const startResult = await __pw_invoke("waitForResponseStart", [serializedMatcher, options?.timeout || null], { pageId: this.#pageId });
|
|
550
|
+
const listenerId = startResult.listenerId;
|
|
551
|
+
const pageId = this.#pageId;
|
|
552
|
+
const r = await __pw_invoke("waitForResponseFinish", [listenerId], { pageId });
|
|
553
|
+
return {
|
|
554
|
+
url: () => r.url, status: () => r.status, statusText: () => r.statusText,
|
|
555
|
+
headers: () => r.headers, headersArray: () => r.headersArray,
|
|
556
|
+
ok: () => r.ok, json: async () => r.json, text: async () => r.text, body: async () => r.body,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
context() {
|
|
560
|
+
const contextId = this.#contextId;
|
|
561
|
+
return new IsolateContext(contextId);
|
|
562
|
+
}
|
|
563
|
+
async click(selector) { return this.locator(selector).click(); }
|
|
564
|
+
async fill(selector, value) { return this.locator(selector).fill(value); }
|
|
565
|
+
async textContent(selector) { return this.locator(selector).textContent(); }
|
|
566
|
+
async innerText(selector) { return this.locator(selector).innerText(); }
|
|
567
|
+
async innerHTML(selector) { return this.locator(selector).innerHTML(); }
|
|
568
|
+
async getAttribute(selector, name) { return this.locator(selector).getAttribute(name); }
|
|
569
|
+
async inputValue(selector) { return this.locator(selector).inputValue(); }
|
|
570
|
+
async isVisible(selector) { return this.locator(selector).isVisible(); }
|
|
571
|
+
async isEnabled(selector) { return this.locator(selector).isEnabled(); }
|
|
572
|
+
async isChecked(selector) { return this.locator(selector).isChecked(); }
|
|
573
|
+
async isHidden(selector) { return this.locator(selector).isHidden(); }
|
|
574
|
+
async isDisabled(selector) { return this.locator(selector).isDisabled(); }
|
|
575
|
+
async screenshot(options) { return __pw_invoke("screenshot", [options || {}], { pageId: this.#pageId }); }
|
|
576
|
+
async setViewportSize(size) { return __pw_invoke("setViewportSize", [size], { pageId: this.#pageId }); }
|
|
577
|
+
async viewportSize() { return __pw_invoke("viewportSize", [], { pageId: this.#pageId }); }
|
|
578
|
+
async emulateMedia(options) { return __pw_invoke("emulateMedia", [options], { pageId: this.#pageId }); }
|
|
579
|
+
async setExtraHTTPHeaders(headers) { return __pw_invoke("setExtraHTTPHeaders", [headers], { pageId: this.#pageId }); }
|
|
580
|
+
async bringToFront() { return __pw_invoke("bringToFront", [], { pageId: this.#pageId }); }
|
|
581
|
+
async close() { return __pw_invoke("close", [], { pageId: this.#pageId }); }
|
|
582
|
+
async isClosed() { return __pw_invoke("isClosed", [], { pageId: this.#pageId }); }
|
|
583
|
+
async pdf(options) { return __pw_invoke("pdf", [options || {}], { pageId: this.#pageId }); }
|
|
584
|
+
async pause() { return __pw_invoke("pause", [], { pageId: this.#pageId }); }
|
|
585
|
+
async frames() { return __pw_invoke("frames", [], { pageId: this.#pageId }); }
|
|
586
|
+
async mainFrame() { return __pw_invoke("mainFrame", [], { pageId: this.#pageId }); }
|
|
587
|
+
get keyboard() {
|
|
588
|
+
const pageId = this.#pageId;
|
|
589
|
+
return {
|
|
590
|
+
async type(text, options) { return __pw_invoke("keyboardType", [text, options], { pageId }); },
|
|
591
|
+
async press(key, options) { return __pw_invoke("keyboardPress", [key, options], { pageId }); },
|
|
592
|
+
async down(key) { return __pw_invoke("keyboardDown", [key], { pageId }); },
|
|
593
|
+
async up(key) { return __pw_invoke("keyboardUp", [key], { pageId }); },
|
|
594
|
+
async insertText(text) { return __pw_invoke("keyboardInsertText", [text], { pageId }); }
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
get mouse() {
|
|
598
|
+
const pageId = this.#pageId;
|
|
599
|
+
return {
|
|
600
|
+
async move(x, y, options) { return __pw_invoke("mouseMove", [x, y, options], { pageId }); },
|
|
601
|
+
async click(x, y, options) { return __pw_invoke("mouseClick", [x, y, options], { pageId }); },
|
|
602
|
+
async down(options) { return __pw_invoke("mouseDown", [options], { pageId }); },
|
|
603
|
+
async up(options) { return __pw_invoke("mouseUp", [options], { pageId }); },
|
|
604
|
+
async wheel(deltaX, deltaY) { return __pw_invoke("mouseWheel", [deltaX, deltaY], { pageId }); }
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
get request() {
|
|
608
|
+
const pageId = this.#pageId;
|
|
609
|
+
return {
|
|
610
|
+
async fetch(url, options) {
|
|
611
|
+
const result = await __pw_invoke("request", [url, options?.method || "GET", options?.data, options?.headers], { pageId });
|
|
612
|
+
return {
|
|
613
|
+
status: () => result.status,
|
|
614
|
+
ok: () => result.ok,
|
|
615
|
+
headers: () => result.headers,
|
|
616
|
+
json: async () => result.json,
|
|
617
|
+
text: async () => result.text,
|
|
618
|
+
body: async () => result.body,
|
|
619
|
+
};
|
|
620
|
+
},
|
|
621
|
+
async get(url, options) { return this.fetch(url, { ...options, method: "GET" }); },
|
|
622
|
+
async post(url, options) { return this.fetch(url, { ...options, method: "POST" }); },
|
|
623
|
+
async put(url, options) { return this.fetch(url, { ...options, method: "PUT" }); },
|
|
624
|
+
async delete(url, options) { return this.fetch(url, { ...options, method: "DELETE" }); },
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
globalThis.IsolatePage = IsolatePage;
|
|
629
|
+
|
|
630
|
+
// IsolateContext class - represents a browser context with a specific contextId
|
|
631
|
+
class IsolateContext {
|
|
632
|
+
#contextId;
|
|
633
|
+
constructor(contextId) { this.#contextId = contextId; }
|
|
634
|
+
get __contextId() { return this.#contextId; }
|
|
635
|
+
|
|
636
|
+
async newPage() {
|
|
637
|
+
const result = await __pw_invoke("newPage", [], { contextId: this.#contextId });
|
|
638
|
+
return new IsolatePage(result.pageId, this.#contextId);
|
|
639
|
+
}
|
|
640
|
+
async close() { return __pw_invoke("closeContext", [], { contextId: this.#contextId }); }
|
|
641
|
+
async clearCookies() { return __pw_invoke("clearCookies", [], { contextId: this.#contextId }); }
|
|
642
|
+
async addCookies(cookies) { return __pw_invoke("addCookies", [cookies], { contextId: this.#contextId }); }
|
|
643
|
+
async cookies(urls) { return __pw_invoke("cookies", [urls], { contextId: this.#contextId }); }
|
|
644
|
+
}
|
|
645
|
+
globalThis.IsolateContext = IsolateContext;
|
|
646
|
+
|
|
647
|
+
// browser global - for creating new contexts
|
|
648
|
+
globalThis.browser = {
|
|
649
|
+
async newContext(options) {
|
|
650
|
+
const result = await __pw_invoke("newContext", [options || null]);
|
|
651
|
+
return new IsolateContext(result.contextId);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// context global - represents the default context
|
|
656
|
+
globalThis.context = new IsolateContext("ctx_0");
|
|
657
|
+
|
|
658
|
+
// page global - represents the default page
|
|
659
|
+
globalThis.page = new IsolatePage("page_0", "ctx_0");
|
|
660
|
+
})();
|
|
661
|
+
`);
|
|
662
|
+
context.evalSync(`
|
|
663
|
+
(function() {
|
|
664
|
+
// Helper to serialize options including RegExp
|
|
665
|
+
function serializeOptions(options) {
|
|
666
|
+
if (!options) return null;
|
|
667
|
+
const serialized = { ...options };
|
|
668
|
+
if (options.name && typeof options.name === 'object' && typeof options.name.source === 'string' && typeof options.name.flags === 'string') {
|
|
669
|
+
serialized.name = { $regex: options.name.source, $flags: options.name.flags };
|
|
670
|
+
}
|
|
671
|
+
return JSON.stringify(serialized);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const INPUT_FILES_VALIDATION_ERROR =
|
|
675
|
+
"setInputFiles() expects a file path string, an array of file path strings, " +
|
|
676
|
+
"a single inline file object ({ name, mimeType, buffer }), or an array of inline file objects.";
|
|
677
|
+
|
|
678
|
+
function isInlineFileObject(value) {
|
|
679
|
+
return !!value
|
|
680
|
+
&& typeof value === 'object'
|
|
681
|
+
&& typeof value.name === 'string'
|
|
682
|
+
&& typeof value.mimeType === 'string'
|
|
683
|
+
&& 'buffer' in value;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function encodeInlineFileBuffer(buffer) {
|
|
687
|
+
if (typeof buffer === 'string') {
|
|
688
|
+
return buffer;
|
|
689
|
+
}
|
|
690
|
+
let bytes;
|
|
691
|
+
if (buffer instanceof ArrayBuffer) {
|
|
692
|
+
bytes = new Uint8Array(buffer);
|
|
693
|
+
} else if (ArrayBuffer.isView(buffer)) {
|
|
694
|
+
bytes = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
695
|
+
} else {
|
|
696
|
+
throw new Error(
|
|
697
|
+
"setInputFiles() inline file buffer must be a base64 string, ArrayBuffer, or TypedArray."
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
let binary = '';
|
|
701
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
702
|
+
binary += String.fromCharCode(bytes[i]);
|
|
703
|
+
}
|
|
704
|
+
return btoa(binary);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function serializeInlineFile(file) {
|
|
708
|
+
return {
|
|
709
|
+
name: file.name,
|
|
710
|
+
mimeType: file.mimeType,
|
|
711
|
+
buffer: encodeInlineFileBuffer(file.buffer),
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function normalizeSetInputFilesArg(files) {
|
|
716
|
+
if (typeof files === 'string') {
|
|
717
|
+
return files;
|
|
718
|
+
}
|
|
719
|
+
if (isInlineFileObject(files)) {
|
|
720
|
+
return serializeInlineFile(files);
|
|
721
|
+
}
|
|
722
|
+
if (!Array.isArray(files)) {
|
|
723
|
+
throw new Error(INPUT_FILES_VALIDATION_ERROR);
|
|
724
|
+
}
|
|
725
|
+
if (files.length === 0) {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
let hasPaths = false;
|
|
730
|
+
let hasInline = false;
|
|
731
|
+
const inlineFiles = [];
|
|
732
|
+
|
|
733
|
+
for (const file of files) {
|
|
734
|
+
if (typeof file === 'string') {
|
|
735
|
+
hasPaths = true;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (isInlineFileObject(file)) {
|
|
739
|
+
hasInline = true;
|
|
740
|
+
inlineFiles.push(serializeInlineFile(file));
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
throw new Error(INPUT_FILES_VALIDATION_ERROR);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (hasPaths && hasInline) {
|
|
747
|
+
throw new Error(
|
|
748
|
+
"setInputFiles() does not support mixing file paths and inline file objects in the same array."
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
return hasInline ? inlineFiles : files;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
class Locator {
|
|
755
|
+
#type; #value; #options; #pageId;
|
|
756
|
+
constructor(type, value, options, pageId) {
|
|
757
|
+
this.#type = type;
|
|
758
|
+
this.#value = value;
|
|
759
|
+
this.#options = options;
|
|
760
|
+
this.#pageId = pageId || "page_0";
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
_getInfo() { return [this.#type, this.#value, this.#options]; }
|
|
764
|
+
_getPageId() { return this.#pageId; }
|
|
765
|
+
|
|
766
|
+
// Helper to create a chained locator
|
|
767
|
+
_chain(childType, childValue, childOptions) {
|
|
768
|
+
const parentInfo = this._getInfo();
|
|
769
|
+
const childInfo = [childType, childValue, childOptions];
|
|
770
|
+
return new Locator("chained", JSON.stringify([parentInfo, childInfo]), null, this.#pageId);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
async click() {
|
|
774
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "click", null], { pageId: this.#pageId });
|
|
775
|
+
}
|
|
776
|
+
async dblclick() {
|
|
777
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "dblclick", null], { pageId: this.#pageId });
|
|
778
|
+
}
|
|
779
|
+
async fill(text) {
|
|
780
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "fill", text], { pageId: this.#pageId });
|
|
781
|
+
}
|
|
782
|
+
async type(text) {
|
|
783
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "type", text], { pageId: this.#pageId });
|
|
784
|
+
}
|
|
785
|
+
async check() {
|
|
786
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "check", null], { pageId: this.#pageId });
|
|
787
|
+
}
|
|
788
|
+
async uncheck() {
|
|
789
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "uncheck", null], { pageId: this.#pageId });
|
|
790
|
+
}
|
|
791
|
+
async selectOption(value) {
|
|
792
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "selectOption", value], { pageId: this.#pageId });
|
|
793
|
+
}
|
|
794
|
+
async clear() {
|
|
795
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "clear", null], { pageId: this.#pageId });
|
|
796
|
+
}
|
|
797
|
+
async press(key) {
|
|
798
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "press", key], { pageId: this.#pageId });
|
|
799
|
+
}
|
|
800
|
+
async hover() {
|
|
801
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "hover", null], { pageId: this.#pageId });
|
|
802
|
+
}
|
|
803
|
+
async focus() {
|
|
804
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "focus", null], { pageId: this.#pageId });
|
|
805
|
+
}
|
|
806
|
+
async textContent() {
|
|
807
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getText", null], { pageId: this.#pageId });
|
|
808
|
+
}
|
|
809
|
+
async inputValue() {
|
|
810
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getValue", null], { pageId: this.#pageId });
|
|
811
|
+
}
|
|
812
|
+
async isVisible() {
|
|
813
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isVisible", null], { pageId: this.#pageId });
|
|
814
|
+
}
|
|
815
|
+
async isEnabled() {
|
|
816
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isEnabled", null], { pageId: this.#pageId });
|
|
817
|
+
}
|
|
818
|
+
async isChecked() {
|
|
819
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isChecked", null], { pageId: this.#pageId });
|
|
820
|
+
}
|
|
821
|
+
async count() {
|
|
822
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "count", null], { pageId: this.#pageId });
|
|
823
|
+
}
|
|
824
|
+
async getAttribute(name) {
|
|
825
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getAttribute", name], { pageId: this.#pageId });
|
|
826
|
+
}
|
|
827
|
+
async isDisabled() {
|
|
828
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isDisabled", null], { pageId: this.#pageId });
|
|
829
|
+
}
|
|
830
|
+
async isHidden() {
|
|
831
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isHidden", null], { pageId: this.#pageId });
|
|
832
|
+
}
|
|
833
|
+
async innerHTML() {
|
|
834
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "innerHTML", null], { pageId: this.#pageId });
|
|
835
|
+
}
|
|
836
|
+
async innerText() {
|
|
837
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "innerText", null], { pageId: this.#pageId });
|
|
838
|
+
}
|
|
839
|
+
async allTextContents() {
|
|
840
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "allTextContents", null], { pageId: this.#pageId });
|
|
841
|
+
}
|
|
842
|
+
async allInnerTexts() {
|
|
843
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "allInnerTexts", null], { pageId: this.#pageId });
|
|
844
|
+
}
|
|
845
|
+
async waitFor(options) {
|
|
846
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "waitFor", options || {}], { pageId: this.#pageId });
|
|
847
|
+
}
|
|
848
|
+
async boundingBox() {
|
|
849
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "boundingBox", null], { pageId: this.#pageId });
|
|
850
|
+
}
|
|
851
|
+
async setInputFiles(files) {
|
|
852
|
+
const serializedFiles = normalizeSetInputFilesArg(files);
|
|
853
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "setInputFiles", serializedFiles], { pageId: this.#pageId });
|
|
854
|
+
}
|
|
855
|
+
async screenshot(options) {
|
|
856
|
+
const base64 = await __pw_invoke("locatorAction", [...this._getInfo(), "screenshot", options || {}], { pageId: this.#pageId });
|
|
857
|
+
return base64;
|
|
858
|
+
}
|
|
859
|
+
async dragTo(target) {
|
|
860
|
+
const targetInfo = target._getInfo();
|
|
861
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "dragTo", targetInfo], { pageId: this.#pageId });
|
|
862
|
+
}
|
|
863
|
+
async scrollIntoViewIfNeeded() {
|
|
864
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "scrollIntoViewIfNeeded", null], { pageId: this.#pageId });
|
|
865
|
+
}
|
|
866
|
+
async highlight() {
|
|
867
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "highlight", null], { pageId: this.#pageId });
|
|
868
|
+
}
|
|
869
|
+
async evaluate(fn, arg) {
|
|
870
|
+
const fnString = typeof fn === 'function' ? fn.toString() : fn;
|
|
871
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "evaluate", [fnString, arg]], { pageId: this.#pageId });
|
|
872
|
+
}
|
|
873
|
+
async evaluateAll(fn, arg) {
|
|
874
|
+
const fnString = typeof fn === 'function' ? fn.toString() : fn;
|
|
875
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "evaluateAll", [fnString, arg]], { pageId: this.#pageId });
|
|
876
|
+
}
|
|
877
|
+
locator(selector) {
|
|
878
|
+
return this._chain("css", selector, null);
|
|
879
|
+
}
|
|
880
|
+
// Chaining: getBy* methods within a locator
|
|
881
|
+
getByRole(role, options) {
|
|
882
|
+
return this._chain("role", role, serializeOptions(options));
|
|
883
|
+
}
|
|
884
|
+
getByText(text) {
|
|
885
|
+
return this._chain("text", text, null);
|
|
886
|
+
}
|
|
887
|
+
getByLabel(label) {
|
|
888
|
+
return this._chain("label", label, null);
|
|
889
|
+
}
|
|
890
|
+
getByPlaceholder(placeholder) {
|
|
891
|
+
return this._chain("placeholder", placeholder, null);
|
|
892
|
+
}
|
|
893
|
+
getByTestId(testId) {
|
|
894
|
+
return this._chain("testId", testId, null);
|
|
895
|
+
}
|
|
896
|
+
getByAltText(altText) {
|
|
897
|
+
return this._chain("altText", altText, null);
|
|
898
|
+
}
|
|
899
|
+
getByTitle(title) {
|
|
900
|
+
return this._chain("title", title, null);
|
|
901
|
+
}
|
|
902
|
+
async all() {
|
|
903
|
+
const n = await this.count();
|
|
904
|
+
const result = [];
|
|
905
|
+
for (let i = 0; i < n; i++) {
|
|
906
|
+
result.push(this.nth(i));
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
909
|
+
}
|
|
910
|
+
nth(index) {
|
|
911
|
+
const existingOpts = this.#options ? JSON.parse(this.#options) : {};
|
|
912
|
+
return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, nth: index }), this.#pageId);
|
|
913
|
+
}
|
|
914
|
+
first() {
|
|
915
|
+
return this.nth(0);
|
|
916
|
+
}
|
|
917
|
+
last() {
|
|
918
|
+
return this.nth(-1);
|
|
919
|
+
}
|
|
920
|
+
filter(options) {
|
|
921
|
+
const existingOpts = this.#options ? JSON.parse(this.#options) : {};
|
|
922
|
+
const serializedFilter = { ...options };
|
|
923
|
+
// Use duck-typing RegExp detection (instanceof fails across isolated-vm boundary)
|
|
924
|
+
const hasText = options.hasText;
|
|
925
|
+
if (hasText && typeof hasText === 'object' && typeof hasText.source === 'string' && typeof hasText.flags === 'string') {
|
|
926
|
+
serializedFilter.hasText = { $regex: hasText.source, $flags: hasText.flags };
|
|
927
|
+
}
|
|
928
|
+
const hasNotText = options.hasNotText;
|
|
929
|
+
if (hasNotText && typeof hasNotText === 'object' && typeof hasNotText.source === 'string' && typeof hasNotText.flags === 'string') {
|
|
930
|
+
serializedFilter.hasNotText = { $regex: hasNotText.source, $flags: hasNotText.flags };
|
|
931
|
+
}
|
|
932
|
+
// Serialize has/hasNot locators using duck-typing
|
|
933
|
+
const has = options.has;
|
|
934
|
+
if (has && typeof has === 'object' && typeof has._getInfo === 'function') {
|
|
935
|
+
serializedFilter.has = { $locator: has._getInfo() };
|
|
936
|
+
}
|
|
937
|
+
const hasNot = options.hasNot;
|
|
938
|
+
if (hasNot && typeof hasNot === 'object' && typeof hasNot._getInfo === 'function') {
|
|
939
|
+
serializedFilter.hasNot = { $locator: hasNot._getInfo() };
|
|
940
|
+
}
|
|
941
|
+
return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, filter: serializedFilter }), this.#pageId);
|
|
942
|
+
}
|
|
943
|
+
or(other) {
|
|
944
|
+
// Create a composite locator that matches either this or other
|
|
945
|
+
const thisInfo = this._getInfo();
|
|
946
|
+
const otherInfo = other._getInfo();
|
|
947
|
+
return new Locator("or", JSON.stringify([thisInfo, otherInfo]), null, this.#pageId);
|
|
948
|
+
}
|
|
949
|
+
and(other) {
|
|
950
|
+
// Create a composite locator that matches both this and other
|
|
951
|
+
const thisInfo = this._getInfo();
|
|
952
|
+
const otherInfo = other._getInfo();
|
|
953
|
+
return new Locator("and", JSON.stringify([thisInfo, otherInfo]), null, this.#pageId);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
globalThis.Locator = Locator;
|
|
957
|
+
})();
|
|
958
|
+
`);
|
|
959
|
+
context.evalSync(`
|
|
960
|
+
(function() {
|
|
961
|
+
// Helper to create locator matchers
|
|
962
|
+
function createLocatorMatchers(locator, baseMatchers) {
|
|
963
|
+
const info = locator._getInfo();
|
|
964
|
+
const pageId = locator._getPageId ? locator._getPageId() : "page_0";
|
|
965
|
+
|
|
966
|
+
// Helper for serializing regex values
|
|
967
|
+
function serializeExpected(expected) {
|
|
968
|
+
if (expected instanceof RegExp) {
|
|
969
|
+
return { $regex: expected.source, $flags: expected.flags };
|
|
970
|
+
}
|
|
971
|
+
return expected;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const locatorMatchers = {
|
|
975
|
+
async toBeVisible(options) {
|
|
976
|
+
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, false, options?.timeout], { pageId });
|
|
977
|
+
},
|
|
978
|
+
async toContainText(expected, options) {
|
|
979
|
+
return __pw_invoke("expectLocator", [...info, "toContainText", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
980
|
+
},
|
|
981
|
+
async toHaveValue(expected, options) {
|
|
982
|
+
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, false, options?.timeout], { pageId });
|
|
983
|
+
},
|
|
984
|
+
async toBeEnabled(options) {
|
|
985
|
+
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, false, options?.timeout], { pageId });
|
|
986
|
+
},
|
|
987
|
+
async toBeChecked(options) {
|
|
988
|
+
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, false, options?.timeout], { pageId });
|
|
989
|
+
},
|
|
990
|
+
async toHaveAttribute(name, value, options) {
|
|
991
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value: serializeExpected(value) }, false, options?.timeout], { pageId });
|
|
992
|
+
},
|
|
993
|
+
async toHaveText(expected, options) {
|
|
994
|
+
return __pw_invoke("expectLocator", [...info, "toHaveText", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
995
|
+
},
|
|
996
|
+
async toHaveCount(count, options) {
|
|
997
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, false, options?.timeout], { pageId });
|
|
998
|
+
},
|
|
999
|
+
async toBeHidden(options) {
|
|
1000
|
+
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, false, options?.timeout], { pageId });
|
|
1001
|
+
},
|
|
1002
|
+
async toBeDisabled(options) {
|
|
1003
|
+
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, false, options?.timeout], { pageId });
|
|
1004
|
+
},
|
|
1005
|
+
async toBeFocused(options) {
|
|
1006
|
+
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, false, options?.timeout], { pageId });
|
|
1007
|
+
},
|
|
1008
|
+
async toBeEmpty(options) {
|
|
1009
|
+
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, false, options?.timeout], { pageId });
|
|
1010
|
+
},
|
|
1011
|
+
// New matchers
|
|
1012
|
+
async toBeAttached(options) {
|
|
1013
|
+
return __pw_invoke("expectLocator", [...info, "toBeAttached", null, false, options?.timeout], { pageId });
|
|
1014
|
+
},
|
|
1015
|
+
async toBeEditable(options) {
|
|
1016
|
+
return __pw_invoke("expectLocator", [...info, "toBeEditable", null, false, options?.timeout], { pageId });
|
|
1017
|
+
},
|
|
1018
|
+
async toHaveClass(expected, options) {
|
|
1019
|
+
return __pw_invoke("expectLocator", [...info, "toHaveClass", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1020
|
+
},
|
|
1021
|
+
async toContainClass(expected, options) {
|
|
1022
|
+
return __pw_invoke("expectLocator", [...info, "toContainClass", expected, false, options?.timeout], { pageId });
|
|
1023
|
+
},
|
|
1024
|
+
async toHaveId(expected, options) {
|
|
1025
|
+
return __pw_invoke("expectLocator", [...info, "toHaveId", expected, false, options?.timeout], { pageId });
|
|
1026
|
+
},
|
|
1027
|
+
async toBeInViewport(options) {
|
|
1028
|
+
return __pw_invoke("expectLocator", [...info, "toBeInViewport", null, false, options?.timeout], { pageId });
|
|
1029
|
+
},
|
|
1030
|
+
async toHaveCSS(name, value, options) {
|
|
1031
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCSS", { name, value: serializeExpected(value) }, false, options?.timeout], { pageId });
|
|
1032
|
+
},
|
|
1033
|
+
async toHaveJSProperty(name, value, options) {
|
|
1034
|
+
return __pw_invoke("expectLocator", [...info, "toHaveJSProperty", { name, value }, false, options?.timeout], { pageId });
|
|
1035
|
+
},
|
|
1036
|
+
async toHaveAccessibleName(expected, options) {
|
|
1037
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleName", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1038
|
+
},
|
|
1039
|
+
async toHaveAccessibleDescription(expected, options) {
|
|
1040
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleDescription", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1041
|
+
},
|
|
1042
|
+
async toHaveRole(expected, options) {
|
|
1043
|
+
return __pw_invoke("expectLocator", [...info, "toHaveRole", expected, false, options?.timeout], { pageId });
|
|
1044
|
+
},
|
|
1045
|
+
not: {
|
|
1046
|
+
async toBeVisible(options) {
|
|
1047
|
+
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, true, options?.timeout], { pageId });
|
|
1048
|
+
},
|
|
1049
|
+
async toContainText(expected, options) {
|
|
1050
|
+
return __pw_invoke("expectLocator", [...info, "toContainText", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1051
|
+
},
|
|
1052
|
+
async toHaveValue(expected, options) {
|
|
1053
|
+
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, true, options?.timeout], { pageId });
|
|
1054
|
+
},
|
|
1055
|
+
async toBeEnabled(options) {
|
|
1056
|
+
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, true, options?.timeout], { pageId });
|
|
1057
|
+
},
|
|
1058
|
+
async toBeChecked(options) {
|
|
1059
|
+
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, true, options?.timeout], { pageId });
|
|
1060
|
+
},
|
|
1061
|
+
async toHaveAttribute(name, value, options) {
|
|
1062
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value: serializeExpected(value) }, true, options?.timeout], { pageId });
|
|
1063
|
+
},
|
|
1064
|
+
async toHaveText(expected, options) {
|
|
1065
|
+
return __pw_invoke("expectLocator", [...info, "toHaveText", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1066
|
+
},
|
|
1067
|
+
async toHaveCount(count, options) {
|
|
1068
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, true, options?.timeout], { pageId });
|
|
1069
|
+
},
|
|
1070
|
+
async toBeHidden(options) {
|
|
1071
|
+
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, true, options?.timeout], { pageId });
|
|
1072
|
+
},
|
|
1073
|
+
async toBeDisabled(options) {
|
|
1074
|
+
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, true, options?.timeout], { pageId });
|
|
1075
|
+
},
|
|
1076
|
+
async toBeFocused(options) {
|
|
1077
|
+
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, true, options?.timeout], { pageId });
|
|
1078
|
+
},
|
|
1079
|
+
async toBeEmpty(options) {
|
|
1080
|
+
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, true, options?.timeout], { pageId });
|
|
1081
|
+
},
|
|
1082
|
+
// New negated matchers
|
|
1083
|
+
async toBeAttached(options) {
|
|
1084
|
+
return __pw_invoke("expectLocator", [...info, "toBeAttached", null, true, options?.timeout], { pageId });
|
|
1085
|
+
},
|
|
1086
|
+
async toBeEditable(options) {
|
|
1087
|
+
return __pw_invoke("expectLocator", [...info, "toBeEditable", null, true, options?.timeout], { pageId });
|
|
1088
|
+
},
|
|
1089
|
+
async toHaveClass(expected, options) {
|
|
1090
|
+
return __pw_invoke("expectLocator", [...info, "toHaveClass", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1091
|
+
},
|
|
1092
|
+
async toContainClass(expected, options) {
|
|
1093
|
+
return __pw_invoke("expectLocator", [...info, "toContainClass", expected, true, options?.timeout], { pageId });
|
|
1094
|
+
},
|
|
1095
|
+
async toHaveId(expected, options) {
|
|
1096
|
+
return __pw_invoke("expectLocator", [...info, "toHaveId", expected, true, options?.timeout], { pageId });
|
|
1097
|
+
},
|
|
1098
|
+
async toBeInViewport(options) {
|
|
1099
|
+
return __pw_invoke("expectLocator", [...info, "toBeInViewport", null, true, options?.timeout], { pageId });
|
|
1100
|
+
},
|
|
1101
|
+
async toHaveCSS(name, value, options) {
|
|
1102
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCSS", { name, value: serializeExpected(value) }, true, options?.timeout], { pageId });
|
|
1103
|
+
},
|
|
1104
|
+
async toHaveJSProperty(name, value, options) {
|
|
1105
|
+
return __pw_invoke("expectLocator", [...info, "toHaveJSProperty", { name, value }, true, options?.timeout], { pageId });
|
|
1106
|
+
},
|
|
1107
|
+
async toHaveAccessibleName(expected, options) {
|
|
1108
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleName", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1109
|
+
},
|
|
1110
|
+
async toHaveAccessibleDescription(expected, options) {
|
|
1111
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleDescription", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1112
|
+
},
|
|
1113
|
+
async toHaveRole(expected, options) {
|
|
1114
|
+
return __pw_invoke("expectLocator", [...info, "toHaveRole", expected, true, options?.timeout], { pageId });
|
|
1115
|
+
},
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// Merge locator matchers with base matchers from test-environment
|
|
1120
|
+
if (baseMatchers) {
|
|
1121
|
+
return {
|
|
1122
|
+
...baseMatchers,
|
|
1123
|
+
...locatorMatchers,
|
|
1124
|
+
not: { ...baseMatchers.not, ...locatorMatchers.not }
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
return locatorMatchers;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// Helper to create page matchers
|
|
1131
|
+
function createPageMatchers(page, baseMatchers) {
|
|
1132
|
+
const pageId = page.__pageId || "page_0";
|
|
1133
|
+
|
|
1134
|
+
function serializeExpected(expected) {
|
|
1135
|
+
if (expected instanceof RegExp) {
|
|
1136
|
+
return { $regex: expected.source, $flags: expected.flags };
|
|
1137
|
+
}
|
|
1138
|
+
return expected;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const pageMatchers = {
|
|
1142
|
+
async toHaveURL(expected, options) {
|
|
1143
|
+
return __pw_invoke("expectPage", ["toHaveURL", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1144
|
+
},
|
|
1145
|
+
async toHaveTitle(expected, options) {
|
|
1146
|
+
return __pw_invoke("expectPage", ["toHaveTitle", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1147
|
+
},
|
|
1148
|
+
not: {
|
|
1149
|
+
async toHaveURL(expected, options) {
|
|
1150
|
+
return __pw_invoke("expectPage", ["toHaveURL", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1151
|
+
},
|
|
1152
|
+
async toHaveTitle(expected, options) {
|
|
1153
|
+
return __pw_invoke("expectPage", ["toHaveTitle", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1154
|
+
},
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
if (baseMatchers) {
|
|
1159
|
+
return {
|
|
1160
|
+
...baseMatchers,
|
|
1161
|
+
...pageMatchers,
|
|
1162
|
+
not: { ...baseMatchers.not, ...pageMatchers.not }
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
return pageMatchers;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Only extend expect if test-environment already defined it
|
|
1169
|
+
if (typeof globalThis.expect === 'function') {
|
|
1170
|
+
const originalExpect = globalThis.expect;
|
|
1171
|
+
globalThis.expect = function(actual) {
|
|
1172
|
+
const baseMatchers = originalExpect(actual);
|
|
1173
|
+
// If actual is a Locator, add locator-specific matchers
|
|
1174
|
+
if (actual && actual.constructor && actual.constructor.name === 'Locator') {
|
|
1175
|
+
return createLocatorMatchers(actual, baseMatchers);
|
|
1176
|
+
}
|
|
1177
|
+
// If actual is the page object (IsolatePage), add page-specific matchers
|
|
1178
|
+
if (actual && actual.__isPage === true) {
|
|
1179
|
+
return createPageMatchers(actual, baseMatchers);
|
|
1180
|
+
}
|
|
1181
|
+
return baseMatchers;
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
// If test-environment not loaded, expect remains undefined
|
|
1185
|
+
})();
|
|
1186
|
+
`);
|
|
1187
|
+
return {
|
|
1188
|
+
dispose() {
|
|
1189
|
+
if (page && requestHandler && responseHandler && requestFailedHandler && consoleHandler && pageErrorHandler) {
|
|
1190
|
+
page.off("request", requestHandler);
|
|
1191
|
+
page.off("response", responseHandler);
|
|
1192
|
+
page.off("requestfailed", requestFailedHandler);
|
|
1193
|
+
page.off("console", consoleHandler);
|
|
1194
|
+
page.off("pageerror", pageErrorHandler);
|
|
1195
|
+
}
|
|
1196
|
+
browserConsoleLogs.length = 0;
|
|
1197
|
+
pageErrors.length = 0;
|
|
1198
|
+
networkRequests.length = 0;
|
|
1199
|
+
networkResponses.length = 0;
|
|
1200
|
+
requestFailures.length = 0;
|
|
1201
|
+
},
|
|
1202
|
+
getBrowserConsoleLogs() {
|
|
1203
|
+
return [...browserConsoleLogs];
|
|
1204
|
+
},
|
|
1205
|
+
getPageErrors() {
|
|
1206
|
+
return [...pageErrors];
|
|
1207
|
+
},
|
|
1208
|
+
getNetworkRequests() {
|
|
1209
|
+
return [...networkRequests];
|
|
1210
|
+
},
|
|
1211
|
+
getNetworkResponses() {
|
|
1212
|
+
return [...networkResponses];
|
|
1213
|
+
},
|
|
1214
|
+
getRequestFailures() {
|
|
1215
|
+
return [...requestFailures];
|
|
1216
|
+
},
|
|
1217
|
+
clearCollected() {
|
|
1218
|
+
browserConsoleLogs.length = 0;
|
|
1219
|
+
pageErrors.length = 0;
|
|
1220
|
+
networkRequests.length = 0;
|
|
1221
|
+
networkResponses.length = 0;
|
|
1222
|
+
requestFailures.length = 0;
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
export {
|
|
1227
|
+
setupPlaywright,
|
|
1228
|
+
getDefaultPlaywrightHandlerMetadata,
|
|
1229
|
+
defaultPlaywrightHandler,
|
|
1230
|
+
createPlaywrightHandler,
|
|
1231
|
+
DEFAULT_PLAYWRIGHT_HANDLER_META
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
//# debugId=58FDD2912C4D791E64756E2164756E21
|