@react-three-dom/playwright 0.2.0 → 0.4.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.cjs +1057 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +528 -79
- package/dist/index.d.ts +528 -79
- package/dist/index.js +1079 -262
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _playwright_test from '@playwright/test';
|
|
2
|
-
import { Page } from '@playwright/test';
|
|
2
|
+
import { Page, Locator } from '@playwright/test';
|
|
3
3
|
|
|
4
4
|
interface ObjectMetadata {
|
|
5
5
|
uuid: string;
|
|
@@ -12,6 +12,10 @@ interface ObjectMetadata {
|
|
|
12
12
|
vertexCount?: number;
|
|
13
13
|
triangleCount?: number;
|
|
14
14
|
instanceCount?: number;
|
|
15
|
+
fov?: number;
|
|
16
|
+
near?: number;
|
|
17
|
+
far?: number;
|
|
18
|
+
zoom?: number;
|
|
15
19
|
position: [number, number, number];
|
|
16
20
|
rotation: [number, number, number];
|
|
17
21
|
scale: [number, number, number];
|
|
@@ -19,6 +23,10 @@ interface ObjectMetadata {
|
|
|
19
23
|
childrenUuids: string[];
|
|
20
24
|
boundsDirty: boolean;
|
|
21
25
|
}
|
|
26
|
+
/** Options for inspect(). Set includeGeometryData: true to get vertex/index buffers (higher cost). */
|
|
27
|
+
interface InspectOptions {
|
|
28
|
+
includeGeometryData?: boolean;
|
|
29
|
+
}
|
|
22
30
|
interface ObjectInspection {
|
|
23
31
|
metadata: ObjectMetadata;
|
|
24
32
|
worldMatrix: number[];
|
|
@@ -39,6 +47,10 @@ interface ObjectInspection {
|
|
|
39
47
|
center: [number, number, number];
|
|
40
48
|
radius: number;
|
|
41
49
|
};
|
|
50
|
+
/** Vertex positions (x,y,z per vertex). Only when inspect(..., { includeGeometryData: true }). */
|
|
51
|
+
positionData?: number[];
|
|
52
|
+
/** Triangle indices. Only when inspect(..., { includeGeometryData: true }) and geometry is indexed. */
|
|
53
|
+
indexData?: number[];
|
|
42
54
|
};
|
|
43
55
|
material?: {
|
|
44
56
|
type: string;
|
|
@@ -67,12 +79,139 @@ interface SceneSnapshot {
|
|
|
67
79
|
objectCount: number;
|
|
68
80
|
tree: SnapshotNode;
|
|
69
81
|
}
|
|
82
|
+
interface CameraState {
|
|
83
|
+
type: string;
|
|
84
|
+
position: [number, number, number];
|
|
85
|
+
rotation: [number, number, number];
|
|
86
|
+
target: [number, number, number];
|
|
87
|
+
fov?: number;
|
|
88
|
+
near: number;
|
|
89
|
+
far: number;
|
|
90
|
+
zoom: number;
|
|
91
|
+
aspect?: number;
|
|
92
|
+
left?: number;
|
|
93
|
+
right?: number;
|
|
94
|
+
top?: number;
|
|
95
|
+
bottom?: number;
|
|
96
|
+
}
|
|
97
|
+
interface BridgeDiagnostics {
|
|
98
|
+
version: string;
|
|
99
|
+
ready: boolean;
|
|
100
|
+
error?: string;
|
|
101
|
+
objectCount: number;
|
|
102
|
+
meshCount: number;
|
|
103
|
+
groupCount: number;
|
|
104
|
+
lightCount: number;
|
|
105
|
+
cameraCount: number;
|
|
106
|
+
materializedDomNodes: number;
|
|
107
|
+
maxDomNodes: number;
|
|
108
|
+
canvasWidth: number;
|
|
109
|
+
canvasHeight: number;
|
|
110
|
+
webglRenderer: string;
|
|
111
|
+
dirtyQueueSize: number;
|
|
112
|
+
}
|
|
70
113
|
declare global {
|
|
71
114
|
interface Window {
|
|
72
115
|
__R3F_DOM_DEBUG__?: boolean;
|
|
73
116
|
}
|
|
74
117
|
}
|
|
75
118
|
|
|
119
|
+
/**
|
|
120
|
+
* @module reporter
|
|
121
|
+
*
|
|
122
|
+
* Rich terminal reporter for Playwright tests. Outputs ANSI-colored status
|
|
123
|
+
* messages for bridge lifecycle events (waiting, connected, error), scene
|
|
124
|
+
* readiness, object lookups (with fuzzy-match suggestions on miss),
|
|
125
|
+
* interaction timings, assertion failures, and full bridge diagnostics.
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Formatted terminal reporter for react-three-dom Playwright tests.
|
|
130
|
+
* Logs bridge lifecycle, scene readiness, interaction timings, assertion
|
|
131
|
+
* failures, and full diagnostics with ANSI colors.
|
|
132
|
+
*/
|
|
133
|
+
declare class R3FReporter {
|
|
134
|
+
private readonly _page;
|
|
135
|
+
private _enabled;
|
|
136
|
+
private _canvasId?;
|
|
137
|
+
constructor(_page: Page, enabled?: boolean, canvasId?: string);
|
|
138
|
+
logBridgeWaiting(): void;
|
|
139
|
+
logBridgeConnected(diag?: BridgeDiagnostics): void;
|
|
140
|
+
logBridgeError(error: string): void;
|
|
141
|
+
logSceneReady(objectCount: number): void;
|
|
142
|
+
logObjectFound(idOrUuid: string, type: string, name?: string): void;
|
|
143
|
+
logObjectNotFound(idOrUuid: string, suggestions?: Array<{
|
|
144
|
+
testId?: string;
|
|
145
|
+
name: string;
|
|
146
|
+
uuid: string;
|
|
147
|
+
}>): void;
|
|
148
|
+
logInteraction(action: string, idOrUuid: string, extra?: string): void;
|
|
149
|
+
logInteractionDone(action: string, idOrUuid: string, durationMs: number): void;
|
|
150
|
+
logAssertionFailure(matcherName: string, id: string, detail: string, diag?: BridgeDiagnostics): void;
|
|
151
|
+
logDiagnostics(): Promise<void>;
|
|
152
|
+
fetchDiagnostics(): Promise<BridgeDiagnostics | null>;
|
|
153
|
+
fetchFuzzyMatches(query: string, limit?: number): Promise<Array<{
|
|
154
|
+
testId?: string;
|
|
155
|
+
name: string;
|
|
156
|
+
uuid: string;
|
|
157
|
+
}>>;
|
|
158
|
+
private _printDiagnosticsSummary;
|
|
159
|
+
private _printDiagnosticsFull;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @module diffSnapshots
|
|
164
|
+
*
|
|
165
|
+
* Pure scene-diff utility. Compares two {@link SceneSnapshot}s by UUID and
|
|
166
|
+
* returns added nodes, removed nodes, and per-field property changes
|
|
167
|
+
* (name, type, testId, visible, position, rotation, scale).
|
|
168
|
+
*
|
|
169
|
+
* Stateless and side-effect-free — safe to call from any context.
|
|
170
|
+
*/
|
|
171
|
+
|
|
172
|
+
/** Describes a single property change on an object that exists in both snapshots. */
|
|
173
|
+
interface SceneDiffChange {
|
|
174
|
+
uuid: string;
|
|
175
|
+
field: string;
|
|
176
|
+
from: unknown;
|
|
177
|
+
to: unknown;
|
|
178
|
+
}
|
|
179
|
+
/** Result of diffing two scene snapshots. */
|
|
180
|
+
interface SceneDiff {
|
|
181
|
+
/** Nodes present in `after` but not in `before` (from `after` tree). */
|
|
182
|
+
added: SnapshotNode[];
|
|
183
|
+
/** Nodes present in `before` but not in `after` (from `before` tree). */
|
|
184
|
+
removed: SnapshotNode[];
|
|
185
|
+
/** Property changes for nodes that exist in both; each entry is one field that changed. */
|
|
186
|
+
changed: SceneDiffChange[];
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Compare two scene snapshots and return added nodes, removed nodes, and
|
|
190
|
+
* property changes for nodes that exist in both.
|
|
191
|
+
*
|
|
192
|
+
* - **added**: nodes in `after` whose uuid was not in `before`.
|
|
193
|
+
* - **removed**: nodes in `before` whose uuid was not in `after`.
|
|
194
|
+
* - **changed**: for each uuid present in both, lists field-level changes
|
|
195
|
+
* (name, type, testId, visible, position, rotation, scale).
|
|
196
|
+
*/
|
|
197
|
+
declare function diffSnapshots(before: SceneSnapshot, after: SceneSnapshot): SceneDiff;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @module waiters
|
|
201
|
+
*
|
|
202
|
+
* Polling-based wait utilities for Playwright tests. Each waiter polls the
|
|
203
|
+
* `window.__R3F_DOM__` bridge until a condition is met or a timeout fires.
|
|
204
|
+
*
|
|
205
|
+
* - {@link waitForSceneReady} — bridge ready + object count stabilised
|
|
206
|
+
* - {@link waitForObject} — bridge ready + specific object exists
|
|
207
|
+
* - {@link waitForIdle} — no property changes for N consecutive frames
|
|
208
|
+
* - {@link waitForNewObject} — new object(s) appear after a baseline snapshot
|
|
209
|
+
* - {@link waitForObjectRemoved} — object no longer in the scene
|
|
210
|
+
*
|
|
211
|
+
* All waiters fail fast with a rich diagnostic if the bridge reports an
|
|
212
|
+
* `_error` state, preventing silent timeouts.
|
|
213
|
+
*/
|
|
214
|
+
|
|
76
215
|
interface WaitForSceneReadyOptions {
|
|
77
216
|
/** How many consecutive stable polls are required. Default: 3 */
|
|
78
217
|
stableChecks?: number;
|
|
@@ -88,7 +227,9 @@ interface WaitForSceneReadyOptions {
|
|
|
88
227
|
* If the bridge exists but `_ready` is false and `_error` is set, this
|
|
89
228
|
* fails immediately with a rich diagnostic message instead of timing out.
|
|
90
229
|
*/
|
|
91
|
-
declare function waitForSceneReady(page: Page, options?: WaitForSceneReadyOptions
|
|
230
|
+
declare function waitForSceneReady(page: Page, options?: WaitForSceneReadyOptions & {
|
|
231
|
+
canvasId?: string;
|
|
232
|
+
}): Promise<void>;
|
|
92
233
|
interface WaitForObjectOptions {
|
|
93
234
|
/** Time to wait for the bridge to appear. Default: 30_000 */
|
|
94
235
|
bridgeTimeout?: number;
|
|
@@ -107,7 +248,9 @@ interface WaitForObjectOptions {
|
|
|
107
248
|
*
|
|
108
249
|
* Fails fast if the bridge reports `_ready: false` with an `_error`.
|
|
109
250
|
*/
|
|
110
|
-
declare function waitForObject(page: Page, idOrUuid: string, options?: WaitForObjectOptions
|
|
251
|
+
declare function waitForObject(page: Page, idOrUuid: string, options?: WaitForObjectOptions & {
|
|
252
|
+
canvasId?: string;
|
|
253
|
+
}): Promise<void>;
|
|
111
254
|
interface WaitForIdleOptions {
|
|
112
255
|
/** Number of consecutive idle frames required. Default: 10 */
|
|
113
256
|
idleFrames?: number;
|
|
@@ -124,7 +267,9 @@ interface WaitForIdleOptions {
|
|
|
124
267
|
*
|
|
125
268
|
* Checks `_ready === true` before starting. Fails fast if `_error` is set.
|
|
126
269
|
*/
|
|
127
|
-
declare function waitForIdle(page: Page, options?: WaitForIdleOptions
|
|
270
|
+
declare function waitForIdle(page: Page, options?: WaitForIdleOptions & {
|
|
271
|
+
canvasId?: string;
|
|
272
|
+
}): Promise<void>;
|
|
128
273
|
interface WaitForNewObjectOptions {
|
|
129
274
|
/**
|
|
130
275
|
* Only consider new objects of this Three.js type (e.g. "Mesh", "Line").
|
|
@@ -175,19 +320,88 @@ interface WaitForNewObjectResult {
|
|
|
175
320
|
* expect(result.count).toBe(1);
|
|
176
321
|
* ```
|
|
177
322
|
*/
|
|
178
|
-
declare function waitForNewObject(page: Page, options?: WaitForNewObjectOptions
|
|
323
|
+
declare function waitForNewObject(page: Page, options?: WaitForNewObjectOptions & {
|
|
324
|
+
canvasId?: string;
|
|
325
|
+
}): Promise<WaitForNewObjectResult>;
|
|
326
|
+
interface WaitForObjectRemovedOptions {
|
|
327
|
+
/** Time to wait for the bridge to appear. Default: 30_000 */
|
|
328
|
+
bridgeTimeout?: number;
|
|
329
|
+
/** Poll interval in ms. Default: 100 */
|
|
330
|
+
pollIntervalMs?: number;
|
|
331
|
+
/** Overall timeout in ms (after bridge is ready). Default: 10_000 */
|
|
332
|
+
timeout?: number;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Wait until the bridge is ready and an object with the given testId or uuid
|
|
336
|
+
* is no longer in the scene. Use for delete flows (e.g. user deletes an object,
|
|
337
|
+
* then you assert it's gone).
|
|
338
|
+
*
|
|
339
|
+
* @param page Playwright Page instance
|
|
340
|
+
* @param idOrUuid testId or uuid of the object that should be removed
|
|
341
|
+
* @param options Timing options
|
|
342
|
+
* @throws If the object is still present after the timeout
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* await r3f.click('delete-button');
|
|
347
|
+
* await r3f.waitForObjectRemoved('item-to-delete');
|
|
348
|
+
* await expect(r3f).not.toExist('item-to-delete');
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
declare function waitForObjectRemoved(page: Page, idOrUuid: string, options?: WaitForObjectRemovedOptions & {
|
|
352
|
+
canvasId?: string;
|
|
353
|
+
}): Promise<void>;
|
|
179
354
|
|
|
180
355
|
/** Options for R3FFixture constructor. */
|
|
181
356
|
interface R3FFixtureOptions {
|
|
182
357
|
/** Auto-enable debug logging (forwards browser [r3f-dom:*] logs to test terminal). */
|
|
183
358
|
debug?: boolean;
|
|
359
|
+
/**
|
|
360
|
+
* Enable rich diagnostic reporting in the terminal.
|
|
361
|
+
* Logs bridge status, scene readiness, interaction details, and
|
|
362
|
+
* failure context automatically. Default: true.
|
|
363
|
+
*/
|
|
364
|
+
report?: boolean;
|
|
365
|
+
/** Target a specific canvas by its canvasId. When omitted, uses the default bridge. */
|
|
366
|
+
canvasId?: string;
|
|
184
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Main API object provided to Playwright tests for interacting with a
|
|
370
|
+
* react-three-dom scene. Wraps queries, interactions, waiters, snapshot
|
|
371
|
+
* diffing, and rich terminal diagnostics. Supports multi-canvas apps
|
|
372
|
+
* via {@link R3FFixture.forCanvas}.
|
|
373
|
+
*/
|
|
185
374
|
declare class R3FFixture {
|
|
186
375
|
private readonly _page;
|
|
187
376
|
private _debugListenerAttached;
|
|
377
|
+
private readonly _reporter;
|
|
378
|
+
/** Canvas ID for multi-canvas apps. Undefined = default bridge. */
|
|
379
|
+
readonly canvasId?: string;
|
|
188
380
|
constructor(_page: Page, opts?: R3FFixtureOptions);
|
|
189
381
|
/** The underlying Playwright Page. */
|
|
190
382
|
get page(): Page;
|
|
383
|
+
/** Access the reporter for custom diagnostic logging. */
|
|
384
|
+
get reporter(): R3FReporter;
|
|
385
|
+
/**
|
|
386
|
+
* Create a scoped fixture targeting a specific canvas instance.
|
|
387
|
+
* All queries, interactions, and assertions on the returned fixture
|
|
388
|
+
* will use `window.__R3F_DOM_INSTANCES__[canvasId]` instead of
|
|
389
|
+
* `window.__R3F_DOM__`.
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* const mainR3f = r3f.forCanvas('main-viewport');
|
|
394
|
+
* const minimapR3f = r3f.forCanvas('minimap');
|
|
395
|
+
* await mainR3f.click('building-42');
|
|
396
|
+
* await expect(minimapR3f).toExist('building-42-marker');
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
forCanvas(canvasId: string): R3FFixture;
|
|
400
|
+
/**
|
|
401
|
+
* List all active canvas IDs registered on the page.
|
|
402
|
+
* Returns an empty array if only the default (unnamed) bridge is active.
|
|
403
|
+
*/
|
|
404
|
+
getCanvasIds(): Promise<string[]>;
|
|
191
405
|
/**
|
|
192
406
|
* Enable debug logging. Turns on `window.__R3F_DOM_DEBUG__` in the browser
|
|
193
407
|
* and forwards all `[r3f-dom:*]` console messages to the Node.js test terminal.
|
|
@@ -199,41 +413,72 @@ declare class R3FFixture {
|
|
|
199
413
|
private _attachDebugListener;
|
|
200
414
|
/** Get object metadata by testId or uuid. Returns null if not found. */
|
|
201
415
|
getObject(idOrUuid: string): Promise<ObjectMetadata | null>;
|
|
202
|
-
/** Get
|
|
203
|
-
|
|
416
|
+
/** Get object metadata by testId (userData.testId). Returns null if not found. */
|
|
417
|
+
getByTestId(testId: string): Promise<ObjectMetadata | null>;
|
|
418
|
+
/** Get object metadata by UUID. Returns null if not found. */
|
|
419
|
+
getByUuid(uuid: string): Promise<ObjectMetadata | null>;
|
|
420
|
+
/** Get all objects with the given name (names are not unique in Three.js). */
|
|
421
|
+
getByName(name: string): Promise<ObjectMetadata[]>;
|
|
422
|
+
/** Get direct children of an object by testId or uuid. */
|
|
423
|
+
getChildren(idOrUuid: string): Promise<ObjectMetadata[]>;
|
|
424
|
+
/** Get parent of an object by testId or uuid. Returns null if root or not found. */
|
|
425
|
+
getParent(idOrUuid: string): Promise<ObjectMetadata | null>;
|
|
426
|
+
/** Get heavy inspection data (Tier 2) by testId or uuid. Pass { includeGeometryData: true } to include vertex positions and triangle indices. */
|
|
427
|
+
inspect(idOrUuid: string, options?: {
|
|
428
|
+
includeGeometryData?: boolean;
|
|
429
|
+
}): Promise<ObjectInspection | null>;
|
|
430
|
+
/**
|
|
431
|
+
* Get world-space position [x, y, z] of an object (from its world matrix).
|
|
432
|
+
* Use for nested objects where local position differs from world position.
|
|
433
|
+
*/
|
|
434
|
+
getWorldPosition(idOrUuid: string): Promise<[number, number, number] | null>;
|
|
204
435
|
/** Take a full scene snapshot. */
|
|
205
436
|
snapshot(): Promise<SceneSnapshot | null>;
|
|
437
|
+
/**
|
|
438
|
+
* Compare two scene snapshots: returns added nodes, removed nodes, and
|
|
439
|
+
* property changes (name, type, testId, visible, position, rotation, scale).
|
|
440
|
+
* Use after taking snapshots before/after an action to assert on scene changes.
|
|
441
|
+
*/
|
|
442
|
+
diffSnapshots(before: SceneSnapshot, after: SceneSnapshot): SceneDiff;
|
|
443
|
+
/**
|
|
444
|
+
* Run an async action and return how many objects were added and removed
|
|
445
|
+
* compared to before the action. Uses snapshots before/after so add and
|
|
446
|
+
* remove are both counted correctly when both happen.
|
|
447
|
+
*/
|
|
448
|
+
trackObjectCount(action: () => Promise<void>): Promise<{
|
|
449
|
+
added: number;
|
|
450
|
+
removed: number;
|
|
451
|
+
}>;
|
|
206
452
|
/** Get the total number of tracked objects. */
|
|
207
453
|
getCount(): Promise<number>;
|
|
454
|
+
/**
|
|
455
|
+
* Return a Playwright locator for the R3F canvas element the bridge is attached to.
|
|
456
|
+
* The canvas has `data-r3f-canvas` set by the bridge (value is the canvasId or "true").
|
|
457
|
+
*/
|
|
458
|
+
getCanvasLocator(): Locator;
|
|
208
459
|
/**
|
|
209
460
|
* Get all objects of a given Three.js type (e.g. "Mesh", "Group", "Line").
|
|
210
|
-
* Useful for BIM/CAD apps to find all walls, doors, etc. by object type.
|
|
211
461
|
*/
|
|
212
462
|
getByType(type: string): Promise<ObjectMetadata[]>;
|
|
463
|
+
/**
|
|
464
|
+
* Get all objects with a given geometry type (e.g. "BoxGeometry", "BufferGeometry").
|
|
465
|
+
*/
|
|
466
|
+
getByGeometryType(type: string): Promise<ObjectMetadata[]>;
|
|
467
|
+
/**
|
|
468
|
+
* Get all objects with a given material type (e.g. "MeshStandardMaterial").
|
|
469
|
+
*/
|
|
470
|
+
getByMaterialType(type: string): Promise<ObjectMetadata[]>;
|
|
213
471
|
/**
|
|
214
472
|
* Get objects that have a specific userData key (and optionally matching value).
|
|
215
|
-
* Useful for BIM/CAD apps where objects are tagged with metadata like
|
|
216
|
-
* `userData.category = "wall"` or `userData.floorId = 2`.
|
|
217
473
|
*/
|
|
218
474
|
getByUserData(key: string, value?: unknown): Promise<ObjectMetadata[]>;
|
|
219
475
|
/**
|
|
220
476
|
* Count objects of a given Three.js type.
|
|
221
|
-
* More efficient than `getByType(type).then(arr => arr.length)`.
|
|
222
477
|
*/
|
|
223
478
|
getCountByType(type: string): Promise<number>;
|
|
224
479
|
/**
|
|
225
480
|
* Batch lookup: get metadata for multiple objects by testId or uuid in a
|
|
226
|
-
* single browser round-trip.
|
|
227
|
-
*
|
|
228
|
-
* Much more efficient than calling `getObject()` in a loop for BIM/CAD
|
|
229
|
-
* scenes with many objects.
|
|
230
|
-
*
|
|
231
|
-
* @example
|
|
232
|
-
* ```typescript
|
|
233
|
-
* const results = await r3f.getObjects(['wall-1', 'door-2', 'window-3']);
|
|
234
|
-
* expect(results['wall-1']).not.toBeNull();
|
|
235
|
-
* expect(results['door-2']?.type).toBe('Mesh');
|
|
236
|
-
* ```
|
|
481
|
+
* single browser round-trip.
|
|
237
482
|
*/
|
|
238
483
|
getObjects(ids: string[]): Promise<Record<string, ObjectMetadata | null>>;
|
|
239
484
|
/**
|
|
@@ -272,6 +517,11 @@ declare class R3FFixture {
|
|
|
272
517
|
* Auto-waits for the object to exist.
|
|
273
518
|
*/
|
|
274
519
|
hover(idOrUuid: string, timeout?: number): Promise<void>;
|
|
520
|
+
/**
|
|
521
|
+
* Unhover / pointer-leave — resets hover state by moving pointer off-canvas.
|
|
522
|
+
* Auto-waits for the bridge to be ready.
|
|
523
|
+
*/
|
|
524
|
+
unhover(timeout?: number): Promise<void>;
|
|
275
525
|
/**
|
|
276
526
|
* Drag a 3D object with a world-space delta vector.
|
|
277
527
|
* Auto-waits for the object to exist.
|
|
@@ -316,9 +566,15 @@ declare class R3FFixture {
|
|
|
316
566
|
eventCount: number;
|
|
317
567
|
pointCount: number;
|
|
318
568
|
}>;
|
|
569
|
+
/**
|
|
570
|
+
* Get the current camera state (position, rotation, fov, near, far, zoom, target).
|
|
571
|
+
* Auto-waits for the bridge to be ready.
|
|
572
|
+
*/
|
|
573
|
+
getCameraState(timeout?: number): Promise<CameraState>;
|
|
319
574
|
/**
|
|
320
575
|
* Wait until the scene is ready — `window.__R3F_DOM__` is available and
|
|
321
576
|
* the object count has stabilised across several consecutive checks.
|
|
577
|
+
* Logs bridge connection and scene readiness to the terminal.
|
|
322
578
|
*/
|
|
323
579
|
waitForSceneReady(options?: WaitForSceneReadyOptions): Promise<void>;
|
|
324
580
|
/**
|
|
@@ -341,10 +597,25 @@ declare class R3FFixture {
|
|
|
341
597
|
* @returns Metadata of the newly added object(s)
|
|
342
598
|
*/
|
|
343
599
|
waitForNewObject(options?: WaitForNewObjectOptions): Promise<WaitForNewObjectResult>;
|
|
600
|
+
/**
|
|
601
|
+
* Wait until an object (by testId or uuid) is no longer in the scene.
|
|
602
|
+
* Use for delete flows: trigger removal, then wait until the object is gone.
|
|
603
|
+
*/
|
|
604
|
+
waitForObjectRemoved(idOrUuid: string, options?: WaitForObjectRemovedOptions): Promise<void>;
|
|
344
605
|
/** Select a 3D object by testId or uuid (highlights in scene). */
|
|
345
606
|
select(idOrUuid: string): Promise<void>;
|
|
346
607
|
/** Clear the current selection. */
|
|
347
608
|
clearSelection(): Promise<void>;
|
|
609
|
+
/**
|
|
610
|
+
* Fetch full bridge diagnostics (version, object counts, GPU info, etc.).
|
|
611
|
+
* Returns null if the bridge is not available.
|
|
612
|
+
*/
|
|
613
|
+
getDiagnostics(): Promise<BridgeDiagnostics | null>;
|
|
614
|
+
/**
|
|
615
|
+
* Print a full diagnostics report to the terminal.
|
|
616
|
+
* Useful at the start of a test suite or when debugging failures.
|
|
617
|
+
*/
|
|
618
|
+
logDiagnostics(): Promise<void>;
|
|
348
619
|
}
|
|
349
620
|
declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions & {
|
|
350
621
|
r3f: R3FFixture;
|
|
@@ -361,11 +632,43 @@ declare function createR3FTest(options?: R3FFixtureOptions): _playwright_test.Te
|
|
|
361
632
|
r3f: R3FFixture;
|
|
362
633
|
}, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
|
|
363
634
|
|
|
635
|
+
/**
|
|
636
|
+
* @module assertions
|
|
637
|
+
*
|
|
638
|
+
* Custom Playwright `expect` matchers for 3D scene testing via react-three-dom.
|
|
639
|
+
*
|
|
640
|
+
* Every matcher auto-retries until the assertion passes or the timeout
|
|
641
|
+
* expires, matching Playwright's built-in assertion behaviour.
|
|
642
|
+
*
|
|
643
|
+
* **Tier 1 — Metadata:** toExist, toBeVisible, toHavePosition,
|
|
644
|
+
* toHaveWorldPosition, toHaveRotation, toHaveScale, toHaveType, toHaveName,
|
|
645
|
+
* toHaveGeometryType, toHaveMaterialType, toHaveChildCount, toHaveParent,
|
|
646
|
+
* toHaveInstanceCount
|
|
647
|
+
*
|
|
648
|
+
* **Tier 2 — Inspection:** toBeInFrustum, toHaveBounds, toHaveColor,
|
|
649
|
+
* toHaveOpacity, toBeTransparent, toHaveVertexCount, toHaveTriangleCount,
|
|
650
|
+
* toHaveUserData, toHaveMapTexture
|
|
651
|
+
*
|
|
652
|
+
* **Scene-level:** toHaveObjectCount, toHaveObjectCountGreaterThan,
|
|
653
|
+
* toHaveCountByType, toHaveTotalTriangleCount,
|
|
654
|
+
* toHaveTotalTriangleCountLessThan
|
|
655
|
+
*
|
|
656
|
+
* **Camera:** toHaveCameraPosition, toHaveCameraFov, toHaveCameraNear,
|
|
657
|
+
* toHaveCameraFar, toHaveCameraZoom
|
|
658
|
+
*
|
|
659
|
+
* **Batch:** toAllExist, toAllBeVisible, toNoneExist
|
|
660
|
+
*/
|
|
661
|
+
|
|
364
662
|
interface R3FMatcherReceiver {
|
|
365
663
|
page: Page;
|
|
664
|
+
canvasId?: string;
|
|
366
665
|
getObject(idOrUuid: string): Promise<ObjectMetadata | null>;
|
|
367
666
|
inspect(idOrUuid: string): Promise<ObjectInspection | null>;
|
|
368
667
|
}
|
|
668
|
+
/** Context provided by Playwright when the matcher is invoked via expect().extend() */
|
|
669
|
+
interface ExpectMatcherContext {
|
|
670
|
+
isNot?: boolean;
|
|
671
|
+
}
|
|
369
672
|
interface MatcherOptions {
|
|
370
673
|
timeout?: number;
|
|
371
674
|
interval?: number;
|
|
@@ -373,15 +676,15 @@ interface MatcherOptions {
|
|
|
373
676
|
type Vec3Opts = MatcherOptions & {
|
|
374
677
|
tolerance?: number;
|
|
375
678
|
};
|
|
376
|
-
declare const
|
|
377
|
-
toExist(this:
|
|
679
|
+
declare const r3fMatchers: {
|
|
680
|
+
toExist(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, opts?: MatcherOptions): Promise<{
|
|
378
681
|
pass: boolean;
|
|
379
682
|
message: () => string;
|
|
380
683
|
name: string;
|
|
381
684
|
expected: string;
|
|
382
685
|
actual: null;
|
|
383
686
|
}>;
|
|
384
|
-
toBeVisible(this:
|
|
687
|
+
toBeVisible(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, opts?: MatcherOptions): Promise<{
|
|
385
688
|
pass: boolean;
|
|
386
689
|
message: () => string;
|
|
387
690
|
name: string;
|
|
@@ -392,84 +695,95 @@ declare const expect: _playwright_test.Expect<{
|
|
|
392
695
|
expected: boolean;
|
|
393
696
|
actual: boolean;
|
|
394
697
|
}>;
|
|
395
|
-
toHavePosition(this:
|
|
698
|
+
toHavePosition(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expected: [number, number, number], tolOpts?: number | Vec3Opts): Promise<{
|
|
396
699
|
pass: boolean;
|
|
397
700
|
message: () => string;
|
|
398
701
|
name: string;
|
|
399
702
|
} | {
|
|
400
|
-
pass:
|
|
703
|
+
pass: boolean;
|
|
401
704
|
message: () => string;
|
|
402
705
|
name: string;
|
|
403
706
|
expected: [number, number, number];
|
|
404
707
|
actual: [number, number, number];
|
|
405
708
|
}>;
|
|
406
|
-
|
|
709
|
+
toHaveWorldPosition(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expected: [number, number, number], tolOpts?: number | Vec3Opts): Promise<{
|
|
407
710
|
pass: boolean;
|
|
408
711
|
message: () => string;
|
|
409
712
|
name: string;
|
|
410
713
|
} | {
|
|
411
|
-
pass:
|
|
714
|
+
pass: boolean;
|
|
412
715
|
message: () => string;
|
|
413
716
|
name: string;
|
|
414
717
|
expected: [number, number, number];
|
|
415
718
|
actual: [number, number, number];
|
|
416
719
|
}>;
|
|
417
|
-
|
|
720
|
+
toHaveRotation(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expected: [number, number, number], tolOpts?: number | Vec3Opts): Promise<{
|
|
418
721
|
pass: boolean;
|
|
419
722
|
message: () => string;
|
|
420
723
|
name: string;
|
|
421
724
|
} | {
|
|
422
|
-
pass:
|
|
725
|
+
pass: boolean;
|
|
423
726
|
message: () => string;
|
|
424
727
|
name: string;
|
|
425
728
|
expected: [number, number, number];
|
|
426
729
|
actual: [number, number, number];
|
|
427
730
|
}>;
|
|
428
|
-
|
|
731
|
+
toHaveScale(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expected: [number, number, number], tolOpts?: number | Vec3Opts): Promise<{
|
|
429
732
|
pass: boolean;
|
|
430
733
|
message: () => string;
|
|
431
734
|
name: string;
|
|
432
735
|
} | {
|
|
433
|
-
pass:
|
|
736
|
+
pass: boolean;
|
|
737
|
+
message: () => string;
|
|
738
|
+
name: string;
|
|
739
|
+
expected: [number, number, number];
|
|
740
|
+
actual: [number, number, number];
|
|
741
|
+
}>;
|
|
742
|
+
toHaveType(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedType: string, opts?: MatcherOptions): Promise<{
|
|
743
|
+
pass: boolean;
|
|
744
|
+
message: () => string;
|
|
745
|
+
name: string;
|
|
746
|
+
} | {
|
|
747
|
+
pass: boolean;
|
|
434
748
|
message: () => string;
|
|
435
749
|
name: string;
|
|
436
750
|
expected: string;
|
|
437
751
|
actual: string;
|
|
438
752
|
}>;
|
|
439
|
-
toHaveName(this:
|
|
753
|
+
toHaveName(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedName: string, opts?: MatcherOptions): Promise<{
|
|
440
754
|
pass: boolean;
|
|
441
755
|
message: () => string;
|
|
442
756
|
name: string;
|
|
443
757
|
} | {
|
|
444
|
-
pass:
|
|
758
|
+
pass: boolean;
|
|
445
759
|
message: () => string;
|
|
446
760
|
name: string;
|
|
447
761
|
expected: string;
|
|
448
762
|
actual: string;
|
|
449
763
|
}>;
|
|
450
|
-
toHaveGeometryType(this:
|
|
764
|
+
toHaveGeometryType(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedGeo: string, opts?: MatcherOptions): Promise<{
|
|
451
765
|
pass: boolean;
|
|
452
766
|
message: () => string;
|
|
453
767
|
name: string;
|
|
454
768
|
} | {
|
|
455
|
-
pass:
|
|
769
|
+
pass: boolean;
|
|
456
770
|
message: () => string;
|
|
457
771
|
name: string;
|
|
458
772
|
expected: string;
|
|
459
773
|
actual: string | undefined;
|
|
460
774
|
}>;
|
|
461
|
-
toHaveMaterialType(this:
|
|
775
|
+
toHaveMaterialType(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedMat: string, opts?: MatcherOptions): Promise<{
|
|
462
776
|
pass: boolean;
|
|
463
777
|
message: () => string;
|
|
464
778
|
name: string;
|
|
465
779
|
} | {
|
|
466
|
-
pass:
|
|
780
|
+
pass: boolean;
|
|
467
781
|
message: () => string;
|
|
468
782
|
name: string;
|
|
469
783
|
expected: string;
|
|
470
784
|
actual: string | undefined;
|
|
471
785
|
}>;
|
|
472
|
-
toHaveChildCount(this:
|
|
786
|
+
toHaveChildCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedCount: number, opts?: MatcherOptions): Promise<{
|
|
473
787
|
pass: boolean;
|
|
474
788
|
message: () => string;
|
|
475
789
|
name: string;
|
|
@@ -480,18 +794,18 @@ declare const expect: _playwright_test.Expect<{
|
|
|
480
794
|
expected: number;
|
|
481
795
|
actual: number;
|
|
482
796
|
}>;
|
|
483
|
-
toHaveParent(this:
|
|
797
|
+
toHaveParent(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedParent: string, opts?: MatcherOptions): Promise<{
|
|
484
798
|
pass: boolean;
|
|
485
799
|
message: () => string;
|
|
486
800
|
name: string;
|
|
487
801
|
} | {
|
|
488
|
-
pass:
|
|
802
|
+
pass: boolean;
|
|
489
803
|
message: () => string;
|
|
490
804
|
name: string;
|
|
491
805
|
expected: string;
|
|
492
806
|
actual: string | null;
|
|
493
807
|
}>;
|
|
494
|
-
toHaveInstanceCount(this:
|
|
808
|
+
toHaveInstanceCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedCount: number, opts?: MatcherOptions): Promise<{
|
|
495
809
|
pass: boolean;
|
|
496
810
|
message: () => string;
|
|
497
811
|
name: string;
|
|
@@ -502,12 +816,12 @@ declare const expect: _playwright_test.Expect<{
|
|
|
502
816
|
expected: number;
|
|
503
817
|
actual: number;
|
|
504
818
|
}>;
|
|
505
|
-
toBeInFrustum(this:
|
|
819
|
+
toBeInFrustum(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, opts?: MatcherOptions): Promise<{
|
|
506
820
|
pass: boolean;
|
|
507
821
|
message: () => string;
|
|
508
822
|
name: string;
|
|
509
823
|
} | {
|
|
510
|
-
pass:
|
|
824
|
+
pass: boolean;
|
|
511
825
|
message: () => string;
|
|
512
826
|
name: string;
|
|
513
827
|
expected: string;
|
|
@@ -516,7 +830,7 @@ declare const expect: _playwright_test.Expect<{
|
|
|
516
830
|
max: [number, number, number];
|
|
517
831
|
};
|
|
518
832
|
}>;
|
|
519
|
-
toHaveBounds(this:
|
|
833
|
+
toHaveBounds(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expected: {
|
|
520
834
|
min: [number, number, number];
|
|
521
835
|
max: [number, number, number];
|
|
522
836
|
}, tolOpts?: number | Vec3Opts): Promise<{
|
|
@@ -524,7 +838,7 @@ declare const expect: _playwright_test.Expect<{
|
|
|
524
838
|
message: () => string;
|
|
525
839
|
name: string;
|
|
526
840
|
} | {
|
|
527
|
-
pass:
|
|
841
|
+
pass: boolean;
|
|
528
842
|
message: () => string;
|
|
529
843
|
name: string;
|
|
530
844
|
expected: {
|
|
@@ -536,40 +850,40 @@ declare const expect: _playwright_test.Expect<{
|
|
|
536
850
|
max: [number, number, number];
|
|
537
851
|
};
|
|
538
852
|
}>;
|
|
539
|
-
toHaveColor(this:
|
|
853
|
+
toHaveColor(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedColor: string, opts?: MatcherOptions): Promise<{
|
|
540
854
|
pass: boolean;
|
|
541
855
|
message: () => string;
|
|
542
856
|
name: string;
|
|
543
857
|
} | {
|
|
544
|
-
pass:
|
|
858
|
+
pass: boolean;
|
|
545
859
|
message: () => string;
|
|
546
860
|
name: string;
|
|
547
861
|
expected: string;
|
|
548
862
|
actual: string | undefined;
|
|
549
863
|
}>;
|
|
550
|
-
toHaveOpacity(this:
|
|
864
|
+
toHaveOpacity(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedOpacity: number, tolOpts?: number | Vec3Opts): Promise<{
|
|
551
865
|
pass: boolean;
|
|
552
866
|
message: () => string;
|
|
553
867
|
name: string;
|
|
554
868
|
} | {
|
|
555
|
-
pass:
|
|
869
|
+
pass: boolean;
|
|
556
870
|
message: () => string;
|
|
557
871
|
name: string;
|
|
558
872
|
expected: number;
|
|
559
873
|
actual: number | undefined;
|
|
560
874
|
}>;
|
|
561
|
-
toBeTransparent(this:
|
|
875
|
+
toBeTransparent(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, opts?: MatcherOptions): Promise<{
|
|
562
876
|
pass: boolean;
|
|
563
877
|
message: () => string;
|
|
564
878
|
name: string;
|
|
565
879
|
} | {
|
|
566
|
-
pass:
|
|
880
|
+
pass: boolean;
|
|
567
881
|
message: () => string;
|
|
568
882
|
name: string;
|
|
569
883
|
expected: boolean;
|
|
570
884
|
actual: boolean | undefined;
|
|
571
885
|
}>;
|
|
572
|
-
toHaveVertexCount(this:
|
|
886
|
+
toHaveVertexCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedCount: number, opts?: MatcherOptions): Promise<{
|
|
573
887
|
pass: boolean;
|
|
574
888
|
message: () => string;
|
|
575
889
|
name: string;
|
|
@@ -580,7 +894,7 @@ declare const expect: _playwright_test.Expect<{
|
|
|
580
894
|
expected: number;
|
|
581
895
|
actual: number;
|
|
582
896
|
}>;
|
|
583
|
-
toHaveTriangleCount(this:
|
|
897
|
+
toHaveTriangleCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedCount: number, opts?: MatcherOptions): Promise<{
|
|
584
898
|
pass: boolean;
|
|
585
899
|
message: () => string;
|
|
586
900
|
name: string;
|
|
@@ -591,23 +905,23 @@ declare const expect: _playwright_test.Expect<{
|
|
|
591
905
|
expected: number;
|
|
592
906
|
actual: number;
|
|
593
907
|
}>;
|
|
594
|
-
toHaveUserData(this:
|
|
908
|
+
toHaveUserData(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, key: string, expectedValue?: unknown, opts?: MatcherOptions): Promise<{
|
|
595
909
|
pass: boolean;
|
|
596
910
|
message: () => string;
|
|
597
911
|
name: string;
|
|
598
912
|
} | {
|
|
599
|
-
pass:
|
|
913
|
+
pass: boolean;
|
|
600
914
|
message: () => string;
|
|
601
915
|
name: string;
|
|
602
916
|
expected: {};
|
|
603
917
|
actual: unknown;
|
|
604
918
|
}>;
|
|
605
|
-
toHaveMapTexture(this:
|
|
919
|
+
toHaveMapTexture(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, id: string, expectedName?: string, opts?: MatcherOptions): Promise<{
|
|
606
920
|
pass: boolean;
|
|
607
921
|
message: () => string;
|
|
608
922
|
name: string;
|
|
609
923
|
} | {
|
|
610
|
-
pass:
|
|
924
|
+
pass: boolean;
|
|
611
925
|
message: () => string;
|
|
612
926
|
name: string;
|
|
613
927
|
expected: string;
|
|
@@ -620,8 +934,8 @@ declare const expect: _playwright_test.Expect<{
|
|
|
620
934
|
* @example expect(r3f).toHaveObjectCount(42);
|
|
621
935
|
* @example expect(r3f).toHaveObjectCount(42, { timeout: 10_000 });
|
|
622
936
|
*/
|
|
623
|
-
toHaveObjectCount(this:
|
|
624
|
-
pass:
|
|
937
|
+
toHaveObjectCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, options?: MatcherOptions): Promise<{
|
|
938
|
+
pass: boolean;
|
|
625
939
|
message: () => string;
|
|
626
940
|
name: string;
|
|
627
941
|
expected: number;
|
|
@@ -633,8 +947,8 @@ declare const expect: _playwright_test.Expect<{
|
|
|
633
947
|
*
|
|
634
948
|
* @example expect(r3f).toHaveObjectCountGreaterThan(10);
|
|
635
949
|
*/
|
|
636
|
-
toHaveObjectCountGreaterThan(this:
|
|
637
|
-
pass:
|
|
950
|
+
toHaveObjectCountGreaterThan(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, min: number, options?: MatcherOptions): Promise<{
|
|
951
|
+
pass: boolean;
|
|
638
952
|
message: () => string;
|
|
639
953
|
name: string;
|
|
640
954
|
expected: string;
|
|
@@ -647,8 +961,8 @@ declare const expect: _playwright_test.Expect<{
|
|
|
647
961
|
* @example expect(r3f).toHaveCountByType('Mesh', 5);
|
|
648
962
|
* @example expect(r3f).toHaveCountByType('Line', 10, { timeout: 10_000 });
|
|
649
963
|
*/
|
|
650
|
-
toHaveCountByType(this:
|
|
651
|
-
pass:
|
|
964
|
+
toHaveCountByType(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, type: string, expected: number, options?: MatcherOptions): Promise<{
|
|
965
|
+
pass: boolean;
|
|
652
966
|
message: () => string;
|
|
653
967
|
name: string;
|
|
654
968
|
expected: number;
|
|
@@ -661,8 +975,8 @@ declare const expect: _playwright_test.Expect<{
|
|
|
661
975
|
* @example expect(r3f).toHaveTotalTriangleCount(50000);
|
|
662
976
|
* @example expect(r3f).not.toHaveTotalTriangleCountGreaterThan(100000); // budget guard
|
|
663
977
|
*/
|
|
664
|
-
toHaveTotalTriangleCount(this:
|
|
665
|
-
pass:
|
|
978
|
+
toHaveTotalTriangleCount(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, options?: MatcherOptions): Promise<{
|
|
979
|
+
pass: boolean;
|
|
666
980
|
message: () => string;
|
|
667
981
|
name: string;
|
|
668
982
|
expected: number;
|
|
@@ -674,36 +988,160 @@ declare const expect: _playwright_test.Expect<{
|
|
|
674
988
|
*
|
|
675
989
|
* @example expect(r3f).toHaveTotalTriangleCountLessThan(100_000);
|
|
676
990
|
*/
|
|
677
|
-
toHaveTotalTriangleCountLessThan(this:
|
|
678
|
-
pass:
|
|
991
|
+
toHaveTotalTriangleCountLessThan(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, max: number, options?: MatcherOptions): Promise<{
|
|
992
|
+
pass: boolean;
|
|
679
993
|
message: () => string;
|
|
680
994
|
name: string;
|
|
681
995
|
expected: string;
|
|
682
996
|
actual: number;
|
|
683
997
|
}>;
|
|
684
|
-
|
|
998
|
+
/**
|
|
999
|
+
* Assert the camera position is close to the expected [x, y, z].
|
|
1000
|
+
*
|
|
1001
|
+
* @example expect(r3f).toHaveCameraPosition([0, 5, 10], 0.1);
|
|
1002
|
+
*/
|
|
1003
|
+
toHaveCameraPosition(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: [number, number, number], tolOpts?: number | Vec3Opts): Promise<{
|
|
1004
|
+
pass: boolean;
|
|
1005
|
+
message: () => string;
|
|
1006
|
+
name: string;
|
|
1007
|
+
expected: [number, number, number];
|
|
1008
|
+
actual: [number, number, number];
|
|
1009
|
+
}>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Assert the camera field of view (PerspectiveCamera only).
|
|
1012
|
+
*
|
|
1013
|
+
* @example expect(r3f).toHaveCameraFov(75);
|
|
1014
|
+
*/
|
|
1015
|
+
toHaveCameraFov(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, tolOpts?: number | Vec3Opts): Promise<{
|
|
1016
|
+
pass: boolean;
|
|
1017
|
+
message: () => string;
|
|
1018
|
+
name: string;
|
|
1019
|
+
expected: number;
|
|
1020
|
+
actual: number | undefined;
|
|
1021
|
+
}>;
|
|
1022
|
+
/**
|
|
1023
|
+
* Assert the camera near clipping plane.
|
|
1024
|
+
*
|
|
1025
|
+
* @example expect(r3f).toHaveCameraNear(0.1);
|
|
1026
|
+
*/
|
|
1027
|
+
toHaveCameraNear(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, tolOpts?: number | Vec3Opts): Promise<{
|
|
1028
|
+
pass: boolean;
|
|
1029
|
+
message: () => string;
|
|
1030
|
+
name: string;
|
|
1031
|
+
expected: number;
|
|
1032
|
+
actual: number;
|
|
1033
|
+
}>;
|
|
1034
|
+
/**
|
|
1035
|
+
* Assert the camera far clipping plane.
|
|
1036
|
+
*
|
|
1037
|
+
* @example expect(r3f).toHaveCameraFar(1000);
|
|
1038
|
+
*/
|
|
1039
|
+
toHaveCameraFar(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, tolOpts?: number | Vec3Opts): Promise<{
|
|
1040
|
+
pass: boolean;
|
|
1041
|
+
message: () => string;
|
|
1042
|
+
name: string;
|
|
1043
|
+
expected: number;
|
|
1044
|
+
actual: number;
|
|
1045
|
+
}>;
|
|
1046
|
+
/**
|
|
1047
|
+
* Assert the camera zoom level.
|
|
1048
|
+
*
|
|
1049
|
+
* @example expect(r3f).toHaveCameraZoom(1);
|
|
1050
|
+
*/
|
|
1051
|
+
toHaveCameraZoom(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, expected: number, tolOpts?: number | Vec3Opts): Promise<{
|
|
1052
|
+
pass: boolean;
|
|
1053
|
+
message: () => string;
|
|
1054
|
+
name: string;
|
|
1055
|
+
expected: number;
|
|
1056
|
+
actual: number;
|
|
1057
|
+
}>;
|
|
1058
|
+
/**
|
|
1059
|
+
* Assert that ALL given objects exist in the scene.
|
|
1060
|
+
* Accepts an array of testIds/uuids or a glob pattern (e.g. "wall-*").
|
|
1061
|
+
*
|
|
1062
|
+
* @example expect(r3f).toAllExist(['wall-1', 'wall-2', 'floor']);
|
|
1063
|
+
* @example expect(r3f).toAllExist('wall-*');
|
|
1064
|
+
*/
|
|
1065
|
+
toAllExist(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, idsOrPattern: string[] | string, opts?: MatcherOptions): Promise<{
|
|
1066
|
+
pass: boolean;
|
|
1067
|
+
message: () => string;
|
|
1068
|
+
name: string;
|
|
1069
|
+
expected: string | string[];
|
|
1070
|
+
actual: {
|
|
1071
|
+
missing: string[];
|
|
1072
|
+
};
|
|
1073
|
+
}>;
|
|
1074
|
+
/**
|
|
1075
|
+
* Assert that ALL given objects are visible.
|
|
1076
|
+
*
|
|
1077
|
+
* @example expect(r3f).toAllBeVisible(['wall-1', 'wall-2', 'floor']);
|
|
1078
|
+
* @example expect(r3f).toAllBeVisible('wall-*');
|
|
1079
|
+
*/
|
|
1080
|
+
toAllBeVisible(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, idsOrPattern: string[] | string, opts?: MatcherOptions): Promise<{
|
|
1081
|
+
pass: boolean;
|
|
1082
|
+
message: () => string;
|
|
1083
|
+
name: string;
|
|
1084
|
+
expected: string | string[];
|
|
1085
|
+
actual: {
|
|
1086
|
+
hidden: string[];
|
|
1087
|
+
};
|
|
1088
|
+
}>;
|
|
1089
|
+
/**
|
|
1090
|
+
* Assert that NONE of the given objects exist in the scene.
|
|
1091
|
+
*
|
|
1092
|
+
* @example expect(r3f).toNoneExist(['deleted-wall', 'old-floor']);
|
|
1093
|
+
* @example expect(r3f).toNoneExist('temp-*');
|
|
1094
|
+
*/
|
|
1095
|
+
toNoneExist(this: ExpectMatcherContext, r3f: R3FMatcherReceiver, idsOrPattern: string[] | string, opts?: MatcherOptions): Promise<{
|
|
1096
|
+
pass: boolean;
|
|
1097
|
+
message: () => string;
|
|
1098
|
+
name: string;
|
|
1099
|
+
expected: string | string[];
|
|
1100
|
+
actual: {
|
|
1101
|
+
found: string[];
|
|
1102
|
+
};
|
|
1103
|
+
}>;
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* @module interactions
|
|
1108
|
+
*
|
|
1109
|
+
* Playwright interaction helpers — thin wrappers around `page.evaluate` calls
|
|
1110
|
+
* to the `window.__R3F_DOM__` bridge interaction methods.
|
|
1111
|
+
*
|
|
1112
|
+
* All object-targeted interactions auto-wait for:
|
|
1113
|
+
* 1. The bridge to be ready (`_ready === true`)
|
|
1114
|
+
* 2. The target object to exist (by testId or uuid)
|
|
1115
|
+
*
|
|
1116
|
+
* This mirrors Playwright's built-in auto-waiting on locators.
|
|
1117
|
+
*
|
|
1118
|
+
* Multi-canvas: pass `canvasId` to target a specific canvas instance.
|
|
1119
|
+
* When undefined, uses the default `window.__R3F_DOM__`.
|
|
1120
|
+
*/
|
|
685
1121
|
|
|
686
1122
|
/** Click a 3D object by its testId or uuid. Auto-waits for the object. */
|
|
687
|
-
declare function click(page: Page, idOrUuid: string, timeout?: number): Promise<void>;
|
|
1123
|
+
declare function click(page: Page, idOrUuid: string, timeout?: number, canvasId?: string): Promise<void>;
|
|
688
1124
|
/** Double-click a 3D object by its testId or uuid. Auto-waits for the object. */
|
|
689
|
-
declare function doubleClick(page: Page, idOrUuid: string, timeout?: number): Promise<void>;
|
|
1125
|
+
declare function doubleClick(page: Page, idOrUuid: string, timeout?: number, canvasId?: string): Promise<void>;
|
|
690
1126
|
/** Right-click / context-menu a 3D object. Auto-waits for the object. */
|
|
691
|
-
declare function contextMenu(page: Page, idOrUuid: string, timeout?: number): Promise<void>;
|
|
1127
|
+
declare function contextMenu(page: Page, idOrUuid: string, timeout?: number, canvasId?: string): Promise<void>;
|
|
692
1128
|
/** Hover over a 3D object. Auto-waits for the object. */
|
|
693
|
-
declare function hover(page: Page, idOrUuid: string, timeout?: number): Promise<void>;
|
|
1129
|
+
declare function hover(page: Page, idOrUuid: string, timeout?: number, canvasId?: string): Promise<void>;
|
|
1130
|
+
/** Unhover / pointer-leave — resets hover state by moving pointer off-canvas. Auto-waits for bridge. */
|
|
1131
|
+
declare function unhover(page: Page, timeout?: number, canvasId?: string): Promise<void>;
|
|
694
1132
|
/** Drag a 3D object with a world-space delta. Auto-waits for the object. */
|
|
695
1133
|
declare function drag(page: Page, idOrUuid: string, delta: {
|
|
696
1134
|
x: number;
|
|
697
1135
|
y: number;
|
|
698
1136
|
z: number;
|
|
699
|
-
}, timeout?: number): Promise<void>;
|
|
1137
|
+
}, timeout?: number, canvasId?: string): Promise<void>;
|
|
700
1138
|
/** Dispatch a wheel/scroll event on a 3D object. Auto-waits for the object. */
|
|
701
1139
|
declare function wheel(page: Page, idOrUuid: string, options?: {
|
|
702
1140
|
deltaY?: number;
|
|
703
1141
|
deltaX?: number;
|
|
704
|
-
}, timeout?: number): Promise<void>;
|
|
1142
|
+
}, timeout?: number, canvasId?: string): Promise<void>;
|
|
705
1143
|
/** Click empty space to trigger onPointerMissed handlers. Auto-waits for bridge. */
|
|
706
|
-
declare function pointerMiss(page: Page, timeout?: number): Promise<void>;
|
|
1144
|
+
declare function pointerMiss(page: Page, timeout?: number, canvasId?: string): Promise<void>;
|
|
707
1145
|
/** Draw a freeform path on the canvas. Auto-waits for bridge. */
|
|
708
1146
|
declare function drawPathOnCanvas(page: Page, points: Array<{
|
|
709
1147
|
x: number;
|
|
@@ -713,11 +1151,22 @@ declare function drawPathOnCanvas(page: Page, points: Array<{
|
|
|
713
1151
|
stepDelayMs?: number;
|
|
714
1152
|
pointerType?: 'mouse' | 'pen' | 'touch';
|
|
715
1153
|
clickAtEnd?: boolean;
|
|
716
|
-
}, timeout?: number): Promise<{
|
|
1154
|
+
}, timeout?: number, canvasId?: string): Promise<{
|
|
717
1155
|
eventCount: number;
|
|
718
1156
|
pointCount: number;
|
|
719
1157
|
}>;
|
|
1158
|
+
/** Get the current camera state (position, rotation, fov, near, far, zoom). Auto-waits for bridge. */
|
|
1159
|
+
declare function getCameraState(page: Page, timeout?: number, canvasId?: string): Promise<CameraState>;
|
|
720
1160
|
|
|
1161
|
+
/**
|
|
1162
|
+
* @module pathGenerators
|
|
1163
|
+
*
|
|
1164
|
+
* Pure geometry utilities that generate arrays of screen-space points for
|
|
1165
|
+
* use with `r3f.drawPath()`. Provides line, quadratic bezier, rectangle,
|
|
1166
|
+
* and circle/ellipse path generators.
|
|
1167
|
+
*
|
|
1168
|
+
* Duplicated from `@react-three-dom/core` to avoid a runtime dependency.
|
|
1169
|
+
*/
|
|
721
1170
|
/** A 2D screen-space point in CSS pixels, relative to the canvas top-left. */
|
|
722
1171
|
interface DrawPoint {
|
|
723
1172
|
/** X coordinate in CSS pixels from canvas left edge. */
|
|
@@ -790,4 +1239,4 @@ declare function circlePath(center: {
|
|
|
790
1239
|
y: number;
|
|
791
1240
|
}, radiusX: number, radiusY?: number, steps?: number, pressure?: number): DrawPoint[];
|
|
792
1241
|
|
|
793
|
-
export { type DrawPoint, type ObjectInspection, type ObjectMetadata, R3FFixture, type R3FFixtureOptions, type SceneSnapshot, type SnapshotNode, type WaitForIdleOptions, type WaitForNewObjectOptions, type WaitForNewObjectResult, type WaitForObjectOptions, type WaitForSceneReadyOptions, circlePath, click, contextMenu, createR3FTest, curvePath, doubleClick, drag, drawPathOnCanvas,
|
|
1242
|
+
export { type BridgeDiagnostics, type CameraState, type DrawPoint, type InspectOptions, type ObjectInspection, type ObjectMetadata, R3FFixture, type R3FFixtureOptions, R3FReporter, type SceneDiff, type SceneDiffChange, type SceneSnapshot, type SnapshotNode, type WaitForIdleOptions, type WaitForNewObjectOptions, type WaitForNewObjectResult, type WaitForObjectOptions, type WaitForObjectRemovedOptions, type WaitForSceneReadyOptions, circlePath, click, contextMenu, createR3FTest, curvePath, diffSnapshots, doubleClick, drag, drawPathOnCanvas, getCameraState, hover, linePath, pointerMiss, r3fMatchers, rectPath, test, unhover, waitForIdle, waitForNewObject, waitForObject, waitForObjectRemoved, waitForSceneReady, wheel };
|