Skip to content

Commit 823307c

Browse files
committed
feat: Add comprehensive UnityWebgl testing suite
1 parent 68e237e commit 823307c

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed

__tests__/index.test.ts

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
/**
2+
* @jest-environment jsdom
3+
*/
4+
//@ts-nocheck
5+
6+
import UnityWebgl from '../lib/core/src/index'
7+
import 'jest-canvas-mock'
8+
9+
// mock UnityInstance methods
10+
const mockLoaderResult = jest.fn()
11+
const mockSendMessage = jest.fn()
12+
const mockSetFullscreen = jest.fn()
13+
const mockQuit = jest.fn()
14+
15+
// mock unity loader
16+
jest.mock('../lib/core/src/loader', () => ({
17+
unityLoader: (_, { resolve }) => {
18+
resolve()
19+
return mockLoaderResult
20+
},
21+
}))
22+
23+
describe('UnityWebgl', () => {
24+
let canvasEl
25+
let mockUnityInstance
26+
27+
const validConfig = {
28+
loaderUrl: 'loader.js',
29+
dataUrl: 'data.json',
30+
frameworkUrl: 'framework.js',
31+
codeUrl: 'code.js',
32+
}
33+
34+
beforeEach(() => {
35+
jest.restoreAllMocks()
36+
jest.clearAllMocks()
37+
38+
canvasEl = document.createElement('canvas')
39+
canvasEl.requestPointerLock = jest.fn()
40+
canvasEl.toDataURL = jest.fn().mockReturnValue('base64-image-data')
41+
42+
// Mock the UnityInstance
43+
mockUnityInstance = {
44+
SendMessage: mockSendMessage,
45+
SetFullscreen: mockSetFullscreen,
46+
Quit: mockQuit.mockResolvedValue(true),
47+
Module: { canvas: canvasEl },
48+
}
49+
50+
// Setup mock global objects
51+
global.window.document.querySelector = (el) => {
52+
if (el === '#canvas') return canvasEl
53+
}
54+
global.window.createUnityInstance = async () => mockUnityInstance
55+
})
56+
57+
afterEach(() => {
58+
canvasEl = null
59+
mockUnityInstance = null
60+
delete global.window.document.querySelector
61+
delete global.window.createUnityInstance
62+
})
63+
64+
describe('Constructor', () => {
65+
it('should create an instance with a canvas selector', () => {
66+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
67+
expect(unityWebgl).toBeInstanceOf(UnityWebgl)
68+
})
69+
70+
it('should create an instance with a canvas element', async () => {
71+
const unityWebgl = new UnityWebgl(canvasEl, validConfig)
72+
await Promise.resolve()
73+
74+
expect(unityWebgl).toBeInstanceOf(UnityWebgl)
75+
expect(unityWebgl._canvas).toBe(canvasEl)
76+
expect(unityWebgl._loader).toBe(mockLoaderResult)
77+
expect(unityWebgl._unity).toBe(mockUnityInstance)
78+
expect(unityWebgl._config).toEqual(validConfig)
79+
})
80+
81+
it('should throw error with invalid config', () => {
82+
expect(() => new UnityWebgl('#canvas', {})).toThrow(TypeError)
83+
expect(() => new UnityWebgl('#canvas', { loaderUrl: 'test' })).toThrow(TypeError)
84+
})
85+
})
86+
87+
describe('create method', () => {
88+
it('should create unity instance successfully', async () => {
89+
const unityWebgl = new UnityWebgl(validConfig)
90+
const eventSpy = jest.spyOn(unityWebgl, 'emit')
91+
92+
await unityWebgl.create(canvasEl)
93+
94+
expect(eventSpy).toHaveBeenCalledWith('beforeMount', unityWebgl)
95+
expect(eventSpy).toHaveBeenCalledWith('mounted', expect.anything(), mockUnityInstance)
96+
97+
eventSpy.mockRestore()
98+
})
99+
100+
it('should handle canvas not found', async () => {
101+
const unityWebgl = new UnityWebgl(validConfig)
102+
const eventSpy = jest.spyOn(unityWebgl, 'emit')
103+
104+
try {
105+
await unityWebgl.create('#element-not-found')
106+
} catch (err) {}
107+
108+
expect(eventSpy).toHaveBeenCalledWith('error', expect.any(Error))
109+
eventSpy.mockRestore()
110+
})
111+
})
112+
113+
describe('sendMessage method', () => {
114+
it('should send message to unity instance', async () => {
115+
const unityWebgl = new UnityWebgl(canvasEl, validConfig)
116+
await Promise.resolve()
117+
118+
unityWebgl.sendMessage('ObjectName', 'MethodName', { data: 'test' })
119+
120+
expect(mockSendMessage).toHaveBeenCalledWith(
121+
'ObjectName',
122+
'MethodName',
123+
JSON.stringify({ data: 'test' })
124+
)
125+
})
126+
127+
it('should warn if unity not instantiated', async () => {
128+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
129+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
130+
await Promise.resolve()
131+
132+
unityWebgl['_unity'] = null
133+
unityWebgl.sendMessage('ObjectName', 'MethodName')
134+
135+
expect(consoleSpy).toHaveBeenCalledWith(
136+
'Unable to Send Message while Unity is not Instantiated.'
137+
)
138+
139+
consoleSpy.mockRestore()
140+
})
141+
})
142+
143+
describe('requestPointerLock method', () => {
144+
it('should request pointer lock', async () => {
145+
const unityWebgl = new UnityWebgl(canvasEl, validConfig)
146+
await Promise.resolve()
147+
148+
unityWebgl.requestPointerLock()
149+
150+
expect(canvasEl.requestPointerLock).toHaveBeenCalled()
151+
})
152+
153+
it('should warn if unity not instantiated', async () => {
154+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
155+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
156+
await Promise.resolve()
157+
158+
unityWebgl['_unity'] = null
159+
unityWebgl.requestPointerLock()
160+
161+
expect(consoleSpy).toHaveBeenCalledWith(
162+
'Unable to requestPointerLock while Unity is not Instantiated.'
163+
)
164+
165+
consoleSpy.mockRestore()
166+
})
167+
})
168+
169+
describe('takeScreenshot method', () => {
170+
it('should take screenshot', async () => {
171+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
172+
await Promise.resolve()
173+
174+
const screenshot = unityWebgl.takeScreenshot('image/jpeg', 0.92)
175+
176+
expect(canvasEl.toDataURL).toHaveBeenCalledWith('image/jpeg', 0.92)
177+
expect(screenshot).toBe('base64-image-data')
178+
})
179+
180+
it('should warn if unity not instantiated', async () => {
181+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
182+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
183+
await Promise.resolve()
184+
185+
unityWebgl['_unity'] = null
186+
unityWebgl.takeScreenshot()
187+
188+
expect(consoleSpy).toHaveBeenCalledWith(
189+
'Unable to take Screenshot while Unity is not Instantiated.'
190+
)
191+
consoleSpy.mockRestore()
192+
})
193+
})
194+
195+
describe('setFullscreen method', () => {
196+
it('should set fullscreen', async () => {
197+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
198+
await Promise.resolve()
199+
200+
unityWebgl.setFullscreen(true)
201+
expect(mockSetFullscreen).toHaveBeenCalledWith(1)
202+
203+
unityWebgl.setFullscreen(false)
204+
expect(mockSetFullscreen).toHaveBeenCalledWith(0)
205+
})
206+
207+
it('should warn if unity not instantiated', async () => {
208+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
209+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
210+
await Promise.resolve()
211+
212+
unityWebgl['_unity'] = null
213+
unityWebgl.setFullscreen(true)
214+
215+
expect(consoleSpy).toHaveBeenCalledWith(
216+
'Unable to set Fullscreen while Unity is not Instantiated.'
217+
)
218+
219+
consoleSpy.mockRestore()
220+
})
221+
})
222+
223+
describe('unload method', () => {
224+
it('should unload unity instance', async () => {
225+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
226+
await Promise.resolve()
227+
228+
const eventSpy = jest.spyOn(unityWebgl, 'emit')
229+
230+
await unityWebgl.unload()
231+
expect(mockLoaderResult).toHaveBeenCalled()
232+
expect(mockQuit).toHaveBeenCalled()
233+
expect(unityWebgl['_unity']).toBeNull()
234+
expect(unityWebgl['_canvas']).toBeNull()
235+
expect(eventSpy).toHaveBeenCalledWith('beforeUnmount', unityWebgl)
236+
expect(eventSpy).toHaveBeenCalledWith('unmounted')
237+
238+
eventSpy.mockRestore()
239+
})
240+
241+
it('should warn if unity not instantiated', async () => {
242+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
243+
await Promise.resolve()
244+
unityWebgl['_unity'] = null
245+
await expect(unityWebgl.unload()).rejects.toBeUndefined()
246+
})
247+
})
248+
249+
describe('unsafe_unload method', () => {
250+
it('should unload unity instance via the unsafe_unload', async () => {
251+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
252+
const eventSpy = jest.spyOn(unityWebgl, 'emit')
253+
await Promise.resolve()
254+
255+
unityWebgl.unsafe_unload()
256+
257+
expect(global.window.document.querySelector('#canvas')).not.toBeNull()
258+
259+
await Promise.resolve()
260+
expect(mockLoaderResult).toHaveBeenCalled()
261+
expect(mockQuit).toHaveBeenCalled()
262+
expect(unityWebgl['_unity']).toBeNull()
263+
expect(unityWebgl['_canvas']).toBeNull()
264+
expect(eventSpy).toHaveBeenCalledWith('beforeUnmount', unityWebgl)
265+
expect(eventSpy).toHaveBeenCalledWith('unmounted')
266+
eventSpy.mockRestore()
267+
})
268+
})
269+
270+
describe('Event', () => {
271+
it('should register and emit events', () => {
272+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
273+
const mockListener = jest.fn()
274+
const mockOnceListener = jest.fn()
275+
276+
unityWebgl.on('test:event', mockListener)
277+
unityWebgl.emit('test:event', 'arg1', 'arg2')
278+
unityWebgl.emit('test:event', 'arg1', 'arg2')
279+
280+
unityWebgl.on('test:once:event', mockOnceListener, { once: true })
281+
unityWebgl.emit('test:once:event')
282+
unityWebgl.emit('test:once:event')
283+
284+
expect(mockListener).toHaveBeenCalledWith('arg1', 'arg2')
285+
expect(mockListener).toHaveBeenCalledTimes(2)
286+
expect(mockOnceListener).toHaveBeenCalledTimes(1)
287+
})
288+
289+
it('should remove event listeners', () => {
290+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
291+
const mockListener = jest.fn()
292+
293+
unityWebgl.on('test:event', mockListener)
294+
unityWebgl.off('test:event', mockListener)
295+
unityWebgl.emit('test:event', 'arg1', 'arg2')
296+
297+
expect(mockListener).not.toHaveBeenCalled()
298+
})
299+
300+
it('should emit unity created cycle event', async () => {
301+
const unityWebgl = new UnityWebgl(validConfig)
302+
const eventSpy = jest.spyOn(unityWebgl, 'emit')
303+
unityWebgl.create('#canvas')
304+
await Promise.resolve()
305+
await unityWebgl.unload()
306+
307+
expect(eventSpy).toHaveBeenCalledWith('beforeMount', unityWebgl)
308+
expect(eventSpy).toHaveBeenCalledWith('mounted', unityWebgl, mockUnityInstance)
309+
expect(eventSpy).toHaveBeenCalledWith('beforeUnmount', unityWebgl)
310+
expect(eventSpy).toHaveBeenCalledWith('unmounted')
311+
312+
eventSpy.mockRestore()
313+
})
314+
})
315+
316+
describe('unity Event', () => {
317+
it('Should correctly handle event listeners with unity', async () => {
318+
const mockHello = jest.fn()
319+
const mockHi = jest.fn()
320+
321+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
322+
await Promise.resolve()
323+
324+
unityWebgl.addUnityListener('hello', mockHello)
325+
unityWebgl.addUnityListener('unity:hi', mockHi)
326+
327+
unityWebgl.emit('hello', 'world')
328+
unityWebgl.emit('unity:hi', 'world')
329+
expect(mockHello).not.toHaveBeenCalledWith('world')
330+
expect(mockHi).toHaveBeenCalledWith('world')
331+
332+
window.dispatchUnityEvent('hello', 'world')
333+
window.dispatchUnityEvent('hi', 'unity')
334+
expect(mockHello).toHaveBeenCalledWith('world')
335+
expect(mockHi).toHaveBeenCalledWith('unity')
336+
})
337+
338+
it('Should correctly remove event listeners with unity', async () => {
339+
const mockHello = jest.fn()
340+
341+
const unityWebgl = new UnityWebgl('#canvas', validConfig)
342+
await Promise.resolve()
343+
344+
unityWebgl.addUnityListener('hello', mockHello)
345+
unityWebgl.removeUnityListener('hello', mockHello)
346+
347+
window.dispatchUnityEvent('hello', 'world')
348+
349+
expect(mockHello).not.toHaveBeenCalled()
350+
})
351+
})
352+
})

0 commit comments

Comments
 (0)