-
Notifications
You must be signed in to change notification settings - Fork 118
/
Copy pathEffectComposer.test.tsx
126 lines (117 loc) · 4.01 KB
/
EffectComposer.test.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import * as React from 'react'
import * as THREE from 'three'
import { vi, describe, it, expect } from 'vitest'
import { extend, createRoot, act } from '@react-three/fiber'
import { EffectComposer } from './EffectComposer'
import { EffectComposer as EffectComposerImpl, RenderPass, Pass, Effect, EffectPass } from 'postprocessing'
// Let React know that we'll be testing effectful components
declare global {
var IS_REACT_ACT_ENVIRONMENT: boolean
}
global.IS_REACT_ACT_ENVIRONMENT = true
// Create virtual R3F root for testing
extend(THREE as any)
const root = createRoot({
style: {} as CSSStyleDeclaration,
addEventListener: (() => {}) as any,
removeEventListener: (() => {}) as any,
width: 1280,
height: 800,
clientWidth: 1280,
clientHeight: 800,
getContext: (() =>
new Proxy(
{},
{
get(_target, prop) {
switch (prop) {
case 'getParameter':
return () => 'WebGL 2' // GL_VERSION
case 'getExtension':
return () => ({}) // EXT_blend_minmax
case 'getContextAttributes':
return () => ({ alpha: true })
case 'getShaderPrecisionFormat':
return () => ({ rangeMin: 1, rangeMax: 1, precision: 1 })
default:
return () => {}
}
},
}
)) as any,
} satisfies Partial<HTMLCanvasElement> as HTMLCanvasElement)
root.configure({ frameloop: 'never' })
const EFFECT_SHADER = 'mainImage() {}'
describe('EffectComposer', () => {
it('should merge effects together', async () => {
const composerRef = React.createRef<EffectComposerImpl>()
const effectA = new Effect('A', EFFECT_SHADER)
const effectB = new Effect('B', EFFECT_SHADER)
const effectC = new Effect('C', EFFECT_SHADER)
const passA = new Pass()
const passB = new Pass()
// Forward order
await act(async () =>
root.render(
<EffectComposer ref={composerRef}>
{/* EffectPass(effectA, effectB) */}
<primitive object={effectA} />
<primitive object={effectB} />
{/* PassA */}
<primitive object={passA} />
{/* EffectPass(effectC) */}
<primitive object={effectC} />
{/* PassB */}
<primitive object={passB} />
</EffectComposer>
)
)
expect(composerRef.current!.passes.map((p) => p.constructor)).toStrictEqual([
RenderPass,
EffectPass,
Pass,
EffectPass,
Pass,
])
// @ts-expect-error
expect((composerRef.current!.passes[1] as EffectPass).effects).toStrictEqual([effectA, effectB])
expect(composerRef.current!.passes[2]).toBe(passA)
// @ts-expect-error
expect((composerRef.current!.passes[3] as EffectPass).effects).toStrictEqual([effectC])
expect(composerRef.current!.passes[4]).toBe(passB)
// NOTE: instance children ordering is unstable until R3F v9, so we remount from scratch
await act(async () => root.render(null))
// Reverse order
await act(async () =>
root.render(
<EffectComposer ref={composerRef}>
{/* PassB */}
<primitive object={passB} />
{/* EffectPass(effectC) */}
<primitive object={effectC} />
{/* PassA */}
<primitive object={passA} />
{/* EffectPass(effectB, effectA) */}
<primitive object={effectB} />
<primitive object={effectA} />
</EffectComposer>
)
)
expect(composerRef.current!.passes.map((p) => p.constructor)).toStrictEqual([
RenderPass,
Pass,
EffectPass,
Pass,
EffectPass,
])
expect(composerRef.current!.passes[1]).toBe(passB)
// @ts-expect-error
expect((composerRef.current!.passes[2] as EffectPass).effects).toStrictEqual([effectC])
expect(composerRef.current!.passes[3]).toBe(passA)
// @ts-expect-error
expect((composerRef.current!.passes[4] as EffectPass).effects).toStrictEqual([effectB, effectA])
})
it.skip('should split convolution effects', async () => {
await act(async () => root.render(null))
})
})