btcp-browser-agent 0.1.0 → 0.1.1

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.
Files changed (136) hide show
  1. package/package.json +8 -9
  2. package/packages/core/dist/actions.d.ts +97 -0
  3. package/packages/core/dist/actions.js +940 -0
  4. package/packages/core/dist/errors.d.ts +138 -0
  5. package/packages/core/dist/errors.js +157 -0
  6. package/packages/core/dist/index.d.ts +120 -0
  7. package/packages/core/dist/index.js +134 -0
  8. package/packages/core/dist/ref-map.d.ts +16 -0
  9. package/packages/core/dist/ref-map.js +91 -0
  10. package/packages/core/dist/snapshot.d.ts +37 -0
  11. package/packages/core/dist/snapshot.js +751 -0
  12. package/packages/core/dist/types.d.ts +396 -0
  13. package/packages/core/dist/types.js +7 -0
  14. package/packages/extension/dist/background.d.ts +227 -0
  15. package/packages/extension/dist/background.js +737 -0
  16. package/packages/extension/dist/content.d.ts +18 -0
  17. package/packages/extension/dist/content.js +149 -0
  18. package/packages/extension/dist/index.d.ts +228 -0
  19. package/packages/extension/dist/index.js +350 -0
  20. package/packages/extension/dist/session-manager.d.ts +87 -0
  21. package/packages/extension/dist/session-manager.js +322 -0
  22. package/packages/extension/{src/session-types.ts → dist/session-types.d.ts} +113 -144
  23. package/packages/extension/dist/session-types.js +5 -0
  24. package/packages/extension/dist/types.d.ts +88 -0
  25. package/packages/extension/dist/types.js +7 -0
  26. package/CLAUDE.md +0 -230
  27. package/SKILL.md +0 -143
  28. package/SNAPSHOT_IMPROVEMENTS.md +0 -302
  29. package/USAGE.md +0 -146
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/index.js.map +0 -1
  32. package/docs/browser-cli-design.md +0 -500
  33. package/examples/chrome-extension/CHANGELOG.md +0 -210
  34. package/examples/chrome-extension/DEBUG.md +0 -231
  35. package/examples/chrome-extension/ERROR_FIXED.md +0 -147
  36. package/examples/chrome-extension/QUICK_TEST.md +0 -189
  37. package/examples/chrome-extension/README.md +0 -149
  38. package/examples/chrome-extension/SESSION_ONLY_MODE.md +0 -305
  39. package/examples/chrome-extension/TEST_WITH_YOUR_TABS.md +0 -97
  40. package/examples/chrome-extension/build.js +0 -43
  41. package/examples/chrome-extension/manifest.json +0 -37
  42. package/examples/chrome-extension/package-lock.json +0 -1063
  43. package/examples/chrome-extension/package.json +0 -21
  44. package/examples/chrome-extension/popup.html +0 -195
  45. package/examples/chrome-extension/src/background.ts +0 -12
  46. package/examples/chrome-extension/src/content.ts +0 -7
  47. package/examples/chrome-extension/src/popup.ts +0 -303
  48. package/examples/chrome-extension/src/scenario-google-github.ts +0 -389
  49. package/examples/chrome-extension/test-page.html +0 -127
  50. package/examples/chrome-extension/tests/README.md +0 -206
  51. package/examples/chrome-extension/tests/scenario-google-to-github-star.ts +0 -380
  52. package/examples/chrome-extension/tsconfig.json +0 -14
  53. package/examples/snapshots/README.md +0 -207
  54. package/examples/snapshots/amazon-com-detail.html +0 -9528
  55. package/examples/snapshots/amazon-com-detail.snapshot.txt +0 -997
  56. package/examples/snapshots/convert-snapshots.ts +0 -97
  57. package/examples/snapshots/edition-cnn-com.html +0 -13292
  58. package/examples/snapshots/edition-cnn-com.snapshot.txt +0 -562
  59. package/examples/snapshots/github-com-microsoft-vscode.html +0 -2916
  60. package/examples/snapshots/github-com-microsoft-vscode.snapshot.txt +0 -455
  61. package/examples/snapshots/google-search.html +0 -20012
  62. package/examples/snapshots/google-search.snapshot.txt +0 -195
  63. package/examples/snapshots/metadata.json +0 -86
  64. package/examples/snapshots/npr-org-templates.html +0 -2031
  65. package/examples/snapshots/npr-org-templates.snapshot.txt +0 -224
  66. package/examples/snapshots/stackoverflow-com.html +0 -5216
  67. package/examples/snapshots/stackoverflow-com.snapshot.txt +0 -2404
  68. package/examples/snapshots/test-all-mode.html +0 -46
  69. package/examples/snapshots/test-all-mode.snapshot.txt +0 -5
  70. package/examples/snapshots/validate.test.ts +0 -296
  71. package/packages/cli/package.json +0 -42
  72. package/packages/cli/src/__tests__/cli.test.ts +0 -434
  73. package/packages/cli/src/__tests__/errors.test.ts +0 -226
  74. package/packages/cli/src/__tests__/executor.test.ts +0 -275
  75. package/packages/cli/src/__tests__/formatter.test.ts +0 -260
  76. package/packages/cli/src/__tests__/parser.test.ts +0 -288
  77. package/packages/cli/src/__tests__/suggestions.test.ts +0 -255
  78. package/packages/cli/src/commands/back.ts +0 -22
  79. package/packages/cli/src/commands/check.ts +0 -33
  80. package/packages/cli/src/commands/clear.ts +0 -33
  81. package/packages/cli/src/commands/click.ts +0 -32
  82. package/packages/cli/src/commands/closetab.ts +0 -31
  83. package/packages/cli/src/commands/eval.ts +0 -41
  84. package/packages/cli/src/commands/fill.ts +0 -30
  85. package/packages/cli/src/commands/focus.ts +0 -33
  86. package/packages/cli/src/commands/forward.ts +0 -22
  87. package/packages/cli/src/commands/goto.ts +0 -34
  88. package/packages/cli/src/commands/help.ts +0 -162
  89. package/packages/cli/src/commands/hover.ts +0 -34
  90. package/packages/cli/src/commands/index.ts +0 -129
  91. package/packages/cli/src/commands/newtab.ts +0 -35
  92. package/packages/cli/src/commands/press.ts +0 -40
  93. package/packages/cli/src/commands/reload.ts +0 -25
  94. package/packages/cli/src/commands/screenshot.ts +0 -27
  95. package/packages/cli/src/commands/scroll.ts +0 -64
  96. package/packages/cli/src/commands/select.ts +0 -35
  97. package/packages/cli/src/commands/snapshot.ts +0 -21
  98. package/packages/cli/src/commands/tab.ts +0 -32
  99. package/packages/cli/src/commands/tabs.ts +0 -26
  100. package/packages/cli/src/commands/text.ts +0 -27
  101. package/packages/cli/src/commands/title.ts +0 -17
  102. package/packages/cli/src/commands/type.ts +0 -38
  103. package/packages/cli/src/commands/uncheck.ts +0 -33
  104. package/packages/cli/src/commands/url.ts +0 -17
  105. package/packages/cli/src/commands/wait.ts +0 -54
  106. package/packages/cli/src/errors.ts +0 -164
  107. package/packages/cli/src/executor.ts +0 -68
  108. package/packages/cli/src/formatter.ts +0 -215
  109. package/packages/cli/src/index.ts +0 -257
  110. package/packages/cli/src/parser.ts +0 -195
  111. package/packages/cli/src/suggestions.ts +0 -207
  112. package/packages/cli/src/terminal/Terminal.ts +0 -365
  113. package/packages/cli/src/terminal/index.ts +0 -5
  114. package/packages/cli/src/types.ts +0 -155
  115. package/packages/cli/tsconfig.json +0 -20
  116. package/packages/core/package.json +0 -35
  117. package/packages/core/src/actions.ts +0 -1210
  118. package/packages/core/src/errors.ts +0 -296
  119. package/packages/core/src/index.test.ts +0 -638
  120. package/packages/core/src/index.ts +0 -220
  121. package/packages/core/src/ref-map.ts +0 -107
  122. package/packages/core/src/snapshot.ts +0 -873
  123. package/packages/core/src/types.ts +0 -536
  124. package/packages/core/tsconfig.json +0 -23
  125. package/packages/extension/README.md +0 -129
  126. package/packages/extension/package.json +0 -43
  127. package/packages/extension/src/background.ts +0 -888
  128. package/packages/extension/src/content.ts +0 -172
  129. package/packages/extension/src/index.ts +0 -579
  130. package/packages/extension/src/session-manager.ts +0 -385
  131. package/packages/extension/src/types.ts +0 -162
  132. package/packages/extension/tsconfig.json +0 -28
  133. package/src/index.ts +0 -64
  134. package/tsconfig.build.json +0 -12
  135. package/tsconfig.json +0 -26
  136. package/vitest.config.ts +0 -13
@@ -1,638 +0,0 @@
1
- /**
2
- * @btcp/core - Tests for DOM actions and snapshot
3
- */
4
-
5
- import { describe, it, expect, beforeEach, vi } from 'vitest';
6
- import { createAgent, createSnapshot, createRefMap, DOMActions } from './index.js';
7
- import type { Command } from './types.js';
8
-
9
- describe('@btcp/core', () => {
10
- beforeEach(() => {
11
- document.body.innerHTML = '';
12
- });
13
-
14
- describe('createAgent', () => {
15
- it('should create an agent instance', () => {
16
- const agent = createAgent(document, window);
17
- expect(agent).toBeDefined();
18
- expect(agent.execute).toBeDefined();
19
- expect(agent.executeJson).toBeDefined();
20
- });
21
- });
22
-
23
- describe('snapshot', () => {
24
- it('should generate snapshot for button', async () => {
25
- document.body.innerHTML = '<button>Click me</button>';
26
- const agent = createAgent(document, window);
27
-
28
- const response = await agent.execute({
29
- id: '1',
30
- action: 'snapshot',
31
- });
32
-
33
- expect(response.success).toBe(true);
34
- if (response.success) {
35
- expect(response.data).toContain('button');
36
- expect(response.data).toContain('Click me');
37
- expect(response.data).toContain('@ref:');
38
- }
39
- });
40
-
41
- it('should generate refs for interactive elements', async () => {
42
- document.body.innerHTML = `
43
- <button>Submit</button>
44
- <a href="/home">Home</a>
45
- <input type="text" placeholder="Name">
46
- `;
47
- const agent = createAgent(document, window);
48
-
49
- const response = await agent.execute({ id: '1', action: 'snapshot' });
50
-
51
- expect(response.success).toBe(true);
52
- if (response.success) {
53
- // Snapshot now returns string directly (refs are internal)
54
- expect(typeof response.data).toBe('string');
55
- expect(response.data.length).toBeGreaterThan(0);
56
- }
57
- });
58
-
59
- it('should skip hidden elements', async () => {
60
- document.body.innerHTML = `
61
- <button>Visible</button>
62
- <button style="display: none">Hidden</button>
63
- `;
64
- const agent = createAgent(document, window);
65
-
66
- const response = await agent.execute({ id: '1', action: 'snapshot' });
67
-
68
- expect(response.success).toBe(true);
69
- if (response.success) {
70
- expect(response.data).toContain('Visible');
71
- expect(response.data).not.toContain('Hidden');
72
- }
73
- });
74
-
75
- it('should use aria-label for name', async () => {
76
- document.body.innerHTML = '<button aria-label="Close dialog">X</button>';
77
- const agent = createAgent(document, window);
78
-
79
- const response = await agent.execute({ id: '1', action: 'snapshot' });
80
-
81
- expect(response.success).toBe(true);
82
- if (response.success) {
83
- expect(response.data).toContain('Close dialog');
84
- }
85
- });
86
-
87
- it('should filter snapshot with grep option', async () => {
88
- document.body.innerHTML = `
89
- <button>Submit</button>
90
- <button>Cancel</button>
91
- <a href="/home">Home</a>
92
- `;
93
- const agent = createAgent(document, window);
94
-
95
- const response = await agent.execute({
96
- id: '1',
97
- action: 'snapshot',
98
- grep: 'Submit',
99
- });
100
-
101
- expect(response.success).toBe(true);
102
- if (response.success) {
103
- expect(response.data).toContain('Submit');
104
- expect(response.data).not.toContain('Cancel');
105
- expect(response.data).not.toContain('Home');
106
- expect(response.data).toContain('grep=Submit');
107
- expect(response.data).toContain('matches=1');
108
- }
109
- });
110
-
111
- it('should return all elements when grep matches none', async () => {
112
- document.body.innerHTML = '<button>Click</button>';
113
- const agent = createAgent(document, window);
114
-
115
- const response = await agent.execute({
116
- id: '1',
117
- action: 'snapshot',
118
- grep: 'nonexistent',
119
- });
120
-
121
- expect(response.success).toBe(true);
122
- if (response.success) {
123
- expect(response.data).toContain('PAGE:');
124
- expect(response.data).not.toContain('Click');
125
- }
126
- });
127
-
128
- it('should support grep ignoreCase option (-i)', async () => {
129
- document.body.innerHTML = `
130
- <button>SUBMIT</button>
131
- <button>Cancel</button>
132
- `;
133
- const agent = createAgent(document, window);
134
-
135
- const response = await agent.execute({
136
- id: '1',
137
- action: 'snapshot',
138
- grep: { pattern: 'submit', ignoreCase: true },
139
- });
140
-
141
- expect(response.success).toBe(true);
142
- if (response.success) {
143
- expect(response.data).toContain('SUBMIT');
144
- expect(response.data).not.toContain('Cancel');
145
- }
146
- });
147
-
148
- it('should support grep invert option (-v)', async () => {
149
- document.body.innerHTML = `
150
- <button>Submit</button>
151
- <button>Cancel</button>
152
- <a href="/home">Home</a>
153
- `;
154
- const agent = createAgent(document, window);
155
-
156
- const response = await agent.execute({
157
- id: '1',
158
- action: 'snapshot',
159
- grep: { pattern: 'BUTTON', invert: true },
160
- });
161
-
162
- expect(response.success).toBe(true);
163
- if (response.success) {
164
- expect(response.data).not.toContain('Submit');
165
- expect(response.data).not.toContain('Cancel');
166
- expect(response.data).toContain('Home');
167
- }
168
- });
169
-
170
- it('should support grep fixedStrings option (-F)', async () => {
171
- document.body.innerHTML = `
172
- <button>Click [here]</button>
173
- <button>Other</button>
174
- `;
175
- const agent = createAgent(document, window);
176
-
177
- const response = await agent.execute({
178
- id: '1',
179
- action: 'snapshot',
180
- grep: { pattern: '[here]', fixedStrings: true },
181
- });
182
-
183
- expect(response.success).toBe(true);
184
- if (response.success) {
185
- expect(response.data).toContain('[here]');
186
- expect(response.data).not.toContain('Other');
187
- }
188
- });
189
- });
190
-
191
- describe('click', () => {
192
- it('should click element by CSS selector', async () => {
193
- document.body.innerHTML = '<button id="btn">Click me</button>';
194
- const button = document.getElementById('btn')!;
195
- const handler = vi.fn();
196
- button.addEventListener('click', handler);
197
-
198
- const agent = createAgent(document, window);
199
- const response = await agent.execute({
200
- id: '1',
201
- action: 'click',
202
- selector: '#btn',
203
- });
204
-
205
- expect(response.success).toBe(true);
206
- expect(handler).toHaveBeenCalled();
207
- });
208
-
209
- it('should click element by ref', async () => {
210
- document.body.innerHTML = '<button>Click me</button>';
211
- const button = document.querySelector('button')!;
212
- const handler = vi.fn();
213
- button.addEventListener('click', handler);
214
-
215
- const agent = createAgent(document, window);
216
- // First get snapshot to generate refs
217
- await agent.execute({ id: '1', action: 'snapshot' });
218
-
219
- const response = await agent.execute({
220
- id: '2',
221
- action: 'click',
222
- selector: '@ref:0',
223
- });
224
-
225
- expect(response.success).toBe(true);
226
- expect(handler).toHaveBeenCalled();
227
- });
228
-
229
- it('should return error for non-existent element', async () => {
230
- const agent = createAgent(document, window);
231
- const response = await agent.execute({
232
- id: '1',
233
- action: 'click',
234
- selector: '#non-existent',
235
- });
236
-
237
- expect(response.success).toBe(false);
238
- if (!response.success) {
239
- expect(response.error).toContain('not found');
240
- }
241
- });
242
- });
243
-
244
- describe('type', () => {
245
- it('should type text into input', async () => {
246
- document.body.innerHTML = '<input id="input" type="text">';
247
- const input = document.getElementById('input') as HTMLInputElement;
248
-
249
- const agent = createAgent(document, window);
250
- const response = await agent.execute({
251
- id: '1',
252
- action: 'type',
253
- selector: '#input',
254
- text: 'Hello',
255
- });
256
-
257
- expect(response.success).toBe(true);
258
- expect(input.value).toBe('Hello');
259
- });
260
-
261
- it('should clear input when clear option is true', async () => {
262
- document.body.innerHTML = '<input id="input" type="text" value="Existing">';
263
- const input = document.getElementById('input') as HTMLInputElement;
264
-
265
- const agent = createAgent(document, window);
266
- const response = await agent.execute({
267
- id: '1',
268
- action: 'type',
269
- selector: '#input',
270
- text: 'New',
271
- clear: true,
272
- });
273
-
274
- expect(response.success).toBe(true);
275
- expect(input.value).toBe('New');
276
- });
277
- });
278
-
279
- describe('fill', () => {
280
- it('should fill input value instantly', async () => {
281
- document.body.innerHTML = '<input id="input" type="text">';
282
- const input = document.getElementById('input') as HTMLInputElement;
283
-
284
- const agent = createAgent(document, window);
285
- const response = await agent.execute({
286
- id: '1',
287
- action: 'fill',
288
- selector: '#input',
289
- value: 'Test Value',
290
- });
291
-
292
- expect(response.success).toBe(true);
293
- expect(input.value).toBe('Test Value');
294
- });
295
-
296
- it('should dispatch input and change events', async () => {
297
- document.body.innerHTML = '<input id="input" type="text">';
298
- const input = document.getElementById('input') as HTMLInputElement;
299
- const inputHandler = vi.fn();
300
- const changeHandler = vi.fn();
301
- input.addEventListener('input', inputHandler);
302
- input.addEventListener('change', changeHandler);
303
-
304
- const agent = createAgent(document, window);
305
- await agent.execute({
306
- id: '1',
307
- action: 'fill',
308
- selector: '#input',
309
- value: 'Test',
310
- });
311
-
312
- expect(inputHandler).toHaveBeenCalled();
313
- expect(changeHandler).toHaveBeenCalled();
314
- });
315
- });
316
-
317
- describe('check/uncheck', () => {
318
- it('should check checkbox', async () => {
319
- document.body.innerHTML = '<input id="cb" type="checkbox">';
320
- const checkbox = document.getElementById('cb') as HTMLInputElement;
321
-
322
- const agent = createAgent(document, window);
323
- const response = await agent.execute({
324
- id: '1',
325
- action: 'check',
326
- selector: '#cb',
327
- });
328
-
329
- expect(response.success).toBe(true);
330
- expect(checkbox.checked).toBe(true);
331
- });
332
-
333
- it('should uncheck checkbox', async () => {
334
- document.body.innerHTML = '<input id="cb" type="checkbox" checked>';
335
- const checkbox = document.getElementById('cb') as HTMLInputElement;
336
-
337
- const agent = createAgent(document, window);
338
- const response = await agent.execute({
339
- id: '1',
340
- action: 'uncheck',
341
- selector: '#cb',
342
- });
343
-
344
- expect(response.success).toBe(true);
345
- expect(checkbox.checked).toBe(false);
346
- });
347
- });
348
-
349
- describe('select', () => {
350
- it('should select option', async () => {
351
- document.body.innerHTML = `
352
- <select id="sel">
353
- <option value="a">A</option>
354
- <option value="b">B</option>
355
- </select>
356
- `;
357
- const select = document.getElementById('sel') as HTMLSelectElement;
358
-
359
- const agent = createAgent(document, window);
360
- const response = await agent.execute({
361
- id: '1',
362
- action: 'select',
363
- selector: '#sel',
364
- values: 'b',
365
- });
366
-
367
- expect(response.success).toBe(true);
368
- expect(select.value).toBe('b');
369
- });
370
-
371
- it('should select multiple options', async () => {
372
- document.body.innerHTML = `
373
- <select id="sel" multiple>
374
- <option value="a">A</option>
375
- <option value="b">B</option>
376
- <option value="c">C</option>
377
- </select>
378
- `;
379
- const select = document.getElementById('sel') as HTMLSelectElement;
380
-
381
- const agent = createAgent(document, window);
382
- const response = await agent.execute({
383
- id: '1',
384
- action: 'select',
385
- selector: '#sel',
386
- values: ['a', 'c'],
387
- });
388
-
389
- expect(response.success).toBe(true);
390
- expect(select.options[0].selected).toBe(true);
391
- expect(select.options[1].selected).toBe(false);
392
- expect(select.options[2].selected).toBe(true);
393
- });
394
- });
395
-
396
- describe('hover', () => {
397
- it('should dispatch hover events', async () => {
398
- document.body.innerHTML = '<button id="btn">Hover</button>';
399
- const button = document.getElementById('btn')!;
400
- const enterHandler = vi.fn();
401
- const overHandler = vi.fn();
402
- button.addEventListener('mouseenter', enterHandler);
403
- button.addEventListener('mouseover', overHandler);
404
-
405
- const agent = createAgent(document, window);
406
- const response = await agent.execute({
407
- id: '1',
408
- action: 'hover',
409
- selector: '#btn',
410
- });
411
-
412
- expect(response.success).toBe(true);
413
- expect(enterHandler).toHaveBeenCalled();
414
- expect(overHandler).toHaveBeenCalled();
415
- });
416
- });
417
-
418
- describe('getText', () => {
419
- it('should get element text', async () => {
420
- document.body.innerHTML = '<div id="text">Hello World</div>';
421
-
422
- const agent = createAgent(document, window);
423
- const response = await agent.execute({
424
- id: '1',
425
- action: 'getText',
426
- selector: '#text',
427
- });
428
-
429
- expect(response.success).toBe(true);
430
- if (response.success) {
431
- expect(response.data.text).toBe('Hello World');
432
- }
433
- });
434
- });
435
-
436
- describe('getAttribute', () => {
437
- it('should get attribute value', async () => {
438
- document.body.innerHTML = '<div id="el" data-value="123"></div>';
439
-
440
- const agent = createAgent(document, window);
441
- const response = await agent.execute({
442
- id: '1',
443
- action: 'getAttribute',
444
- selector: '#el',
445
- attribute: 'data-value',
446
- });
447
-
448
- expect(response.success).toBe(true);
449
- if (response.success) {
450
- expect(response.data.value).toBe('123');
451
- }
452
- });
453
- });
454
-
455
- describe('isVisible', () => {
456
- it('should return true for visible element', async () => {
457
- document.body.innerHTML = '<button id="btn">Visible</button>';
458
-
459
- const agent = createAgent(document, window);
460
- const response = await agent.execute({
461
- id: '1',
462
- action: 'isVisible',
463
- selector: '#btn',
464
- });
465
-
466
- expect(response.success).toBe(true);
467
- if (response.success) {
468
- expect(response.data.visible).toBe(true);
469
- }
470
- });
471
-
472
- it('should return false for hidden element', async () => {
473
- document.body.innerHTML = '<button id="btn" style="display: none">Hidden</button>';
474
-
475
- const agent = createAgent(document, window);
476
- const response = await agent.execute({
477
- id: '1',
478
- action: 'isVisible',
479
- selector: '#btn',
480
- });
481
-
482
- expect(response.success).toBe(true);
483
- if (response.success) {
484
- expect(response.data.visible).toBe(false);
485
- }
486
- });
487
- });
488
-
489
- describe('isEnabled', () => {
490
- it('should return false for disabled element', async () => {
491
- document.body.innerHTML = '<button id="btn" disabled>Disabled</button>';
492
-
493
- const agent = createAgent(document, window);
494
- const response = await agent.execute({
495
- id: '1',
496
- action: 'isEnabled',
497
- selector: '#btn',
498
- });
499
-
500
- expect(response.success).toBe(true);
501
- if (response.success) {
502
- expect(response.data.enabled).toBe(false);
503
- }
504
- });
505
- });
506
-
507
- describe('isChecked', () => {
508
- it('should return true for checked checkbox', async () => {
509
- document.body.innerHTML = '<input id="cb" type="checkbox" checked>';
510
-
511
- const agent = createAgent(document, window);
512
- const response = await agent.execute({
513
- id: '1',
514
- action: 'isChecked',
515
- selector: '#cb',
516
- });
517
-
518
- expect(response.success).toBe(true);
519
- if (response.success) {
520
- expect(response.data.checked).toBe(true);
521
- }
522
- });
523
- });
524
-
525
- describe('scroll', () => {
526
- it('should scroll window', async () => {
527
- const scrollBy = vi.spyOn(window, 'scrollBy').mockImplementation(() => {});
528
-
529
- const agent = createAgent(document, window);
530
- const response = await agent.execute({
531
- id: '1',
532
- action: 'scroll',
533
- y: 100,
534
- });
535
-
536
- expect(response.success).toBe(true);
537
- expect(scrollBy).toHaveBeenCalled();
538
- });
539
- });
540
-
541
- describe('scrollIntoView', () => {
542
- it('should scroll element into view', async () => {
543
- document.body.innerHTML = '<div id="target">Target</div>';
544
- const element = document.getElementById('target')!;
545
- element.scrollIntoView = vi.fn();
546
-
547
- const agent = createAgent(document, window);
548
- const response = await agent.execute({
549
- id: '1',
550
- action: 'scrollIntoView',
551
- selector: '#target',
552
- });
553
-
554
- expect(response.success).toBe(true);
555
- expect(element.scrollIntoView).toHaveBeenCalled();
556
- });
557
- });
558
-
559
- describe('evaluate', () => {
560
- it('should evaluate JavaScript expression', async () => {
561
- document.title = 'Test Page';
562
-
563
- const agent = createAgent(document, window);
564
- const response = await agent.execute({
565
- id: '1',
566
- action: 'evaluate',
567
- script: 'document.title',
568
- });
569
-
570
- expect(response.success).toBe(true);
571
- if (response.success) {
572
- expect(response.data.result).toBe('Test Page');
573
- }
574
- });
575
- });
576
-
577
- describe('executeJson', () => {
578
- it('should execute command from JSON string', async () => {
579
- document.body.innerHTML = '<button id="btn">Click</button>';
580
- const button = document.getElementById('btn')!;
581
- const handler = vi.fn();
582
- button.addEventListener('click', handler);
583
-
584
- const agent = createAgent(document, window);
585
- const responseJson = await agent.executeJson(
586
- JSON.stringify({ id: '1', action: 'click', selector: '#btn' })
587
- );
588
-
589
- const response = JSON.parse(responseJson);
590
- expect(response.success).toBe(true);
591
- expect(handler).toHaveBeenCalled();
592
- });
593
-
594
- it('should return error for invalid JSON', async () => {
595
- const agent = createAgent(document, window);
596
- const responseJson = await agent.executeJson('invalid json');
597
-
598
- const response = JSON.parse(responseJson);
599
- expect(response.success).toBe(false);
600
- expect(response.error).toContain('parse');
601
- });
602
- });
603
-
604
- describe('refMap', () => {
605
- it('should create and use ref map', () => {
606
- document.body.innerHTML = '<button id="btn">Click</button>';
607
- const button = document.getElementById('btn')!;
608
-
609
- const refMap = createRefMap();
610
- const ref = refMap.generateRef(button);
611
-
612
- expect(ref).toMatch(/^@ref:\d+$/);
613
- expect(refMap.get(ref)).toBe(button);
614
- });
615
-
616
- it('should return same ref for same element', () => {
617
- document.body.innerHTML = '<button id="btn">Click</button>';
618
- const button = document.getElementById('btn')!;
619
-
620
- const refMap = createRefMap();
621
- const ref1 = refMap.generateRef(button);
622
- const ref2 = refMap.generateRef(button);
623
-
624
- expect(ref1).toBe(ref2);
625
- });
626
-
627
- it('should clear refs', () => {
628
- document.body.innerHTML = '<button id="btn">Click</button>';
629
- const button = document.getElementById('btn')!;
630
-
631
- const refMap = createRefMap();
632
- const ref = refMap.generateRef(button);
633
- refMap.clear();
634
-
635
- expect(refMap.get(ref)).toBeNull();
636
- });
637
- });
638
- });