|
@@ -1,4 +1,4 @@
|
|
-import { describe, beforeAll, it, expect } from 'vitest'
|
|
|
|
|
|
+import { beforeAll, describe, expect, it } from 'vitest'
|
|
import * as THREE from 'three'
|
|
import * as THREE from 'three'
|
|
import { Mesh, Scene } from 'three'
|
|
import { Mesh, Scene } from 'three'
|
|
import type { TresObject } from '../types'
|
|
import type { TresObject } from '../types'
|
|
@@ -13,202 +13,212 @@ describe('nodeOps', () => {
|
|
extend(THREE)
|
|
extend(THREE)
|
|
nodeOps = getNodeOps()
|
|
nodeOps = getNodeOps()
|
|
})
|
|
})
|
|
- it('createElement should create an instance with given tag', async () => {
|
|
|
|
|
|
+ describe('createElement', () => {
|
|
|
|
+ it('creates an instance with given tag', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresMesh'
|
|
|
|
- const props = { args: [] }
|
|
|
|
|
|
+ const tag = 'TresMesh'
|
|
|
|
+ const props = { args: [] }
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.isObject3D).toBeTruthy()
|
|
|
|
- expect(instance).toBeInstanceOf(Mesh)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.isObject3D).toBeTruthy()
|
|
|
|
+ expect(instance).toBeInstanceOf(Mesh)
|
|
|
|
+ })
|
|
|
|
|
|
- it('createElement should create an instance with given tag and props', async () => {
|
|
|
|
|
|
+ it('creates an instance with given tag and props', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresTorusGeometry'
|
|
|
|
- const props = { args: [10, 3, 16, 100] }
|
|
|
|
|
|
+ const tag = 'TresTorusGeometry'
|
|
|
|
+ const props = { args: [10, 3, 16, 100] }
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.parameters.radius).toBe(10)
|
|
|
|
- expect(instance?.parameters.tube).toBe(3)
|
|
|
|
- expect(instance?.parameters.radialSegments).toBe(16)
|
|
|
|
- expect(instance?.parameters.tubularSegments).toBe(100)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.parameters.radius).toBe(10)
|
|
|
|
+ expect(instance?.parameters.tube).toBe(3)
|
|
|
|
+ expect(instance?.parameters.radialSegments).toBe(16)
|
|
|
|
+ expect(instance?.parameters.tubularSegments).toBe(100)
|
|
|
|
+ })
|
|
|
|
|
|
- it.skip('createElement should create an camera instance', async () => {
|
|
|
|
|
|
+ it.skip('creates an camera instance', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresPerspectiveCamera'
|
|
|
|
- const props = { args: [75, 2, 0.1, 5] }
|
|
|
|
|
|
+ const tag = 'TresPerspectiveCamera'
|
|
|
|
+ const props = { args: [75, 2, 0.1, 5] }
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.isCamera).toBeTruthy()
|
|
|
|
- expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.isCamera).toBeTruthy()
|
|
|
|
+ expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
|
|
|
|
+ })
|
|
|
|
|
|
- it.skip('createElement should log a warning if the camera doesnt have a position', async () => {
|
|
|
|
|
|
+ it.skip('logs a warning if the camera doesnt have a position', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresPerspectiveCamera'
|
|
|
|
- const props = { args: [75, 2, 0.1, 5] }
|
|
|
|
|
|
+ const tag = 'TresPerspectiveCamera'
|
|
|
|
+ const props = { args: [75, 2, 0.1, 5] }
|
|
|
|
|
|
- // Spy
|
|
|
|
- const consoleWarnSpy = vi.spyOn(console, 'warn')
|
|
|
|
- consoleWarnSpy.mockImplementation(() => { })
|
|
|
|
|
|
+ // Spy
|
|
|
|
+ const consoleWarnSpy = vi.spyOn(console, 'warn')
|
|
|
|
+ consoleWarnSpy.mockImplementation(() => { })
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.isCamera).toBeTruthy()
|
|
|
|
- expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
|
|
|
|
- expect(consoleWarnSpy).toHaveBeenCalled()
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.isCamera).toBeTruthy()
|
|
|
|
+ expect(instance).toBeInstanceOf(THREE.PerspectiveCamera)
|
|
|
|
+ expect(consoleWarnSpy).toHaveBeenCalled()
|
|
|
|
+ })
|
|
|
|
|
|
- it('createElement should add attach material property if instance is a material', () => {
|
|
|
|
|
|
+ it('adds material with "attach" property if instance is a material', () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresMeshStandardMaterial'
|
|
|
|
- const props = { args: [] }
|
|
|
|
|
|
+ const tag = 'TresMeshStandardMaterial'
|
|
|
|
+ const props = { args: [] }
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.isMaterial).toBeTruthy()
|
|
|
|
- expect(instance?.attach).toBe('material')
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.isMaterial).toBeTruthy()
|
|
|
|
+ expect(instance?.attach).toBe('material')
|
|
|
|
+ })
|
|
|
|
|
|
- it('createElement should add attach geometry property if instance is a geometry', () => {
|
|
|
|
|
|
+ it('adds attach geometry property if instance is a geometry', () => {
|
|
// Setup
|
|
// Setup
|
|
- const tag = 'TresTorusGeometry'
|
|
|
|
- const props = { args: [] }
|
|
|
|
|
|
+ const tag = 'TresTorusGeometry'
|
|
|
|
+ const props = { args: [] }
|
|
|
|
|
|
- // Test
|
|
|
|
- const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const instance = nodeOps.createElement(tag, undefined, undefined, props)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(instance?.isBufferGeometry).toBeTruthy()
|
|
|
|
- expect(instance?.attach).toBe('geometry')
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(instance?.isBufferGeometry).toBeTruthy()
|
|
|
|
+ expect(instance?.attach).toBe('geometry')
|
|
|
|
+ })
|
|
})
|
|
})
|
|
|
|
|
|
- it('insert should insert child into parent', async () => {
|
|
|
|
|
|
+ describe('insert', () => {
|
|
|
|
+ it('inserts child into parent', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const parent = new Scene()
|
|
|
|
- parent.__tres = {
|
|
|
|
- root: {
|
|
|
|
- registerCamera: () => { },
|
|
|
|
- registerObjectAtPointerEventHandler: () => { },
|
|
|
|
- },
|
|
|
|
- }
|
|
|
|
- const child = new Mesh()
|
|
|
|
-
|
|
|
|
- child.__tres = {
|
|
|
|
- root: null,
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Fake vnodes
|
|
|
|
- child.__vnode = {
|
|
|
|
- type: 'TresMesh',
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Test
|
|
|
|
- nodeOps.insert(child, parent, null)
|
|
|
|
-
|
|
|
|
- // Assert
|
|
|
|
- expect(parent.children.includes(child)).toBeTruthy()
|
|
|
|
|
|
+ const parent = new Scene()
|
|
|
|
+ parent.__tres = {
|
|
|
|
+ root: {
|
|
|
|
+ registerCamera: () => { },
|
|
|
|
+ registerObjectAtPointerEventHandler: () => { },
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ const child = new Mesh()
|
|
|
|
+
|
|
|
|
+ child.__tres = {
|
|
|
|
+ root: null,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Fake vnodes
|
|
|
|
+ child.__vnode = {
|
|
|
|
+ type: 'TresMesh',
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Test
|
|
|
|
+ nodeOps.insert(child, parent, null)
|
|
|
|
+
|
|
|
|
+ // Assert
|
|
|
|
+ expect(parent.children.includes(child)).toBeTruthy()
|
|
|
|
+ })
|
|
})
|
|
})
|
|
|
|
|
|
- it.skip('remove: removes child from parent', async () => {
|
|
|
|
|
|
+ describe('remove', () => {
|
|
|
|
+ it.skip('removes child from parent', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const parent = new Scene() as unknown as TresObject
|
|
|
|
- const child = new Mesh() as unknown as TresObject
|
|
|
|
|
|
+ const parent = new Scene() as unknown as TresObject
|
|
|
|
+ const child = new Mesh() as unknown as TresObject
|
|
|
|
|
|
- // Fake vnodes
|
|
|
|
- child.__vnode = {
|
|
|
|
- type: 'TresMesh',
|
|
|
|
- }
|
|
|
|
- nodeOps.insert(child, parent)
|
|
|
|
|
|
+ // Fake vnodes
|
|
|
|
+ child.__vnode = {
|
|
|
|
+ type: 'TresMesh',
|
|
|
|
+ }
|
|
|
|
+ nodeOps.insert(child, parent)
|
|
|
|
|
|
- // Test
|
|
|
|
- nodeOps.remove(child)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ nodeOps.remove(child)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(!parent.children.includes(child)).toBeTruthy()
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(!parent.children.includes(child)).toBeTruthy()
|
|
|
|
+ })
|
|
})
|
|
})
|
|
|
|
|
|
- it('patchProp should patch property of node', async () => {
|
|
|
|
|
|
+ describe('patchProp', () => {
|
|
|
|
+ it('patches property of node', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const node = nodeOps.createElement('Mesh')!
|
|
|
|
- const prop = 'visible'
|
|
|
|
- const nextValue = false
|
|
|
|
|
|
+ const node = nodeOps.createElement('Mesh')!
|
|
|
|
+ const prop = 'visible'
|
|
|
|
+ const nextValue = false
|
|
|
|
|
|
- // Test
|
|
|
|
- nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(node.visible === nextValue)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(node.visible === nextValue)
|
|
|
|
+ })
|
|
|
|
|
|
- it('patchProp should patch traverse pierced props', async () => {
|
|
|
|
|
|
+ it('patches/traverses pierced props', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const node = nodeOps.createElement('Mesh')!
|
|
|
|
- const prop = 'position-x'
|
|
|
|
- const nextValue = 5
|
|
|
|
|
|
+ const node = nodeOps.createElement('Mesh')!
|
|
|
|
+ const prop = 'position-x'
|
|
|
|
+ const nextValue = 5
|
|
|
|
|
|
- // Test
|
|
|
|
- nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(node.position.x === nextValue)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(node.position.x === nextValue)
|
|
|
|
+ })
|
|
|
|
|
|
- it('patchProp it should not patch traverse pierced props of existing dashed properties', async () => {
|
|
|
|
|
|
+ it('does not patch/traverse pierced props of existing dashed properties', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const node = nodeOps.createElement('Mesh')!
|
|
|
|
- const prop = 'cast-shadow'
|
|
|
|
- const nextValue = true
|
|
|
|
|
|
+ const node = nodeOps.createElement('Mesh')!
|
|
|
|
+ const prop = 'cast-shadow'
|
|
|
|
+ const nextValue = true
|
|
|
|
|
|
- // Test
|
|
|
|
- nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ nodeOps.patchProp(node, prop, null, nextValue)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(node.castShadow === nextValue)
|
|
|
|
- })
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(node.castShadow === nextValue)
|
|
|
|
+ })
|
|
|
|
|
|
- it('patchProp should preserve ALL_CAPS_CASE in pierced props', () => {
|
|
|
|
|
|
+ it('preserves ALL_CAPS_CASE in pierced props', () => {
|
|
// Issue: https://github.com/Tresjs/tres/issues/605
|
|
// Issue: https://github.com/Tresjs/tres/issues/605
|
|
- const { createElement, patchProp } = nodeOps
|
|
|
|
- const node = createElement('TresMeshStandardMaterial', undefined, undefined, {})!
|
|
|
|
- const allCapsKey = 'STANDARD'
|
|
|
|
- const allCapsUnderscoresKey = 'USE_UVS'
|
|
|
|
- const allCapsValue = 'hello'
|
|
|
|
- const allCapsUnderscoresValue = 'goodbye'
|
|
|
|
-
|
|
|
|
- patchProp(node, `defines-${allCapsKey}`, null, allCapsValue)
|
|
|
|
- patchProp(node, `defines-${allCapsUnderscoresKey}`, null, allCapsUnderscoresValue)
|
|
|
|
-
|
|
|
|
- expect(node.defines[allCapsKey]).equals(allCapsValue)
|
|
|
|
- expect(node.defines[allCapsUnderscoresKey]).equals(allCapsUnderscoresValue)
|
|
|
|
|
|
+ const { createElement, patchProp } = nodeOps
|
|
|
|
+ const node = createElement('TresMeshStandardMaterial', undefined, undefined, {})!
|
|
|
|
+ const allCapsKey = 'STANDARD'
|
|
|
|
+ const allCapsUnderscoresKey = 'USE_UVS'
|
|
|
|
+ const allCapsValue = 'hello'
|
|
|
|
+ const allCapsUnderscoresValue = 'goodbye'
|
|
|
|
+
|
|
|
|
+ patchProp(node, `defines-${allCapsKey}`, null, allCapsValue)
|
|
|
|
+ patchProp(node, `defines-${allCapsUnderscoresKey}`, null, allCapsUnderscoresValue)
|
|
|
|
+
|
|
|
|
+ expect(node.defines[allCapsKey]).equals(allCapsValue)
|
|
|
|
+ expect(node.defines[allCapsUnderscoresKey]).equals(allCapsUnderscoresValue)
|
|
|
|
+ })
|
|
})
|
|
})
|
|
|
|
|
|
- it('parentNode: returns parent of a node', async () => {
|
|
|
|
|
|
+ describe('parentNode', () => {
|
|
|
|
+ it('returns parent of a node', async () => {
|
|
// Setup
|
|
// Setup
|
|
- const parent: TresObject = new Scene()
|
|
|
|
- const child: TresObject = nodeOps.createElement('Mesh')!
|
|
|
|
- parent.children.push(child)
|
|
|
|
- child.parent = parent
|
|
|
|
|
|
+ const parent: TresObject = new Scene()
|
|
|
|
+ const child: TresObject = nodeOps.createElement('Mesh')!
|
|
|
|
+ parent.children.push(child)
|
|
|
|
+ child.parent = parent
|
|
|
|
|
|
- // Test
|
|
|
|
- const parentNode = nodeOps.parentNode(child)
|
|
|
|
|
|
+ // Test
|
|
|
|
+ const parentNode = nodeOps.parentNode(child)
|
|
|
|
|
|
- // Assert
|
|
|
|
- expect(parentNode === parent)
|
|
|
|
|
|
+ // Assert
|
|
|
|
+ expect(parentNode === parent)
|
|
|
|
+ })
|
|
})
|
|
})
|
|
})
|
|
})
|