btcp-browser-agent 0.1.7 → 0.1.8

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/package.json CHANGED
@@ -1,69 +1,69 @@
1
- {
2
- "name": "btcp-browser-agent",
3
- "version": "0.1.7",
4
- "description": "Give AI agents the power to control browsers. A foundation for building agentic systems with smart DOM snapshots and stable element references.",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "default": "./dist/index.js"
13
- },
14
- "./core": {
15
- "types": "./packages/core/dist/index.d.ts",
16
- "import": "./packages/core/dist/index.js",
17
- "default": "./packages/core/dist/index.js"
18
- },
19
- "./extension": {
20
- "types": "./packages/extension/dist/index.d.ts",
21
- "import": "./packages/extension/dist/index.js",
22
- "default": "./packages/extension/dist/index.js"
23
- },
24
- "./extension/content": {
25
- "types": "./packages/extension/dist/content.d.ts",
26
- "import": "./packages/extension/dist/content.js",
27
- "default": "./packages/extension/dist/content.js"
28
- },
29
- "./extension/background": {
30
- "types": "./packages/extension/dist/background.d.ts",
31
- "import": "./packages/extension/dist/background.js",
32
- "default": "./packages/extension/dist/background.js"
33
- }
34
- },
35
- "scripts": {
36
- "build": "npm run build:packages && tsc -p tsconfig.build.json",
37
- "build:packages": "tsc -p packages/core/tsconfig.json && tsc -p packages/extension/tsconfig.json && tsc -p packages/cli/tsconfig.json",
38
- "clean": "rm -rf dist packages/*/dist",
39
- "prepare": "npm run build",
40
- "test": "vitest run",
41
- "test:watch": "vitest",
42
- "typecheck": "tsc --noEmit"
43
- },
44
- "workspaces": [
45
- "packages/core",
46
- "packages/extension",
47
- "packages/cli"
48
- ],
49
- "files": [
50
- "dist",
51
- "packages/core/dist",
52
- "packages/extension/dist",
53
- "!**/__tests__",
54
- "!**/*.map"
55
- ],
56
- "license": "Apache-2.0",
57
- "repository": {
58
- "type": "git",
59
- "url": "git+https://github.com/browser-tool-calling-protocol/btcp-browser-agent.git"
60
- },
61
- "dependencies": {},
62
- "devDependencies": {
63
- "@types/chrome": "^0.0.268",
64
- "@types/node": "^20.10.0",
65
- "jsdom": "^24.0.0",
66
- "typescript": "^5.3.0",
67
- "vitest": "^2.0.0"
68
- }
69
- }
1
+ {
2
+ "name": "btcp-browser-agent",
3
+ "version": "0.1.8",
4
+ "description": "Give AI agents the power to control browsers. A foundation for building agentic systems with smart DOM snapshots and stable element references.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./core": {
15
+ "types": "./packages/core/dist/index.d.ts",
16
+ "import": "./packages/core/dist/index.js",
17
+ "default": "./packages/core/dist/index.js"
18
+ },
19
+ "./extension": {
20
+ "types": "./packages/extension/dist/index.d.ts",
21
+ "import": "./packages/extension/dist/index.js",
22
+ "default": "./packages/extension/dist/index.js"
23
+ },
24
+ "./extension/content": {
25
+ "types": "./packages/extension/dist/content.d.ts",
26
+ "import": "./packages/extension/dist/content.js",
27
+ "default": "./packages/extension/dist/content.js"
28
+ },
29
+ "./extension/background": {
30
+ "types": "./packages/extension/dist/background.d.ts",
31
+ "import": "./packages/extension/dist/background.js",
32
+ "default": "./packages/extension/dist/background.js"
33
+ }
34
+ },
35
+ "scripts": {
36
+ "build": "npm run build:packages && tsc -p tsconfig.build.json",
37
+ "build:packages": "tsc -p packages/core/tsconfig.json && tsc -p packages/extension/tsconfig.json && tsc -p packages/cli/tsconfig.json",
38
+ "clean": "rm -rf dist packages/*/dist",
39
+ "prepare": "npm run build",
40
+ "test": "vitest run",
41
+ "test:watch": "vitest",
42
+ "typecheck": "tsc --noEmit"
43
+ },
44
+ "workspaces": [
45
+ "packages/core",
46
+ "packages/extension",
47
+ "packages/cli"
48
+ ],
49
+ "files": [
50
+ "dist",
51
+ "packages/core/dist",
52
+ "packages/extension/dist",
53
+ "!**/__tests__",
54
+ "!**/*.map"
55
+ ],
56
+ "license": "Apache-2.0",
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/browser-tool-calling-protocol/btcp-browser-agent.git"
60
+ },
61
+ "dependencies": {},
62
+ "devDependencies": {
63
+ "@types/chrome": "^0.0.268",
64
+ "@types/node": "^20.10.0",
65
+ "jsdom": "^24.0.0",
66
+ "typescript": "^5.3.0",
67
+ "vitest": "^2.0.0"
68
+ }
69
+ }
@@ -4,7 +4,8 @@
4
4
  * Element interaction handlers using native browser APIs.
5
5
  */
6
6
  import { createSnapshot } from './snapshot.js';
7
- import { DetailedError, createElementNotFoundError, createElementNotCompatibleError, createTimeoutError, createInvalidParametersError, } from './errors.js';
7
+ import { DetailedError, createElementNotFoundError, createElementNotCompatibleError, createTimeoutError, createInvalidParametersError, createVerificationError, } from './errors.js';
8
+ import { assertConnected, assertValueContains, assertValueEquals, assertChecked, assertSelected, waitForAssertion, } from './assertions.js';
8
9
  // Command ID counter for auto-generated IDs
9
10
  let commandIdCounter = 0;
10
11
  /**
@@ -336,12 +337,15 @@ export class DOMActions {
336
337
  element.dispatchEvent(new MouseEvent('mouseup', eventInit));
337
338
  element.dispatchEvent(new MouseEvent('click', eventInit));
338
339
  }
339
- return { clicked: true };
340
+ // Check if element is still connected (graceful - doesn't throw)
341
+ // Element may be intentionally removed by click handlers (e.g., modal close, navigation)
342
+ const connectionResult = assertConnected(element);
343
+ return { success: true, error: null, connected: connectionResult.success };
340
344
  }
341
345
  async dblclick(selector) {
342
346
  const element = this.getElement(selector);
343
347
  element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }));
344
- return { clicked: true };
348
+ return { success: true, error: null };
345
349
  }
346
350
  async type(selector, text, options = {}) {
347
351
  const element = this.getElement(selector);
@@ -366,7 +370,12 @@ export class DOMActions {
366
370
  }
367
371
  }
368
372
  element.dispatchEvent(new Event('change', { bubbles: true }));
369
- return { typed: true };
373
+ // Wait for verification that value contains typed text
374
+ const result = await waitForAssertion(() => assertValueContains(element, text), { timeout: 1000, interval: 50 });
375
+ if (!result.success) {
376
+ throw createVerificationError('type', result, selector);
377
+ }
378
+ return { success: true, error: null };
370
379
  }
371
380
  async fill(selector, value) {
372
381
  const element = this.getElement(selector);
@@ -379,7 +388,12 @@ export class DOMActions {
379
388
  element.value = value;
380
389
  element.dispatchEvent(new Event('input', { bubbles: true }));
381
390
  element.dispatchEvent(new Event('change', { bubbles: true }));
382
- return { filled: true };
391
+ // Wait for verification that value equals expected
392
+ const result = await waitForAssertion(() => assertValueEquals(element, value), { timeout: 1000, interval: 50 });
393
+ if (!result.success) {
394
+ throw createVerificationError('fill', result, selector);
395
+ }
396
+ return { success: true, error: null };
383
397
  }
384
398
  async clear(selector) {
385
399
  const element = this.getElement(selector);
@@ -388,7 +402,7 @@ export class DOMActions {
388
402
  element.dispatchEvent(new Event('input', { bubbles: true }));
389
403
  element.dispatchEvent(new Event('change', { bubbles: true }));
390
404
  }
391
- return { cleared: true };
405
+ return { success: true, error: null };
392
406
  }
393
407
  async check(selector) {
394
408
  const element = this.getElement(selector);
@@ -400,7 +414,12 @@ export class DOMActions {
400
414
  if (!element.checked) {
401
415
  element.click();
402
416
  }
403
- return { checked: true };
417
+ // Wait for verification that element is checked
418
+ const result = await waitForAssertion(() => assertChecked(element, true), { timeout: 1000, interval: 50 });
419
+ if (!result.success) {
420
+ throw createVerificationError('check', result, selector);
421
+ }
422
+ return { success: true, error: null };
404
423
  }
405
424
  async uncheck(selector) {
406
425
  const element = this.getElement(selector);
@@ -412,7 +431,12 @@ export class DOMActions {
412
431
  if (element.checked) {
413
432
  element.click();
414
433
  }
415
- return { unchecked: true };
434
+ // Wait for verification that element is unchecked
435
+ const result = await waitForAssertion(() => assertChecked(element, false), { timeout: 1000, interval: 50 });
436
+ if (!result.success) {
437
+ throw createVerificationError('uncheck', result, selector);
438
+ }
439
+ return { success: true, error: null };
416
440
  }
417
441
  async select(selector, values) {
418
442
  const element = this.getElement(selector);
@@ -426,27 +450,32 @@ export class DOMActions {
426
450
  option.selected = valueArray.includes(option.value);
427
451
  }
428
452
  element.dispatchEvent(new Event('change', { bubbles: true }));
429
- return { selected: valueArray };
453
+ // Wait for verification that expected options are selected
454
+ const result = await waitForAssertion(() => assertSelected(element, valueArray), { timeout: 1000, interval: 50 });
455
+ if (!result.success) {
456
+ throw createVerificationError('select', result, selector);
457
+ }
458
+ return { success: true, error: null, values: valueArray };
430
459
  }
431
460
  async focus(selector) {
432
461
  const element = this.getElement(selector);
433
462
  if (element instanceof HTMLElement) {
434
463
  element.focus();
435
464
  }
436
- return { focused: true };
465
+ return { success: true, error: null };
437
466
  }
438
467
  async blur(selector) {
439
468
  const element = this.getElement(selector);
440
469
  if (element instanceof HTMLElement) {
441
470
  element.blur();
442
471
  }
443
- return { blurred: true };
472
+ return { success: true, error: null };
444
473
  }
445
474
  async hover(selector) {
446
475
  const element = this.getElement(selector);
447
476
  element.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
448
477
  element.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
449
- return { hovered: true };
478
+ return { success: true, error: null };
450
479
  }
451
480
  async scroll(selector, options) {
452
481
  // Validate parameter combinations
@@ -481,12 +510,12 @@ export class DOMActions {
481
510
  else {
482
511
  this.window.scrollBy(deltaX, deltaY);
483
512
  }
484
- return { scrolled: true };
513
+ return { success: true, error: null };
485
514
  }
486
515
  async scrollIntoView(selector, block = 'center') {
487
516
  const element = this.getElement(selector);
488
517
  element.scrollIntoView({ behavior: 'smooth', block });
489
- return { scrolled: true };
518
+ return { success: true, error: null };
490
519
  }
491
520
  async snapshot(options) {
492
521
  const root = options.selector
@@ -512,32 +541,34 @@ export class DOMActions {
512
541
  async querySelector(selector) {
513
542
  const element = this.queryElement(selector);
514
543
  if (!element) {
515
- return { found: false };
544
+ return { success: false, error: `Element not found: ${selector}` };
516
545
  }
517
546
  const ref = this.refMap.generateRef(element);
518
- return { found: true, ref };
547
+ return { success: true, error: null, ref };
519
548
  }
520
549
  async querySelectorAll(selector) {
521
550
  const elements = this.queryElements(selector);
522
551
  const refs = elements.map((el) => this.refMap.generateRef(el));
523
- return { count: elements.length, refs };
552
+ return { success: true, error: null, count: elements.length, refs };
524
553
  }
525
554
  async getText(selector) {
526
555
  const element = this.getElement(selector);
527
- return { text: element.textContent };
556
+ return { success: true, error: null, text: element.textContent };
528
557
  }
529
558
  async getAttribute(selector, attribute) {
530
559
  const element = this.getElement(selector);
531
- return { value: element.getAttribute(attribute) };
560
+ return { success: true, error: null, value: element.getAttribute(attribute) };
532
561
  }
533
562
  async getProperty(selector, property) {
534
563
  const element = this.getElement(selector);
535
- return { value: element[property] };
564
+ return { success: true, error: null, value: element[property] };
536
565
  }
537
566
  async getBoundingBox(selector) {
538
567
  const element = this.getElement(selector);
539
568
  const rect = element.getBoundingClientRect();
540
569
  return {
570
+ success: true,
571
+ error: null,
541
572
  box: {
542
573
  x: rect.x,
543
574
  y: rect.y,
@@ -549,23 +580,23 @@ export class DOMActions {
549
580
  async isVisible(selector) {
550
581
  const element = this.queryElement(selector);
551
582
  if (!element || !(element instanceof HTMLElement)) {
552
- return { visible: false };
583
+ return { success: true, error: null, visible: false };
553
584
  }
554
585
  const style = this.window.getComputedStyle(element);
555
586
  const visible = style.display !== 'none' &&
556
587
  style.visibility !== 'hidden' &&
557
588
  style.opacity !== '0';
558
- return { visible };
589
+ return { success: true, error: null, visible };
559
590
  }
560
591
  async isEnabled(selector) {
561
592
  const element = this.getElement(selector);
562
593
  const enabled = !element.disabled;
563
- return { enabled };
594
+ return { success: true, error: null, enabled };
564
595
  }
565
596
  async isChecked(selector) {
566
597
  const element = this.getElement(selector);
567
598
  const checked = element.checked ?? false;
568
- return { checked };
599
+ return { success: true, error: null, checked };
569
600
  }
570
601
  async press(key, selector, modifiers = []) {
571
602
  const target = selector
@@ -584,23 +615,23 @@ export class DOMActions {
584
615
  target.dispatchEvent(new KeyboardEvent('keydown', eventInit));
585
616
  target.dispatchEvent(new KeyboardEvent('keypress', eventInit));
586
617
  target.dispatchEvent(new KeyboardEvent('keyup', eventInit));
587
- return { pressed: true };
618
+ return { success: true, error: null };
588
619
  }
589
620
  async keyDown(key) {
590
621
  const target = this.document.activeElement || this.document.body;
591
622
  target.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true }));
592
- return { down: true };
623
+ return { success: true, error: null };
593
624
  }
594
625
  async keyUp(key) {
595
626
  const target = this.document.activeElement || this.document.body;
596
627
  target.dispatchEvent(new KeyboardEvent('keyup', { key, bubbles: true }));
597
- return { up: true };
628
+ return { success: true, error: null };
598
629
  }
599
630
  async wait(selector, options = {}) {
600
631
  const { state = 'visible', timeout = 5000 } = options;
601
632
  if (!selector) {
602
633
  await this.sleep(timeout);
603
- return { waited: true };
634
+ return { success: true, error: null };
604
635
  }
605
636
  const startTime = Date.now();
606
637
  let lastState;
@@ -649,7 +680,7 @@ export class DOMActions {
649
680
  break;
650
681
  }
651
682
  if (conditionMet) {
652
- return { waited: true };
683
+ return { success: true, error: null };
653
684
  }
654
685
  await this.sleep(100);
655
686
  }
@@ -659,7 +690,7 @@ export class DOMActions {
659
690
  async evaluate(script, args) {
660
691
  const fn = new Function(...(args?.map((_, i) => `arg${i}`) || []), `return (${script})`);
661
692
  const result = fn.call(this.window, ...(args || []));
662
- return { result };
693
+ return { success: true, error: null, result };
663
694
  }
664
695
  /**
665
696
  * Validate element capabilities before attempting an action
@@ -765,15 +796,15 @@ export class DOMActions {
765
796
  // Create overlay container with absolute positioning covering entire document
766
797
  this.overlayContainer = this.document.createElement('div');
767
798
  this.overlayContainer.id = 'btcp-highlight-overlay';
768
- this.overlayContainer.style.cssText = `
769
- position: absolute;
770
- top: 0;
771
- left: 0;
772
- width: ${this.document.documentElement.scrollWidth}px;
773
- height: ${this.document.documentElement.scrollHeight}px;
774
- pointer-events: none;
775
- z-index: 999999;
776
- contain: layout style paint;
799
+ this.overlayContainer.style.cssText = `
800
+ position: absolute;
801
+ top: 0;
802
+ left: 0;
803
+ width: ${this.document.documentElement.scrollWidth}px;
804
+ height: ${this.document.documentElement.scrollHeight}px;
805
+ pointer-events: none;
806
+ z-index: 999999;
807
+ contain: layout style paint;
777
808
  `;
778
809
  let highlightedCount = 0;
779
810
  // Create border overlays and labels for each ref
@@ -794,17 +825,17 @@ export class DOMActions {
794
825
  const border = this.document.createElement('div');
795
826
  border.className = 'btcp-ref-border';
796
827
  border.dataset.ref = ref;
797
- border.style.cssText = `
798
- position: absolute;
799
- width: ${bbox.width}px;
800
- height: ${bbox.height}px;
801
- transform: translate3d(${bbox.left + this.window.scrollX}px, ${bbox.top + this.window.scrollY}px, 0);
802
- border: 2px solid rgba(59, 130, 246, 0.8);
803
- border-radius: 2px;
804
- box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2);
805
- pointer-events: none;
806
- will-change: transform;
807
- contain: layout style paint;
828
+ border.style.cssText = `
829
+ position: absolute;
830
+ width: ${bbox.width}px;
831
+ height: ${bbox.height}px;
832
+ transform: translate3d(${bbox.left + this.window.scrollX}px, ${bbox.top + this.window.scrollY}px, 0);
833
+ border: 2px solid rgba(59, 130, 246, 0.8);
834
+ border-radius: 2px;
835
+ box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2);
836
+ pointer-events: none;
837
+ will-change: transform;
838
+ contain: layout style paint;
808
839
  `;
809
840
  // Create label
810
841
  const label = this.document.createElement('div');
@@ -812,21 +843,21 @@ export class DOMActions {
812
843
  label.dataset.ref = ref;
813
844
  // Extract number from ref (e.g., "@ref:5" -> "5")
814
845
  label.textContent = ref.replace('@ref:', '');
815
- label.style.cssText = `
816
- position: absolute;
817
- transform: translate3d(${bbox.left + this.window.scrollX}px, ${bbox.top + this.window.scrollY}px, 0);
818
- background: rgba(59, 130, 246, 0.9);
819
- color: white;
820
- padding: 2px 6px;
821
- border-radius: 3px;
822
- font-family: monospace;
823
- font-size: 11px;
824
- font-weight: bold;
825
- box-shadow: 0 2px 4px rgba(0,0,0,0.3);
826
- pointer-events: none;
827
- white-space: nowrap;
828
- will-change: transform;
829
- contain: layout style paint;
846
+ label.style.cssText = `
847
+ position: absolute;
848
+ transform: translate3d(${bbox.left + this.window.scrollX}px, ${bbox.top + this.window.scrollY}px, 0);
849
+ background: rgba(59, 130, 246, 0.9);
850
+ color: white;
851
+ padding: 2px 6px;
852
+ border-radius: 3px;
853
+ font-family: monospace;
854
+ font-size: 11px;
855
+ font-weight: bold;
856
+ box-shadow: 0 2px 4px rgba(0,0,0,0.3);
857
+ pointer-events: none;
858
+ white-space: nowrap;
859
+ will-change: transform;
860
+ contain: layout style paint;
830
861
  `;
831
862
  this.overlayContainer.appendChild(border);
832
863
  this.overlayContainer.appendChild(label);
@@ -852,7 +883,7 @@ export class DOMActions {
852
883
  };
853
884
  // Use passive listener for better scroll performance
854
885
  this.window.addEventListener('scroll', this.scrollListener, { passive: true });
855
- return { highlighted: highlightedCount };
886
+ return { success: true, error: null, count: highlightedCount };
856
887
  }
857
888
  /**
858
889
  * Invalidate snapshot data (called on navigation or manual clear)
@@ -921,7 +952,7 @@ export class DOMActions {
921
952
  */
922
953
  async clearHighlight() {
923
954
  this.clearExistingOverlay();
924
- return { cleared: true };
955
+ return { success: true, error: null };
925
956
  }
926
957
  /**
927
958
  * Remove existing overlay if it exists
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @btcp/core - Assertions Module
3
+ *
4
+ * Provides verification utilities for DOM actions with async waiting support.
5
+ * Returns structured results for consistent error handling.
6
+ */
7
+ /**
8
+ * Base interface for all action results
9
+ * Provides unified success/error pattern across all DOM operations
10
+ *
11
+ * Use intersection types to add action-specific data:
12
+ * @example
13
+ * ```typescript
14
+ * type ClickResult = ActionResult & { connected: boolean };
15
+ * type GetTextResult = ActionResult & { text: string | null };
16
+ * ```
17
+ */
18
+ export interface ActionResult {
19
+ /** Whether the action succeeded */
20
+ success: boolean;
21
+ /** Error message if action failed, null otherwise */
22
+ error: string | null;
23
+ }
24
+ /**
25
+ * Result of a single assertion check
26
+ */
27
+ export interface AssertionResult {
28
+ /** Whether the assertion succeeded */
29
+ success: boolean;
30
+ /** Error message if assertion failed, null otherwise */
31
+ error: string | null;
32
+ /** Human-readable description of what was checked */
33
+ description: string;
34
+ /** The expected value */
35
+ expected: unknown;
36
+ /** The actual value found */
37
+ actual: unknown;
38
+ /** Additional context information */
39
+ context?: Record<string, unknown>;
40
+ }
41
+ /**
42
+ * Options for waiting on an assertion
43
+ */
44
+ export interface WaitForAssertionOptions {
45
+ /** Maximum time to wait in milliseconds (default: 1000) */
46
+ timeout?: number;
47
+ /** Interval between checks in milliseconds (default: 50) */
48
+ interval?: number;
49
+ }
50
+ /**
51
+ * Result of waiting for an assertion
52
+ */
53
+ export interface WaitResult {
54
+ /** Whether the assertion passed within the timeout */
55
+ success: boolean;
56
+ /** Total time elapsed in milliseconds */
57
+ elapsed: number;
58
+ /** Number of attempts made */
59
+ attempts: number;
60
+ /** The final assertion result */
61
+ result: AssertionResult;
62
+ }
63
+ /**
64
+ * Assert that an element is still connected to the DOM
65
+ */
66
+ export declare function assertConnected(element: Element): AssertionResult;
67
+ /**
68
+ * Assert that an input/textarea value contains the expected text
69
+ */
70
+ export declare function assertValueContains(element: HTMLInputElement | HTMLTextAreaElement, text: string): AssertionResult;
71
+ /**
72
+ * Assert that an input/textarea value equals the expected value exactly
73
+ */
74
+ export declare function assertValueEquals(element: HTMLInputElement | HTMLTextAreaElement, value: string): AssertionResult;
75
+ /**
76
+ * Assert that a checkbox/radio is in the expected checked state
77
+ */
78
+ export declare function assertChecked(element: HTMLInputElement, expected: boolean): AssertionResult;
79
+ /**
80
+ * Assert that a select element has the expected values selected
81
+ */
82
+ export declare function assertSelected(element: HTMLSelectElement, values: string[]): AssertionResult;
83
+ /**
84
+ * Assert that a URL matches the expected origin
85
+ */
86
+ export declare function assertUrlOrigin(actualUrl: string, expectedUrl: string): AssertionResult;
87
+ /**
88
+ * Assert that an element is visible (or hidden)
89
+ */
90
+ export declare function assertVisible(element: HTMLElement, win: Window, expected?: boolean): AssertionResult;
91
+ /**
92
+ * Assert that an element is enabled (or disabled)
93
+ */
94
+ export declare function assertEnabled(element: HTMLElement, expected?: boolean): AssertionResult;
95
+ /**
96
+ * Wait for an assertion to pass within a timeout period
97
+ *
98
+ * Polls the assertion function at regular intervals until it passes
99
+ * or the timeout is reached.
100
+ *
101
+ * @param assertFn - Function that returns an AssertionResult
102
+ * @param options - Timeout and interval options
103
+ * @returns WaitResult with success status and timing information
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const result = await waitForAssertion(
108
+ * () => assertValueEquals(input, 'hello'),
109
+ * { timeout: 1000, interval: 50 }
110
+ * );
111
+ *
112
+ * if (!result.success) {
113
+ * throw createVerificationError('fill', result, selector);
114
+ * }
115
+ * ```
116
+ */
117
+ export declare function waitForAssertion(assertFn: () => AssertionResult, options?: WaitForAssertionOptions): Promise<WaitResult>;
118
+ //# sourceMappingURL=assertions.d.ts.map