Skip to content

test(🧪): render Canvas and its Jest mock under React Native Testing Library - #529

Draft
YevheniiKotyrlo wants to merge 4 commits into
wcandillon:mainfrom
YevheniiKotyrlo:test/component-test-tier
Draft

YevheniiKotyrlo wants to merge 4 commits into
wcandillon:mainfrom
YevheniiKotyrlo:test/component-test-tier

Conversation

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor

Problem

Every spec under packages/webgpu/src/__tests__ goes through the e2e harness: jest.config.js gives the tree a globalSetup that waits for the example app. So nothing renders a component under Jest. The Jest mock's Canvas, which apps render in their own Jest tests, has no test of its own, and Canvas's ref handle is checked only on a device. The repo also has no React 19 renderer for such tests: react-test-renderer is deprecated with React 19.

Solution

jest.unit.config.js runs src/__tests__/unit with React Native's Jest preset and React Native Testing Library 14, which renders on test-renderer (1.1, the React 19.1 line) instead of react-test-renderer. The e2e config skips that directory, and CI runs yarn test:unit in the build job next to the plugin's tests. The whole tier takes about 2 s; Vitest 5 with vitest-native ran the same spec 0.2 s faster warm and 3.6 s slower cold, not enough to justify a second runner.

Tests

  • Canvas.test.tsx, with a stand-in RNWebGPU and View's measureLayout: the context is created at the layout size the view measures relative to itself; on the web the size is left to the polyfill; the ref handle survives re-renders; a state setter as the ref settles; unmount retires the context once; a context name other than webgpu throws.
  • mock.test.tsx: the mock's handle survives re-renders, a state setter as its ref settles, it answers -1 and null and throws from getNativeSurface(), and it keeps its own props off the View it renders.

Against Canvas.tsx and mock.ts from before #525, six of the ten fail: a new handle on every render, Maximum update depth exceeded, and the bounding-box measurement.

Verification

yarn lint · yarn tsc · yarn turbo run build --filter='./packages/*' · the Expo template's web build · yarn test:plugin · yarn test:unit (10 passed) · yarn check-dawn · yarn build:docs. With the e2e config, jest --listTests lists no file from src/__tests__/unit.

…andle once

getContext() measured the canvas with getBoundingClientRect(), which includes
the transforms of the view and its ancestors, so a context made while the
canvas was drawn under transform: [{ scale: 0.5 }] got half its layout size
for canvas.width/height and clientWidth/clientHeight. measureLayout() relative
to the view itself answers its layout size without transforms, synchronously
on the new architecture. react-native-web's measureLayout() answers from a
timeout, so on the web the polyfill sizes the context from its <canvas>
element's clientWidth/clientHeight, which getNativeSurface() now reports too.

Canvas passed useImperativeHandle no dependency list, so every render built a
new handle and React re-attached the ref. The handle depends only on contextId
and viewRef, fixed for the canvas's lifetime; the Jest mock builds its handle
once as well.
…heck

The Tests screen's rerender() kept one pending resolver, so a request made
before the previous one committed left that promise unresolved until the eval
timed out. useRerender() numbers the requests, and the effect after a commit
resolves every request that commit rendered. The Canvas spec requests two
re-renders together and a third after them.

isNativeApp() in setup.ts, total over TestOS, replaces the native-app check
the specs spelled four ways.
…lace each

getNativeSurface() and the context each looked up the canvas element and read
its clientWidth/clientHeight; one helper each now holds that. WebPolyfill.spec
derives its polyfill type from RNWebGPU's and covers the rest of the module:
a second context at an unchanged size writes no attribute, since a write
clears the drawing buffer; getNativeSurface() writes none and binds its DOM
methods to the element; present() is a callable no-op. Canvas drops its
unused state setter binding.
…ibrary

Every spec under src/__tests__ goes through the e2e harness, which waits for
the example app, so nothing rendered a component under Jest and the Jest
mock's Canvas had no test of its own. jest.unit.config.js runs
src/__tests__/unit with React Native's Jest preset and React Native Testing
Library 14 on test-renderer, React 19's replacement for react-test-renderer;
CI runs it in the build job beside the plugin's tests.

The Canvas spec drives a stand-in RNWebGPU module and View's measureLayout:
the context is created at the layout size the view measures relative to
itself, the web leaves the size to the polyfill, the ref handle survives
re-renders, a state setter as the ref settles, and unmount retires the
context once. The mock's spec holds its handle and its loud failures.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant