phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
982 lines (757 loc) • 26.8 kB
JavaScript
var Group = require('../../../src/gameobjects/group/Group');
function createMockScene ()
{
return {
sys: {
updateList: {
add: vi.fn(),
remove: vi.fn()
},
displayList: {}
}
};
}
function MockChild (active)
{
this.active = (active !== undefined) ? active : true;
this.visible = true;
this.x = 0;
this.y = 0;
this.alpha = 1;
this.depth = 0;
this.scaleX = 1;
this.scaleY = 1;
this.rotation = 0;
this.on = vi.fn();
this.off = vi.fn();
this.emit = vi.fn();
this.setActive = function (val) { this.active = val; return this; };
this.setVisible = function (val) { this.visible = val; return this; };
this.update = vi.fn();
this.destroy = vi.fn();
this.removeFromDisplayList = vi.fn();
this.removeFromUpdateList = vi.fn();
}
function createMockChild (active)
{
return new MockChild(active);
}
function createMockClassType ()
{
return function MockClassType (scene, x, y, key, frame)
{
this.scene = scene;
this.x = x || 0;
this.y = y || 0;
this.key = key || null;
this.frame = frame || null;
this.active = true;
this.visible = true;
this.alpha = 1;
this.depth = 0;
this.scaleX = 1;
this.scaleY = 1;
this.rotation = 0;
this.on = vi.fn();
this.off = vi.fn();
this.emit = vi.fn();
this.setActive = function (val) { this.active = val; return this; };
this.setVisible = function (val) { this.visible = val; return this; };
this.destroy = vi.fn();
this.addToDisplayList = vi.fn();
this.addToUpdateList = vi.fn();
this.removeFromDisplayList = vi.fn();
this.removeFromUpdateList = vi.fn();
this.update = vi.fn();
};
}
describe('Group', function ()
{
var scene;
beforeEach(function ()
{
scene = createMockScene();
});
describe('constructor', function ()
{
it('should create a group with default property values', function ()
{
var group = new Group(scene);
expect(group.scene).toBe(scene);
expect(group.isParent).toBe(true);
expect(group.type).toBe('Group');
expect(group.name).toBe('');
expect(group.active).toBe(true);
expect(group.maxSize).toBe(-1);
expect(group.defaultKey).toBeNull();
expect(group.defaultFrame).toBeNull();
expect(group.runChildUpdate).toBe(false);
expect(group.createCallback).toBeNull();
expect(group.removeCallback).toBeNull();
expect(group.createMultipleCallback).toBeNull();
});
it('should start with an empty children set', function ()
{
var group = new Group(scene);
expect(group.children).toBeDefined();
expect(group.children.size).toBe(0);
});
it('should apply config options', function ()
{
var cb = function () {};
var group = new Group(scene, null, {
name: 'bullets',
active: false,
maxSize: 10,
defaultKey: 'bullet',
defaultFrame: 0,
runChildUpdate: true,
createCallback: cb
});
expect(group.name).toBe('bullets');
expect(group.active).toBe(false);
expect(group.maxSize).toBe(10);
expect(group.defaultKey).toBe('bullet');
expect(group.defaultFrame).toBe(0);
expect(group.runChildUpdate).toBe(true);
expect(group.createCallback).toBe(cb);
});
it('should accept a plain object as the children argument and treat it as config', function ()
{
var group = new Group(scene, { name: 'fromConfig', maxSize: 5 });
expect(group.name).toBe('fromConfig');
expect(group.maxSize).toBe(5);
});
it('should add children passed as an array', function ()
{
var child1 = createMockChild();
var child2 = createMockChild();
var group = new Group(scene, [ child1, child2 ]);
expect(group.getLength()).toBe(2);
expect(group.contains(child1)).toBe(true);
expect(group.contains(child2)).toBe(true);
});
});
describe('add', function ()
{
it('should add a child to the group', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
expect(group.contains(child)).toBe(true);
expect(group.getLength()).toBe(1);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var child = createMockChild();
var result = group.add(child);
expect(result).toBe(group);
});
it('should call createCallback when adding a child', function ()
{
var called = false;
var calledWith = null;
var group = new Group(scene, null, {
createCallback: function (child)
{
called = true;
calledWith = child;
}
});
var child = createMockChild();
group.add(child);
expect(called).toBe(true);
expect(calledWith).toBe(child);
});
it('should not add beyond maxSize', function ()
{
var group = new Group(scene, null, { maxSize: 2 });
var child1 = createMockChild();
var child2 = createMockChild();
var child3 = createMockChild();
group.add(child1);
group.add(child2);
group.add(child3);
expect(group.getLength()).toBe(2);
expect(group.contains(child3)).toBe(false);
});
it('should register a DESTROY listener on the child', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
expect(child.on).toHaveBeenCalled();
});
});
describe('addMultiple', function ()
{
it('should add multiple children at once', function ()
{
var group = new Group(scene);
var children = [ createMockChild(), createMockChild(), createMockChild() ];
group.addMultiple(children);
expect(group.getLength()).toBe(3);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.addMultiple([]);
expect(result).toBe(group);
});
});
describe('remove', function ()
{
it('should remove a child from the group', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
group.remove(child);
expect(group.contains(child)).toBe(false);
expect(group.getLength()).toBe(0);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
var result = group.remove(child);
expect(result).toBe(group);
});
it('should call removeCallback when removing a child', function ()
{
var calledWith = null;
var group = new Group(scene, null, {
removeCallback: function (child)
{
calledWith = child;
}
});
var child = createMockChild();
group.add(child);
group.remove(child);
expect(calledWith).toBe(child);
});
it('should do nothing if the child is not in the group', function ()
{
var group = new Group(scene);
var child = createMockChild();
var other = createMockChild();
group.add(child);
group.remove(other);
expect(group.getLength()).toBe(1);
});
it('should unregister the DESTROY listener from the child', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
group.remove(child);
expect(child.off).toHaveBeenCalled();
});
});
describe('clear', function ()
{
it('should remove all children', function ()
{
var group = new Group(scene);
group.add(createMockChild());
group.add(createMockChild());
group.add(createMockChild());
group.clear();
expect(group.getLength()).toBe(0);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.clear();
expect(result).toBe(group);
});
it('should call destroy on children when destroyChild is true', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
group.clear(false, true);
expect(child.destroy).toHaveBeenCalled();
});
it('should call removeFromDisplayList when removeFromScene is true', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
group.clear(true, false);
expect(child.removeFromDisplayList).toHaveBeenCalled();
expect(child.removeFromUpdateList).toHaveBeenCalled();
});
});
describe('contains', function ()
{
it('should return true for a member of the group', function ()
{
var group = new Group(scene);
var child = createMockChild();
group.add(child);
expect(group.contains(child)).toBe(true);
});
it('should return false for a non-member', function ()
{
var group = new Group(scene);
var child = createMockChild();
expect(group.contains(child)).toBe(false);
});
});
describe('getChildren', function ()
{
it('should return an array of all members', function ()
{
var group = new Group(scene);
var child1 = createMockChild();
var child2 = createMockChild();
group.add(child1);
group.add(child2);
var result = group.getChildren();
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(2);
expect(result).toContain(child1);
expect(result).toContain(child2);
});
it('should return an empty array when group is empty', function ()
{
var group = new Group(scene);
expect(group.getChildren()).toEqual([]);
});
});
describe('getLength', function ()
{
it('should return zero for an empty group', function ()
{
var group = new Group(scene);
expect(group.getLength()).toBe(0);
});
it('should return the correct count after adding and removing members', function ()
{
var group = new Group(scene);
var child1 = createMockChild();
var child2 = createMockChild();
group.add(child1);
group.add(child2);
expect(group.getLength()).toBe(2);
group.remove(child1);
expect(group.getLength()).toBe(1);
});
});
describe('isFull', function ()
{
it('should return false when maxSize is -1 (unlimited)', function ()
{
var group = new Group(scene);
expect(group.isFull()).toBe(false);
});
it('should return false when group has fewer members than maxSize', function ()
{
var group = new Group(scene, null, { maxSize: 5 });
group.add(createMockChild());
group.add(createMockChild());
expect(group.isFull()).toBe(false);
});
it('should return true when group has reached maxSize', function ()
{
var group = new Group(scene, null, { maxSize: 2 });
group.add(createMockChild());
group.add(createMockChild());
expect(group.isFull()).toBe(true);
});
});
describe('countActive', function ()
{
it('should count active members by default', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
group.add(createMockChild(true));
group.add(createMockChild(false));
expect(group.countActive()).toBe(2);
});
it('should count inactive members when passed false', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
group.add(createMockChild(false));
group.add(createMockChild(false));
expect(group.countActive(false)).toBe(2);
});
it('should return zero when group is empty', function ()
{
var group = new Group(scene);
expect(group.countActive()).toBe(0);
});
});
describe('getTotalUsed', function ()
{
it('should return the count of active members', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
group.add(createMockChild(false));
expect(group.getTotalUsed()).toBe(1);
});
});
describe('getTotalFree', function ()
{
it('should return a large number when maxSize is -1', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
expect(group.getTotalFree()).toBeGreaterThan(1000);
});
it('should return remaining capacity when maxSize is set', function ()
{
var group = new Group(scene, null, { maxSize: 10 });
group.add(createMockChild(true));
group.add(createMockChild(true));
group.add(createMockChild(false));
// maxSize - active = 10 - 2 = 8
expect(group.getTotalFree()).toBe(8);
});
});
describe('getMatching', function ()
{
it('should return members matching a property value', function ()
{
var group = new Group(scene);
var activeChild = createMockChild(true);
var inactiveChild = createMockChild(false);
group.add(activeChild);
group.add(inactiveChild);
var result = group.getMatching('active', true);
expect(result.length).toBe(1);
expect(result[0]).toBe(activeChild);
});
it('should return an empty array when no members match', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
var result = group.getMatching('active', false);
expect(result).toEqual([]);
});
});
describe('getFirst', function ()
{
it('should return the first member matching the active state', function ()
{
var group = new Group(scene);
var active1 = createMockChild(true);
var active2 = createMockChild(true);
var inactive = createMockChild(false);
group.add(inactive);
group.add(active1);
group.add(active2);
var result = group.getFirst(true, false);
expect(result).toBe(active1);
});
it('should return null when no member matches and createIfNull is false', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
var result = group.getFirst(false, false);
expect(result).toBeNull();
});
it('should assign x and y to the found member', function ()
{
var group = new Group(scene);
var child = createMockChild(true);
group.add(child);
group.getFirst(true, false, 100, 200);
expect(child.x).toBe(100);
expect(child.y).toBe(200);
});
});
describe('getLast', function ()
{
it('should return the last member matching the active state', function ()
{
var group = new Group(scene);
var active1 = createMockChild(true);
var active2 = createMockChild(true);
group.add(active1);
group.add(active2);
var result = group.getLast(true, false);
expect(result).toBe(active2);
});
it('should return null when no member matches', function ()
{
var group = new Group(scene);
group.add(createMockChild(true));
var result = group.getLast(false, false);
expect(result).toBeNull();
});
});
describe('getFirstAlive', function ()
{
it('should return the first active member', function ()
{
var group = new Group(scene);
var alive = createMockChild(true);
var dead = createMockChild(false);
group.add(alive);
group.add(dead);
expect(group.getFirstAlive(false)).toBe(alive);
});
});
describe('getFirstDead', function ()
{
it('should return the first inactive member', function ()
{
var group = new Group(scene);
var alive = createMockChild(true);
var dead = createMockChild(false);
group.add(alive);
group.add(dead);
expect(group.getFirstDead(false)).toBe(dead);
});
});
describe('setActive', function ()
{
it('should set the active property of the group', function ()
{
var group = new Group(scene);
group.setActive(false);
expect(group.active).toBe(false);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.setActive(true);
expect(result).toBe(group);
});
});
describe('setName', function ()
{
it('should set the name property of the group', function ()
{
var group = new Group(scene);
group.setName('myGroup');
expect(group.name).toBe('myGroup');
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.setName('test');
expect(result).toBe(group);
});
});
describe('kill', function ()
{
it('should deactivate a member of the group', function ()
{
var group = new Group(scene);
var child = createMockChild(true);
group.add(child);
group.kill(child);
expect(child.active).toBe(false);
});
it('should not affect objects not in the group', function ()
{
var group = new Group(scene);
var outsider = createMockChild(true);
group.kill(outsider);
expect(outsider.active).toBe(true);
});
});
describe('killAndHide', function ()
{
it('should deactivate and hide a member of the group', function ()
{
var group = new Group(scene);
var child = createMockChild(true);
child.visible = true;
group.add(child);
group.killAndHide(child);
expect(child.active).toBe(false);
expect(child.visible).toBe(false);
});
it('should not affect objects not in the group', function ()
{
var group = new Group(scene);
var outsider = createMockChild(true);
group.killAndHide(outsider);
expect(outsider.active).toBe(true);
expect(outsider.visible).toBe(true);
});
});
describe('preUpdate', function ()
{
it('should not call child update when runChildUpdate is false', function ()
{
var group = new Group(scene, null, { runChildUpdate: false });
var child = createMockChild(true);
group.add(child);
group.preUpdate(100, 16);
expect(child.update).not.toHaveBeenCalled();
});
it('should call update on active children when runChildUpdate is true', function ()
{
var group = new Group(scene, null, { runChildUpdate: true });
var activeChild = createMockChild(true);
var inactiveChild = createMockChild(false);
group.add(activeChild);
group.add(inactiveChild);
group.preUpdate(100, 16);
expect(activeChild.update).toHaveBeenCalledWith(100, 16);
expect(inactiveChild.update).not.toHaveBeenCalled();
});
it('should not call update when group has no children', function ()
{
var group = new Group(scene, null, { runChildUpdate: true });
// should not throw
expect(function () { group.preUpdate(0, 16); }).not.toThrow();
});
});
describe('propertyValueSet', function ()
{
it('should set a named property on all children', function ()
{
var group = new Group(scene);
var child1 = createMockChild();
var child2 = createMockChild();
group.add(child1);
group.add(child2);
group.propertyValueSet('alpha', 0.5);
expect(child1.alpha).toBe(0.5);
expect(child2.alpha).toBe(0.5);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.propertyValueSet('alpha', 1);
expect(result).toBe(group);
});
});
describe('propertyValueInc', function ()
{
it('should increment a named property on all children', function ()
{
var group = new Group(scene);
var child = createMockChild();
child.depth = 5;
group.add(child);
group.propertyValueInc('depth', 3);
expect(child.depth).toBe(8);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.propertyValueInc('x', 1);
expect(result).toBe(group);
});
});
describe('setX', function ()
{
it('should set x on all children', function ()
{
var group = new Group(scene);
var child1 = createMockChild();
var child2 = createMockChild();
child1.x = 0;
child2.x = 0;
group.add(child1);
group.add(child2);
group.setX(100);
expect(child1.x).toBe(100);
expect(child2.x).toBe(100);
});
it('should apply step offset per iteration', function ()
{
var group = new Group(scene);
var child1 = createMockChild();
var child2 = createMockChild();
child1.x = 0;
child2.x = 0;
group.add(child1);
group.add(child2);
group.setX(0, 50);
expect(child1.x).toBe(0);
expect(child2.x).toBe(50);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.setX(0);
expect(result).toBe(group);
});
});
describe('setY', function ()
{
it('should set y on all children', function ()
{
var group = new Group(scene);
var child = createMockChild();
child.y = 0;
group.add(child);
group.setY(200);
expect(child.y).toBe(200);
});
});
describe('setXY', function ()
{
it('should set x and y on all children', function ()
{
var group = new Group(scene);
var child = createMockChild();
child.x = 0;
child.y = 0;
group.add(child);
group.setXY(50, 75);
expect(child.x).toBe(50);
expect(child.y).toBe(75);
});
it('should return this for chaining', function ()
{
var group = new Group(scene);
var result = group.setXY(0, 0);
expect(result).toBe(group);
});
});
describe('create', function ()
{
it('should return null when the group is full', function ()
{
var MockType = createMockClassType();
var group = new Group(scene, null, { maxSize: 0, classType: MockType });
var result = group.create(0, 0, 'key');
expect(result).toBeNull();
});
it('should create an instance of classType and add it to the group', function ()
{
var MockType = createMockClassType();
var group = new Group(scene, null, { classType: MockType });
var result = group.create(10, 20, 'testKey');
expect(result).toBeInstanceOf(MockType);
expect(result.x).toBe(10);
expect(result.y).toBe(20);
expect(result.key).toBe('testKey');
expect(group.getLength()).toBe(1);
});
});
describe('destroy', function ()
{
it('should clear all children and unset scene', function ()
{
var group = new Group(scene);
group.add(createMockChild());
group.add(createMockChild());
group.destroy();
expect(group.scene).toBeUndefined();
expect(group.children).toBeUndefined();
});
it('should not throw if called on an already-destroyed group', function ()
{
var group = new Group(scene);
group.destroy();
expect(function () { group.destroy(); }).not.toThrow();
});
});
});