Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(test-renderer): react 18 support & use new act API #1891

Merged
merged 17 commits into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ module.exports = {
moduleFileExtensions: ['js', 'ts', 'tsx'],
verbose: false,
testTimeout: 30000,
setupFilesAfterEnv: ['<rootDir>/packages/shared/setupTests.ts'],
setupFilesAfterEnv: ['<rootDir>/packages/shared/setupTests.ts', '<rootDir>/packages/fiber/tests/setupTests.ts'],
}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@
"@changesets/changelog-git": "^0.1.8",
"@changesets/cli": "^2.17.0",
"@preconstruct/cli": "^2.1.1",
"@testing-library/react": "^12.0.0",
"@testing-library/react": "^13.0.0-alpha.5",
"@types/jest": "^27.0.1",
"@types/lodash-es": "^4.17.4",
"@types/react": "^17.0.19",
"@types/react-dom": "^17.0.9",
"@types/react-native": "^0.65.3",
Expand Down
2 changes: 0 additions & 2 deletions packages/fiber/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
"expo-asset": "^8.4.3",
"expo-file-system": "^13.0.3",
"expo-gl": "^11.0.3",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"react-merge-refs": "^1.1.0",
"react-reconciler": "^0.27.0-beta-96ca8d915-20211115",
"react-use-measure": "^2.1.1",
Expand Down
34 changes: 34 additions & 0 deletions packages/fiber/src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ export function calculateDpr(dpr: Dpr) {
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr
}

/**
* Picks or omits keys from an object
* `omit` will filter out keys, and otherwise cherry-pick them.
*/
export function filterKeys<TObj extends { [key: string]: any }, TOmit extends boolean, TKey extends keyof TObj>(
obj: TObj,
omit: TOmit,
...keys: TKey[]
): TOmit extends true ? Omit<TObj, TKey> : Pick<TObj, TKey> {
const keysToSelect = new Set(keys)

return Object.entries(obj).reduce((acc, [key, value]) => {
const shouldInclude = !omit

if (keysToSelect.has(key as TKey) === shouldInclude) {
acc[key] = value
}

return acc
}, {} as any)
}

/**
* Clones an object and cherry-picks keys.
*/
export const pick = <TObj>(obj: Partial<TObj>, keys: Array<keyof TObj>) =>
filterKeys<Partial<TObj>, false, keyof TObj>(obj, false, ...keys)

/**
* Clones an object and prunes or omits keys.
*/
export const omit = <TObj>(obj: Partial<TObj>, keys: Array<keyof TObj>) =>
filterKeys<Partial<TObj>, true, keyof TObj>(obj, true, ...keys)

// A collection of compare functions
export const is = {
obj: (a: any) => a === Object(a) && !is.arr(a) && typeof a !== 'function',
Expand Down
1 change: 1 addition & 0 deletions packages/fiber/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export type {
RootState,
} from './core/store'
export type { ThreeEvent, Events, EventManager } from './core/events'
export type { ObjectMap } from './core/utils'
export * from './web/Canvas'
export * from './web'
1 change: 1 addition & 0 deletions packages/fiber/src/native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export type {
RootState,
} from './core/store'
export type { ThreeEvent, Events, EventManager } from './core/events'
export type { ObjectMap } from './core/utils'
export * from './native/Canvas'
export * from './native/index'
10 changes: 4 additions & 6 deletions packages/fiber/src/native/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import * as THREE from 'three'
import { View, ViewProps, ViewStyle, LayoutChangeEvent, StyleSheet } from 'react-native'
import { ExpoWebGLRenderingContext, GLView } from 'expo-gl'
import { UseStore } from 'zustand'
import pick from 'lodash-es/pick'
import omit from 'lodash-es/omit'
import { pick, omit } from '../core/utils'
import { GLContext, extend, render, unmountComponentAtNode, RenderProps } from './index'
import { createTouchEvents } from './events'
import { RootState } from '../core/store'
Expand All @@ -25,10 +24,9 @@ type UnblockProps = {
children: React.ReactNode
}

const CANVAS_PROPS = [
const CANVAS_PROPS: Array<keyof Props> = [
'gl',
'events',
'size',
'shadows',
'linear',
'flat',
Expand Down Expand Up @@ -72,8 +70,8 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<View, Props>(
const [context, setContext] = React.useState<GLContext | null>(null)
const [bind, setBind] = React.useState()

const canvasProps = pick(props, CANVAS_PROPS)
const viewProps = omit(props, CANVAS_PROPS)
const canvasProps = pick<Props>(props, CANVAS_PROPS)
const viewProps = omit<Props>(props, CANVAS_PROPS)
const [block, setBlock] = React.useState<SetBlock>(false)
const [error, setError] = React.useState<any>(false)

Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/src/native/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ function unmountComponentAtNode(context: GLContext, callback?: (context: GLConte
}
}

const act = reconciler.act
const act = (React as any).unstable_act
function createPortal(children: React.ReactNode, container: THREE.Object3D): React.ReactNode {
return reconciler.createPortal(children, container, null, null)
}
Expand Down
12 changes: 5 additions & 7 deletions packages/fiber/src/web/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import * as THREE from 'three'
import mergeRefs from 'react-merge-refs'
import useMeasure, { Options as ResizeOptions } from 'react-use-measure'
import { UseStore } from 'zustand'
import pick from 'lodash-es/pick'
import omit from 'lodash-es/omit'
import { pick, omit } from '../core/utils'
import { extend, render, unmountComponentAtNode, RenderProps } from './index'
import { createPointerEvents } from './events'
import { RootState } from '../core/store'
Expand All @@ -22,10 +21,9 @@ export interface Props
type SetBlock = false | Promise<null> | null
type UnblockProps = { set: React.Dispatch<React.SetStateAction<SetBlock>>; children: React.ReactNode }

const CANVAS_PROPS = [
const CANVAS_PROPS: Array<keyof Props> = [
'gl',
'events',
'size',
'shadows',
'linear',
'flat',
Expand Down Expand Up @@ -71,8 +69,8 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<HTMLCanvasElement, Props>(f
const [containerRef, { width, height }] = useMeasure({ scroll: true, debounce: { scroll: 50, resize: 0 }, ...resize })
const canvasRef = React.useRef<HTMLCanvasElement>(null!)

const canvasProps = pick(props, CANVAS_PROPS)
const divProps = omit(props, CANVAS_PROPS)
const canvasProps = pick<Props>(props, CANVAS_PROPS)
const divProps = omit<Props>(props, CANVAS_PROPS)
const [block, setBlock] = React.useState<SetBlock>(false)
const [error, setError] = React.useState<any>(false)

Expand All @@ -96,7 +94,7 @@ export const Canvas = /*#__PURE__*/ React.forwardRef<HTMLCanvasElement, Props>(f
},
)
}
}, [width, height, children, canvasProps])
}, [width, height, children, canvasProps, events])

React.useEffect(() => {
const container = canvasRef.current
Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/src/web/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ function unmountComponentAtNode<TElement extends Element>(canvas: TElement, call
}
}

const act = reconciler.act
const act = (React as any).unstable_act
function createPortal(children: React.ReactNode, container: THREE.Object3D): React.ReactNode {
return reconciler.createPortal(children, container, null, null)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/tests/core/is.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { is } from '../../src/core/is'
import { is } from '../../src/core/utils'

describe('is', () => {
const myFunc = () => null
Expand Down
5 changes: 5 additions & 0 deletions packages/fiber/tests/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { extend } from '../src'
import * as THREE from 'three'

// Extend catalogue for render API in tests
extend(THREE)
2 changes: 1 addition & 1 deletion packages/fiber/tests/web/canvas.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react'
import { render, RenderResult } from '@testing-library/react'
import { createWebGLContext } from '@react-three/test-renderer/src/createWebGLContext'

import { Canvas, act, useThree } from '../../src/web'
import { Canvas, act } from '../../src'

// @ts-ignore
HTMLCanvasElement.prototype.getContext = function () {
Expand Down
12 changes: 7 additions & 5 deletions packages/fiber/tests/web/web.core.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ describe('web core', () => {
})

expect(scene.children[0].position.x).toEqual(7)
expect(renders).toBe(12)
expect(renders).toBe(6)
})

it('updates types & names', async () => {
Expand Down Expand Up @@ -352,7 +352,7 @@ describe('web core', () => {
unmountComponentAtNode(canvas)
})

expect(log).toEqual(['render Foo', 'render Foo', 'mount Foo', 'unmount Foo'])
expect(log).toEqual(['render Foo', 'mount Foo', 'unmount Foo'])
CodyJasonBennett marked this conversation as resolved.
Show resolved Hide resolved
})

it('will make an Orthographic Camera & set the position', async () => {
Expand Down Expand Up @@ -468,14 +468,16 @@ describe('web core', () => {
}
}

expect(() => {
act(async () => {
const testExtend = async () => {
await act(async () => {
extend({ MyColor })

// @ts-expect-error we're testing the extend feature, i'm not adding it to the namespace
render(<myColor args={[0x0000ff]} />, canvas)
})
}).not.toThrow()
}

expect(() => testExtend()).not.toThrow()
})

it('should set renderer props via gl prop', async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/tests/web/web.events.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react'
import { render, fireEvent, RenderResult } from '@testing-library/react'
import { createWebGLContext } from '@react-three/test-renderer/src/createWebGLContext'

import { Canvas, act } from '../../src/web/index'
import { Canvas, act } from '../../src'

// @ts-ignore
HTMLCanvasElement.prototype.getContext = function () {
Expand Down
2 changes: 1 addition & 1 deletion packages/fiber/tests/web/web.hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { createWebGLContext } from '@react-three/test-renderer/src/createWebGLCo

import { asyncUtils } from '../../../shared/asyncUtils'

import { render, advance, useLoader, act, useThree, useGraph, useFrame, ObjectMap } from '../../src/web/index'
import { render, advance, useLoader, act, useThree, useGraph, useFrame, ObjectMap } from '../../src'

const resolvers = []

Expand Down
3 changes: 3 additions & 0 deletions packages/shared/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ import 'regenerator-runtime/runtime'

import { pointerEventPolyfill } from './pointerEventPolyfill'

// @ts-ignore
global.IS_REACT_ACT_ENVIRONMENT = true

pointerEventPolyfill()
62 changes: 11 additions & 51 deletions packages/test-renderer/src/__tests__/RTTR.core.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ReactThreeTestRenderer from '../index'
type ExampleComp = Mesh<BoxBufferGeometry, Material>

describe('ReactThreeTestRenderer Core', () => {
it('renders a simple component in default blocking mode', async () => {
it('renders a simple component', async () => {
const Mesh = () => {
return (
<mesh>
Expand All @@ -26,29 +26,16 @@ describe('ReactThreeTestRenderer Core', () => {
expect(renderer.scene.children[0].type).toEqual('Mesh')
})

it('renders a simple component in legacy mode', async () => {
it('renders a simple component with useTransition', async () => {
const Mesh = () => {
return (
<mesh>
<boxGeometry args={[2, 2]} />
<meshBasicMaterial />
</mesh>
)
}
const renderer = await ReactThreeTestRenderer.create(
<React.Suspense fallback={null}>
<Mesh />
</React.Suspense>,
{ mode: 'legacy' },
)
const [name, setName] = React.useState<string>()

expect(renderer.scene.children[0].type).toEqual('Mesh')
})
React.useLayoutEffect(() => {
;(React as any).startTransition(() => void setName('mesh'))
})

it('renders a simple component in concurrent mode', async () => {
const Mesh = () => {
return (
<mesh>
<mesh name={name}>
<boxGeometry args={[2, 2]} />
<meshBasicMaterial />
</mesh>
Expand All @@ -58,10 +45,9 @@ describe('ReactThreeTestRenderer Core', () => {
<React.Suspense fallback={null}>
<Mesh />
</React.Suspense>,
{ mode: 'concurrent' },
)

expect(renderer.scene.children[0].type).toEqual('Mesh')
expect(renderer.scene.children[0].props.name).toEqual('mesh')
})

it('renders an empty scene', async () => {
Expand Down Expand Up @@ -151,7 +137,7 @@ describe('ReactThreeTestRenderer Core', () => {
const renderer = await ReactThreeTestRenderer.create(<Component />)

expect(renderer.scene.children[0].instance.position.x).toEqual(7)
expect(renders).toBe(12)
expect(renders).toBe(6)
})

it('updates types & names', async () => {
Expand Down Expand Up @@ -305,16 +291,7 @@ describe('ReactThreeTestRenderer Core', () => {
await renderer.update(<Log key="bar" name="Bar" />)
await renderer.unmount()

expect(log).toEqual([
'render Foo',
'render Foo',
'mount Foo',
'render Bar',
'render Bar',
'unmount Foo',
'mount Bar',
'unmount Bar',
])
expect(log).toEqual(['render Foo', 'mount Foo', 'render Bar', 'unmount Foo', 'mount Bar', 'unmount Bar'])
})

it('gives a ref to native components', async () => {
Expand Down Expand Up @@ -356,24 +333,7 @@ describe('ReactThreeTestRenderer Core', () => {
}

const vertices = new Float32Array([
-1.0,
-1.0,
1.0,
1.0,
-1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
-1.0,
1.0,
1.0,
-1.0,
-1.0,
1.0,
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
])

const Mesh = () => {
Expand Down