@testspectra/matchers 1.2.0 → 1.2.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.
@@ -8,7 +8,7 @@
8
8
  * DSL layer contains zero platform branching.
9
9
  */
10
10
  import type { TestSpectraWorkerConfig } from './worker_config.js';
11
- import type { CDPNetworkEntry, MockInterceptHandle, MockRule, ScopedSelector, ScrollOptions, SpectraBrowserBridge, SwipeOptions } from './types.js';
11
+ import type { CDPNetworkEntry, ElementBounds, MockInterceptHandle, MockRule, ScopedSelector, ScrollOptions, SpectraBrowserBridge, SwipeOptions } from './types.js';
12
12
  /**
13
13
  * @deprecated Renamed to `TestSpectraWorkerConfig` (now shared by E2E and component testing).
14
14
  * Kept as an alias for backwards compatibility.
@@ -120,6 +120,16 @@ export interface PlatformDriverBridge extends SpectraBrowserBridge {
120
120
  value: string;
121
121
  }>;
122
122
  count(selector: string | ScopedSelector): Promise<number>;
123
+ waitForElementRemoved(selector: string | ScopedSelector, timeoutMs?: number, index?: number | null): Promise<void>;
124
+ waitForUndisplayed(selector: string | ScopedSelector, opts?: {
125
+ timeout?: number;
126
+ }, index?: number | null): Promise<void>;
127
+ waitForClickable(selector: string | ScopedSelector, opts?: {
128
+ timeout?: number;
129
+ }, index?: number | null): Promise<boolean>;
130
+ getBounds(selector: string | ScopedSelector, index?: number | null): Promise<ElementBounds>;
131
+ closest(selector: string | ScopedSelector, targetSelector: string, index?: number | null): Promise<string | null>;
132
+ clickAt(x: number, y: number): Promise<void>;
123
133
  pressKey(key: string | number): Promise<void>;
124
134
  scroll(options?: ScrollOptions): Promise<void>;
125
135
  swipe(options: SwipeOptions): Promise<void>;
package/dist/types.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Canonical action keys supported across TestSpectra runner and database models.
3
3
  * @see backend/src/models/test_step.rs
4
4
  */
5
- export type ActionKey = 'navigate' | 'click' | 'type' | 'clear' | 'select' | 'scroll' | 'swipe' | 'wait' | 'waitForElement' | 'pressKey' | 'longPress' | 'doubleClick' | 'hover' | 'focus' | 'blur' | 'dragDrop' | 'upload' | 'back' | 'refresh';
5
+ export type ActionKey = 'navigate' | 'click' | 'type' | 'clear' | 'select' | 'scroll' | 'swipe' | 'wait' | 'waitForElement' | 'waitForElementRemoved' | 'waitForUndisplayed' | 'waitForClickable' | 'pressKey' | 'longPress' | 'doubleClick' | 'hover' | 'focus' | 'blur' | 'dragDrop' | 'upload' | 'back' | 'refresh';
6
6
  /**
7
7
  * Canonical assertion keys supported across TestSpectra runner and database models.
8
8
  * @see backend/src/models/test_step.rs
@@ -73,6 +73,22 @@ export interface ScrollOptions {
73
73
  /** Optional target element selector to scroll directly into view */
74
74
  selector?: ElementTarget;
75
75
  }
76
+ /**
77
+ * Bounding rectangle of an element — mirrors `Element.getBoundingClientRect()` on web
78
+ * and the `bounds: [left, top, right, bottom]` field of an Android accessibility node.
79
+ */
80
+ export interface ElementBounds {
81
+ /** Horizontal position relative to viewport (alias of `left`). */
82
+ x: number;
83
+ /** Vertical position relative to viewport (alias of `top`). */
84
+ y: number;
85
+ top: number;
86
+ right: number;
87
+ bottom: number;
88
+ left: number;
89
+ width: number;
90
+ height: number;
91
+ }
76
92
  /**
77
93
  * Configuration options for touch swipe gestures (mobile & web).
78
94
  *
@@ -111,6 +127,10 @@ export interface ClickOptions {
111
127
  text?: string;
112
128
  /** Click type: standard single click or double click */
113
129
  clickType?: 'single' | 'double';
130
+ /** X coordinate for a coordinate-based click (relative to the element). */
131
+ x?: number;
132
+ /** Y coordinate for a coordinate-based click (relative to the element). */
133
+ y?: number;
114
134
  }
115
135
  /**
116
136
  * Configuration options for typing input into form elements.
@@ -795,6 +815,58 @@ export interface SingleElementProxy extends ElementReceiverAssertions<Promise<vo
795
815
  waitForDisplayed(opts?: {
796
816
  timeout?: number;
797
817
  }): Promise<boolean>;
818
+ /**
819
+ * Waits for the element to be removed from the DOM within the specified timeout.
820
+ * Opposite of `waitForElement()` — poll until the element no longer exists.
821
+ *
822
+ * @param timeoutMs Timeout in milliseconds (default: 5000ms).
823
+ */
824
+ waitForElementRemoved(timeoutMs?: number): Promise<void>;
825
+ /**
826
+ * Waits for the element to be hidden, detached, or not displayed within the specified timeout.
827
+ * Opposite of `waitForDisplayed()` — poll until the element is no longer visible.
828
+ *
829
+ * @param opts Optional timeout configuration object.
830
+ */
831
+ waitForUndisplayed(opts?: {
832
+ timeout?: number;
833
+ }): Promise<void>;
834
+ /**
835
+ * Waits until the element is enabled, visible, and clickable within the specified timeout.
836
+ *
837
+ * @param opts Optional timeout configuration object.
838
+ * @returns Promise resolving to true if the element became clickable, false on timeout.
839
+ */
840
+ waitForClickable(opts?: {
841
+ timeout?: number;
842
+ }): Promise<boolean>;
843
+ /**
844
+ * Returns the element's bounding rectangle (position + size relative to viewport).
845
+ *
846
+ * @example
847
+ * ```ts
848
+ * const bounds = await Spectra.get('#modal').getBounds();
849
+ * console.log(bounds.x, bounds.y, bounds.width, bounds.height);
850
+ * ```
851
+ */
852
+ getBounds(): Promise<ElementBounds>;
853
+ /**
854
+ * Returns the parent element of this element in the DOM tree.
855
+ *
856
+ * @example
857
+ * ```ts
858
+ * const parent = await Spectra.get('#child').parent();
859
+ * await parent.shouldBeVisible();
860
+ * ```
861
+ */
862
+ parent(): SingleElementProxy;
863
+ /**
864
+ * Finds the closest ancestor that matches the selector (mirrors `Element.closest()`).
865
+ *
866
+ * @param selector CSS selector to match against ancestors.
867
+ * @returns Promise resolving to the closest matching ancestor, or null if none found.
868
+ */
869
+ closest(selector: string): Promise<SingleElementProxy | null>;
798
870
  /**
799
871
  * Returns the inner text content of the element.
800
872
  *
@@ -1000,6 +1072,17 @@ export interface SpectraBrowserBridge extends BrowserReceiverAssertions {
1000
1072
  timeout?: number;
1001
1073
  timeoutMsg?: string;
1002
1074
  }): Promise<boolean>;
1075
+ /**
1076
+ * Clicks at absolute viewport coordinates (x, y).
1077
+ *
1078
+ * @param x Horizontal viewport coordinate.
1079
+ * @param y Vertical viewport coordinate.
1080
+ * @example
1081
+ * ```ts
1082
+ * await Spectra.browser.clickAt(100, 200);
1083
+ * ```
1084
+ */
1085
+ clickAt(x: number, y: number): Promise<void>;
1003
1086
  /**
1004
1087
  * Retrieves captured browser console log entries.
1005
1088
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testspectra/matchers",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Canonical TypeScript contracts and ambient type definitions for TestSpectra",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/contract.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  import type { TestSpectraWorkerConfig } from './worker_config.js';
12
12
  import type {
13
13
  CDPNetworkEntry,
14
+ ElementBounds,
14
15
  MockInterceptHandle,
15
16
  MockRule,
16
17
  ScopedSelector,
@@ -171,6 +172,21 @@ export interface PlatformDriverBridge extends SpectraBrowserBridge {
171
172
  getCSSProperty(selector: string | ScopedSelector, name: string, index?: number | null): Promise<{ value: string }>;
172
173
  count(selector: string | ScopedSelector): Promise<number>;
173
174
 
175
+ waitForElementRemoved(selector: string | ScopedSelector, timeoutMs?: number, index?: number | null): Promise<void>;
176
+ waitForUndisplayed(
177
+ selector: string | ScopedSelector,
178
+ opts?: { timeout?: number },
179
+ index?: number | null,
180
+ ): Promise<void>;
181
+ waitForClickable(
182
+ selector: string | ScopedSelector,
183
+ opts?: { timeout?: number },
184
+ index?: number | null,
185
+ ): Promise<boolean>;
186
+ getBounds(selector: string | ScopedSelector, index?: number | null): Promise<ElementBounds>;
187
+ closest(selector: string | ScopedSelector, targetSelector: string, index?: number | null): Promise<string | null>;
188
+ clickAt(x: number, y: number): Promise<void>;
189
+
174
190
  // --- Gestures & Keys ---
175
191
  pressKey(key: string | number): Promise<void>;
176
192
  scroll(options?: ScrollOptions): Promise<void>;
package/src/types.ts CHANGED
@@ -12,6 +12,9 @@ export type ActionKey =
12
12
  | 'swipe'
13
13
  | 'wait'
14
14
  | 'waitForElement'
15
+ | 'waitForElementRemoved'
16
+ | 'waitForUndisplayed'
17
+ | 'waitForClickable'
15
18
  | 'pressKey'
16
19
  | 'longPress'
17
20
  | 'doubleClick'
@@ -147,6 +150,23 @@ export interface ScrollOptions {
147
150
  selector?: ElementTarget;
148
151
  }
149
152
 
153
+ /**
154
+ * Bounding rectangle of an element — mirrors `Element.getBoundingClientRect()` on web
155
+ * and the `bounds: [left, top, right, bottom]` field of an Android accessibility node.
156
+ */
157
+ export interface ElementBounds {
158
+ /** Horizontal position relative to viewport (alias of `left`). */
159
+ x: number;
160
+ /** Vertical position relative to viewport (alias of `top`). */
161
+ y: number;
162
+ top: number;
163
+ right: number;
164
+ bottom: number;
165
+ left: number;
166
+ width: number;
167
+ height: number;
168
+ }
169
+
150
170
  /**
151
171
  * Configuration options for touch swipe gestures (mobile & web).
152
172
  *
@@ -187,6 +207,10 @@ export interface ClickOptions {
187
207
  text?: string;
188
208
  /** Click type: standard single click or double click */
189
209
  clickType?: 'single' | 'double';
210
+ /** X coordinate for a coordinate-based click (relative to the element). */
211
+ x?: number;
212
+ /** Y coordinate for a coordinate-based click (relative to the element). */
213
+ y?: number;
190
214
  }
191
215
 
192
216
  /**
@@ -979,6 +1003,60 @@ export interface SingleElementProxy extends ElementReceiverAssertions<Promise<vo
979
1003
  */
980
1004
  waitForDisplayed(opts?: { timeout?: number }): Promise<boolean>;
981
1005
 
1006
+ /**
1007
+ * Waits for the element to be removed from the DOM within the specified timeout.
1008
+ * Opposite of `waitForElement()` — poll until the element no longer exists.
1009
+ *
1010
+ * @param timeoutMs Timeout in milliseconds (default: 5000ms).
1011
+ */
1012
+ waitForElementRemoved(timeoutMs?: number): Promise<void>;
1013
+
1014
+ /**
1015
+ * Waits for the element to be hidden, detached, or not displayed within the specified timeout.
1016
+ * Opposite of `waitForDisplayed()` — poll until the element is no longer visible.
1017
+ *
1018
+ * @param opts Optional timeout configuration object.
1019
+ */
1020
+ waitForUndisplayed(opts?: { timeout?: number }): Promise<void>;
1021
+
1022
+ /**
1023
+ * Waits until the element is enabled, visible, and clickable within the specified timeout.
1024
+ *
1025
+ * @param opts Optional timeout configuration object.
1026
+ * @returns Promise resolving to true if the element became clickable, false on timeout.
1027
+ */
1028
+ waitForClickable(opts?: { timeout?: number }): Promise<boolean>;
1029
+
1030
+ /**
1031
+ * Returns the element's bounding rectangle (position + size relative to viewport).
1032
+ *
1033
+ * @example
1034
+ * ```ts
1035
+ * const bounds = await Spectra.get('#modal').getBounds();
1036
+ * console.log(bounds.x, bounds.y, bounds.width, bounds.height);
1037
+ * ```
1038
+ */
1039
+ getBounds(): Promise<ElementBounds>;
1040
+
1041
+ /**
1042
+ * Returns the parent element of this element in the DOM tree.
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * const parent = await Spectra.get('#child').parent();
1047
+ * await parent.shouldBeVisible();
1048
+ * ```
1049
+ */
1050
+ parent(): SingleElementProxy;
1051
+
1052
+ /**
1053
+ * Finds the closest ancestor that matches the selector (mirrors `Element.closest()`).
1054
+ *
1055
+ * @param selector CSS selector to match against ancestors.
1056
+ * @returns Promise resolving to the closest matching ancestor, or null if none found.
1057
+ */
1058
+ closest(selector: string): Promise<SingleElementProxy | null>;
1059
+
982
1060
  /**
983
1061
  * Returns the inner text content of the element.
984
1062
  *
@@ -1204,6 +1282,18 @@ export interface SpectraBrowserBridge extends BrowserReceiverAssertions {
1204
1282
  */
1205
1283
  waitUntil(fn: () => Promise<boolean> | boolean, opts?: { timeout?: number; timeoutMsg?: string }): Promise<boolean>;
1206
1284
 
1285
+ /**
1286
+ * Clicks at absolute viewport coordinates (x, y).
1287
+ *
1288
+ * @param x Horizontal viewport coordinate.
1289
+ * @param y Vertical viewport coordinate.
1290
+ * @example
1291
+ * ```ts
1292
+ * await Spectra.browser.clickAt(100, 200);
1293
+ * ```
1294
+ */
1295
+ clickAt(x: number, y: number): Promise<void>;
1296
+
1207
1297
  /**
1208
1298
  * Retrieves captured browser console log entries.
1209
1299
  *
Binary file
Binary file