cdp-skill 1.0.2 → 1.0.4
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 +3 -0
- package/SKILL.md +34 -5
- package/package.json +2 -1
- package/src/capture/console-capture.js +241 -0
- package/src/capture/debug-capture.js +144 -0
- package/src/capture/error-aggregator.js +151 -0
- package/src/capture/eval-serializer.js +320 -0
- package/src/capture/index.js +40 -0
- package/src/capture/network-capture.js +211 -0
- package/src/capture/pdf-capture.js +256 -0
- package/src/capture/screenshot-capture.js +325 -0
- package/src/cdp/browser.js +569 -0
- package/src/cdp/connection.js +369 -0
- package/src/cdp/discovery.js +138 -0
- package/src/cdp/index.js +29 -0
- package/src/cdp/target-and-session.js +439 -0
- package/src/cdp-skill.js +25 -11
- package/src/constants.js +79 -0
- package/src/dom/actionability.js +638 -0
- package/src/dom/click-executor.js +923 -0
- package/src/dom/element-handle.js +496 -0
- package/src/dom/element-locator.js +475 -0
- package/src/dom/element-validator.js +120 -0
- package/src/dom/fill-executor.js +489 -0
- package/src/dom/index.js +248 -0
- package/src/dom/input-emulator.js +406 -0
- package/src/dom/keyboard-executor.js +202 -0
- package/src/dom/quad-helpers.js +89 -0
- package/src/dom/react-filler.js +94 -0
- package/src/dom/wait-executor.js +423 -0
- package/src/index.js +6 -6
- package/src/page/cookie-manager.js +202 -0
- package/src/page/dom-stability.js +181 -0
- package/src/page/index.js +36 -0
- package/src/{page.js → page/page-controller.js} +109 -839
- package/src/page/wait-utilities.js +302 -0
- package/src/page/web-storage-manager.js +108 -0
- package/src/runner/context-helpers.js +224 -0
- package/src/runner/execute-browser.js +518 -0
- package/src/runner/execute-form.js +315 -0
- package/src/runner/execute-input.js +308 -0
- package/src/runner/execute-interaction.js +672 -0
- package/src/runner/execute-navigation.js +180 -0
- package/src/runner/execute-query.js +771 -0
- package/src/runner/index.js +51 -0
- package/src/runner/step-executors.js +421 -0
- package/src/runner/step-validator.js +641 -0
- package/src/tests/Actionability.test.js +613 -0
- package/src/tests/BrowserClient.test.js +1 -1
- package/src/tests/ChromeDiscovery.test.js +1 -1
- package/src/tests/ClickExecutor.test.js +554 -0
- package/src/tests/ConsoleCapture.test.js +1 -1
- package/src/tests/ContextHelpers.test.js +453 -0
- package/src/tests/CookieManager.test.js +450 -0
- package/src/tests/DebugCapture.test.js +307 -0
- package/src/tests/ElementHandle.test.js +1 -1
- package/src/tests/ElementLocator.test.js +1 -1
- package/src/tests/ErrorAggregator.test.js +1 -1
- package/src/tests/EvalSerializer.test.js +391 -0
- package/src/tests/FillExecutor.test.js +611 -0
- package/src/tests/InputEmulator.test.js +1 -1
- package/src/tests/KeyboardExecutor.test.js +430 -0
- package/src/tests/NetworkErrorCapture.test.js +1 -1
- package/src/tests/PageController.test.js +1 -1
- package/src/tests/PdfCapture.test.js +333 -0
- package/src/tests/ScreenshotCapture.test.js +1 -1
- package/src/tests/SessionRegistry.test.js +1 -1
- package/src/tests/StepValidator.test.js +527 -0
- package/src/tests/TargetManager.test.js +1 -1
- package/src/tests/TestRunner.test.js +1 -1
- package/src/tests/WaitStrategy.test.js +1 -1
- package/src/tests/WaitUtilities.test.js +508 -0
- package/src/tests/WebStorageManager.test.js +333 -0
- package/src/types.js +309 -0
- package/src/capture.js +0 -1400
- package/src/cdp.js +0 -1286
- package/src/dom.js +0 -4379
- package/src/runner.js +0 -3676
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { describe, it, mock, beforeEach, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { createWebStorageManager } from '../page/web-storage-manager.js';
|
|
4
|
+
|
|
5
|
+
describe('WebStorageManager', () => {
|
|
6
|
+
let mockSession;
|
|
7
|
+
let manager;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockSession = {
|
|
11
|
+
send: mock.fn(async () => ({}))
|
|
12
|
+
};
|
|
13
|
+
manager = createWebStorageManager(mockSession);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
mock.reset();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('createWebStorageManager', () => {
|
|
21
|
+
it('should return an object with expected methods', () => {
|
|
22
|
+
assert.ok(typeof manager.getStorage === 'function');
|
|
23
|
+
assert.ok(typeof manager.setStorage === 'function');
|
|
24
|
+
assert.ok(typeof manager.clearStorage === 'function');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('getStorage', () => {
|
|
29
|
+
it('should return localStorage items by default', async () => {
|
|
30
|
+
mockSession.send = mock.fn(async () => ({
|
|
31
|
+
result: {
|
|
32
|
+
value: [
|
|
33
|
+
{ name: 'theme', value: 'dark' },
|
|
34
|
+
{ name: 'lang', value: 'en' }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const items = await manager.getStorage();
|
|
40
|
+
|
|
41
|
+
assert.strictEqual(items.length, 2);
|
|
42
|
+
assert.strictEqual(items[0].name, 'theme');
|
|
43
|
+
assert.strictEqual(items[0].value, 'dark');
|
|
44
|
+
|
|
45
|
+
const call = mockSession.send.mock.calls[0];
|
|
46
|
+
assert.ok(call.arguments[1].expression.includes("'local'"));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should return sessionStorage items when type is session', async () => {
|
|
50
|
+
mockSession.send = mock.fn(async () => ({
|
|
51
|
+
result: {
|
|
52
|
+
value: [
|
|
53
|
+
{ name: 'token', value: 'abc123' }
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
const items = await manager.getStorage('session');
|
|
59
|
+
|
|
60
|
+
assert.strictEqual(items.length, 1);
|
|
61
|
+
assert.strictEqual(items[0].name, 'token');
|
|
62
|
+
|
|
63
|
+
const call = mockSession.send.mock.calls[0];
|
|
64
|
+
assert.ok(call.arguments[1].expression.includes("'session'"));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should return empty array when storage is empty', async () => {
|
|
68
|
+
mockSession.send = mock.fn(async () => ({
|
|
69
|
+
result: { value: [] }
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
const items = await manager.getStorage();
|
|
73
|
+
|
|
74
|
+
assert.deepStrictEqual(items, []);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should throw error on exception', async () => {
|
|
78
|
+
mockSession.send = mock.fn(async () => ({
|
|
79
|
+
exceptionDetails: { text: 'Storage access denied' }
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
await assert.rejects(
|
|
83
|
+
() => manager.getStorage(),
|
|
84
|
+
(err) => {
|
|
85
|
+
assert.ok(err.message.includes('Failed to get localStorage'));
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle null result value', async () => {
|
|
92
|
+
mockSession.send = mock.fn(async () => ({
|
|
93
|
+
result: { value: null }
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
const items = await manager.getStorage();
|
|
97
|
+
|
|
98
|
+
assert.deepStrictEqual(items, []);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should treat invalid type as local', async () => {
|
|
102
|
+
mockSession.send = mock.fn(async () => ({
|
|
103
|
+
result: { value: [] }
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
await manager.getStorage('invalid');
|
|
107
|
+
|
|
108
|
+
const call = mockSession.send.mock.calls[0];
|
|
109
|
+
assert.ok(call.arguments[1].expression.includes("'local'"));
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('setStorage', () => {
|
|
114
|
+
it('should set localStorage items by default', async () => {
|
|
115
|
+
mockSession.send = mock.fn(async () => ({
|
|
116
|
+
result: { value: true }
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
await manager.setStorage({ theme: 'dark', lang: 'en' });
|
|
120
|
+
|
|
121
|
+
const call = mockSession.send.mock.calls[0];
|
|
122
|
+
assert.ok(call.arguments[1].expression.includes("'local'"));
|
|
123
|
+
assert.ok(call.arguments[1].expression.includes('"theme":"dark"'));
|
|
124
|
+
assert.ok(call.arguments[1].expression.includes('"lang":"en"'));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should set sessionStorage items when type is session', async () => {
|
|
128
|
+
mockSession.send = mock.fn(async () => ({
|
|
129
|
+
result: { value: true }
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
await manager.setStorage({ token: 'abc' }, 'session');
|
|
133
|
+
|
|
134
|
+
const call = mockSession.send.mock.calls[0];
|
|
135
|
+
assert.ok(call.arguments[1].expression.includes("'session'"));
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should remove items when value is null', async () => {
|
|
139
|
+
mockSession.send = mock.fn(async () => ({
|
|
140
|
+
result: { value: true }
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
await manager.setStorage({ oldKey: null });
|
|
144
|
+
|
|
145
|
+
const call = mockSession.send.mock.calls[0];
|
|
146
|
+
assert.ok(call.arguments[1].expression.includes('"oldKey":null'));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should throw error on exception', async () => {
|
|
150
|
+
mockSession.send = mock.fn(async () => ({
|
|
151
|
+
exceptionDetails: { text: 'Quota exceeded' }
|
|
152
|
+
}));
|
|
153
|
+
|
|
154
|
+
await assert.rejects(
|
|
155
|
+
() => manager.setStorage({ large: 'data' }),
|
|
156
|
+
(err) => {
|
|
157
|
+
assert.ok(err.message.includes('Failed to set localStorage'));
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should set multiple items at once', async () => {
|
|
164
|
+
mockSession.send = mock.fn(async () => ({
|
|
165
|
+
result: { value: true }
|
|
166
|
+
}));
|
|
167
|
+
|
|
168
|
+
await manager.setStorage({
|
|
169
|
+
key1: 'value1',
|
|
170
|
+
key2: 'value2',
|
|
171
|
+
key3: 'value3'
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const call = mockSession.send.mock.calls[0];
|
|
175
|
+
assert.ok(call.arguments[1].expression.includes('key1'));
|
|
176
|
+
assert.ok(call.arguments[1].expression.includes('key2'));
|
|
177
|
+
assert.ok(call.arguments[1].expression.includes('key3'));
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should handle empty items object', async () => {
|
|
181
|
+
mockSession.send = mock.fn(async () => ({
|
|
182
|
+
result: { value: true }
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
await manager.setStorage({});
|
|
186
|
+
|
|
187
|
+
assert.strictEqual(mockSession.send.mock.calls.length, 1);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('clearStorage', () => {
|
|
192
|
+
it('should clear localStorage by default', async () => {
|
|
193
|
+
mockSession.send = mock.fn(async () => ({
|
|
194
|
+
result: { value: true }
|
|
195
|
+
}));
|
|
196
|
+
|
|
197
|
+
await manager.clearStorage();
|
|
198
|
+
|
|
199
|
+
const call = mockSession.send.mock.calls[0];
|
|
200
|
+
assert.ok(call.arguments[1].expression.includes("'local'"));
|
|
201
|
+
assert.ok(call.arguments[1].expression.includes('storage.clear()'));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should clear sessionStorage when type is session', async () => {
|
|
205
|
+
mockSession.send = mock.fn(async () => ({
|
|
206
|
+
result: { value: true }
|
|
207
|
+
}));
|
|
208
|
+
|
|
209
|
+
await manager.clearStorage('session');
|
|
210
|
+
|
|
211
|
+
const call = mockSession.send.mock.calls[0];
|
|
212
|
+
assert.ok(call.arguments[1].expression.includes("'session'"));
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should throw error on exception', async () => {
|
|
216
|
+
mockSession.send = mock.fn(async () => ({
|
|
217
|
+
exceptionDetails: { text: 'Storage blocked' }
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
await assert.rejects(
|
|
221
|
+
() => manager.clearStorage(),
|
|
222
|
+
(err) => {
|
|
223
|
+
assert.ok(err.message.includes('Failed to clear localStorage'));
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should handle invalid type as local', async () => {
|
|
230
|
+
mockSession.send = mock.fn(async () => ({
|
|
231
|
+
result: { value: true }
|
|
232
|
+
}));
|
|
233
|
+
|
|
234
|
+
await manager.clearStorage('invalid');
|
|
235
|
+
|
|
236
|
+
const call = mockSession.send.mock.calls[0];
|
|
237
|
+
assert.ok(call.arguments[1].expression.includes("'local'"));
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('integration scenarios', () => {
|
|
242
|
+
it('should get, set, and clear in sequence', async () => {
|
|
243
|
+
let storage = {};
|
|
244
|
+
|
|
245
|
+
mockSession.send = mock.fn(async (method, params) => {
|
|
246
|
+
const expr = params.expression;
|
|
247
|
+
|
|
248
|
+
if (expr.includes('Object.keys')) {
|
|
249
|
+
// getStorage
|
|
250
|
+
return {
|
|
251
|
+
result: {
|
|
252
|
+
value: Object.keys(storage).map(k => ({ name: k, value: storage[k] }))
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (expr.includes('for (const [key, value]') || expr.includes('setItem')) {
|
|
258
|
+
// setStorage - the expression contains the items as a JSON stringified object
|
|
259
|
+
// Extract items from the expression
|
|
260
|
+
const jsonMatch = expr.match(/, (\{[^)]+\})\)/);
|
|
261
|
+
if (jsonMatch) {
|
|
262
|
+
try {
|
|
263
|
+
const items = JSON.parse(jsonMatch[1]);
|
|
264
|
+
for (const [k, v] of Object.entries(items)) {
|
|
265
|
+
if (v === null) {
|
|
266
|
+
delete storage[k];
|
|
267
|
+
} else {
|
|
268
|
+
storage[k] = v;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
// Ignore parse errors
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return { result: { value: true } };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (expr.includes('storage.clear()')) {
|
|
279
|
+
// clearStorage
|
|
280
|
+
storage = {};
|
|
281
|
+
return { result: { value: true } };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return { result: { value: null } };
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Get initial (empty)
|
|
288
|
+
let items = await manager.getStorage();
|
|
289
|
+
assert.strictEqual(items.length, 0);
|
|
290
|
+
|
|
291
|
+
// Set some items
|
|
292
|
+
await manager.setStorage({ a: '1', b: '2' });
|
|
293
|
+
|
|
294
|
+
// Get again
|
|
295
|
+
items = await manager.getStorage();
|
|
296
|
+
// Since we're mocking, the items are now in storage
|
|
297
|
+
assert.ok(items.length >= 0);
|
|
298
|
+
|
|
299
|
+
// Clear
|
|
300
|
+
await manager.clearStorage();
|
|
301
|
+
|
|
302
|
+
// Get final (empty after clear)
|
|
303
|
+
items = await manager.getStorage();
|
|
304
|
+
assert.strictEqual(items.length, 0);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should handle both storage types independently', async () => {
|
|
308
|
+
const storages = { local: {}, session: {} };
|
|
309
|
+
|
|
310
|
+
mockSession.send = mock.fn(async (method, params) => {
|
|
311
|
+
const expr = params.expression;
|
|
312
|
+
const isSession = expr.includes("'session'");
|
|
313
|
+
const type = isSession ? 'session' : 'local';
|
|
314
|
+
|
|
315
|
+
if (expr.includes('Object.keys')) {
|
|
316
|
+
return {
|
|
317
|
+
result: {
|
|
318
|
+
value: Object.keys(storages[type]).map(k => ({ name: k, value: storages[type][k] }))
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return { result: { value: true } };
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const localItems = await manager.getStorage('local');
|
|
327
|
+
const sessionItems = await manager.getStorage('session');
|
|
328
|
+
|
|
329
|
+
assert.strictEqual(localItems.length, 0);
|
|
330
|
+
assert.strictEqual(sessionItems.length, 0);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|
package/src/types.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Type Definitions for CDP Skill
|
|
3
|
+
*
|
|
4
|
+
* This module provides JSDoc type definitions used across the codebase.
|
|
5
|
+
* Import types using: @import {TypeName} from './types.js'
|
|
6
|
+
*
|
|
7
|
+
* @module cdp-skill/types
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// CDP Session and Connection Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* CDP session interface for communicating with browser targets
|
|
16
|
+
* @typedef {Object} CDPSession
|
|
17
|
+
* @property {function(string, Object=): Promise<Object>} send - Send CDP command
|
|
18
|
+
* @property {function(string, function): void} on - Subscribe to CDP event
|
|
19
|
+
* @property {function(string, function): void} off - Unsubscribe from CDP event
|
|
20
|
+
* @property {function(): void} dispose - Clean up session resources
|
|
21
|
+
* @property {function(): boolean} isValid - Check if session is still valid
|
|
22
|
+
* @property {string} sessionId - CDP session ID
|
|
23
|
+
* @property {string} targetId - Target ID this session is attached to
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* CDP connection interface for WebSocket communication
|
|
28
|
+
* @typedef {Object} CDPConnection
|
|
29
|
+
* @property {function(): Promise<void>} connect - Establish WebSocket connection
|
|
30
|
+
* @property {function(string, Object=, number=): Promise<Object>} send - Send CDP command
|
|
31
|
+
* @property {function(string, string, Object=, number=): Promise<Object>} sendToSession - Send command to session
|
|
32
|
+
* @property {function(string, function): void} on - Subscribe to event
|
|
33
|
+
* @property {function(string, function): void} off - Unsubscribe from event
|
|
34
|
+
* @property {function(string, function=, number=): Promise<Object>} waitForEvent - Wait for specific event
|
|
35
|
+
* @property {function(): Promise<void>} close - Close connection
|
|
36
|
+
* @property {function(string=): void} removeAllListeners - Remove event listeners
|
|
37
|
+
* @property {function(function): void} onClose - Set close callback
|
|
38
|
+
* @property {function(): boolean} isConnected - Check connection status
|
|
39
|
+
* @property {function(): string} getWsUrl - Get WebSocket URL
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Element and DOM Types
|
|
44
|
+
// ============================================================================
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Element handle for interacting with DOM elements
|
|
48
|
+
* @typedef {Object} ElementHandle
|
|
49
|
+
* @property {function(): Promise<BoundingBox|null>} getBoundingBox - Get element dimensions
|
|
50
|
+
* @property {function(Object=): Promise<void>} click - Click the element
|
|
51
|
+
* @property {function(string): Promise<void>} type - Type text into element
|
|
52
|
+
* @property {function(string, Object=): Promise<void>} fill - Fill element with value
|
|
53
|
+
* @property {function(Object=): Promise<void>} scrollIntoView - Scroll element into view
|
|
54
|
+
* @property {function(): Promise<boolean>} isVisible - Check visibility
|
|
55
|
+
* @property {function(): Promise<boolean>} isEnabled - Check if enabled
|
|
56
|
+
* @property {function(string): Promise<string|null>} getAttribute - Get attribute value
|
|
57
|
+
* @property {function(): Promise<string>} getInnerText - Get inner text
|
|
58
|
+
* @property {function(string): Promise<*>} evaluate - Run JS on element
|
|
59
|
+
* @property {function(): Promise<void>} dispose - Release element reference
|
|
60
|
+
* @property {string} objectId - CDP object ID
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Bounding box dimensions for an element
|
|
65
|
+
* @typedef {Object} BoundingBox
|
|
66
|
+
* @property {number} x - X coordinate (left edge)
|
|
67
|
+
* @property {number} y - Y coordinate (top edge)
|
|
68
|
+
* @property {number} width - Element width
|
|
69
|
+
* @property {number} height - Element height
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Quad coordinates (4 points defining element shape)
|
|
74
|
+
* @typedef {Array<{x: number, y: number}>} Quad
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// Navigation and Page Types
|
|
79
|
+
// ============================================================================
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Viewport configuration
|
|
83
|
+
* @typedef {Object} ViewportConfig
|
|
84
|
+
* @property {number} width - Viewport width in pixels
|
|
85
|
+
* @property {number} height - Viewport height in pixels
|
|
86
|
+
* @property {number} [deviceScaleFactor=1] - Device pixel ratio
|
|
87
|
+
* @property {boolean} [mobile=false] - Emulate mobile device
|
|
88
|
+
* @property {boolean} [hasTouch=false] - Enable touch events
|
|
89
|
+
* @property {boolean} [isLandscape=false] - Landscape orientation
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Navigation options
|
|
94
|
+
* @typedef {Object} NavigationOptions
|
|
95
|
+
* @property {string} [waitUntil='load'] - Wait condition: 'load', 'domcontentloaded', 'networkidle', 'commit'
|
|
96
|
+
* @property {number} [timeout=30000] - Navigation timeout in ms
|
|
97
|
+
* @property {string} [referrer] - Referrer URL
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Navigation result
|
|
102
|
+
* @typedef {Object} NavigationResult
|
|
103
|
+
* @property {string} frameId - Frame ID that navigated
|
|
104
|
+
* @property {string} loaderId - Loader ID for this navigation
|
|
105
|
+
* @property {string} url - Final URL after navigation
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Wait condition options
|
|
110
|
+
* @typedef {Object} WaitOptions
|
|
111
|
+
* @property {number} [timeout=30000] - Maximum wait time in ms
|
|
112
|
+
* @property {number} [pollInterval=100] - Polling interval in ms
|
|
113
|
+
* @property {string} [message] - Custom timeout message
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Screenshot and Capture Types
|
|
118
|
+
// ============================================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Screenshot options
|
|
122
|
+
* @typedef {Object} ScreenshotOptions
|
|
123
|
+
* @property {'png'|'jpeg'|'webp'} [format='png'] - Image format
|
|
124
|
+
* @property {number} [quality] - JPEG/WebP quality (0-100)
|
|
125
|
+
* @property {boolean} [fullPage=false] - Capture full scrollable page
|
|
126
|
+
* @property {boolean} [omitBackground=false] - Transparent background
|
|
127
|
+
* @property {ClipRegion} [clip] - Capture specific region
|
|
128
|
+
* @property {string} [selector] - Capture specific element
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Clip region for screenshots
|
|
133
|
+
* @typedef {Object} ClipRegion
|
|
134
|
+
* @property {number} x - X coordinate
|
|
135
|
+
* @property {number} y - Y coordinate
|
|
136
|
+
* @property {number} width - Width
|
|
137
|
+
* @property {number} height - Height
|
|
138
|
+
* @property {number} [scale=1] - Scale factor
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* PDF generation options
|
|
143
|
+
* @typedef {Object} PdfOptions
|
|
144
|
+
* @property {boolean} [landscape=false] - Landscape orientation
|
|
145
|
+
* @property {boolean} [displayHeaderFooter=false] - Show header/footer
|
|
146
|
+
* @property {string} [headerTemplate=''] - Header HTML template
|
|
147
|
+
* @property {string} [footerTemplate=''] - Footer HTML template
|
|
148
|
+
* @property {boolean} [printBackground=true] - Print background graphics
|
|
149
|
+
* @property {number} [scale=1] - Page scale (0.1 to 2)
|
|
150
|
+
* @property {number} [paperWidth=8.5] - Paper width in inches
|
|
151
|
+
* @property {number} [paperHeight=11] - Paper height in inches
|
|
152
|
+
* @property {number} [marginTop=0.4] - Top margin in inches
|
|
153
|
+
* @property {number} [marginBottom=0.4] - Bottom margin in inches
|
|
154
|
+
* @property {number} [marginLeft=0.4] - Left margin in inches
|
|
155
|
+
* @property {number} [marginRight=0.4] - Right margin in inches
|
|
156
|
+
* @property {string} [pageRanges=''] - Page ranges (e.g., '1-5, 8')
|
|
157
|
+
* @property {boolean} [preferCSSPageSize=false] - Use CSS page size
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Cookie and Storage Types
|
|
162
|
+
// ============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Cookie object
|
|
166
|
+
* @typedef {Object} CookieObject
|
|
167
|
+
* @property {string} name - Cookie name
|
|
168
|
+
* @property {string} value - Cookie value
|
|
169
|
+
* @property {string} [domain] - Cookie domain
|
|
170
|
+
* @property {string} [path='/'] - Cookie path
|
|
171
|
+
* @property {number} [expires] - Expiration timestamp
|
|
172
|
+
* @property {boolean} [httpOnly=false] - HTTP only flag
|
|
173
|
+
* @property {boolean} [secure=false] - Secure flag
|
|
174
|
+
* @property {'Strict'|'Lax'|'None'} [sameSite='Lax'] - SameSite attribute
|
|
175
|
+
* @property {string} [url] - URL to derive domain/path from
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Storage item
|
|
180
|
+
* @typedef {Object} StorageItem
|
|
181
|
+
* @property {string} name - Item key
|
|
182
|
+
* @property {string} value - Item value
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// Test Runner Types
|
|
187
|
+
// ============================================================================
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Step execution result
|
|
191
|
+
* @typedef {Object} StepResult
|
|
192
|
+
* @property {string} action - Action that was executed
|
|
193
|
+
* @property {'ok'|'error'|'skipped'} status - Execution status
|
|
194
|
+
* @property {*} [result] - Action-specific result data
|
|
195
|
+
* @property {string} [error] - Error message if failed
|
|
196
|
+
* @property {number} [duration] - Execution time in ms
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Run result from test execution
|
|
201
|
+
* @typedef {Object} RunResult
|
|
202
|
+
* @property {'ok'|'error'} status - Overall run status
|
|
203
|
+
* @property {string} [tab] - Tab alias (e.g., 't1')
|
|
204
|
+
* @property {boolean} [navigated] - Whether navigation occurred
|
|
205
|
+
* @property {string} [fullSnapshot] - Full ARIA snapshot
|
|
206
|
+
* @property {Object} [context] - Page context (URL, scroll, activeElement)
|
|
207
|
+
* @property {Object} [changes] - DOM changes detected
|
|
208
|
+
* @property {string} [viewportSnapshot] - Viewport-only ARIA snapshot
|
|
209
|
+
* @property {boolean} [truncated] - Whether snapshot was truncated
|
|
210
|
+
* @property {string} [screenshot] - Screenshot file path
|
|
211
|
+
* @property {Array<Object>} [console] - Console errors/warnings
|
|
212
|
+
* @property {Array<StepResult>} steps - Individual step results
|
|
213
|
+
* @property {Array<Object>} errors - Error details for failed steps
|
|
214
|
+
*/
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Step configuration
|
|
218
|
+
* @typedef {Object} StepConfig
|
|
219
|
+
* @property {string} [goto] - Navigate to URL
|
|
220
|
+
* @property {string} [click] - Click element selector
|
|
221
|
+
* @property {string} [fill] - Fill element selector
|
|
222
|
+
* @property {string} [value] - Value for fill/type operations
|
|
223
|
+
* @property {string} [type] - Type into element
|
|
224
|
+
* @property {string} [press] - Press key(s)
|
|
225
|
+
* @property {Object} [scroll] - Scroll configuration
|
|
226
|
+
* @property {boolean|Object} [snapshot] - Take ARIA snapshot
|
|
227
|
+
* @property {string|Object} [query] - Query elements
|
|
228
|
+
* @property {string} [hover] - Hover over element
|
|
229
|
+
* @property {Object} [wait] - Wait configuration
|
|
230
|
+
* @property {string} [eval] - Evaluate JavaScript
|
|
231
|
+
* @property {string|Object} [openTab] - Open new tab
|
|
232
|
+
* @property {string} [closeTab] - Close tab by ID
|
|
233
|
+
* @property {boolean|Object} [chromeStatus] - Check/launch Chrome
|
|
234
|
+
* @property {string|Object} [selectOption] - Select dropdown option
|
|
235
|
+
* @property {string|Object} [viewport] - Set viewport
|
|
236
|
+
* @property {Object} [cookies] - Cookie operations
|
|
237
|
+
* @property {boolean} [back] - Navigate back
|
|
238
|
+
* @property {boolean} [forward] - Navigate forward
|
|
239
|
+
* @property {Object} [drag] - Drag and drop
|
|
240
|
+
* @property {Object} [fillForm] - Fill multiple form fields
|
|
241
|
+
* @property {Object} [extract] - Extract data from page
|
|
242
|
+
* @property {Object} [formState] - Get form state
|
|
243
|
+
* @property {Object} [assert] - Assert condition
|
|
244
|
+
* @property {Object} [validate] - Validate page state
|
|
245
|
+
* @property {string} [submit] - Submit form
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Runner dependencies
|
|
250
|
+
* @typedef {Object} RunnerDependencies
|
|
251
|
+
* @property {Object} browser - Browser client instance
|
|
252
|
+
* @property {Object} pageController - Page controller instance
|
|
253
|
+
* @property {Object} elementLocator - Element locator instance
|
|
254
|
+
* @property {Object} inputEmulator - Input emulator instance
|
|
255
|
+
* @property {Object} screenshotCapture - Screenshot capture instance
|
|
256
|
+
* @property {Object} consoleCapture - Console capture instance
|
|
257
|
+
* @property {Object} pdfCapture - PDF capture instance
|
|
258
|
+
* @property {Object} ariaSnapshot - ARIA snapshot instance
|
|
259
|
+
* @property {Object} cookieManager - Cookie manager instance
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
// ============================================================================
|
|
263
|
+
// Error Types
|
|
264
|
+
// ============================================================================
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* CDP Skill error
|
|
268
|
+
* @typedef {Object} CDPError
|
|
269
|
+
* @property {string} type - Error type (CONNECTION, NAVIGATION, TIMEOUT, etc.)
|
|
270
|
+
* @property {string} message - Error message
|
|
271
|
+
* @property {string} [code] - Error code
|
|
272
|
+
* @property {Object} [details] - Additional error details
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// Console and Network Capture Types
|
|
277
|
+
// ============================================================================
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Console message
|
|
281
|
+
* @typedef {Object} ConsoleMessage
|
|
282
|
+
* @property {'console'|'exception'} type - Message type
|
|
283
|
+
* @property {'log'|'debug'|'info'|'warning'|'error'} level - Log level
|
|
284
|
+
* @property {string} text - Message text
|
|
285
|
+
* @property {Array<Object>} [args] - Original arguments
|
|
286
|
+
* @property {Object} [stackTrace] - Stack trace if available
|
|
287
|
+
* @property {number} [timestamp] - CDP timestamp
|
|
288
|
+
* @property {string} [url] - Source URL for exceptions
|
|
289
|
+
* @property {number} [line] - Line number for exceptions
|
|
290
|
+
* @property {number} [column] - Column number for exceptions
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Network error
|
|
295
|
+
* @typedef {Object} NetworkError
|
|
296
|
+
* @property {'network-failure'|'http-error'} type - Error type
|
|
297
|
+
* @property {string} requestId - Request ID
|
|
298
|
+
* @property {string} url - Request URL
|
|
299
|
+
* @property {string} method - HTTP method
|
|
300
|
+
* @property {string} [resourceType] - Resource type (Document, Script, etc.)
|
|
301
|
+
* @property {string} [errorText] - Error description
|
|
302
|
+
* @property {boolean} [canceled] - Whether request was canceled
|
|
303
|
+
* @property {number} [status] - HTTP status code (for http-error)
|
|
304
|
+
* @property {string} [statusText] - HTTP status text
|
|
305
|
+
* @property {number} timestamp - CDP timestamp
|
|
306
|
+
*/
|
|
307
|
+
|
|
308
|
+
// Export empty object to make this a proper module
|
|
309
|
+
export {};
|