Files
cocos-engine/tests/core/test-node.js
Santy-Wang cf3e10b6c4 sync some unit test from 2.4 (#9321)
* add unit test

* add more unit test

* refine

* add test

* add more unit test

* add more unit test

* more change

* add commit

* add unit test

* commit package-lock.json

* revert some

* refine code

* add more test

* fix bugs

* fix bugs
2021-09-13 19:05:39 +08:00

437 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// jshint ignore: start
largeModule('Node', SetupEngine);
test('basic test', function () {
var node = new cc.Node();
ok(node.name, 'node has default name');
strictEqual(new cc.Node('myNode').name, 'myNode', 'can specify node name');
strictEqual(node.active, true, 'node is active');
node.active = false;
strictEqual(node.active, false, 'node is deactive');
node._destroyImmediate();
strictEqual(node.isValid, false, 'node can be destoryed');
});
test('test hierarchy', function () {
var parent = new cc.Node();
var child1 = new cc.Node();
var child2 = new cc.Node();
strictEqual(parent.parent, null, 'node\'s default parent is null');
strictEqual(parent.childrenCount, 0, 'node\'s default child count is 0');
child1.parent = parent;
ok(child1.parent === parent, 'can get/set parent');
strictEqual(parent.childrenCount, 1, 'child count increased to 1');
ok(parent.children[0] === child1, 'can get child1');
child2.parent = parent;
strictEqual(parent.childrenCount, 2, 'child count increased to 2');
ok(parent.children[1] === child2, 'can get child2');
child1.destroy();
FO._deferredDestroy();
strictEqual(parent.childrenCount, 1, 'child count should return to 1');
ok(parent.children[0] === child2, 'only child2 left');
child2.parent = null;
strictEqual(parent.childrenCount, 0, 'child2 detached');
parent.addChild(child2);
strictEqual(parent.childrenCount, 1, 'child2 attached by using addChild');
});
test('test walk', function () {
var A = new cc.Node('A');
var B = new cc.Node('B');
var C = new cc.Node('C');
var D = new cc.Node('D');
var E = new cc.Node('E');
var F = new cc.Node('F');
var G = new cc.Node('G');
var H = new cc.Node('H');
var I = new cc.Node('I');
// A
// |
// B-C
// |
// D-E-F
// / |
// G-H I
B.parent = A;
C.parent = A;
D.parent = B;
E.parent = B;
F.parent = B;
G.parent = E;
H.parent = E;
I.parent = F;
var walkHistory = '';
A.walk(function (node) {
walkHistory += node.name;
}, function (node) {
walkHistory += node.name + '*';
});
strictEqual(walkHistory, 'ABDD*EGG*HH*E*FII*F*B*CC*A*', 'walk history should be the same as predicted');
});
test('activeInHierarchy', function () {
var parent = new cc.Node();
var child = new cc.Node();
child.parent = parent;
strictEqual(parent.activeInHierarchy, false, 'parent should not activeInHierarchy before add to scene');
strictEqual(child.activeInHierarchy, false, 'child should not activeInHierarchy before add to scene');
cc.director.getScene().addChild(parent);
strictEqual(parent.activeInHierarchy, true, 'parent should become activeInHierarchy after add to scene');
strictEqual(child.activeInHierarchy, true, 'child should become activeInHierarchy after add to scene');
child.active = false;
strictEqual(parent.activeInHierarchy, true, 'parent unchanged');
strictEqual(child.activeInHierarchy, false, 'child deactiveInHierarchy');
parent.active = false;
strictEqual(parent.activeInHierarchy, false, 'parent deactiveInHierarchy');
strictEqual(child.activeInHierarchy, false, 'child still deactiveInHierarchy');
child.active = true;
strictEqual(parent.activeInHierarchy, false, 'parent unchanged');
strictEqual(child.activeInHierarchy, false, 'child deactiveInHierarchy because parent deactived');
parent.active = true;
strictEqual(parent.activeInHierarchy, true, 'parent become activeInHierarchy');
strictEqual(child.activeInHierarchy, true, 'child become activeInHierarchy because parent actived');
parent.removeFromParent();
strictEqual(parent.activeInHierarchy, false, 'parent should not activeInHierarchy after remove from scene');
strictEqual(child.activeInHierarchy, false, 'child should not activeInHierarchy after remove from scene');
});
test('activeInHierarchy should be false after destroy', function () {
var parent = new cc.Node();
var child = new cc.Node();
child.parent = parent;
cc.director.getScene().addChild(parent);
parent.destroy();
cc.game.step();
strictEqual(parent.activeInHierarchy, false, 'parent should not activeInHierarchy after destroy');
strictEqual(child.activeInHierarchy, false, 'child should not activeInHierarchy after destroy');
});
test('nodes should be destroyed with the scene', function () {
var child = new cc.Node();
var scene = cc.director.getScene();
child.parent = scene;
cc.director.runSceneImmediate(new cc.Scene());
strictEqual(child.activeInHierarchy, false, 'nodes should not activeInHierarchy after destroy');
strictEqual(child.isValid, false, 'nodes should be destroyed with the scene');
});
test('activation logic for component', function () {
// 这里主要测试node不是测试component
// my component
var MyComponentBase = cc.Class({
name: 'MyComponentBase',
extends: CallbackTester,
editor: {
executeInEditMode: true
},
});
var MyComponent = cc.Class({
name: 'MyComponent',
extends: MyComponentBase,
ctor: function () {
this.expect(CallbackTester.OnLoad, 'call onLoad while attaching to node');
this.expect(CallbackTester.OnEnable, 'then call onEnable if node active', true);
},
start: function () {
this._assert(MyComponent.start);
},
update: null,
lateUpdate: null
});
MyComponent.start = "MyCompStart";
var obj = new cc.Node();
cc.director.getScene().addChild(obj);
var comp = obj.addComponent(MyComponent); // onEnable
comp.expect(MyComponent.start, 'call start after onEnable');
cc.game.step();
comp.notExpect(MyComponent.start, 'start should be called only once');
cc.game.step();
strictEqual(comp.node, obj, 'can get node from component');
comp.expect(CallbackTester.OnDisable);
obj.active = false; // onDisable
comp.expect(CallbackTester.OnEnable);
obj.active = true; // onEnable
//strictEqual(obj.getComponent(cc.Transform), obj.transform, 'getComponent: can get transform');
ok(obj.getComponent(MyComponent) === comp, 'getComponent: can get my component');
ok(obj.getComponent(cc.js.getClassName(MyComponent)) === comp, 'getComponent: can get my component by name');
ok(obj.getComponent(MyComponentBase) === comp, 'getComponent: can get component by base type');
ok(obj.getComponent(cc.js.getClassName(MyComponentBase)) === comp, 'getComponent: can get component by base name');
comp.expect(CallbackTester.OnDisable, 'should called onDisable when destory');
comp.destroy(); // onDisable
strictEqual(obj.getComponent(MyComponent), comp, 'can still get component in this frame');
comp.expect(CallbackTester.OnDestroy);
FO._deferredDestroy(); // onDestroy
strictEqual(obj.getComponent(MyComponent), null, 'can not get component after this frame');
comp.stopTest();
cc.js.unregisterClass(MyComponent, MyComponentBase);
});
test('get self components', function () {
var MyComponent = cc.Class({
name: 'MyComponent',
extends: cc.Component
});
var obj = new cc.Node("New Node 1");
cc.director.getScene().addChild(obj);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
//-- layer 1
var obj1 = new cc.Node("New Node 2");
obj1.parent = obj;
var obj2 = new cc.Node("New Node 3");
var comp = obj2.addComponent(MyComponent);
obj2.parent = obj1;
//-- layer 2
var obj3 = new cc.Node("New Node 4");
obj3.parent = obj2;
var obj4 = new cc.Node("New Node 5");
obj4.addComponent(MyComponent);
obj4.parent = obj3;
ok(obj.getComponents(MyComponent).length === 3, 'getComponents: can get my component array');
ok(obj.getComponentInChildren(MyComponent) === comp, 'getComponentInChildren: can get my component in children');
ok(obj.getComponentsInChildren(MyComponent).length === 5, 'getComponentsInChildren: can get my components in children and self');
cc.js.unregisterClass(MyComponent);
});
test('should not include self component', function () {
var MyComponent = cc.Class({
name: 'MyComponent',
extends: cc.Component
});
var obj = new cc.Node("New Node");
cc.director.getScene().addChild(obj);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
var obj1 = new cc.Node("New Node 1");
obj1.parent = obj;
ok(obj.getComponentInChildren(MyComponent) === null, 'getComponentInChildren should not include self component');
cc.js.unregisterClass(MyComponent);
});
test('should include self component', function () {
var MyComponent = cc.Class({
name: 'MyComponent',
extends: cc.Component
});
var obj = new cc.Node("New Node");
cc.director.getScene().addChild(obj);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
obj.addComponent(MyComponent);
var obj1 = new cc.Node("New Node 1");
obj1.parent = obj;
ok(obj.getComponentsInChildren(MyComponent).length === 3, 'getComponentsInChildren should include self component');
cc.js.unregisterClass(MyComponent);
});
test('destroy', function () {
var parent = new cc.Node();
var child = new cc.Node();
parent.addChild(child);
cc.director.getScene().addChild(parent);
// add child component
var ChildComp = cc.Class({
extends: CallbackTester,
editor: {
executeInEditMode: true
},
ctor: function () {
this.expect([CallbackTester.OnLoad, CallbackTester.OnEnable]);
}
});
var childComp = child.addComponent(ChildComp);
// expect ondisable
childComp.expect(CallbackTester.OnDisable, 'should disable while destroy parent');
childComp.notExpect(CallbackTester.OnDestroy, 'can not destroyed before the end of this frame');
// call destroy
parent.destroy();
childComp.notExpect(CallbackTester.OnDisable, 'child comp should only disabled once');
childComp.notExpect(CallbackTester.OnEnable, 'child component should not re-enable when parent destroying');
childComp.expect(CallbackTester.OnDestroy, 'should destroyed at the end of frame');
// try add component after destroy
var ChildComp_new = cc.Class({
extends: CallbackTester,
ctor: function () {
this.expect(CallbackTester.OnLoad, 'new child component should onLoad even if added after destroy');
this.expect(CallbackTester.OnEnable, 'new child component should enable even if added after destroy', true);
this.expect(CallbackTester.OnDisable, 'new component\'s onDisable should be called before its onDestroy', true);
this.expect(CallbackTester.OnDestroy, 'new component should also destroyed at the end of frame', true);
}
});
var childComp_new = child.addComponent(ChildComp_new);
var NewParentComp = cc.Class({
extends: CallbackTester,
ctor: function () {
this.expect([CallbackTester.OnLoad,
CallbackTester.OnEnable,
CallbackTester.OnDisable,
CallbackTester.OnDestroy]);
}
});
var newParentComp = parent.addComponent(NewParentComp);
// try add child after destroy
var NewChildNodeComp = cc.Class({
extends: CallbackTester,
ctor: function () {
this.expect([CallbackTester.OnLoad,
CallbackTester.OnEnable,
CallbackTester.OnDisable,
CallbackTester.OnDestroy]);
}
});
var newChildNode = new cc.Node();
parent.addChild(newChildNode);
var newChildNodeComp = newChildNode.addComponent(NewChildNodeComp);
// do destory
FO._deferredDestroy();
strictEqual(childComp_new.isValid, false, 'node will finally destroyed with its component which added after calling destroy');
strictEqual(childComp.isValid, false, 'node will destroyed with its child components');
strictEqual(child.isValid, false, 'node will destroyed with its children');
strictEqual(newChildNode.isValid, false, 'node will destroyed with its new children');
childComp.stopTest();
childComp_new.stopTest();
newParentComp.stopTest();
newChildNodeComp.stopTest();
});
test('isChildOf', function () {
var ent1 = new cc.Node();
var ent2 = new cc.Node();
var ent3 = new cc.Node();
ent1.addChild(ent2);
ent2.addChild(ent3);
strictEqual(ent1.isChildOf(ent2), false, 'not a child of its children');
strictEqual(ent1.isChildOf(ent1), true, 'is child of itself');
strictEqual(ent2.isChildOf(ent1), true, 'is child of its parent');
strictEqual(ent3.isChildOf(ent1), true, 'is child of its ancestor');
});
test('attach events', function () {
var scene = cc.director.getScene();
var parent = new cc.Node();
var child = new cc.Node();
var attachedNodes = {};
var onAttach = cc.engine.on('node-attach-to-scene', function (node) {
if (node.uuid in attachedNodes) {
ok(false, 'already attached!');
}
attachedNodes[node.uuid] = true;
});
var onDetach = cc.engine.on('node-detach-from-scene', function (node) {
if (!(node.uuid in attachedNodes)) {
ok(false, 'not yet attached!');
}
delete attachedNodes[node.uuid];
});
child.parent = parent;
strictEqual(child.uuid in attachedNodes, false, 'child node should not attach scene if parent also detached');
parent.parent = scene;
strictEqual(parent.uuid in attachedNodes, true, 'parent node should attach to scene');
strictEqual(child.uuid in attachedNodes, true, 'child node should attach to scene');
parent.parent = null;
strictEqual(parent.uuid in attachedNodes, false, 'child node should also detached if parent become detached');
strictEqual(child.uuid in attachedNodes, false, 'parent node should detached');
cc.engine.off('node-attach-to-scene', onAttach);
cc.engine.off('node-detach-from-scene', onDetach);
});
test('getBoundingBox', function () {
var node = new cc.Node();
node.anchorX = 0.5;
node.anchorY = 0.5;
node.width = 10;
node.height = 20;
deepEqual(node.getBoundingBox(), cc.rect(-5, -10, 10, 20), 'should compute anchor');
});