@react-three-dom/cypress 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -9,6 +9,10 @@ interface ObjectMetadata {
9
9
  vertexCount?: number;
10
10
  triangleCount?: number;
11
11
  instanceCount?: number;
12
+ fov?: number;
13
+ near?: number;
14
+ far?: number;
15
+ zoom?: number;
12
16
  position: [number, number, number];
13
17
  rotation: [number, number, number];
14
18
  scale: [number, number, number];
@@ -36,6 +40,8 @@ interface ObjectInspection {
36
40
  center: [number, number, number];
37
41
  radius: number;
38
42
  };
43
+ positionData?: number[];
44
+ indexData?: number[];
39
45
  };
40
46
  material?: {
41
47
  type: string;
@@ -57,6 +63,11 @@ interface SnapshotNode {
57
63
  position: [number, number, number];
58
64
  rotation: [number, number, number];
59
65
  scale: [number, number, number];
66
+ geometryType?: string;
67
+ materialType?: string;
68
+ vertexCount?: number;
69
+ triangleCount?: number;
70
+ instanceCount?: number;
60
71
  children: SnapshotNode[];
61
72
  }
62
73
  interface SceneSnapshot {
@@ -64,6 +75,49 @@ interface SceneSnapshot {
64
75
  objectCount: number;
65
76
  tree: SnapshotNode;
66
77
  }
78
+ interface BridgeDiagnostics {
79
+ version: string;
80
+ ready: boolean;
81
+ error?: string;
82
+ objectCount: number;
83
+ meshCount: number;
84
+ groupCount: number;
85
+ lightCount: number;
86
+ cameraCount: number;
87
+ materializedDomNodes: number;
88
+ maxDomNodes: number;
89
+ canvasWidth: number;
90
+ canvasHeight: number;
91
+ webglRenderer: string;
92
+ dirtyQueueSize: number;
93
+ }
94
+ interface CameraState {
95
+ type: string;
96
+ position: [number, number, number];
97
+ rotation: [number, number, number];
98
+ target: [number, number, number];
99
+ fov?: number;
100
+ near: number;
101
+ far: number;
102
+ zoom: number;
103
+ aspect?: number;
104
+ left?: number;
105
+ right?: number;
106
+ top?: number;
107
+ bottom?: number;
108
+ }
109
+
110
+ interface SceneDiffChange {
111
+ uuid: string;
112
+ field: string;
113
+ from: unknown;
114
+ to: unknown;
115
+ }
116
+ interface SceneDiff {
117
+ added: SnapshotNode[];
118
+ removed: SnapshotNode[];
119
+ changed: SceneDiffChange[];
120
+ }
67
121
 
68
122
  // ---------------------------------------------------------------------------
69
123
  // TypeScript declarations for @react-three-dom/cypress
@@ -78,31 +132,85 @@ interface SceneSnapshot {
78
132
  declare global {
79
133
  namespace Cypress {
80
134
  interface Chainable {
135
+ // ---- Multi-canvas ----
136
+ /**
137
+ * Switch all subsequent r3f commands to target a specific canvas instance.
138
+ * Pass `null` to switch back to the default canvas.
139
+ * @example cy.r3fUseCanvas('minimap'); cy.r3fClick('marker');
140
+ */
141
+ r3fUseCanvas(canvasId: string | null): Chainable<void>;
142
+ /** List all active canvas IDs registered on the page. */
143
+ r3fGetCanvasIds(): Chainable<string[]>;
144
+
145
+ // ---- Debug / Reporter ----
146
+ /** Enable debug logging. Mirrors [r3f-dom:*] browser logs to Cypress command log. */
147
+ r3fEnableDebug(): Chainable<void>;
148
+ /**
149
+ * Enable the R3F reporter for rich terminal output (bridge status, object lookup,
150
+ * interaction timing, diagnostics). Requires `registerR3FTasks(on)` in cypress.config.ts.
151
+ */
152
+ r3fEnableReporter(enabled?: boolean): Chainable<void>;
153
+ /** Log the full scene tree to the Cypress command log and browser console. */
154
+ r3fLogScene(): Chainable<void>;
155
+
156
+ // ---- Diagnostics ----
157
+ /** Get bridge diagnostics (object counts, DOM state, GPU info). */
158
+ r3fGetDiagnostics(): Chainable<BridgeDiagnostics | null>;
159
+ /** Log bridge diagnostics to the Cypress command log and browser console. */
160
+ r3fLogDiagnostics(): Chainable<void>;
161
+ /** Fuzzy search for objects by partial testId, name, or uuid. */
162
+ r3fFuzzyFind(query: string, limit?: number): Chainable<ObjectMetadata[]>;
163
+
81
164
  // ---- Interactions ----
82
- /** Click a 3D object by testId or uuid. */
165
+ /** Click a 3D object by testId or uuid. Auto-waits for bridge + object. */
83
166
  r3fClick(idOrUuid: string): Chainable<void>;
84
- /** Double-click a 3D object by testId or uuid. */
167
+ /** Double-click a 3D object by testId or uuid. Auto-waits for bridge + object. */
85
168
  r3fDoubleClick(idOrUuid: string): Chainable<void>;
86
- /** Right-click / context-menu a 3D object by testId or uuid. */
169
+ /** Right-click / context-menu a 3D object by testId or uuid. Auto-waits for bridge + object. */
87
170
  r3fContextMenu(idOrUuid: string): Chainable<void>;
88
- /** Hover over a 3D object by testId or uuid. */
171
+ /** Hover over a 3D object by testId or uuid. Auto-waits for bridge + object. */
89
172
  r3fHover(idOrUuid: string): Chainable<void>;
90
- /** Drag a 3D object with a world-space delta vector. */
173
+ /** Unhover / pointer-leave resets hover state. Auto-waits for bridge. */
174
+ r3fUnhover(): Chainable<void>;
175
+ /** Drag a 3D object with a world-space delta vector. Auto-waits for bridge + object. */
91
176
  r3fDrag(idOrUuid: string, delta: { x: number; y: number; z: number }): Chainable<void>;
92
- /** Dispatch a wheel/scroll event on a 3D object. */
177
+ /** Dispatch a wheel/scroll event on a 3D object. Auto-waits for bridge + object. */
93
178
  r3fWheel(idOrUuid: string, options?: { deltaY?: number; deltaX?: number }): Chainable<void>;
94
- /** Click empty space to trigger onPointerMissed handlers. */
179
+ /** Click empty space to trigger onPointerMissed handlers. Auto-waits for bridge. */
95
180
  r3fPointerMiss(): Chainable<void>;
181
+ /** Draw a freeform path on the canvas (for drawing/annotation apps). Auto-waits for bridge. */
182
+ r3fDrawPath(
183
+ points: Array<{ x: number; y: number; pressure?: number }>,
184
+ options?: { stepDelayMs?: number; pointerType?: 'mouse' | 'pen' | 'touch'; clickAtEnd?: boolean },
185
+ ): Chainable<{ eventCount: number; pointCount: number }>;
96
186
 
97
187
  // ---- Selection ----
98
- /** Select a 3D object (highlights in scene). */
188
+ /** Select a 3D object (highlights in scene). Auto-waits for bridge + object. */
99
189
  r3fSelect(idOrUuid: string): Chainable<void>;
100
- /** Clear the current selection. */
190
+ /** Clear the current selection. Auto-waits for bridge. */
101
191
  r3fClearSelection(): Chainable<void>;
102
192
 
103
193
  // ---- Queries ----
104
194
  /** Get object metadata by testId or uuid. */
105
195
  r3fGetObject(idOrUuid: string): Chainable<ObjectMetadata | null>;
196
+ /** Get object metadata by testId. */
197
+ r3fGetByTestId(testId: string): Chainable<ObjectMetadata | null>;
198
+ /** Get all objects with the given name (object.name). */
199
+ r3fGetByName(name: string): Chainable<ObjectMetadata[]>;
200
+ /** Get object metadata by uuid only. */
201
+ r3fGetByUuid(uuid: string): Chainable<ObjectMetadata | null>;
202
+ /** Get direct children of an object by testId or uuid. */
203
+ r3fGetChildren(idOrUuid: string): Chainable<ObjectMetadata[]>;
204
+ /** Get parent of an object by testId or uuid. */
205
+ r3fGetParent(idOrUuid: string): Chainable<ObjectMetadata | null>;
206
+ /** Get the R3F canvas element (data-r3f-canvas). */
207
+ r3fGetCanvas(): Chainable<JQuery<HTMLCanvasElement>>;
208
+ /** Get world-space position [x, y, z] of an object. */
209
+ r3fGetWorldPosition(idOrUuid: string): Chainable<[number, number, number] | null>;
210
+ /** Compare two scene snapshots (added, removed, changed). */
211
+ r3fDiffSnapshots(before: SceneSnapshot, after: SceneSnapshot): Chainable<SceneDiff>;
212
+ /** Run an action and return { added, removed } object count change. */
213
+ r3fTrackObjectCount(action: () => Cypress.Chainable<unknown>): Chainable<{ added: number; removed: number }>;
106
214
  /** Get heavy inspection data (Tier 2) by testId or uuid. */
107
215
  r3fInspect(idOrUuid: string): Chainable<ObjectInspection | null>;
108
216
  /** Take a full scene snapshot. */
@@ -110,6 +218,24 @@ declare global {
110
218
  /** Get the total number of tracked objects. */
111
219
  r3fGetCount(): Chainable<number>;
112
220
 
221
+ // ---- BIM/CAD queries ----
222
+ /** Get all objects of a given Three.js type (e.g. "Mesh", "Group", "Line"). */
223
+ r3fGetByType(type: string): Chainable<ObjectMetadata[]>;
224
+ /** Get all objects with a given geometry type (e.g. "BoxGeometry"). */
225
+ r3fGetByGeometryType(type: string): Chainable<ObjectMetadata[]>;
226
+ /** Get all objects with a given material type (e.g. "MeshStandardMaterial"). */
227
+ r3fGetByMaterialType(type: string): Chainable<ObjectMetadata[]>;
228
+ /** Get objects that have a specific userData key (and optionally matching value). */
229
+ r3fGetByUserData(key: string, value?: unknown): Chainable<ObjectMetadata[]>;
230
+ /** Count objects of a given Three.js type. */
231
+ r3fGetCountByType(type: string): Chainable<number>;
232
+ /** Batch lookup: get metadata for multiple objects by testId or uuid. */
233
+ r3fGetObjects(ids: string[]): Chainable<Record<string, ObjectMetadata | null>>;
234
+
235
+ // ---- Camera ----
236
+ /** Get current camera state (position, rotation, fov, near, far, zoom, target). */
237
+ r3fGetCameraState(): Chainable<CameraState>;
238
+
113
239
  // ---- Waiters ----
114
240
  /** Wait until the scene is ready (bridge available, object count stable). */
115
241
  r3fWaitForSceneReady(options?: {
@@ -123,29 +249,113 @@ declare global {
123
249
  pollIntervalMs?: number;
124
250
  timeout?: number;
125
251
  }): Chainable<void>;
252
+ /** Wait until a specific object (by testId or uuid) exists in the scene. */
253
+ r3fWaitForObject(
254
+ idOrUuid: string,
255
+ options?: {
256
+ bridgeTimeout?: number;
257
+ objectTimeout?: number;
258
+ pollIntervalMs?: number;
259
+ },
260
+ ): Chainable<void>;
261
+ /** Wait until new object(s) appear in the scene (for drawing/annotation apps). */
262
+ r3fWaitForNewObject(options?: {
263
+ type?: string;
264
+ nameContains?: string;
265
+ pollIntervalMs?: number;
266
+ timeout?: number;
267
+ }): Chainable<{ newObjects: ObjectMetadata[]; newUuids: string[]; count: number }>;
268
+ /** Wait until an object (by testId or uuid) is no longer in the scene. */
269
+ r3fWaitForObjectRemoved(
270
+ idOrUuid: string,
271
+ options?: { bridgeTimeout?: number; pollIntervalMs?: number; timeout?: number },
272
+ ): Chainable<void>;
126
273
  }
127
274
 
128
275
  interface Assertion {
276
+ // ---- Tier 1: Metadata-based assertions (cheap) ----
129
277
  /** Assert that a 3D object with the given testId/uuid exists. */
130
278
  r3fExist(idOrUuid: string): Assertion;
131
279
  /** Assert that a 3D object is visible. */
132
280
  r3fVisible(idOrUuid: string): Assertion;
133
- /** Assert that a 3D object is in the camera frustum. */
134
- r3fInFrustum(idOrUuid: string): Assertion;
135
- /** Assert object position within tolerance. */
136
- r3fPosition(
137
- idOrUuid: string,
138
- expected: [number, number, number],
139
- tolerance?: number,
140
- ): Assertion;
281
+ /** Assert object local position within tolerance. */
282
+ r3fPosition(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
283
+ /** Assert object world position within tolerance. */
284
+ r3fWorldPosition(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
285
+ /** Assert object rotation (Euler radians) within tolerance. */
286
+ r3fRotation(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
287
+ /** Assert object scale within tolerance. */
288
+ r3fScale(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
289
+ /** Assert object type (Mesh, Group, Line, Points, etc.). */
290
+ r3fType(idOrUuid: string, expectedType: string): Assertion;
291
+ /** Assert object name. */
292
+ r3fName(idOrUuid: string, expectedName: string): Assertion;
293
+ /** Assert geometry type (BoxGeometry, PlaneGeometry, BufferGeometry, etc.). */
294
+ r3fGeometryType(idOrUuid: string, expectedGeoType: string): Assertion;
295
+ /** Assert material type (MeshStandardMaterial, ShaderMaterial, etc.). */
296
+ r3fMaterialType(idOrUuid: string, expectedMatType: string): Assertion;
297
+ /** Assert number of direct children. */
298
+ r3fChildCount(idOrUuid: string, expectedCount: number): Assertion;
299
+ /** Assert object's parent by testId, uuid, or name. */
300
+ r3fParent(idOrUuid: string, expectedParent: string): Assertion;
141
301
  /** Assert InstancedMesh instance count. */
142
302
  r3fInstanceCount(idOrUuid: string, expectedCount: number): Assertion;
303
+
304
+ // ---- Tier 2: Inspection-based assertions (heavier) ----
305
+ /** Assert that a 3D object is in the camera frustum. */
306
+ r3fInFrustum(idOrUuid: string): Assertion;
143
307
  /** Assert world-space bounding box within tolerance. */
144
308
  r3fBounds(
145
309
  idOrUuid: string,
146
310
  expected: { min: [number, number, number]; max: [number, number, number] },
147
311
  tolerance?: number,
148
312
  ): Assertion;
313
+ /** Assert material color (hex string, e.g. '#ff0000'). */
314
+ r3fColor(idOrUuid: string, expectedColor: string): Assertion;
315
+ /** Assert material opacity (0–1) within tolerance. */
316
+ r3fOpacity(idOrUuid: string, expectedOpacity: number, tolerance?: number): Assertion;
317
+ /** Assert material.transparent === true. */
318
+ r3fTransparent(idOrUuid: string): Assertion;
319
+ /** Assert geometry vertex count. */
320
+ r3fVertexCount(idOrUuid: string, expectedCount: number): Assertion;
321
+ /** Assert geometry triangle count. */
322
+ r3fTriangleCount(idOrUuid: string, expectedCount: number): Assertion;
323
+ /** Assert a specific key (and optionally value) in userData. */
324
+ r3fUserData(idOrUuid: string, key: string, expectedValue?: unknown): Assertion;
325
+ /** Assert material has a map texture (optionally by name). */
326
+ r3fMapTexture(idOrUuid: string, expectedMapName?: string): Assertion;
327
+
328
+ // ---- Scene-level assertions ----
329
+ /** Assert total object count in the scene. */
330
+ r3fObjectCount(expected: number): Assertion;
331
+ /** Assert total object count is greater than a minimum. */
332
+ r3fObjectCountGreaterThan(min: number): Assertion;
333
+ /** Assert count of objects of a specific type. */
334
+ r3fCountByType(type: string, expected: number): Assertion;
335
+ /** Assert total triangle count across all meshes. */
336
+ r3fTotalTriangleCount(expected: number): Assertion;
337
+ /** Assert total triangle count is less than a maximum (performance budget). */
338
+ r3fTotalTriangleCountLessThan(max: number): Assertion;
339
+
340
+ // ---- Camera assertions ----
341
+ /** Assert camera position within tolerance. */
342
+ r3fCameraPosition(expected: [number, number, number], tolerance?: number): Assertion;
343
+ /** Assert camera field of view (PerspectiveCamera). */
344
+ r3fCameraFov(expected: number, tolerance?: number): Assertion;
345
+ /** Assert camera near clipping plane. */
346
+ r3fCameraNear(expected: number, tolerance?: number): Assertion;
347
+ /** Assert camera far clipping plane. */
348
+ r3fCameraFar(expected: number, tolerance?: number): Assertion;
349
+ /** Assert camera zoom level. */
350
+ r3fCameraZoom(expected: number, tolerance?: number): Assertion;
351
+
352
+ // ---- Batch assertions ----
353
+ /** Assert ALL given objects exist. Accepts array of ids or glob pattern (e.g. "wall-*"). */
354
+ r3fAllExist(idsOrPattern: string[] | string): Assertion;
355
+ /** Assert ALL given objects are visible. Accepts array of ids or glob pattern. */
356
+ r3fAllVisible(idsOrPattern: string[] | string): Assertion;
357
+ /** Assert NONE of the given objects exist. Accepts array of ids or glob pattern. */
358
+ r3fNoneExist(idsOrPattern: string[] | string): Assertion;
149
359
  }
150
360
  }
151
361
  }
package/dist/index.d.ts CHANGED
@@ -9,6 +9,10 @@ interface ObjectMetadata {
9
9
  vertexCount?: number;
10
10
  triangleCount?: number;
11
11
  instanceCount?: number;
12
+ fov?: number;
13
+ near?: number;
14
+ far?: number;
15
+ zoom?: number;
12
16
  position: [number, number, number];
13
17
  rotation: [number, number, number];
14
18
  scale: [number, number, number];
@@ -36,6 +40,8 @@ interface ObjectInspection {
36
40
  center: [number, number, number];
37
41
  radius: number;
38
42
  };
43
+ positionData?: number[];
44
+ indexData?: number[];
39
45
  };
40
46
  material?: {
41
47
  type: string;
@@ -57,6 +63,11 @@ interface SnapshotNode {
57
63
  position: [number, number, number];
58
64
  rotation: [number, number, number];
59
65
  scale: [number, number, number];
66
+ geometryType?: string;
67
+ materialType?: string;
68
+ vertexCount?: number;
69
+ triangleCount?: number;
70
+ instanceCount?: number;
60
71
  children: SnapshotNode[];
61
72
  }
62
73
  interface SceneSnapshot {
@@ -64,6 +75,49 @@ interface SceneSnapshot {
64
75
  objectCount: number;
65
76
  tree: SnapshotNode;
66
77
  }
78
+ interface BridgeDiagnostics {
79
+ version: string;
80
+ ready: boolean;
81
+ error?: string;
82
+ objectCount: number;
83
+ meshCount: number;
84
+ groupCount: number;
85
+ lightCount: number;
86
+ cameraCount: number;
87
+ materializedDomNodes: number;
88
+ maxDomNodes: number;
89
+ canvasWidth: number;
90
+ canvasHeight: number;
91
+ webglRenderer: string;
92
+ dirtyQueueSize: number;
93
+ }
94
+ interface CameraState {
95
+ type: string;
96
+ position: [number, number, number];
97
+ rotation: [number, number, number];
98
+ target: [number, number, number];
99
+ fov?: number;
100
+ near: number;
101
+ far: number;
102
+ zoom: number;
103
+ aspect?: number;
104
+ left?: number;
105
+ right?: number;
106
+ top?: number;
107
+ bottom?: number;
108
+ }
109
+
110
+ interface SceneDiffChange {
111
+ uuid: string;
112
+ field: string;
113
+ from: unknown;
114
+ to: unknown;
115
+ }
116
+ interface SceneDiff {
117
+ added: SnapshotNode[];
118
+ removed: SnapshotNode[];
119
+ changed: SceneDiffChange[];
120
+ }
67
121
 
68
122
  // ---------------------------------------------------------------------------
69
123
  // TypeScript declarations for @react-three-dom/cypress
@@ -78,31 +132,85 @@ interface SceneSnapshot {
78
132
  declare global {
79
133
  namespace Cypress {
80
134
  interface Chainable {
135
+ // ---- Multi-canvas ----
136
+ /**
137
+ * Switch all subsequent r3f commands to target a specific canvas instance.
138
+ * Pass `null` to switch back to the default canvas.
139
+ * @example cy.r3fUseCanvas('minimap'); cy.r3fClick('marker');
140
+ */
141
+ r3fUseCanvas(canvasId: string | null): Chainable<void>;
142
+ /** List all active canvas IDs registered on the page. */
143
+ r3fGetCanvasIds(): Chainable<string[]>;
144
+
145
+ // ---- Debug / Reporter ----
146
+ /** Enable debug logging. Mirrors [r3f-dom:*] browser logs to Cypress command log. */
147
+ r3fEnableDebug(): Chainable<void>;
148
+ /**
149
+ * Enable the R3F reporter for rich terminal output (bridge status, object lookup,
150
+ * interaction timing, diagnostics). Requires `registerR3FTasks(on)` in cypress.config.ts.
151
+ */
152
+ r3fEnableReporter(enabled?: boolean): Chainable<void>;
153
+ /** Log the full scene tree to the Cypress command log and browser console. */
154
+ r3fLogScene(): Chainable<void>;
155
+
156
+ // ---- Diagnostics ----
157
+ /** Get bridge diagnostics (object counts, DOM state, GPU info). */
158
+ r3fGetDiagnostics(): Chainable<BridgeDiagnostics | null>;
159
+ /** Log bridge diagnostics to the Cypress command log and browser console. */
160
+ r3fLogDiagnostics(): Chainable<void>;
161
+ /** Fuzzy search for objects by partial testId, name, or uuid. */
162
+ r3fFuzzyFind(query: string, limit?: number): Chainable<ObjectMetadata[]>;
163
+
81
164
  // ---- Interactions ----
82
- /** Click a 3D object by testId or uuid. */
165
+ /** Click a 3D object by testId or uuid. Auto-waits for bridge + object. */
83
166
  r3fClick(idOrUuid: string): Chainable<void>;
84
- /** Double-click a 3D object by testId or uuid. */
167
+ /** Double-click a 3D object by testId or uuid. Auto-waits for bridge + object. */
85
168
  r3fDoubleClick(idOrUuid: string): Chainable<void>;
86
- /** Right-click / context-menu a 3D object by testId or uuid. */
169
+ /** Right-click / context-menu a 3D object by testId or uuid. Auto-waits for bridge + object. */
87
170
  r3fContextMenu(idOrUuid: string): Chainable<void>;
88
- /** Hover over a 3D object by testId or uuid. */
171
+ /** Hover over a 3D object by testId or uuid. Auto-waits for bridge + object. */
89
172
  r3fHover(idOrUuid: string): Chainable<void>;
90
- /** Drag a 3D object with a world-space delta vector. */
173
+ /** Unhover / pointer-leave resets hover state. Auto-waits for bridge. */
174
+ r3fUnhover(): Chainable<void>;
175
+ /** Drag a 3D object with a world-space delta vector. Auto-waits for bridge + object. */
91
176
  r3fDrag(idOrUuid: string, delta: { x: number; y: number; z: number }): Chainable<void>;
92
- /** Dispatch a wheel/scroll event on a 3D object. */
177
+ /** Dispatch a wheel/scroll event on a 3D object. Auto-waits for bridge + object. */
93
178
  r3fWheel(idOrUuid: string, options?: { deltaY?: number; deltaX?: number }): Chainable<void>;
94
- /** Click empty space to trigger onPointerMissed handlers. */
179
+ /** Click empty space to trigger onPointerMissed handlers. Auto-waits for bridge. */
95
180
  r3fPointerMiss(): Chainable<void>;
181
+ /** Draw a freeform path on the canvas (for drawing/annotation apps). Auto-waits for bridge. */
182
+ r3fDrawPath(
183
+ points: Array<{ x: number; y: number; pressure?: number }>,
184
+ options?: { stepDelayMs?: number; pointerType?: 'mouse' | 'pen' | 'touch'; clickAtEnd?: boolean },
185
+ ): Chainable<{ eventCount: number; pointCount: number }>;
96
186
 
97
187
  // ---- Selection ----
98
- /** Select a 3D object (highlights in scene). */
188
+ /** Select a 3D object (highlights in scene). Auto-waits for bridge + object. */
99
189
  r3fSelect(idOrUuid: string): Chainable<void>;
100
- /** Clear the current selection. */
190
+ /** Clear the current selection. Auto-waits for bridge. */
101
191
  r3fClearSelection(): Chainable<void>;
102
192
 
103
193
  // ---- Queries ----
104
194
  /** Get object metadata by testId or uuid. */
105
195
  r3fGetObject(idOrUuid: string): Chainable<ObjectMetadata | null>;
196
+ /** Get object metadata by testId. */
197
+ r3fGetByTestId(testId: string): Chainable<ObjectMetadata | null>;
198
+ /** Get all objects with the given name (object.name). */
199
+ r3fGetByName(name: string): Chainable<ObjectMetadata[]>;
200
+ /** Get object metadata by uuid only. */
201
+ r3fGetByUuid(uuid: string): Chainable<ObjectMetadata | null>;
202
+ /** Get direct children of an object by testId or uuid. */
203
+ r3fGetChildren(idOrUuid: string): Chainable<ObjectMetadata[]>;
204
+ /** Get parent of an object by testId or uuid. */
205
+ r3fGetParent(idOrUuid: string): Chainable<ObjectMetadata | null>;
206
+ /** Get the R3F canvas element (data-r3f-canvas). */
207
+ r3fGetCanvas(): Chainable<JQuery<HTMLCanvasElement>>;
208
+ /** Get world-space position [x, y, z] of an object. */
209
+ r3fGetWorldPosition(idOrUuid: string): Chainable<[number, number, number] | null>;
210
+ /** Compare two scene snapshots (added, removed, changed). */
211
+ r3fDiffSnapshots(before: SceneSnapshot, after: SceneSnapshot): Chainable<SceneDiff>;
212
+ /** Run an action and return { added, removed } object count change. */
213
+ r3fTrackObjectCount(action: () => Cypress.Chainable<unknown>): Chainable<{ added: number; removed: number }>;
106
214
  /** Get heavy inspection data (Tier 2) by testId or uuid. */
107
215
  r3fInspect(idOrUuid: string): Chainable<ObjectInspection | null>;
108
216
  /** Take a full scene snapshot. */
@@ -110,6 +218,24 @@ declare global {
110
218
  /** Get the total number of tracked objects. */
111
219
  r3fGetCount(): Chainable<number>;
112
220
 
221
+ // ---- BIM/CAD queries ----
222
+ /** Get all objects of a given Three.js type (e.g. "Mesh", "Group", "Line"). */
223
+ r3fGetByType(type: string): Chainable<ObjectMetadata[]>;
224
+ /** Get all objects with a given geometry type (e.g. "BoxGeometry"). */
225
+ r3fGetByGeometryType(type: string): Chainable<ObjectMetadata[]>;
226
+ /** Get all objects with a given material type (e.g. "MeshStandardMaterial"). */
227
+ r3fGetByMaterialType(type: string): Chainable<ObjectMetadata[]>;
228
+ /** Get objects that have a specific userData key (and optionally matching value). */
229
+ r3fGetByUserData(key: string, value?: unknown): Chainable<ObjectMetadata[]>;
230
+ /** Count objects of a given Three.js type. */
231
+ r3fGetCountByType(type: string): Chainable<number>;
232
+ /** Batch lookup: get metadata for multiple objects by testId or uuid. */
233
+ r3fGetObjects(ids: string[]): Chainable<Record<string, ObjectMetadata | null>>;
234
+
235
+ // ---- Camera ----
236
+ /** Get current camera state (position, rotation, fov, near, far, zoom, target). */
237
+ r3fGetCameraState(): Chainable<CameraState>;
238
+
113
239
  // ---- Waiters ----
114
240
  /** Wait until the scene is ready (bridge available, object count stable). */
115
241
  r3fWaitForSceneReady(options?: {
@@ -123,29 +249,113 @@ declare global {
123
249
  pollIntervalMs?: number;
124
250
  timeout?: number;
125
251
  }): Chainable<void>;
252
+ /** Wait until a specific object (by testId or uuid) exists in the scene. */
253
+ r3fWaitForObject(
254
+ idOrUuid: string,
255
+ options?: {
256
+ bridgeTimeout?: number;
257
+ objectTimeout?: number;
258
+ pollIntervalMs?: number;
259
+ },
260
+ ): Chainable<void>;
261
+ /** Wait until new object(s) appear in the scene (for drawing/annotation apps). */
262
+ r3fWaitForNewObject(options?: {
263
+ type?: string;
264
+ nameContains?: string;
265
+ pollIntervalMs?: number;
266
+ timeout?: number;
267
+ }): Chainable<{ newObjects: ObjectMetadata[]; newUuids: string[]; count: number }>;
268
+ /** Wait until an object (by testId or uuid) is no longer in the scene. */
269
+ r3fWaitForObjectRemoved(
270
+ idOrUuid: string,
271
+ options?: { bridgeTimeout?: number; pollIntervalMs?: number; timeout?: number },
272
+ ): Chainable<void>;
126
273
  }
127
274
 
128
275
  interface Assertion {
276
+ // ---- Tier 1: Metadata-based assertions (cheap) ----
129
277
  /** Assert that a 3D object with the given testId/uuid exists. */
130
278
  r3fExist(idOrUuid: string): Assertion;
131
279
  /** Assert that a 3D object is visible. */
132
280
  r3fVisible(idOrUuid: string): Assertion;
133
- /** Assert that a 3D object is in the camera frustum. */
134
- r3fInFrustum(idOrUuid: string): Assertion;
135
- /** Assert object position within tolerance. */
136
- r3fPosition(
137
- idOrUuid: string,
138
- expected: [number, number, number],
139
- tolerance?: number,
140
- ): Assertion;
281
+ /** Assert object local position within tolerance. */
282
+ r3fPosition(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
283
+ /** Assert object world position within tolerance. */
284
+ r3fWorldPosition(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
285
+ /** Assert object rotation (Euler radians) within tolerance. */
286
+ r3fRotation(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
287
+ /** Assert object scale within tolerance. */
288
+ r3fScale(idOrUuid: string, expected: [number, number, number], tolerance?: number): Assertion;
289
+ /** Assert object type (Mesh, Group, Line, Points, etc.). */
290
+ r3fType(idOrUuid: string, expectedType: string): Assertion;
291
+ /** Assert object name. */
292
+ r3fName(idOrUuid: string, expectedName: string): Assertion;
293
+ /** Assert geometry type (BoxGeometry, PlaneGeometry, BufferGeometry, etc.). */
294
+ r3fGeometryType(idOrUuid: string, expectedGeoType: string): Assertion;
295
+ /** Assert material type (MeshStandardMaterial, ShaderMaterial, etc.). */
296
+ r3fMaterialType(idOrUuid: string, expectedMatType: string): Assertion;
297
+ /** Assert number of direct children. */
298
+ r3fChildCount(idOrUuid: string, expectedCount: number): Assertion;
299
+ /** Assert object's parent by testId, uuid, or name. */
300
+ r3fParent(idOrUuid: string, expectedParent: string): Assertion;
141
301
  /** Assert InstancedMesh instance count. */
142
302
  r3fInstanceCount(idOrUuid: string, expectedCount: number): Assertion;
303
+
304
+ // ---- Tier 2: Inspection-based assertions (heavier) ----
305
+ /** Assert that a 3D object is in the camera frustum. */
306
+ r3fInFrustum(idOrUuid: string): Assertion;
143
307
  /** Assert world-space bounding box within tolerance. */
144
308
  r3fBounds(
145
309
  idOrUuid: string,
146
310
  expected: { min: [number, number, number]; max: [number, number, number] },
147
311
  tolerance?: number,
148
312
  ): Assertion;
313
+ /** Assert material color (hex string, e.g. '#ff0000'). */
314
+ r3fColor(idOrUuid: string, expectedColor: string): Assertion;
315
+ /** Assert material opacity (0–1) within tolerance. */
316
+ r3fOpacity(idOrUuid: string, expectedOpacity: number, tolerance?: number): Assertion;
317
+ /** Assert material.transparent === true. */
318
+ r3fTransparent(idOrUuid: string): Assertion;
319
+ /** Assert geometry vertex count. */
320
+ r3fVertexCount(idOrUuid: string, expectedCount: number): Assertion;
321
+ /** Assert geometry triangle count. */
322
+ r3fTriangleCount(idOrUuid: string, expectedCount: number): Assertion;
323
+ /** Assert a specific key (and optionally value) in userData. */
324
+ r3fUserData(idOrUuid: string, key: string, expectedValue?: unknown): Assertion;
325
+ /** Assert material has a map texture (optionally by name). */
326
+ r3fMapTexture(idOrUuid: string, expectedMapName?: string): Assertion;
327
+
328
+ // ---- Scene-level assertions ----
329
+ /** Assert total object count in the scene. */
330
+ r3fObjectCount(expected: number): Assertion;
331
+ /** Assert total object count is greater than a minimum. */
332
+ r3fObjectCountGreaterThan(min: number): Assertion;
333
+ /** Assert count of objects of a specific type. */
334
+ r3fCountByType(type: string, expected: number): Assertion;
335
+ /** Assert total triangle count across all meshes. */
336
+ r3fTotalTriangleCount(expected: number): Assertion;
337
+ /** Assert total triangle count is less than a maximum (performance budget). */
338
+ r3fTotalTriangleCountLessThan(max: number): Assertion;
339
+
340
+ // ---- Camera assertions ----
341
+ /** Assert camera position within tolerance. */
342
+ r3fCameraPosition(expected: [number, number, number], tolerance?: number): Assertion;
343
+ /** Assert camera field of view (PerspectiveCamera). */
344
+ r3fCameraFov(expected: number, tolerance?: number): Assertion;
345
+ /** Assert camera near clipping plane. */
346
+ r3fCameraNear(expected: number, tolerance?: number): Assertion;
347
+ /** Assert camera far clipping plane. */
348
+ r3fCameraFar(expected: number, tolerance?: number): Assertion;
349
+ /** Assert camera zoom level. */
350
+ r3fCameraZoom(expected: number, tolerance?: number): Assertion;
351
+
352
+ // ---- Batch assertions ----
353
+ /** Assert ALL given objects exist. Accepts array of ids or glob pattern (e.g. "wall-*"). */
354
+ r3fAllExist(idsOrPattern: string[] | string): Assertion;
355
+ /** Assert ALL given objects are visible. Accepts array of ids or glob pattern. */
356
+ r3fAllVisible(idsOrPattern: string[] | string): Assertion;
357
+ /** Assert NONE of the given objects exist. Accepts array of ids or glob pattern. */
358
+ r3fNoneExist(idsOrPattern: string[] | string): Assertion;
149
359
  }
150
360
  }
151
361
  }