@ricsam/isolate-playwright 0.1.2 → 0.1.5
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 +170 -45
- package/dist/cjs/client.cjs +287 -0
- package/dist/cjs/client.cjs.map +10 -0
- package/dist/cjs/index.cjs +431 -530
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/types.cjs +26 -0
- package/dist/cjs/types.cjs.map +9 -0
- package/dist/mjs/client.mjs +256 -0
- package/dist/mjs/client.mjs.map +10 -0
- package/dist/mjs/index.mjs +431 -530
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/types.mjs +3 -0
- package/dist/mjs/types.mjs.map +9 -0
- package/dist/types/client.d.ts +18 -0
- package/dist/types/index.d.ts +49 -18
- package/dist/types/types.d.ts +68 -0
- package/package.json +12 -1
package/README.md
CHANGED
|
@@ -1,48 +1,137 @@
|
|
|
1
1
|
# @ricsam/isolate-playwright
|
|
2
2
|
|
|
3
|
-
Playwright bridge for running browser
|
|
3
|
+
Playwright bridge for running browser automation in a V8 sandbox. Execute untrusted Playwright code against a real browser page while keeping the logic isolated.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm add @ricsam/isolate-playwright playwright
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage with isolate-runtime (Recommended)
|
|
12
|
+
|
|
13
|
+
The easiest way to use this package is through `@ricsam/isolate-runtime`:
|
|
14
|
+
|
|
15
|
+
### Script Mode (No Tests)
|
|
16
|
+
|
|
17
|
+
Run browser automation scripts without a test framework:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createRuntime } from "@ricsam/isolate-runtime";
|
|
21
|
+
import { chromium } from "playwright";
|
|
22
|
+
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
const page = await browser.newPage();
|
|
25
|
+
|
|
26
|
+
const runtime = await createRuntime({
|
|
27
|
+
playwright: {
|
|
28
|
+
page,
|
|
29
|
+
baseUrl: "https://example.com",
|
|
30
|
+
console: true, // Print browser console logs to stdout
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Run a script - page is available, but expect is not
|
|
35
|
+
await runtime.eval(`
|
|
36
|
+
await page.goto("/");
|
|
37
|
+
const title = await page.title();
|
|
38
|
+
console.log("Page title:", title);
|
|
39
|
+
`);
|
|
40
|
+
|
|
41
|
+
// Get collected network data
|
|
42
|
+
const data = runtime.playwright.getCollectedData();
|
|
43
|
+
console.log("Network requests:", data.networkRequests.length);
|
|
44
|
+
|
|
45
|
+
await runtime.dispose();
|
|
46
|
+
await browser.close();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Test Mode (With Test Framework)
|
|
50
|
+
|
|
51
|
+
For tests, enable `testEnvironment` which provides `describe`, `it`, and `expect`. Playwright extends `expect` with locator matchers:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { createRuntime } from "@ricsam/isolate-runtime";
|
|
55
|
+
import { chromium } from "playwright";
|
|
56
|
+
|
|
57
|
+
const browser = await chromium.launch({ headless: true });
|
|
58
|
+
const page = await browser.newPage();
|
|
59
|
+
|
|
60
|
+
const runtime = await createRuntime({
|
|
61
|
+
testEnvironment: true, // Provides describe, it, expect
|
|
62
|
+
playwright: {
|
|
63
|
+
page,
|
|
64
|
+
baseUrl: "https://example.com",
|
|
65
|
+
onBrowserConsoleLog: (entry) => console.log("[browser]", entry.level, ...entry.args),
|
|
66
|
+
onNetworkRequest: (info) => console.log("Request:", info.url),
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await runtime.eval(`
|
|
71
|
+
describe("homepage", () => {
|
|
72
|
+
it("loads correctly", async () => {
|
|
73
|
+
await page.goto("/");
|
|
74
|
+
const heading = page.getByRole("heading", { name: "Example Domain" });
|
|
75
|
+
await expect(heading).toBeVisible(); // Locator matcher from playwright
|
|
76
|
+
expect(await page.title()).toBe("Example Domain"); // Primitive matcher from test-environment
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
`);
|
|
80
|
+
|
|
81
|
+
// Run tests using test-environment
|
|
82
|
+
const results = await runtime.testEnvironment.runTests();
|
|
83
|
+
console.log(`${results.passed}/${results.total} tests passed`);
|
|
84
|
+
|
|
85
|
+
// Get collected browser data
|
|
86
|
+
const data = runtime.playwright.getCollectedData();
|
|
87
|
+
console.log("Browser console logs:", data.browserConsoleLogs);
|
|
88
|
+
|
|
89
|
+
await runtime.dispose();
|
|
90
|
+
await browser.close();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Low-level Usage (Direct ivm)
|
|
94
|
+
|
|
95
|
+
For advanced use cases with direct isolated-vm access:
|
|
4
96
|
|
|
5
97
|
```typescript
|
|
6
98
|
import ivm from "isolated-vm";
|
|
7
99
|
import { chromium } from "playwright";
|
|
8
|
-
import { setupPlaywright
|
|
100
|
+
import { setupPlaywright } from "@ricsam/isolate-playwright";
|
|
101
|
+
import { setupTestEnvironment, runTests } from "@ricsam/isolate-test-environment";
|
|
9
102
|
|
|
10
|
-
// Create browser and page
|
|
11
103
|
const browser = await chromium.launch();
|
|
12
104
|
const page = await browser.newPage();
|
|
13
105
|
|
|
14
|
-
// Create isolate and context
|
|
15
106
|
const isolate = new ivm.Isolate();
|
|
16
107
|
const context = await isolate.createContext();
|
|
17
108
|
|
|
18
|
-
// Setup
|
|
109
|
+
// Setup test-environment first (provides describe, it, expect)
|
|
110
|
+
await setupTestEnvironment(context);
|
|
111
|
+
|
|
112
|
+
// Then setup playwright (extends expect with locator matchers)
|
|
19
113
|
const handle = await setupPlaywright(context, {
|
|
20
114
|
page,
|
|
21
115
|
timeout: 30000,
|
|
22
116
|
baseUrl: "https://example.com",
|
|
23
117
|
onNetworkRequest: (info) => console.log("Request:", info.url),
|
|
24
118
|
onNetworkResponse: (info) => console.log("Response:", info.status),
|
|
25
|
-
|
|
119
|
+
onBrowserConsoleLog: (entry) => console.log(`[${entry.level}]`, ...entry.args),
|
|
26
120
|
});
|
|
27
121
|
|
|
28
122
|
// Load and run untrusted test code
|
|
29
123
|
await context.eval(`
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
test("can interact with elements", async () => {
|
|
37
|
-
const link = page.locator("a");
|
|
38
|
-
await expect(link).toBeVisible();
|
|
39
|
-
const text = await link.textContent();
|
|
40
|
-
expect(text).toContain("More information");
|
|
124
|
+
describe("homepage", () => {
|
|
125
|
+
it("loads correctly", async () => {
|
|
126
|
+
await page.goto("/");
|
|
127
|
+
const heading = page.getByRole("heading", { name: "Example Domain" });
|
|
128
|
+
await expect(heading).toBeVisible();
|
|
129
|
+
});
|
|
41
130
|
});
|
|
42
131
|
`);
|
|
43
132
|
|
|
44
|
-
// Run tests
|
|
45
|
-
const results = await
|
|
133
|
+
// Run tests
|
|
134
|
+
const results = await runTests(context);
|
|
46
135
|
console.log(`${results.passed}/${results.total} tests passed`);
|
|
47
136
|
|
|
48
137
|
// Cleanup
|
|
@@ -52,18 +141,44 @@ isolate.dispose();
|
|
|
52
141
|
await browser.close();
|
|
53
142
|
```
|
|
54
143
|
|
|
55
|
-
|
|
144
|
+
## Handler-based API (for Remote Execution)
|
|
145
|
+
|
|
146
|
+
For daemon/client architectures where the browser runs on the client:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { createPlaywrightHandler, setupPlaywright, type PlaywrightCallback } from "@ricsam/isolate-playwright";
|
|
150
|
+
import { chromium } from "playwright";
|
|
151
|
+
|
|
152
|
+
// On the client: create handler from page
|
|
153
|
+
const browser = await chromium.launch();
|
|
154
|
+
const page = await browser.newPage();
|
|
155
|
+
const handler: PlaywrightCallback = createPlaywrightHandler(page, {
|
|
156
|
+
timeout: 30000,
|
|
157
|
+
baseUrl: "https://example.com",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// On the daemon: setup playwright with handler (instead of page)
|
|
161
|
+
const handle = await setupPlaywright(context, {
|
|
162
|
+
handler, // Handler callback instead of direct page
|
|
163
|
+
onBrowserConsoleLog: (entry) => sendToClient("browserConsoleLog", entry),
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Injected Globals (in isolate)
|
|
168
|
+
|
|
56
169
|
- `page` - Page object with navigation and locator methods
|
|
57
|
-
- `test(name, fn)` - Register a test
|
|
58
|
-
- `expect(actual)` - Assertion helper for locators and primitives
|
|
59
170
|
- `Locator` - Locator class for element interactions
|
|
171
|
+
- `expect` - Extended with locator matchers (only if test-environment is loaded first)
|
|
172
|
+
|
|
173
|
+
## Page Methods
|
|
60
174
|
|
|
61
|
-
**Page Methods:**
|
|
62
175
|
- `page.goto(url, options?)` - Navigate to URL
|
|
63
176
|
- `page.reload()` - Reload page
|
|
64
177
|
- `page.url()` - Get current URL (sync)
|
|
65
178
|
- `page.title()` - Get page title
|
|
66
179
|
- `page.content()` - Get page HTML
|
|
180
|
+
- `page.click(selector)` - Click element (shorthand)
|
|
181
|
+
- `page.fill(selector, value)` - Fill input (shorthand)
|
|
67
182
|
- `page.waitForSelector(selector, options?)` - Wait for element
|
|
68
183
|
- `page.waitForTimeout(ms)` - Wait for milliseconds
|
|
69
184
|
- `page.waitForLoadState(state?)` - Wait for load state
|
|
@@ -74,43 +189,53 @@ await browser.close();
|
|
|
74
189
|
- `page.getByLabel(label)` - Get locator by label
|
|
75
190
|
- `page.getByPlaceholder(text)` - Get locator by placeholder
|
|
76
191
|
- `page.getByTestId(id)` - Get locator by test ID
|
|
192
|
+
- `page.request.get(url)` - HTTP GET request with page cookies
|
|
193
|
+
- `page.request.post(url, options?)` - HTTP POST request with page cookies
|
|
194
|
+
|
|
195
|
+
## Locator Methods
|
|
77
196
|
|
|
78
|
-
**Locator Methods:**
|
|
79
197
|
- `click()`, `dblclick()`, `hover()`, `focus()`
|
|
80
198
|
- `fill(text)`, `type(text)`, `clear()`, `press(key)`
|
|
81
199
|
- `check()`, `uncheck()`, `selectOption(value)`
|
|
82
200
|
- `textContent()`, `inputValue()`
|
|
83
201
|
- `isVisible()`, `isEnabled()`, `isChecked()`, `count()`
|
|
202
|
+
- `nth(index)` - Get nth matching element
|
|
203
|
+
|
|
204
|
+
## Expect Matchers (for Locators)
|
|
205
|
+
|
|
206
|
+
These matchers are available when using playwright with test-environment:
|
|
84
207
|
|
|
85
|
-
|
|
86
|
-
- `
|
|
87
|
-
- `toContainText(text)`, `toHaveValue(value)`
|
|
208
|
+
- `toBeVisible(options?)`, `toBeEnabled(options?)`, `toBeChecked(options?)`
|
|
209
|
+
- `toContainText(text, options?)`, `toHaveValue(value, options?)`
|
|
88
210
|
- All matchers support `.not` modifier
|
|
211
|
+
- All matchers support `{ timeout: number }` option
|
|
89
212
|
|
|
90
|
-
|
|
91
|
-
- `toBe(expected)`, `toEqual(expected)`
|
|
92
|
-
- `toBeTruthy()`, `toBeFalsy()`
|
|
93
|
-
- `toContain(item)`
|
|
213
|
+
## Handle Methods
|
|
94
214
|
|
|
95
|
-
**Handle Methods:**
|
|
96
215
|
- `dispose()` - Clean up event listeners
|
|
97
|
-
- `
|
|
216
|
+
- `getBrowserConsoleLogs()` - Get captured browser console logs
|
|
98
217
|
- `getNetworkRequests()` - Get captured network requests
|
|
99
218
|
- `getNetworkResponses()` - Get captured network responses
|
|
100
219
|
- `clearCollected()` - Clear all collected data
|
|
101
220
|
|
|
102
|
-
|
|
221
|
+
## Setup Options
|
|
103
222
|
|
|
104
223
|
```typescript
|
|
105
|
-
interface
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
error?: string;
|
|
113
|
-
duration: number;
|
|
114
|
-
}>;
|
|
224
|
+
interface PlaywrightSetupOptions {
|
|
225
|
+
page?: Page; // Direct page object (for local use)
|
|
226
|
+
handler?: PlaywrightCallback; // Handler callback (for remote use)
|
|
227
|
+
timeout?: number; // Default timeout for operations
|
|
228
|
+
baseUrl?: string; // Base URL for relative navigation
|
|
229
|
+
console?: boolean; // Route browser console logs through console handler
|
|
230
|
+
onEvent?: (event: PlaywrightEvent) => void; // Unified event callback
|
|
115
231
|
}
|
|
116
|
-
|
|
232
|
+
|
|
233
|
+
type PlaywrightEvent =
|
|
234
|
+
| { type: "browserConsoleLog"; level: string; args: unknown[]; timestamp: number }
|
|
235
|
+
| { type: "networkRequest"; url: string; method: string; headers: Record<string, string>; ... }
|
|
236
|
+
| { type: "networkResponse"; url: string; status: number; headers: Record<string, string>; ... };
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/playwright/src/client.ts
|
|
31
|
+
var exports_client = {};
|
|
32
|
+
__export(exports_client, {
|
|
33
|
+
createPlaywrightHandler: () => createPlaywrightHandler
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(exports_client);
|
|
36
|
+
function getLocator(page, selectorType, selectorValue, optionsJson) {
|
|
37
|
+
const options = optionsJson ? JSON.parse(optionsJson) : undefined;
|
|
38
|
+
const nthIndex = options?.nth;
|
|
39
|
+
const roleOptions = options ? { ...options } : undefined;
|
|
40
|
+
if (roleOptions) {
|
|
41
|
+
delete roleOptions.nth;
|
|
42
|
+
}
|
|
43
|
+
let locator;
|
|
44
|
+
switch (selectorType) {
|
|
45
|
+
case "css":
|
|
46
|
+
locator = page.locator(selectorValue);
|
|
47
|
+
break;
|
|
48
|
+
case "role":
|
|
49
|
+
locator = page.getByRole(selectorValue, roleOptions && Object.keys(roleOptions).length > 0 ? roleOptions : undefined);
|
|
50
|
+
break;
|
|
51
|
+
case "text":
|
|
52
|
+
locator = page.getByText(selectorValue);
|
|
53
|
+
break;
|
|
54
|
+
case "label":
|
|
55
|
+
locator = page.getByLabel(selectorValue);
|
|
56
|
+
break;
|
|
57
|
+
case "placeholder":
|
|
58
|
+
locator = page.getByPlaceholder(selectorValue);
|
|
59
|
+
break;
|
|
60
|
+
case "testId":
|
|
61
|
+
locator = page.getByTestId(selectorValue);
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
locator = page.locator(selectorValue);
|
|
65
|
+
}
|
|
66
|
+
if (nthIndex !== undefined) {
|
|
67
|
+
locator = locator.nth(nthIndex);
|
|
68
|
+
}
|
|
69
|
+
return locator;
|
|
70
|
+
}
|
|
71
|
+
async function executeLocatorAction(locator, action, actionArg, timeout) {
|
|
72
|
+
switch (action) {
|
|
73
|
+
case "click":
|
|
74
|
+
await locator.click({ timeout });
|
|
75
|
+
return null;
|
|
76
|
+
case "dblclick":
|
|
77
|
+
await locator.dblclick({ timeout });
|
|
78
|
+
return null;
|
|
79
|
+
case "fill":
|
|
80
|
+
await locator.fill(String(actionArg ?? ""), { timeout });
|
|
81
|
+
return null;
|
|
82
|
+
case "type":
|
|
83
|
+
await locator.pressSequentially(String(actionArg ?? ""), { timeout });
|
|
84
|
+
return null;
|
|
85
|
+
case "check":
|
|
86
|
+
await locator.check({ timeout });
|
|
87
|
+
return null;
|
|
88
|
+
case "uncheck":
|
|
89
|
+
await locator.uncheck({ timeout });
|
|
90
|
+
return null;
|
|
91
|
+
case "selectOption":
|
|
92
|
+
await locator.selectOption(String(actionArg ?? ""), { timeout });
|
|
93
|
+
return null;
|
|
94
|
+
case "clear":
|
|
95
|
+
await locator.clear({ timeout });
|
|
96
|
+
return null;
|
|
97
|
+
case "press":
|
|
98
|
+
await locator.press(String(actionArg ?? ""), { timeout });
|
|
99
|
+
return null;
|
|
100
|
+
case "hover":
|
|
101
|
+
await locator.hover({ timeout });
|
|
102
|
+
return null;
|
|
103
|
+
case "focus":
|
|
104
|
+
await locator.focus({ timeout });
|
|
105
|
+
return null;
|
|
106
|
+
case "getText":
|
|
107
|
+
return await locator.textContent({ timeout });
|
|
108
|
+
case "getValue":
|
|
109
|
+
return await locator.inputValue({ timeout });
|
|
110
|
+
case "isVisible":
|
|
111
|
+
return await locator.isVisible();
|
|
112
|
+
case "isEnabled":
|
|
113
|
+
return await locator.isEnabled();
|
|
114
|
+
case "isChecked":
|
|
115
|
+
return await locator.isChecked();
|
|
116
|
+
case "count":
|
|
117
|
+
return await locator.count();
|
|
118
|
+
default:
|
|
119
|
+
throw new Error(`Unknown action: ${action}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function executeExpectAssertion(locator, matcher, expected, negated, timeout) {
|
|
123
|
+
switch (matcher) {
|
|
124
|
+
case "toBeVisible": {
|
|
125
|
+
const isVisible = await locator.isVisible();
|
|
126
|
+
if (negated) {
|
|
127
|
+
if (isVisible)
|
|
128
|
+
throw new Error("Expected element to not be visible, but it was visible");
|
|
129
|
+
} else {
|
|
130
|
+
if (!isVisible)
|
|
131
|
+
throw new Error("Expected element to be visible, but it was not");
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "toContainText": {
|
|
136
|
+
const text = await locator.textContent({ timeout });
|
|
137
|
+
const matches = text?.includes(String(expected)) ?? false;
|
|
138
|
+
if (negated) {
|
|
139
|
+
if (matches)
|
|
140
|
+
throw new Error(`Expected text to not contain "${expected}", but got "${text}"`);
|
|
141
|
+
} else {
|
|
142
|
+
if (!matches)
|
|
143
|
+
throw new Error(`Expected text to contain "${expected}", but got "${text}"`);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "toHaveValue": {
|
|
148
|
+
const value = await locator.inputValue({ timeout });
|
|
149
|
+
const matches = value === String(expected);
|
|
150
|
+
if (negated) {
|
|
151
|
+
if (matches)
|
|
152
|
+
throw new Error(`Expected value to not be "${expected}", but it was`);
|
|
153
|
+
} else {
|
|
154
|
+
if (!matches)
|
|
155
|
+
throw new Error(`Expected value to be "${expected}", but got "${value}"`);
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case "toBeEnabled": {
|
|
160
|
+
const isEnabled = await locator.isEnabled();
|
|
161
|
+
if (negated) {
|
|
162
|
+
if (isEnabled)
|
|
163
|
+
throw new Error("Expected element to be disabled, but it was enabled");
|
|
164
|
+
} else {
|
|
165
|
+
if (!isEnabled)
|
|
166
|
+
throw new Error("Expected element to be enabled, but it was disabled");
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "toBeChecked": {
|
|
171
|
+
const isChecked = await locator.isChecked();
|
|
172
|
+
if (negated) {
|
|
173
|
+
if (isChecked)
|
|
174
|
+
throw new Error("Expected element to not be checked, but it was checked");
|
|
175
|
+
} else {
|
|
176
|
+
if (!isChecked)
|
|
177
|
+
throw new Error("Expected element to be checked, but it was not");
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
default:
|
|
182
|
+
throw new Error(`Unknown matcher: ${matcher}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function createPlaywrightHandler(page, options) {
|
|
186
|
+
const timeout = options?.timeout ?? 30000;
|
|
187
|
+
const baseUrl = options?.baseUrl;
|
|
188
|
+
return async (op) => {
|
|
189
|
+
try {
|
|
190
|
+
switch (op.type) {
|
|
191
|
+
case "goto": {
|
|
192
|
+
const [url, waitUntil] = op.args;
|
|
193
|
+
const targetUrl = baseUrl && !url.startsWith("http") ? `${baseUrl}${url}` : url;
|
|
194
|
+
await page.goto(targetUrl, {
|
|
195
|
+
timeout,
|
|
196
|
+
waitUntil: waitUntil ?? "load"
|
|
197
|
+
});
|
|
198
|
+
return { ok: true };
|
|
199
|
+
}
|
|
200
|
+
case "reload":
|
|
201
|
+
await page.reload({ timeout });
|
|
202
|
+
return { ok: true };
|
|
203
|
+
case "url":
|
|
204
|
+
return { ok: true, value: page.url() };
|
|
205
|
+
case "title":
|
|
206
|
+
return { ok: true, value: await page.title() };
|
|
207
|
+
case "content":
|
|
208
|
+
return { ok: true, value: await page.content() };
|
|
209
|
+
case "waitForSelector": {
|
|
210
|
+
const [selector, optionsJson] = op.args;
|
|
211
|
+
const opts = optionsJson ? JSON.parse(optionsJson) : {};
|
|
212
|
+
await page.waitForSelector(selector, { timeout, ...opts });
|
|
213
|
+
return { ok: true };
|
|
214
|
+
}
|
|
215
|
+
case "waitForTimeout": {
|
|
216
|
+
const [ms] = op.args;
|
|
217
|
+
await page.waitForTimeout(ms);
|
|
218
|
+
return { ok: true };
|
|
219
|
+
}
|
|
220
|
+
case "waitForLoadState": {
|
|
221
|
+
const [state] = op.args;
|
|
222
|
+
await page.waitForLoadState(state ?? "load", { timeout });
|
|
223
|
+
return { ok: true };
|
|
224
|
+
}
|
|
225
|
+
case "evaluate": {
|
|
226
|
+
const [script] = op.args;
|
|
227
|
+
const result = await page.evaluate(script);
|
|
228
|
+
return { ok: true, value: result };
|
|
229
|
+
}
|
|
230
|
+
case "locatorAction": {
|
|
231
|
+
const [selectorType, selectorValue, roleOptions, action, actionArg] = op.args;
|
|
232
|
+
const locator = getLocator(page, selectorType, selectorValue, roleOptions);
|
|
233
|
+
const result = await executeLocatorAction(locator, action, actionArg, timeout);
|
|
234
|
+
return { ok: true, value: result };
|
|
235
|
+
}
|
|
236
|
+
case "expectLocator": {
|
|
237
|
+
const [selectorType, selectorValue, roleOptions, matcher, expected, negated, customTimeout] = op.args;
|
|
238
|
+
const locator = getLocator(page, selectorType, selectorValue, roleOptions);
|
|
239
|
+
const effectiveTimeout = customTimeout ?? timeout;
|
|
240
|
+
await executeExpectAssertion(locator, matcher, expected, negated ?? false, effectiveTimeout);
|
|
241
|
+
return { ok: true };
|
|
242
|
+
}
|
|
243
|
+
case "request": {
|
|
244
|
+
const [url, method, data, headers] = op.args;
|
|
245
|
+
const targetUrl = baseUrl && !url.startsWith("http") ? `${baseUrl}${url}` : url;
|
|
246
|
+
const requestOptions = {
|
|
247
|
+
timeout
|
|
248
|
+
};
|
|
249
|
+
if (headers) {
|
|
250
|
+
requestOptions.headers = headers;
|
|
251
|
+
}
|
|
252
|
+
if (data !== undefined && data !== null) {
|
|
253
|
+
requestOptions.data = data;
|
|
254
|
+
}
|
|
255
|
+
const response = await page.request.fetch(targetUrl, {
|
|
256
|
+
method,
|
|
257
|
+
...requestOptions
|
|
258
|
+
});
|
|
259
|
+
const text = await response.text();
|
|
260
|
+
let json = null;
|
|
261
|
+
try {
|
|
262
|
+
json = JSON.parse(text);
|
|
263
|
+
} catch {}
|
|
264
|
+
return {
|
|
265
|
+
ok: true,
|
|
266
|
+
value: {
|
|
267
|
+
status: response.status(),
|
|
268
|
+
ok: response.ok(),
|
|
269
|
+
headers: response.headers(),
|
|
270
|
+
text,
|
|
271
|
+
json,
|
|
272
|
+
body: null
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
default:
|
|
277
|
+
return { ok: false, error: { name: "Error", message: `Unknown operation: ${op.type}` } };
|
|
278
|
+
}
|
|
279
|
+
} catch (err) {
|
|
280
|
+
const error = err;
|
|
281
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
//# debugId=32EDBABEF8B46B5164756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/client.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Client-safe exports for @ricsam/isolate-playwright\n * This module can be imported without loading isolated-vm\n */\n\nimport type { Page, Locator as PlaywrightLocator } from \"playwright\";\nimport type {\n PlaywrightOperation,\n PlaywrightResult,\n} from \"@ricsam/isolate-protocol\";\n\n// Re-export types\nexport type {\n NetworkRequestInfo,\n NetworkResponseInfo,\n BrowserConsoleLogEntry,\n PlaywrightSetupOptions,\n PlaywrightOptions,\n PlaywrightHandle,\n} from \"./types.cjs\";\n\n// Import PlaywrightCallback for use in function return type\nimport type { PlaywrightCallback } from \"./types.cjs\";\nexport type { PlaywrightCallback };\n\nexport type { PlaywrightOperation, PlaywrightResult, PlaywrightEvent } from \"@ricsam/isolate-protocol\";\n\n// ============================================================================\n// Helper: Get locator from selector info\n// ============================================================================\n\nfunction getLocator(\n page: Page,\n selectorType: string,\n selectorValue: string,\n optionsJson: string | null\n): PlaywrightLocator {\n // Parse options and extract nth if present\n const options = optionsJson ? JSON.parse(optionsJson) : undefined;\n const nthIndex = options?.nth;\n\n // For role selectors, pass options (excluding nth) to getByRole\n const roleOptions = options ? { ...options } : undefined;\n if (roleOptions) {\n delete roleOptions.nth;\n }\n\n let locator: PlaywrightLocator;\n switch (selectorType) {\n case \"css\":\n locator = page.locator(selectorValue);\n break;\n case \"role\":\n locator = page.getByRole(\n selectorValue as Parameters<Page[\"getByRole\"]>[0],\n roleOptions && Object.keys(roleOptions).length > 0 ? roleOptions : undefined\n );\n break;\n case \"text\":\n locator = page.getByText(selectorValue);\n break;\n case \"label\":\n locator = page.getByLabel(selectorValue);\n break;\n case \"placeholder\":\n locator = page.getByPlaceholder(selectorValue);\n break;\n case \"testId\":\n locator = page.getByTestId(selectorValue);\n break;\n default:\n locator = page.locator(selectorValue);\n }\n\n // Apply nth if specified\n if (nthIndex !== undefined) {\n locator = locator.nth(nthIndex);\n }\n\n return locator;\n}\n\n// ============================================================================\n// Helper: Execute locator action\n// ============================================================================\n\nasync function executeLocatorAction(\n locator: PlaywrightLocator,\n action: string,\n actionArg: unknown,\n timeout: number\n): Promise<unknown> {\n switch (action) {\n case \"click\":\n await locator.click({ timeout });\n return null;\n case \"dblclick\":\n await locator.dblclick({ timeout });\n return null;\n case \"fill\":\n await locator.fill(String(actionArg ?? \"\"), { timeout });\n return null;\n case \"type\":\n await locator.pressSequentially(String(actionArg ?? \"\"), { timeout });\n return null;\n case \"check\":\n await locator.check({ timeout });\n return null;\n case \"uncheck\":\n await locator.uncheck({ timeout });\n return null;\n case \"selectOption\":\n await locator.selectOption(String(actionArg ?? \"\"), { timeout });\n return null;\n case \"clear\":\n await locator.clear({ timeout });\n return null;\n case \"press\":\n await locator.press(String(actionArg ?? \"\"), { timeout });\n return null;\n case \"hover\":\n await locator.hover({ timeout });\n return null;\n case \"focus\":\n await locator.focus({ timeout });\n return null;\n case \"getText\":\n return await locator.textContent({ timeout });\n case \"getValue\":\n return await locator.inputValue({ timeout });\n case \"isVisible\":\n return await locator.isVisible();\n case \"isEnabled\":\n return await locator.isEnabled();\n case \"isChecked\":\n return await locator.isChecked();\n case \"count\":\n return await locator.count();\n default:\n throw new Error(`Unknown action: ${action}`);\n }\n}\n\n// ============================================================================\n// Helper: Execute expect assertion\n// ============================================================================\n\nasync function executeExpectAssertion(\n locator: PlaywrightLocator,\n matcher: string,\n expected: unknown,\n negated: boolean,\n timeout: number\n): Promise<void> {\n switch (matcher) {\n case \"toBeVisible\": {\n const isVisible = await locator.isVisible();\n if (negated) {\n if (isVisible) throw new Error(\"Expected element to not be visible, but it was visible\");\n } else {\n if (!isVisible) throw new Error(\"Expected element to be visible, but it was not\");\n }\n break;\n }\n case \"toContainText\": {\n const text = await locator.textContent({ timeout });\n const matches = text?.includes(String(expected)) ?? false;\n if (negated) {\n if (matches) throw new Error(`Expected text to not contain \"${expected}\", but got \"${text}\"`);\n } else {\n if (!matches) throw new Error(`Expected text to contain \"${expected}\", but got \"${text}\"`);\n }\n break;\n }\n case \"toHaveValue\": {\n const value = await locator.inputValue({ timeout });\n const matches = value === String(expected);\n if (negated) {\n if (matches) throw new Error(`Expected value to not be \"${expected}\", but it was`);\n } else {\n if (!matches) throw new Error(`Expected value to be \"${expected}\", but got \"${value}\"`);\n }\n break;\n }\n case \"toBeEnabled\": {\n const isEnabled = await locator.isEnabled();\n if (negated) {\n if (isEnabled) throw new Error(\"Expected element to be disabled, but it was enabled\");\n } else {\n if (!isEnabled) throw new Error(\"Expected element to be enabled, but it was disabled\");\n }\n break;\n }\n case \"toBeChecked\": {\n const isChecked = await locator.isChecked();\n if (negated) {\n if (isChecked) throw new Error(\"Expected element to not be checked, but it was checked\");\n } else {\n if (!isChecked) throw new Error(\"Expected element to be checked, but it was not\");\n }\n break;\n }\n default:\n throw new Error(`Unknown matcher: ${matcher}`);\n }\n}\n\n// ============================================================================\n// Create Playwright Handler (for remote use)\n// ============================================================================\n\n/**\n * Create a playwright handler from a Page object.\n * This handler is called by the daemon (via callback) when sandbox needs page operations.\n * Used for remote runtime where the browser runs on the client.\n */\nexport function createPlaywrightHandler(\n page: Page,\n options?: { timeout?: number; baseUrl?: string }\n): PlaywrightCallback {\n const timeout = options?.timeout ?? 30000;\n const baseUrl = options?.baseUrl;\n\n return async (op: PlaywrightOperation): Promise<PlaywrightResult> => {\n try {\n switch (op.type) {\n case \"goto\": {\n const [url, waitUntil] = op.args as [string, string?];\n const targetUrl = baseUrl && !url.startsWith(\"http\") ? `${baseUrl}${url}` : url;\n await page.goto(targetUrl, {\n timeout,\n waitUntil: (waitUntil as \"load\" | \"domcontentloaded\" | \"networkidle\") ?? \"load\",\n });\n return { ok: true };\n }\n case \"reload\":\n await page.reload({ timeout });\n return { ok: true };\n case \"url\":\n return { ok: true, value: page.url() };\n case \"title\":\n return { ok: true, value: await page.title() };\n case \"content\":\n return { ok: true, value: await page.content() };\n case \"waitForSelector\": {\n const [selector, optionsJson] = op.args as [string, string?];\n const opts = optionsJson ? JSON.parse(optionsJson) : {};\n await page.waitForSelector(selector, { timeout, ...opts });\n return { ok: true };\n }\n case \"waitForTimeout\": {\n const [ms] = op.args as [number];\n await page.waitForTimeout(ms);\n return { ok: true };\n }\n case \"waitForLoadState\": {\n const [state] = op.args as [string?];\n await page.waitForLoadState(\n (state as \"load\" | \"domcontentloaded\" | \"networkidle\") ?? \"load\",\n { timeout }\n );\n return { ok: true };\n }\n case \"evaluate\": {\n const [script] = op.args as [string];\n const result = await page.evaluate(script);\n return { ok: true, value: result };\n }\n case \"locatorAction\": {\n const [selectorType, selectorValue, roleOptions, action, actionArg] = op.args as [\n string,\n string,\n string | null,\n string,\n unknown\n ];\n const locator = getLocator(page, selectorType, selectorValue, roleOptions);\n const result = await executeLocatorAction(locator, action, actionArg, timeout);\n return { ok: true, value: result };\n }\n case \"expectLocator\": {\n const [selectorType, selectorValue, roleOptions, matcher, expected, negated, customTimeout] = op.args as [\n string,\n string,\n string | null,\n string,\n unknown,\n boolean,\n number?\n ];\n const locator = getLocator(page, selectorType, selectorValue, roleOptions);\n const effectiveTimeout = customTimeout ?? timeout;\n await executeExpectAssertion(locator, matcher, expected, negated ?? false, effectiveTimeout);\n return { ok: true };\n }\n case \"request\": {\n const [url, method, data, headers] = op.args as [\n string,\n string,\n unknown,\n Record<string, string>?\n ];\n const targetUrl = baseUrl && !url.startsWith(\"http\") ? `${baseUrl}${url}` : url;\n const requestOptions: {\n method?: string;\n data?: unknown;\n headers?: Record<string, string>;\n timeout?: number;\n } = {\n timeout,\n };\n if (headers) {\n requestOptions.headers = headers;\n }\n if (data !== undefined && data !== null) {\n requestOptions.data = data;\n }\n\n const response = await page.request.fetch(targetUrl, {\n method: method as \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"HEAD\" | \"OPTIONS\",\n ...requestOptions,\n });\n\n // Get response data - try to parse as JSON, fall back to text\n const text = await response.text();\n let json: unknown = null;\n try {\n json = JSON.parse(text);\n } catch {\n // Not valid JSON, that's ok\n }\n\n return {\n ok: true,\n value: {\n status: response.status(),\n ok: response.ok(),\n headers: response.headers(),\n text,\n json,\n body: null, // ArrayBuffer not easily serializable, use text/json instead\n },\n };\n }\n default:\n return { ok: false, error: { name: \"Error\", message: `Unknown operation: ${(op as PlaywrightOperation).type}` } };\n }\n } catch (err) {\n const error = err as Error;\n return { ok: false, error: { name: error.name, message: error.message } };\n }\n };\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "32EDBABEF8B46B5164756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|