Appearance
Testing
FreshLike with every other application, testing is an important factor when releasing into the wild. React Three Fiber can be tested using @react-three/test-renderer.
Installation
bash
npm install @react-three/test-renderer --save-devReact Three Test Renderer is testing library agnostic — it works with jest, jasmine, etc.
Basic Setup
jsx
import ReactThreeTestRenderer from '@react-three/test-renderer'
import { MyRotatingBox } from './App'
test('mesh to have two children', async () => {
const renderer = await ReactThreeTestRenderer.create(<MyRotatingBox />)
})
test('click event makes box bigger', async () => {
const renderer = await ReactThreeTestRenderer.create(<MyRotatingBox />)
})Testing Scene Structure
Get the scene and its children from the test instance:
js
const meshChildren = renderer.scene.childrenUse allChildren to get geometry and materials (not just groups):
js
const meshChildren = renderer.scene.children[0].allChildrenINFO
children is meant for groups and does not return geometry and materials. Use allChildren to get all children including geometry and materials.
Assert on the structure:
js
expect(meshChildren.length).toBe(2)Full test:
js
test('mesh to have two children', async () => {
const renderer = await ReactThreeTestRenderer.create(<MyRotatingBox />)
const mesh = renderer.scene.children[0].allChildren
expect(mesh.length).toBe(2)
})Testing Interactions
Use the fireEvent method on a test instance to simulate user events:
js
const mesh = renderer.scene.children[0]
await renderer.fireEvent(mesh, 'click')Then assert on the resulting state:
js
expect(mesh.props.scale).toBe(1.5)Full interaction test:
js
test('click event makes box bigger', async () => {
const renderer = await ReactThreeTestRenderer.create(<MyRotatingBox />)
const mesh = renderer.scene.children[0]
expect(mesh.props.scale).toBe(1)
await renderer.fireEvent(mesh, 'click')
expect(mesh.props.scale).toBe(1.5)
})Testing with act (v9+)
In R3F v9, act is exported from React itself:
tsx
import { act } from 'react'
import { createRoot } from '@react-three/fiber'
const store = await act(async () => createRoot(canvas).render(<App />))
console.log(store.getState())StrictMode in Tests (v9)
StrictMode is now correctly inherited from a parent renderer. Previously it had to be redeclared within the canvas:
diff
<StrictMode>
<Canvas>
- <StrictMode>
- // ...
- </StrictMode>
+ // ...
</Canvas>
</StrictMode>Exercises
- Check the color of a mesh: access
mesh.props.material-coloror traverseallChildren - Check rotation using the
advanceFramesmethod on the renderer - Test loading states with Suspense fallbacks