Cannot render <Canvas> in React Three Test Renderer

Hi,
I’m getting this error when trying to render the R3F <Canvas> component in react three test renderer:

R3F: Canvas is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively

Upon extending ‘Canvas’, I’m getting this error:

TypeError: target is not a constructor

All of my troubleshooting has been leading me to believe that rendering the canvas is not something that should be done with this renderer, although how would I test functionality of a custom component that contains three.js logic inside of a tag? Would the only way be to split it up so that said component is isolated away from the three.js logic?

Thanks!

You’ll have to elaborate on what you’re trying to do such as what does your code structure look like?

it’s telling you that you somehow did this:

<Canvas>
  <canvas>

this is the same as new THREE.Canvas() and there is no such class in the import * as THREE namespace. <canvas> is a dom element, it is only valid in the dom, same qs divs and spans. everything inside the r3f <Canvas> is purely threejs, there can be no dom stuff in there.

1 Like

Slightly confused. I get that there is no THREE.Canvas() in the import * as THREE from 'three' namespace, but if the r3f <Canvas> is purely three.js inside, why would the error(s) be coming up if that’s all I’m trying to render?

(See “Tests” tab)

PS: Apologies for not giving sandboxes in the original question, trying to get in the habit of it! :slight_smile:

this must be an issue with test renderer. there is no way you should be forced to extend canvas, what would that even mean. i’ll forward it to the maintainers. the sandbox def helped, thanks!

wait, i think this is using test renderer wrong. you are supposed to render your app, not a dom canvas. meshes, components with groups, materials etc. create is a (headless) canvas.

const renderer = await ReactThreeTestRenderer.create(<mesh />) // ✅

function App() {
  return <mesh />
}

const renderer = await ReactThreeTestRenderer.create(<App />) // ✅

const renderer = await ReactThreeTestRenderer.create(<div />) // 💀
const renderer = await ReactThreeTestRenderer.create(<Canvas />) // 💀 (because it renders a dom canvas node)

Ah okay. If .create renders a headless canvas, then it wouldn’t make sense to try and put another one within it, especially since the R3F <Canvas> renders a dom <canvas> node (something I just realized).

My original motivation to try and test like this was because I was doing some logic with views inside my <Canvas> and wanted to test it without wrapping it in a custom component or copying individual internals into ReactThreeTestRenderer.create(). Given your explanation, though, I think abstracting my code inside <Canvas> into more separately testable custom components would be the way to go. In other words, viewing <Canvas> as a portal into the three.js environment, not as an actual three.js component that I would want to test.

1 Like