cdp-tunnel 1.0.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/.github/workflows/publish.yml +92 -0
- package/.github/workflows/release-assets.yml +50 -0
- package/LICENSE +81 -0
- package/PUBLISH.md +65 -0
- package/README.md +228 -0
- package/cli/guide.html +753 -0
- package/cli/icon.svg +13 -0
- package/cli/icon128.png +0 -0
- package/cli/index.js +357 -0
- package/docs/README_CN.md +204 -0
- package/docs/config-page-screenshot.png +0 -0
- package/extension-new/background.js +294 -0
- package/extension-new/cdp/handler/forward.js +44 -0
- package/extension-new/cdp/handler/local.js +233 -0
- package/extension-new/cdp/handler/special.js +442 -0
- package/extension-new/cdp/index.js +104 -0
- package/extension-new/cdp/response.js +49 -0
- package/extension-new/config-page-preview.html +769 -0
- package/extension-new/config-page.js +318 -0
- package/extension-new/core/debugger.js +310 -0
- package/extension-new/core/state.js +384 -0
- package/extension-new/core/websocket.js +326 -0
- package/extension-new/features/automation-badge.js +113 -0
- package/extension-new/features/screencast.js +221 -0
- package/extension-new/icons/icon128.png +0 -0
- package/extension-new/icons/icon16.png +0 -0
- package/extension-new/icons/icon48.png +0 -0
- package/extension-new/manifest.json +39 -0
- package/extension-new/popup.html +72 -0
- package/extension-new/popup.js +34 -0
- package/extension-new/utils/config.js +20 -0
- package/extension-new/utils/diagnostics.js +560 -0
- package/extension-new/utils/helpers.js +25 -0
- package/extension-new/utils/logger.js +64 -0
- package/package.json +42 -0
- package/server/modules/config.js +28 -0
- package/server/modules/logger.js +197 -0
- package/server/proxy-server.js +1431 -0
- package/tests/playwright-demo.js +45 -0
- package/tests/playwright-interactive.js +261 -0
- package/tests/playwright-multi-demo.js +60 -0
- package/tests/playwright-multi.js +85 -0
- package/tests/playwright-single.js +41 -0
- package/tests/screenshot-config.js +35 -0
- package/tests/test-client.js +89 -0
- package/tests/test-multi-client.js +129 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
console.log('[Playwright] Connecting to http://localhost:9221...');
|
|
5
|
+
|
|
6
|
+
const browser = await chromium.connectOverCDP('http://localhost:9221');
|
|
7
|
+
console.log('[Playwright] Connected!');
|
|
8
|
+
|
|
9
|
+
const context = browser.contexts()[0];
|
|
10
|
+
const pages = context?.pages() || [];
|
|
11
|
+
console.log('[Playwright] Found', pages.length, 'page(s)');
|
|
12
|
+
|
|
13
|
+
console.log('\n>>> 请现在打开配置页面查看状态:');
|
|
14
|
+
console.log('>>> chrome-extension://bchclccgjmihieacfmaelkpfjlghhoph/config-page-preview.html');
|
|
15
|
+
console.log('>>> 等待 10 秒...\n');
|
|
16
|
+
|
|
17
|
+
await new Promise(r => setTimeout(r, 10000));
|
|
18
|
+
|
|
19
|
+
console.log('[Playwright] Creating new page...');
|
|
20
|
+
const page = await context.newPage();
|
|
21
|
+
await page.goto('https://www.baidu.com');
|
|
22
|
+
console.log('[Playwright] New page URL:', page.url());
|
|
23
|
+
|
|
24
|
+
console.log('\n>>> 新页面已创建,请查看配置页面是否显示');
|
|
25
|
+
console.log('>>> 等待 10 秒...\n');
|
|
26
|
+
|
|
27
|
+
await new Promise(r => setTimeout(r, 10000));
|
|
28
|
+
|
|
29
|
+
console.log('[Playwright] Scrolling...');
|
|
30
|
+
for (let i = 0; i < 3; i++) {
|
|
31
|
+
await page.evaluate(() => window.scrollBy(0, 100));
|
|
32
|
+
await new Promise(r => setTimeout(r, 500));
|
|
33
|
+
console.log(' Scrolled', i + 1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('\n>>> 滚动完成,请查看配置页面');
|
|
37
|
+
console.log('>>> 等待 5 秒后关闭...\n');
|
|
38
|
+
|
|
39
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
40
|
+
|
|
41
|
+
console.log('[Playwright] Done!');
|
|
42
|
+
await browser.close();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
|
|
4
|
+
const SERVER_URL = process.env.CDP_SERVER || 'http://localhost:9221';
|
|
5
|
+
|
|
6
|
+
const clients = [];
|
|
7
|
+
let currentClient = 0;
|
|
8
|
+
|
|
9
|
+
async function createClient(name) {
|
|
10
|
+
console.log(`[${name}] Connecting to ${SERVER_URL}...`);
|
|
11
|
+
|
|
12
|
+
const browser = await chromium.connectOverCDP(SERVER_URL);
|
|
13
|
+
const context = browser.contexts()[0];
|
|
14
|
+
|
|
15
|
+
console.log(`[${name}] Connected!`);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
browser,
|
|
20
|
+
context,
|
|
21
|
+
pages: context?.pages() || [],
|
|
22
|
+
commandId: 1
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
console.log('\n=== Playwright Multi-Client Interactive Test ===\n');
|
|
28
|
+
console.log(`Server: ${SERVER_URL}\n`);
|
|
29
|
+
|
|
30
|
+
const rl = readline.createInterface({
|
|
31
|
+
input: process.stdin,
|
|
32
|
+
output: process.stdout
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const commands = {
|
|
36
|
+
help: () => {
|
|
37
|
+
console.log(`
|
|
38
|
+
Commands:
|
|
39
|
+
c <name> - Create new client with name
|
|
40
|
+
l - List all clients
|
|
41
|
+
s <client> <page> - Switch to client/page
|
|
42
|
+
n <url> - Create new page with URL
|
|
43
|
+
g <url> - Navigate current page to URL
|
|
44
|
+
scroll <distance> - Scroll current page
|
|
45
|
+
click <selector> - Click element on current page
|
|
46
|
+
type <selector> <text> - Type text into element
|
|
47
|
+
eval <code> - Evaluate JavaScript
|
|
48
|
+
screenshot <file> - Take screenshot
|
|
49
|
+
info - Show current page info
|
|
50
|
+
close <client> - Close specific client
|
|
51
|
+
q - Quit
|
|
52
|
+
`);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
list: () => {
|
|
56
|
+
console.log(`\nClients (${clients.length}):`);
|
|
57
|
+
clients.forEach((c, i) => {
|
|
58
|
+
console.log(` [${i}] ${c.name} - ${c.pages.length} page(s)`);
|
|
59
|
+
c.pages.forEach((p, j) => {
|
|
60
|
+
console.log(` Page ${j}: ${p.url()?.substring(0, 50)}`);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
console.log('');
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
create: async (name) => {
|
|
67
|
+
if (!name) {
|
|
68
|
+
console.log('Usage: c <name>');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const client = await createClient(name);
|
|
72
|
+
clients.push(client);
|
|
73
|
+
currentClient = clients.length - 1;
|
|
74
|
+
console.log(`Created client "${name}", switched to it.\n`);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
switch: (clientIdx, pageIdx) => {
|
|
78
|
+
const ci = parseInt(clientIdx);
|
|
79
|
+
const pi = parseInt(pageIdx) || 0;
|
|
80
|
+
if (ci >= 0 && ci < clients.length) {
|
|
81
|
+
currentClient = ci;
|
|
82
|
+
console.log(`Switched to client ${ci}, page ${pi}\n`);
|
|
83
|
+
} else {
|
|
84
|
+
console.log('Invalid client index\n');
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
newPage: async (url) => {
|
|
89
|
+
const client = clients[currentClient];
|
|
90
|
+
if (!client) {
|
|
91
|
+
console.log('No client selected. Use "c <name>" to create one.\n');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const page = await client.context.newPage();
|
|
95
|
+
client.pages.push(page);
|
|
96
|
+
if (url) {
|
|
97
|
+
await page.goto(url);
|
|
98
|
+
}
|
|
99
|
+
console.log(`Created page ${client.pages.length - 1}: ${page.url()}\n`);
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
goto: async (url) => {
|
|
103
|
+
const client = clients[currentClient];
|
|
104
|
+
const page = client?.pages[0];
|
|
105
|
+
if (!page) {
|
|
106
|
+
console.log('No page available.\n');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
await page.goto(url);
|
|
110
|
+
console.log(`Navigated to: ${page.url()}\n`);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
scroll: async (distance = 100) => {
|
|
114
|
+
const client = clients[currentClient];
|
|
115
|
+
const page = client?.pages[0];
|
|
116
|
+
if (!page) return;
|
|
117
|
+
await page.evaluate((d) => window.scrollBy(0, d), parseInt(distance));
|
|
118
|
+
console.log(`Scrolled ${distance}px\n`);
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
click: async (selector) => {
|
|
122
|
+
const client = clients[currentClient];
|
|
123
|
+
const page = client?.pages[0];
|
|
124
|
+
if (!page) return;
|
|
125
|
+
await page.click(selector);
|
|
126
|
+
console.log(`Clicked: ${selector}\n`);
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
type: async (selector, text) => {
|
|
130
|
+
const client = clients[currentClient];
|
|
131
|
+
const page = client?.pages[0];
|
|
132
|
+
if (!page) return;
|
|
133
|
+
await page.fill(selector, text);
|
|
134
|
+
console.log(`Typed into: ${selector}\n`);
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
eval: async (code) => {
|
|
138
|
+
const client = clients[currentClient];
|
|
139
|
+
const page = client?.pages[0];
|
|
140
|
+
if (!page) return;
|
|
141
|
+
const result = await page.evaluate(code);
|
|
142
|
+
console.log(`Result:`, result, '\n');
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
screenshot: async (filename = 'screenshot.png') => {
|
|
146
|
+
const client = clients[currentClient];
|
|
147
|
+
const page = client?.pages[0];
|
|
148
|
+
if (!page) return;
|
|
149
|
+
await page.screenshot({ path: `tests/${filename}` });
|
|
150
|
+
console.log(`Saved: tests/${filename}\n`);
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
info: async () => {
|
|
154
|
+
const client = clients[currentClient];
|
|
155
|
+
const page = client?.pages[0];
|
|
156
|
+
if (!page) {
|
|
157
|
+
console.log('No page available.\n');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
console.log(`
|
|
161
|
+
Client: ${client.name}
|
|
162
|
+
Page URL: ${page.url()}
|
|
163
|
+
Page Title: ${await page.title()}
|
|
164
|
+
`);
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
closeClient: async (idx) => {
|
|
168
|
+
const i = parseInt(idx);
|
|
169
|
+
if (i >= 0 && i < clients.length) {
|
|
170
|
+
await clients[i].browser.close();
|
|
171
|
+
console.log(`Closed client ${i}: ${clients[i].name}\n`);
|
|
172
|
+
clients.splice(i, 1);
|
|
173
|
+
if (currentClient >= clients.length) {
|
|
174
|
+
currentClient = Math.max(0, clients.length - 1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
quit: async () => {
|
|
180
|
+
console.log('\nClosing all clients...');
|
|
181
|
+
for (const c of clients) {
|
|
182
|
+
await c.browser.close();
|
|
183
|
+
}
|
|
184
|
+
rl.close();
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
console.log('Type "help" for commands.\n');
|
|
190
|
+
|
|
191
|
+
rl.on('line', async (input) => {
|
|
192
|
+
const parts = input.trim().split(/\s+/);
|
|
193
|
+
const cmd = parts[0];
|
|
194
|
+
const args = parts.slice(1);
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
switch (cmd) {
|
|
198
|
+
case 'help':
|
|
199
|
+
case 'h':
|
|
200
|
+
case '?':
|
|
201
|
+
commands.help();
|
|
202
|
+
break;
|
|
203
|
+
case 'l':
|
|
204
|
+
case 'list':
|
|
205
|
+
commands.list();
|
|
206
|
+
break;
|
|
207
|
+
case 'c':
|
|
208
|
+
await commands.create(args[0]);
|
|
209
|
+
break;
|
|
210
|
+
case 's':
|
|
211
|
+
commands.switch(args[0], args[1]);
|
|
212
|
+
break;
|
|
213
|
+
case 'n':
|
|
214
|
+
await commands.newPage(args[0]);
|
|
215
|
+
break;
|
|
216
|
+
case 'g':
|
|
217
|
+
await commands.goto(args[0]);
|
|
218
|
+
break;
|
|
219
|
+
case 'scroll':
|
|
220
|
+
await commands.scroll(args[0]);
|
|
221
|
+
break;
|
|
222
|
+
case 'click':
|
|
223
|
+
await commands.click(args[0]);
|
|
224
|
+
break;
|
|
225
|
+
case 'type':
|
|
226
|
+
await commands.type(args[0], args[1]);
|
|
227
|
+
break;
|
|
228
|
+
case 'eval':
|
|
229
|
+
await commands.eval(args.join(' '));
|
|
230
|
+
break;
|
|
231
|
+
case 'screenshot':
|
|
232
|
+
await commands.screenshot(args[0]);
|
|
233
|
+
break;
|
|
234
|
+
case 'info':
|
|
235
|
+
case 'i':
|
|
236
|
+
await commands.info();
|
|
237
|
+
break;
|
|
238
|
+
case 'close':
|
|
239
|
+
await commands.closeClient(args[0]);
|
|
240
|
+
break;
|
|
241
|
+
case 'q':
|
|
242
|
+
case 'quit':
|
|
243
|
+
case 'exit':
|
|
244
|
+
await commands.quit();
|
|
245
|
+
break;
|
|
246
|
+
default:
|
|
247
|
+
console.log('Unknown command. Type "help" for commands.\n');
|
|
248
|
+
}
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error('Error:', err.message, '\n');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
rl.prompt();
|
|
254
|
+
}).on('close', async () => {
|
|
255
|
+
await commands.quit();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
rl.prompt();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
const SERVER_URL = process.env.CDP_SERVER || 'http://localhost:9221';
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
console.log('\n=== 多客户端测试 ===\n');
|
|
7
|
+
console.log('服务器地址:', SERVER_URL);
|
|
8
|
+
console.log('\n提示: 所有客户端连接同一个端点,服务器自动分配不同的 clientId\n');
|
|
9
|
+
|
|
10
|
+
const clients = [];
|
|
11
|
+
|
|
12
|
+
// 创建 3 个客户端
|
|
13
|
+
for (let i = 1; i <= 3; i++) {
|
|
14
|
+
console.log(`[Client ${i}] 连接中...`);
|
|
15
|
+
const browser = await chromium.connectOverCDP(SERVER_URL);
|
|
16
|
+
const context = browser.contexts()[0];
|
|
17
|
+
clients.push({ id: i, browser, context, pages: [] });
|
|
18
|
+
console.log(`[Client ${i}] 已连接!`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('\n>>> 请打开配置页面查看 3 个 CDP 客户端:');
|
|
22
|
+
console.log('>>> chrome-extension://bchclccgjmihieacfmaelkpfjlghhoph/config-page-preview.html');
|
|
23
|
+
console.log('>>> 等待 15 秒...\n');
|
|
24
|
+
|
|
25
|
+
await new Promise(r => setTimeout(r, 15000));
|
|
26
|
+
|
|
27
|
+
// 每个客户端创建一个页面
|
|
28
|
+
for (const client of clients) {
|
|
29
|
+
console.log(`[Client ${client.id}] 创建页面...`);
|
|
30
|
+
const page = await client.context.newPage();
|
|
31
|
+
await page.goto('https://www.baidu.com');
|
|
32
|
+
client.pages.push(page);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('\n>>> 3 个页面已创建,等待 10 秒...\n');
|
|
36
|
+
await new Promise(r => setTimeout(r, 10000));
|
|
37
|
+
|
|
38
|
+
// 并发操作
|
|
39
|
+
console.log('>>> 并发滚动测试...\n');
|
|
40
|
+
await Promise.all(clients.map(async (client) => {
|
|
41
|
+
for (let i = 0; i < 3; i++) {
|
|
42
|
+
await client.pages[0].evaluate(() => window.scrollBy(0, 100));
|
|
43
|
+
console.log(`[Client ${client.id}] 滚动 ${i + 1}`);
|
|
44
|
+
await new Promise(r => setTimeout(r, 300));
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
console.log('\n>>> 测试完成,等待 5 秒后关闭...\n');
|
|
49
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
50
|
+
|
|
51
|
+
// 关闭所有客户端
|
|
52
|
+
for (const client of clients) {
|
|
53
|
+
console.log(`[Client ${client.id}] 关闭...`);
|
|
54
|
+
await client.browser.close();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('\n所有客户端已关闭。');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
const SERVER_URL = process.env.CDP_SERVER || 'http://localhost:9221';
|
|
4
|
+
const NUM_CLIENTS = parseInt(process.env.NUM_CLIENTS) || 2;
|
|
5
|
+
|
|
6
|
+
async function createClient(clientId) {
|
|
7
|
+
console.log(`[${clientId}] Connecting to ${SERVER_URL}...`);
|
|
8
|
+
|
|
9
|
+
const browser = await chromium.connectOverCDP(SERVER_URL);
|
|
10
|
+
console.log(`[${clientId}] Connected!`);
|
|
11
|
+
|
|
12
|
+
const context = browser.contexts()[0];
|
|
13
|
+
const pages = context?.pages() || [];
|
|
14
|
+
console.log(`[${clientId}] Found ${pages.length} page(s)`);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
id: clientId,
|
|
18
|
+
browser,
|
|
19
|
+
context,
|
|
20
|
+
pages,
|
|
21
|
+
async createPage(url) {
|
|
22
|
+
console.log(`[${clientId}] Creating new page: ${url}`);
|
|
23
|
+
const page = await this.context.newPage();
|
|
24
|
+
await page.goto(url);
|
|
25
|
+
this.pages.push(page);
|
|
26
|
+
return page;
|
|
27
|
+
},
|
|
28
|
+
async scroll(pageIndex = 0, distance = 100) {
|
|
29
|
+
const page = this.pages[pageIndex];
|
|
30
|
+
if (page) {
|
|
31
|
+
console.log(`[${clientId}] Scrolling page ${pageIndex}...`);
|
|
32
|
+
await page.evaluate((d) => window.scrollBy(0, d), distance);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async click(pageIndex = 0, selector) {
|
|
36
|
+
const page = this.pages[pageIndex];
|
|
37
|
+
if (page) {
|
|
38
|
+
console.log(`[${clientId}] Clicking "${selector}" on page ${pageIndex}...`);
|
|
39
|
+
await page.click(selector);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async close() {
|
|
43
|
+
console.log(`[${clientId}] Closing...`);
|
|
44
|
+
await this.browser.close();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function main() {
|
|
50
|
+
console.log(`\n=== Starting ${NUM_CLIENTS} Playwright clients ===\n`);
|
|
51
|
+
|
|
52
|
+
const clients = [];
|
|
53
|
+
|
|
54
|
+
for (let i = 0; i < NUM_CLIENTS; i++) {
|
|
55
|
+
const clientId = `client-${i + 1}`;
|
|
56
|
+
const client = await createClient(clientId);
|
|
57
|
+
clients.push(client);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('\n=== All clients connected ===\n');
|
|
61
|
+
|
|
62
|
+
await Promise.all(clients.map(async (client, idx) => {
|
|
63
|
+
await client.createPage(`https://www.baidu.com`);
|
|
64
|
+
await client.pages[client.pages.length - 1].waitForTimeout(1000 * (idx + 1));
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
console.log('\n=== Testing concurrent scroll ===\n');
|
|
68
|
+
|
|
69
|
+
await Promise.all(clients.map(async (client) => {
|
|
70
|
+
for (let i = 0; i < 3; i++) {
|
|
71
|
+
await client.scroll(0, 100);
|
|
72
|
+
await new Promise(r => setTimeout(r, 500));
|
|
73
|
+
}
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
console.log('\n=== Test completed ===\n');
|
|
77
|
+
|
|
78
|
+
for (const client of clients) {
|
|
79
|
+
await client.close();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log('All clients closed.');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
const SERVER_URL = process.env.CDP_SERVER || 'http://localhost:9221';
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
console.log(`[Playwright] Connecting to ${SERVER_URL}...`);
|
|
7
|
+
|
|
8
|
+
const browser = await chromium.connectOverCDP(SERVER_URL);
|
|
9
|
+
|
|
10
|
+
console.log('[Playwright] Connected!');
|
|
11
|
+
|
|
12
|
+
const contexts = browser.contexts();
|
|
13
|
+
console.log(`[Playwright] Found ${contexts.length} context(s)`);
|
|
14
|
+
|
|
15
|
+
const pages = contexts[0]?.pages() || [];
|
|
16
|
+
console.log(`[Playwright] Found ${pages.length} page(s)`);
|
|
17
|
+
|
|
18
|
+
if (pages.length > 0) {
|
|
19
|
+
const page = pages[0];
|
|
20
|
+
console.log(`[Playwright] First page URL: ${page.url()}`);
|
|
21
|
+
|
|
22
|
+
console.log('[Playwright] Scrolling...');
|
|
23
|
+
await page.evaluate(() => window.scrollBy(0, 100));
|
|
24
|
+
|
|
25
|
+
console.log('[Playwright] Taking screenshot...');
|
|
26
|
+
await page.screenshot({ path: 'tests/screenshot-playwright.png' });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log('[Playwright] Creating new page...');
|
|
30
|
+
const newPage = await contexts[0].newPage();
|
|
31
|
+
await newPage.goto('https://www.baidu.com');
|
|
32
|
+
console.log(`[Playwright] New page URL: ${newPage.url()}`);
|
|
33
|
+
|
|
34
|
+
await newPage.waitForTimeout(2000);
|
|
35
|
+
|
|
36
|
+
console.log('[Playwright] Done!');
|
|
37
|
+
|
|
38
|
+
await browser.close();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
console.log('启动浏览器...');
|
|
5
|
+
|
|
6
|
+
const browser = await chromium.launch({ headless: false });
|
|
7
|
+
const context = await browser.newContext({
|
|
8
|
+
viewport: { width: 1400, height: 900 }
|
|
9
|
+
});
|
|
10
|
+
const page = await context.newPage();
|
|
11
|
+
|
|
12
|
+
// 打开配置页面
|
|
13
|
+
const configUrl = 'chrome-extension://bchclccgjmihieacfmaelkpfjlghhoph/config-page-preview.html';
|
|
14
|
+
console.log('打开配置页面:', configUrl);
|
|
15
|
+
|
|
16
|
+
await page.goto(configUrl);
|
|
17
|
+
await page.waitForTimeout(2000);
|
|
18
|
+
|
|
19
|
+
// 截图
|
|
20
|
+
const screenshotPath = 'docs/config-page-screenshot.png';
|
|
21
|
+
await page.screenshot({
|
|
22
|
+
path: screenshotPath,
|
|
23
|
+
fullPage: true
|
|
24
|
+
});
|
|
25
|
+
console.log('截图已保存:', screenshotPath);
|
|
26
|
+
|
|
27
|
+
console.log('\n请在浏览器中查看配置页面,然后手动截图');
|
|
28
|
+
console.log('等待 30 秒...');
|
|
29
|
+
|
|
30
|
+
await page.waitForTimeout(30000);
|
|
31
|
+
|
|
32
|
+
await browser.close();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const WebSocket = require('ws');
|
|
2
|
+
|
|
3
|
+
const SERVER_URL = process.argv[2] || 'ws://localhost:9221';
|
|
4
|
+
const CLIENT_ID = process.argv[3] || 'test-client-1';
|
|
5
|
+
|
|
6
|
+
console.log(`[Test Client ${CLIENT_ID}] Connecting to ${SERVER_URL}...`);
|
|
7
|
+
|
|
8
|
+
const ws = new WebSocket(SERVER_URL);
|
|
9
|
+
|
|
10
|
+
ws.on('open', () => {
|
|
11
|
+
console.log(`[Test Client ${CLIENT_ID}] Connected!`);
|
|
12
|
+
|
|
13
|
+
ws.send(JSON.stringify({
|
|
14
|
+
type: 'identify',
|
|
15
|
+
clientId: CLIENT_ID
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
console.log(`[Test Client ${CLIENT_ID}] Sent identify message`);
|
|
19
|
+
|
|
20
|
+
console.log(`[Test Client ${CLIENT_ID}] Enabling Target domain...`);
|
|
21
|
+
ws.send(JSON.stringify({
|
|
22
|
+
id: 1,
|
|
23
|
+
method: 'Target.setDiscoverTargets',
|
|
24
|
+
params: { discover: true }
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
console.log(`[Test Client ${CLIENT_ID}] Getting targets...`);
|
|
29
|
+
ws.send(JSON.stringify({
|
|
30
|
+
id: 2,
|
|
31
|
+
method: 'Target.getTargets',
|
|
32
|
+
params: {}
|
|
33
|
+
}));
|
|
34
|
+
}, 1000);
|
|
35
|
+
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
console.log(`[Test Client ${CLIENT_ID}] Creating new page...`);
|
|
38
|
+
ws.send(JSON.stringify({
|
|
39
|
+
id: 3,
|
|
40
|
+
method: 'Target.createTarget',
|
|
41
|
+
params: { url: 'https://www.baidu.com' }
|
|
42
|
+
}));
|
|
43
|
+
}, 2000);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
ws.on('message', (data) => {
|
|
47
|
+
try {
|
|
48
|
+
const msg = JSON.parse(data.toString());
|
|
49
|
+
|
|
50
|
+
if (msg.method && msg.method.startsWith('Target.')) {
|
|
51
|
+
console.log(`[Test Client ${CLIENT_ID}] Event: ${msg.method}`,
|
|
52
|
+
msg.params?.targetInfo?.url || msg.params?.targetId || '');
|
|
53
|
+
} else if (msg.id) {
|
|
54
|
+
console.log(`[Test Client ${CLIENT_ID}] Response to #${msg.id}:`,
|
|
55
|
+
msg.result ? 'success' : msg.error);
|
|
56
|
+
if (msg.result && msg.result.targetInfos) {
|
|
57
|
+
console.log(` Targets: ${msg.result.targetInfos.length}`);
|
|
58
|
+
msg.result.targetInfos.forEach(t => {
|
|
59
|
+
console.log(` - ${t.type}: ${t.url || t.title}`);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (msg.result && msg.result.targetId) {
|
|
63
|
+
console.log(` Created target: ${msg.result.targetId}`);
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
console.log(`[Test Client ${CLIENT_ID}] Message:`, msg.type || msg.method);
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.log(`[Test Client ${CLIENT_ID}] Raw message:`, data.toString().substring(0, 100));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
ws.on('close', () => {
|
|
74
|
+
console.log(`[Test Client ${CLIENT_ID}] Disconnected`);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
ws.on('error', (err) => {
|
|
78
|
+
console.error(`[Test Client ${CLIENT_ID}] Error:`, err.message);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
process.on('SIGINT', () => {
|
|
82
|
+
console.log(`\n[Test Client ${CLIENT_ID}] Closing...`);
|
|
83
|
+
ws.close();
|
|
84
|
+
process.exit(0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log('\nUsage: node test-client.js [server_url] [client_id]');
|
|
88
|
+
console.log('Example: node test-client.js ws://localhost:9221 client-1');
|
|
89
|
+
console.log('\nPress Ctrl+C to exit\n');
|