@saiden/browse 0.2.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 +210 -0
- package/dist/browser.d.ts +48 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.integration.test.d.ts +2 -0
- package/dist/browser.integration.test.d.ts.map +1 -0
- package/dist/browser.integration.test.js +173 -0
- package/dist/browser.integration.test.js.map +1 -0
- package/dist/browser.js +250 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.test.d.ts +2 -0
- package/dist/browser.test.d.ts.map +1 -0
- package/dist/browser.test.js +73 -0
- package/dist/browser.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +247 -0
- package/dist/cli.js.map +1 -0
- package/dist/image.d.ts +21 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +131 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +41 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +103 -0
- package/dist/logger.js.map +1 -0
- package/dist/logger.test.d.ts +2 -0
- package/dist/logger.test.d.ts.map +1 -0
- package/dist/logger.test.js +146 -0
- package/dist/logger.test.js.map +1 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +541 -0
- package/dist/mcp.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +88 -0
- package/dist/server.js.map +1 -0
- package/dist/server.test.d.ts +2 -0
- package/dist/server.test.d.ts.map +1 -0
- package/dist/server.test.js +164 -0
- package/dist/server.test.js.map +1 -0
- package/dist/types.d.ts +125 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# @saiden/browse
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@saiden/browse)
|
|
4
|
+
[](https://github.com/saiden-dev/browse/actions/workflows/ci.yml)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
|
|
8
|
+
#### Headless browser automation for Claude Code using Playwright WebKit.
|
|
9
|
+
|
|
10
|
+
<img width="1040" height="588" alt="image" src="https://github.com/user-attachments/assets/e5436f5c-b46d-4d1b-8f5a-54044969d095" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @saiden/browse
|
|
16
|
+
npx playwright install webkit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## CLI Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Take a screenshot
|
|
23
|
+
claude-browse https://example.com
|
|
24
|
+
|
|
25
|
+
# Custom viewport and output
|
|
26
|
+
claude-browse -o page.png -w 1920 -h 1080 https://example.com
|
|
27
|
+
|
|
28
|
+
# Query elements
|
|
29
|
+
claude-browse -q "a[href]" https://example.com
|
|
30
|
+
claude-browse -q "img" -j https://example.com # JSON output
|
|
31
|
+
|
|
32
|
+
# Click and interact
|
|
33
|
+
claude-browse -c "button.submit" https://example.com
|
|
34
|
+
claude-browse -t "input[name=q]=hello" -c "button[type=submit]" https://google.com
|
|
35
|
+
|
|
36
|
+
# Chain actions
|
|
37
|
+
claude-browse -c ".cookie-accept" -c "a.nav-link" -q "h1" https://example.com
|
|
38
|
+
|
|
39
|
+
# Interactive mode (visible browser)
|
|
40
|
+
claude-browse -i --headed https://example.com
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Server Mode
|
|
44
|
+
|
|
45
|
+
Start a persistent browser server that accepts commands via HTTP:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
claude-browse -s 3000 # headless
|
|
49
|
+
claude-browse -s 3000 --headed # visible browser
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Send commands:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Navigate
|
|
56
|
+
curl -X POST localhost:3000 -d '{"cmd":"goto","url":"https://example.com"}'
|
|
57
|
+
|
|
58
|
+
# Click
|
|
59
|
+
curl -X POST localhost:3000 -d '{"cmd":"click","selector":"button.submit"}'
|
|
60
|
+
|
|
61
|
+
# Type
|
|
62
|
+
curl -X POST localhost:3000 -d '{"cmd":"type","selector":"#search","text":"hello"}'
|
|
63
|
+
|
|
64
|
+
# Query elements
|
|
65
|
+
curl -X POST localhost:3000 -d '{"cmd":"query","selector":"a[href]"}'
|
|
66
|
+
|
|
67
|
+
# Screenshot
|
|
68
|
+
curl -X POST localhost:3000 -d '{"cmd":"screenshot","path":"page.png"}'
|
|
69
|
+
|
|
70
|
+
# Get current URL
|
|
71
|
+
curl -X POST localhost:3000 -d '{"cmd":"url"}'
|
|
72
|
+
|
|
73
|
+
# Get page HTML
|
|
74
|
+
curl -X POST localhost:3000 -d '{"cmd":"html"}'
|
|
75
|
+
|
|
76
|
+
# Navigation
|
|
77
|
+
curl -X POST localhost:3000 -d '{"cmd":"back"}'
|
|
78
|
+
curl -X POST localhost:3000 -d '{"cmd":"forward"}'
|
|
79
|
+
curl -X POST localhost:3000 -d '{"cmd":"reload"}'
|
|
80
|
+
|
|
81
|
+
# Wait
|
|
82
|
+
curl -X POST localhost:3000 -d '{"cmd":"wait","ms":2000}'
|
|
83
|
+
|
|
84
|
+
# Close server
|
|
85
|
+
curl -X POST localhost:3000 -d '{"cmd":"close"}'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Claude Code Plugin (Recommended)
|
|
89
|
+
|
|
90
|
+
Install as a Claude Code plugin for the best integration:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Via marketplace (recommended)
|
|
94
|
+
claude plugin marketplace add https://github.com/saiden-dev/claude-plugins
|
|
95
|
+
claude plugin install browse
|
|
96
|
+
|
|
97
|
+
# Or direct from GitHub
|
|
98
|
+
claude plugin install github:saiden-dev/browse
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Prerequisites:** Node.js 18+ (the MCP server runs via npx)
|
|
102
|
+
|
|
103
|
+
### Plugin Features
|
|
104
|
+
|
|
105
|
+
**Slash Commands:**
|
|
106
|
+
|
|
107
|
+
| Command | Description |
|
|
108
|
+
|---------|-------------|
|
|
109
|
+
| `/browse:start` | Start an interactive browsing session |
|
|
110
|
+
| `/browse:goto <url>` | Navigate to URL and describe findings |
|
|
111
|
+
| `/browse:screenshot` | Take a screenshot of the current page |
|
|
112
|
+
| `/browse:scrape <url>` | Scrape content from a webpage |
|
|
113
|
+
| `/browse:analyze` | Analyze current page content and structure |
|
|
114
|
+
| `/browse:extract [selector]` | Extract structured data from page |
|
|
115
|
+
| `/browse:fill [data]` | Help fill out forms |
|
|
116
|
+
| `/browse:compare [action]` | Compare page states before/after action |
|
|
117
|
+
| `/browse:save` | Save current session state to file |
|
|
118
|
+
| `/browse:restore` | Restore a previously saved session |
|
|
119
|
+
| `/browse:end` | End the browsing session and close browser |
|
|
120
|
+
|
|
121
|
+
**MCP Resources (@ mentions):**
|
|
122
|
+
|
|
123
|
+
| Resource | Description |
|
|
124
|
+
|----------|-------------|
|
|
125
|
+
| `@browse:browser://state` | Browser state (URL, title, launched) |
|
|
126
|
+
| `@browse:browser://html` | Page HTML (truncated to 10KB) |
|
|
127
|
+
| `@browse:browser://html/full` | Complete page HTML |
|
|
128
|
+
| `@browse:browser://screenshot` | Page screenshot as base64 PNG |
|
|
129
|
+
|
|
130
|
+
## MCP Server (Standalone)
|
|
131
|
+
|
|
132
|
+
Use with any MCP-compatible client:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Run the MCP server
|
|
136
|
+
browse-mcp
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Add to Claude Code's MCP config (`~/.claude/settings.json`):
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"mcpServers": {
|
|
144
|
+
"browser": {
|
|
145
|
+
"command": "browse-mcp"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Available Tools:** `goto`, `click`, `type`, `query`, `screenshot`, `url`, `html`, `back`, `forward`, `reload`, `wait`, `eval`
|
|
152
|
+
|
|
153
|
+
**Image Processing Tools:** `favicon`, `convert`, `resize`, `crop`, `compress`, `thumbnail`
|
|
154
|
+
|
|
155
|
+
## Programmatic Usage
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { ClaudeBrowser, startServer } from '@saiden/browse';
|
|
159
|
+
|
|
160
|
+
// Direct browser control
|
|
161
|
+
const browser = new ClaudeBrowser({
|
|
162
|
+
headless: true,
|
|
163
|
+
width: 1280,
|
|
164
|
+
height: 800,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await browser.launch();
|
|
168
|
+
await browser.goto('https://example.com');
|
|
169
|
+
|
|
170
|
+
const elements = await browser.query('a[href]');
|
|
171
|
+
console.log(elements);
|
|
172
|
+
|
|
173
|
+
await browser.click('button.submit');
|
|
174
|
+
await browser.type('#input', 'hello');
|
|
175
|
+
await browser.screenshot('page.png');
|
|
176
|
+
|
|
177
|
+
await browser.close();
|
|
178
|
+
|
|
179
|
+
// Or start a server
|
|
180
|
+
const server = await startServer({ port: 3000, headless: false });
|
|
181
|
+
// Server runs until closed via HTTP or SIGINT
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## API
|
|
185
|
+
|
|
186
|
+
### ClaudeBrowser
|
|
187
|
+
|
|
188
|
+
- `launch()` - Launch the browser
|
|
189
|
+
- `close()` - Close the browser
|
|
190
|
+
- `goto(url)` - Navigate to URL
|
|
191
|
+
- `click(selector)` - Click element
|
|
192
|
+
- `type(selector, text)` - Type into input
|
|
193
|
+
- `query(selector)` - Query elements, returns attributes
|
|
194
|
+
- `screenshot(path?, fullPage?)` - Take screenshot
|
|
195
|
+
- `getUrl()` - Get current URL and title
|
|
196
|
+
- `getHtml(full?)` - Get page HTML
|
|
197
|
+
- `back()` / `forward()` / `reload()` - Navigation
|
|
198
|
+
- `wait(ms)` - Wait for timeout
|
|
199
|
+
- `newPage()` - Open new page
|
|
200
|
+
- `executeCommand(cmd)` - Execute a command object
|
|
201
|
+
|
|
202
|
+
### BrowserServer
|
|
203
|
+
|
|
204
|
+
- `start()` - Start HTTP server
|
|
205
|
+
- `stop()` - Stop server and close browser
|
|
206
|
+
- `getPort()` - Get server port
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type BrowserContext, type Page } from 'playwright';
|
|
2
|
+
import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
|
|
3
|
+
export declare class ClaudeBrowser {
|
|
4
|
+
private browser;
|
|
5
|
+
private context;
|
|
6
|
+
private page;
|
|
7
|
+
private options;
|
|
8
|
+
constructor(options?: BrowserOptions);
|
|
9
|
+
launch(): Promise<void>;
|
|
10
|
+
close(): Promise<void>;
|
|
11
|
+
private ensurePage;
|
|
12
|
+
/** Get the current page instance (for advanced usage) */
|
|
13
|
+
getPage(): Page | null;
|
|
14
|
+
/** Get the browser context (for advanced usage like cookies) */
|
|
15
|
+
getContext(): BrowserContext | null;
|
|
16
|
+
goto(url: string): Promise<{
|
|
17
|
+
url: string;
|
|
18
|
+
title: string;
|
|
19
|
+
}>;
|
|
20
|
+
click(selector: string): Promise<{
|
|
21
|
+
url: string;
|
|
22
|
+
}>;
|
|
23
|
+
type(selector: string, text: string): Promise<void>;
|
|
24
|
+
query(selector: string): Promise<ElementInfo[]>;
|
|
25
|
+
screenshot(path?: string, fullPage?: boolean): Promise<{
|
|
26
|
+
path: string;
|
|
27
|
+
buffer?: Buffer;
|
|
28
|
+
}>;
|
|
29
|
+
getUrl(): Promise<{
|
|
30
|
+
url: string;
|
|
31
|
+
title: string;
|
|
32
|
+
}>;
|
|
33
|
+
getHtml(full?: boolean): Promise<string>;
|
|
34
|
+
back(): Promise<{
|
|
35
|
+
url: string;
|
|
36
|
+
}>;
|
|
37
|
+
forward(): Promise<{
|
|
38
|
+
url: string;
|
|
39
|
+
}>;
|
|
40
|
+
reload(): Promise<{
|
|
41
|
+
url: string;
|
|
42
|
+
}>;
|
|
43
|
+
wait(ms?: number): Promise<void>;
|
|
44
|
+
newPage(): Promise<void>;
|
|
45
|
+
eval(script: string): Promise<unknown>;
|
|
46
|
+
executeCommand(cmd: BrowserCommand): Promise<CommandResponse>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAU,MAAM,YAAY,CAAC;AAElF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/F,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,GAAE,cAAmB;IAQlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,UAAU;IAOlB,yDAAyD;IACzD,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,gEAAgE;IAChE,UAAU,IAAI,cAAc,GAAG,IAAI;IAI7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1D,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB/C,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvF,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKjD,OAAO,CAAC,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtC,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhC,OAAO,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlC,IAAI,CAAC,EAAE,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAsIpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.integration.test.d.ts","sourceRoot":"","sources":["../src/browser.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { ClaudeBrowser } from './browser.js';
|
|
3
|
+
describe('ClaudeBrowser Integration', () => {
|
|
4
|
+
let browser;
|
|
5
|
+
beforeAll(async () => {
|
|
6
|
+
browser = new ClaudeBrowser({ headless: true });
|
|
7
|
+
await browser.launch();
|
|
8
|
+
}, 30000);
|
|
9
|
+
afterAll(async () => {
|
|
10
|
+
await browser.close();
|
|
11
|
+
});
|
|
12
|
+
describe('navigation', () => {
|
|
13
|
+
it('navigates to a URL and returns title', async () => {
|
|
14
|
+
const result = await browser.goto('https://example.com');
|
|
15
|
+
expect(result.url).toContain('example.com');
|
|
16
|
+
expect(result.title).toBe('Example Domain');
|
|
17
|
+
});
|
|
18
|
+
it('gets current URL and title', async () => {
|
|
19
|
+
const result = await browser.getUrl();
|
|
20
|
+
expect(result.url).toContain('example.com');
|
|
21
|
+
expect(result.title).toBe('Example Domain');
|
|
22
|
+
});
|
|
23
|
+
it('gets page HTML', async () => {
|
|
24
|
+
const html = await browser.getHtml();
|
|
25
|
+
expect(html.toLowerCase()).toContain('<!doctype html>');
|
|
26
|
+
expect(html).toContain('Example Domain');
|
|
27
|
+
});
|
|
28
|
+
it('gets full page HTML', async () => {
|
|
29
|
+
const html = await browser.getHtml(true);
|
|
30
|
+
expect(html.toLowerCase()).toContain('<!doctype html>');
|
|
31
|
+
expect(html.length).toBeGreaterThan(100);
|
|
32
|
+
});
|
|
33
|
+
it('reloads the page', async () => {
|
|
34
|
+
const result = await browser.reload();
|
|
35
|
+
expect(result.url).toContain('example.com');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('DOM interaction', () => {
|
|
39
|
+
it('queries elements', async () => {
|
|
40
|
+
const elements = await browser.query('h1');
|
|
41
|
+
expect(elements.length).toBe(1);
|
|
42
|
+
expect(elements[0].tag).toBe('h1');
|
|
43
|
+
expect(elements[0].text).toContain('Example Domain');
|
|
44
|
+
});
|
|
45
|
+
it('queries multiple elements', async () => {
|
|
46
|
+
const elements = await browser.query('p');
|
|
47
|
+
expect(elements.length).toBeGreaterThan(0);
|
|
48
|
+
expect(elements[0].tag).toBe('p');
|
|
49
|
+
});
|
|
50
|
+
it('clicks an element', async () => {
|
|
51
|
+
await browser.goto('https://example.com');
|
|
52
|
+
const result = await browser.click('a');
|
|
53
|
+
expect(result.url).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('screenshots', () => {
|
|
57
|
+
it('takes a screenshot', async () => {
|
|
58
|
+
await browser.goto('https://example.com');
|
|
59
|
+
const result = await browser.screenshot('screenshots/test-integration.png');
|
|
60
|
+
expect(result.path).toContain('test-integration.png');
|
|
61
|
+
expect(result.buffer).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
it('takes a full page screenshot', async () => {
|
|
64
|
+
const result = await browser.screenshot('screenshots/test-full.png', true);
|
|
65
|
+
expect(result.path).toContain('test-full.png');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('wait', () => {
|
|
69
|
+
it('waits for specified time', async () => {
|
|
70
|
+
const start = Date.now();
|
|
71
|
+
await browser.wait(100);
|
|
72
|
+
const elapsed = Date.now() - start;
|
|
73
|
+
expect(elapsed).toBeGreaterThanOrEqual(90);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('eval', () => {
|
|
77
|
+
it('evaluates JavaScript', async () => {
|
|
78
|
+
await browser.goto('https://example.com');
|
|
79
|
+
const result = await browser.eval('document.title');
|
|
80
|
+
expect(result).toBe('Example Domain');
|
|
81
|
+
});
|
|
82
|
+
it('evaluates expressions', async () => {
|
|
83
|
+
const result = await browser.eval('1 + 1');
|
|
84
|
+
expect(result).toBe(2);
|
|
85
|
+
});
|
|
86
|
+
it('evaluates complex expressions', async () => {
|
|
87
|
+
const result = await browser.eval('document.querySelectorAll("p").length');
|
|
88
|
+
expect(result).toBeGreaterThan(0);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('pages', () => {
|
|
92
|
+
it('creates a new page', async () => {
|
|
93
|
+
await browser.newPage();
|
|
94
|
+
const result = await browser.getUrl();
|
|
95
|
+
expect(result.url).toBe('about:blank');
|
|
96
|
+
});
|
|
97
|
+
it('navigates in new page', async () => {
|
|
98
|
+
const result = await browser.goto('https://example.com');
|
|
99
|
+
expect(result.title).toBe('Example Domain');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('executeCommand', () => {
|
|
103
|
+
it('handles goto command', async () => {
|
|
104
|
+
const result = await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
|
|
105
|
+
expect(result.ok).toBe(true);
|
|
106
|
+
if (result.ok) {
|
|
107
|
+
expect(result.title).toBe('Example Domain');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
it('handles query command', async () => {
|
|
111
|
+
const result = await browser.executeCommand({ cmd: 'query', selector: 'h1' });
|
|
112
|
+
expect(result.ok).toBe(true);
|
|
113
|
+
if (result.ok) {
|
|
114
|
+
expect(result.count).toBe(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
it('handles url command', async () => {
|
|
118
|
+
const result = await browser.executeCommand({ cmd: 'url' });
|
|
119
|
+
expect(result.ok).toBe(true);
|
|
120
|
+
if (result.ok) {
|
|
121
|
+
expect(result.url).toContain('example.com');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
it('handles html command', async () => {
|
|
125
|
+
const result = await browser.executeCommand({ cmd: 'html' });
|
|
126
|
+
expect(result.ok).toBe(true);
|
|
127
|
+
if (result.ok) {
|
|
128
|
+
expect(result.html).toContain('Example');
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
it('handles wait command', async () => {
|
|
132
|
+
const result = await browser.executeCommand({ cmd: 'wait', ms: 50 });
|
|
133
|
+
expect(result.ok).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
it('handles eval command', async () => {
|
|
136
|
+
const result = await browser.executeCommand({ cmd: 'eval', script: '2+2' });
|
|
137
|
+
expect(result.ok).toBe(true);
|
|
138
|
+
if (result.ok) {
|
|
139
|
+
expect(result.result).toBe(4);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
it('handles screenshot command', async () => {
|
|
143
|
+
const result = await browser.executeCommand({
|
|
144
|
+
cmd: 'screenshot',
|
|
145
|
+
path: 'screenshots/cmd-test.png',
|
|
146
|
+
});
|
|
147
|
+
expect(result.ok).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
it('handles reload command', async () => {
|
|
150
|
+
const result = await browser.executeCommand({ cmd: 'reload' });
|
|
151
|
+
expect(result.ok).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
it('handles click command', async () => {
|
|
154
|
+
await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
|
|
155
|
+
const result = await browser.executeCommand({ cmd: 'click', selector: 'a' });
|
|
156
|
+
expect(result.ok).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
it('handles newpage command', async () => {
|
|
159
|
+
const result = await browser.executeCommand({ cmd: 'newpage' });
|
|
160
|
+
expect(result.ok).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
it('handles back command', async () => {
|
|
163
|
+
await browser.executeCommand({ cmd: 'goto', url: 'https://example.com' });
|
|
164
|
+
const result = await browser.executeCommand({ cmd: 'back' });
|
|
165
|
+
expect(result.ok).toBe(true);
|
|
166
|
+
});
|
|
167
|
+
it('handles forward command', async () => {
|
|
168
|
+
const result = await browser.executeCommand({ cmd: 'forward' });
|
|
169
|
+
expect(result.ok).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=browser.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.integration.test.js","sourceRoot":"","sources":["../src/browser.integration.test.ts"],"names":[],"mappings":"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"}
|