import { expect, test } from '@playwright/test'; const fixtures = [ ['GLB', 'Box.glb'], ['Draco GLB', 'Duck.optimized.glb'], ['OBJ', 'Cube.obj'], ['FBX', 'Cube.fbx'], ['DAE', 'Cube.dae'], ['IFC', 'Cube.ifc'], ['double PLY', 'DoublePrecision.ply'], ] as const; for (const [label, fixture] of fixtures) { test(`viewer3d renders ${label} with Three.js r185`, async ({ page }) => { const runtimeErrors: string[] = []; page.on('pageerror', (error) => runtimeErrors.push(error.message)); page.on('console', (message) => { if (message.type() === 'error') runtimeErrors.push(message.text()); }); await page.goto(`http://127.0.0.1:3333/?model=/samples/${fixture}`); await page.waitForFunction( () => Boolean( ( window as Window & { __viewer?: { current?: object }; } ).__viewer?.current, ), undefined, { timeout: 20_000 }, ); const scene = await page.evaluate(() => { const current = ( window as Window & { __viewer?: { current?: { traverse: (visitor: (node: unknown) => void) => void; }; }; } ).__viewer?.current; let renderables = 0; let vertices = 0; let invalidValues = 0; let float64Attributes = 0; current?.traverse((node: unknown) => { const geometry = ( node as { geometry?: { attributes?: { position?: { array: ArrayLike; count: number; }; }; }; } ).geometry; const position = geometry?.attributes?.position; if (!position) return; renderables += 1; vertices += position.count; if (position.array instanceof Float64Array) float64Attributes += 1; for (let index = 0; index < position.array.length; index += 1) { if (!Number.isFinite(position.array[index])) invalidValues += 1; } }); return { canvases: document.querySelectorAll('canvas').length, float64Attributes, invalidValues, renderables, vertices, }; }); expect(scene.canvases).toBe(1); expect(scene.renderables).toBeGreaterThan(0); expect(scene.vertices).toBeGreaterThan(0); expect(scene.invalidValues).toBe(0); expect(scene.float64Attributes).toBe(0); expect(runtimeErrors).toEqual([]); }); }