UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

1,266 lines (919 loc) 33.4 kB
var BaseTween = require('../../../src/tweens/tween/BaseTween'); var TWEEN_CONST = require('../../../src/tweens/tween/const'); function createParent () { return { makeActive: function () {}, remove: function () {} }; } function createTween (parent) { if (parent === undefined) { parent = createParent(); } var tween = new BaseTween(parent); // dispatchEvent is defined on subclasses; stub it here so methods don't throw tween.dispatchEvent = function () {}; return tween; } describe('BaseTween', function () { describe('constructor', function () { it('should store the parent reference', function () { var parent = createParent(); var tween = createTween(parent); expect(tween.parent).toBe(parent); }); it('should initialise data as an empty array', function () { var tween = createTween(); expect(Array.isArray(tween.data)).toBe(true); expect(tween.data.length).toBe(0); }); it('should initialise totalData to zero', function () { var tween = createTween(); expect(tween.totalData).toBe(0); }); it('should initialise startDelay to zero', function () { var tween = createTween(); expect(tween.startDelay).toBe(0); }); it('should initialise hasStarted to false', function () { var tween = createTween(); expect(tween.hasStarted).toBe(false); }); it('should initialise timeScale to one', function () { var tween = createTween(); expect(tween.timeScale).toBe(1); }); it('should initialise loop to zero', function () { var tween = createTween(); expect(tween.loop).toBe(0); }); it('should initialise loopDelay to zero', function () { var tween = createTween(); expect(tween.loopDelay).toBe(0); }); it('should initialise loopCounter to zero', function () { var tween = createTween(); expect(tween.loopCounter).toBe(0); }); it('should initialise completeDelay to zero', function () { var tween = createTween(); expect(tween.completeDelay).toBe(0); }); it('should initialise countdown to zero', function () { var tween = createTween(); expect(tween.countdown).toBe(0); }); it('should initialise state to PENDING', function () { var tween = createTween(); expect(tween.state).toBe(TWEEN_CONST.PENDING); }); it('should initialise paused to false', function () { var tween = createTween(); expect(tween.paused).toBe(false); }); it('should initialise persist to false', function () { var tween = createTween(); expect(tween.persist).toBe(false); }); it('should initialise all callbacks to null', function () { var tween = createTween(); expect(tween.callbacks.onActive).toBeNull(); expect(tween.callbacks.onComplete).toBeNull(); expect(tween.callbacks.onLoop).toBeNull(); expect(tween.callbacks.onPause).toBeNull(); expect(tween.callbacks.onRepeat).toBeNull(); expect(tween.callbacks.onResume).toBeNull(); expect(tween.callbacks.onStart).toBeNull(); expect(tween.callbacks.onStop).toBeNull(); expect(tween.callbacks.onUpdate).toBeNull(); expect(tween.callbacks.onYoyo).toBeNull(); }); }); describe('setTimeScale', function () { it('should set timeScale to the given value', function () { var tween = createTween(); tween.setTimeScale(2); expect(tween.timeScale).toBe(2); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.setTimeScale(1)).toBe(tween); }); it('should accept zero', function () { var tween = createTween(); tween.setTimeScale(0); expect(tween.timeScale).toBe(0); }); it('should accept fractional values', function () { var tween = createTween(); tween.setTimeScale(0.5); expect(tween.timeScale).toBeCloseTo(0.5); }); it('should accept negative values', function () { var tween = createTween(); tween.setTimeScale(-1); expect(tween.timeScale).toBe(-1); }); }); describe('getTimeScale', function () { it('should return the current timeScale', function () { var tween = createTween(); expect(tween.getTimeScale()).toBe(1); }); it('should reflect a value set via setTimeScale', function () { var tween = createTween(); tween.setTimeScale(3); expect(tween.getTimeScale()).toBe(3); }); it('should return zero when timeScale is zero', function () { var tween = createTween(); tween.setTimeScale(0); expect(tween.getTimeScale()).toBe(0); }); }); describe('isPlaying', function () { it('should return false when tween is in PENDING state', function () { var tween = createTween(); expect(tween.isPlaying()).toBe(false); }); it('should return true when tween is ACTIVE and not paused', function () { var tween = createTween(); tween.setActiveState(); expect(tween.isPlaying()).toBe(true); }); it('should return false when tween is ACTIVE but paused', function () { var tween = createTween(); tween.setActiveState(); tween.paused = true; expect(tween.isPlaying()).toBe(false); }); it('should return false when tween is PENDING_REMOVE', function () { var tween = createTween(); tween.setPendingRemoveState(); expect(tween.isPlaying()).toBe(false); }); }); describe('isPaused', function () { it('should return false by default', function () { var tween = createTween(); expect(tween.isPaused()).toBe(false); }); it('should return true after pausing', function () { var tween = createTween(); tween.paused = true; expect(tween.isPaused()).toBe(true); }); it('should match the paused property directly', function () { var tween = createTween(); tween.paused = true; expect(tween.isPaused()).toBe(tween.paused); }); }); describe('pause', function () { it('should set paused to true', function () { var tween = createTween(); tween.pause(); expect(tween.paused).toBe(true); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.pause()).toBe(tween); }); it('should dispatch an event when pausing', function () { var tween = createTween(); var dispatched = false; tween.dispatchEvent = function () { dispatched = true; }; tween.pause(); expect(dispatched).toBe(true); }); it('should not dispatch an event if already paused', function () { var tween = createTween(); var callCount = 0; tween.paused = true; tween.dispatchEvent = function () { callCount++; }; tween.pause(); expect(callCount).toBe(0); }); it('should not change paused state if already paused', function () { var tween = createTween(); tween.paused = true; tween.pause(); expect(tween.paused).toBe(true); }); }); describe('resume', function () { it('should set paused to false when paused', function () { var tween = createTween(); tween.paused = true; tween.resume(); expect(tween.paused).toBe(false); }); it('should return the tween instance for chaining', function () { var tween = createTween(); tween.paused = true; expect(tween.resume()).toBe(tween); }); it('should dispatch an event when resuming', function () { var tween = createTween(); var dispatched = false; tween.paused = true; tween.dispatchEvent = function () { dispatched = true; }; tween.resume(); expect(dispatched).toBe(true); }); it('should not dispatch an event if not paused', function () { var tween = createTween(); var callCount = 0; tween.dispatchEvent = function () { callCount++; }; tween.resume(); expect(callCount).toBe(0); }); it('should not change paused state if already unpaused', function () { var tween = createTween(); tween.resume(); expect(tween.paused).toBe(false); }); }); describe('makeActive', function () { it('should call parent.makeActive with this tween', function () { var parent = createParent(); var received = null; parent.makeActive = function (t) { received = t; }; var tween = createTween(parent); tween.makeActive(); expect(received).toBe(tween); }); it('should dispatch an event', function () { var tween = createTween(); var dispatched = false; tween.dispatchEvent = function () { dispatched = true; }; tween.makeActive(); expect(dispatched).toBe(true); }); }); describe('onCompleteHandler', function () { it('should set state to PENDING_REMOVE', function () { var tween = createTween(); tween.onCompleteHandler(); expect(tween.state).toBe(TWEEN_CONST.PENDING_REMOVE); }); it('should dispatch a complete event', function () { var tween = createTween(); var dispatched = false; tween.dispatchEvent = function () { dispatched = true; }; tween.onCompleteHandler(); expect(dispatched).toBe(true); }); }); describe('complete', function () { it('should call onCompleteHandler when no delay is given', function () { var tween = createTween(); var called = false; tween.onCompleteHandler = function () { called = true; }; tween.complete(); expect(called).toBe(true); }); it('should call onCompleteHandler when delay is zero', function () { var tween = createTween(); var called = false; tween.onCompleteHandler = function () { called = true; }; tween.complete(0); expect(called).toBe(true); }); it('should set state to COMPLETE_DELAY when a delay is given', function () { var tween = createTween(); tween.complete(500); expect(tween.state).toBe(TWEEN_CONST.COMPLETE_DELAY); }); it('should set countdown to the delay value', function () { var tween = createTween(); tween.complete(500); expect(tween.countdown).toBe(500); }); it('should not call onCompleteHandler immediately when delay is given', function () { var tween = createTween(); var called = false; tween.onCompleteHandler = function () { called = true; }; tween.complete(500); expect(called).toBe(false); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.complete()).toBe(tween); }); }); describe('completeAfterLoop', function () { it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.completeAfterLoop()).toBe(tween); }); it('should reduce loopCounter to the given loops value when loopCounter is greater', function () { var tween = createTween(); tween.loopCounter = 5; tween.completeAfterLoop(2); expect(tween.loopCounter).toBe(2); }); it('should not change loopCounter when it is already equal to loops', function () { var tween = createTween(); tween.loopCounter = 2; tween.completeAfterLoop(2); expect(tween.loopCounter).toBe(2); }); it('should not change loopCounter when it is less than loops', function () { var tween = createTween(); tween.loopCounter = 1; tween.completeAfterLoop(5); expect(tween.loopCounter).toBe(1); }); it('should default loops to zero', function () { var tween = createTween(); tween.loopCounter = 3; tween.completeAfterLoop(); expect(tween.loopCounter).toBe(0); }); }); describe('remove', function () { it('should call parent.remove with this tween', function () { var parent = createParent(); var received = null; parent.remove = function (t) { received = t; }; var tween = createTween(parent); tween.remove(); expect(received).toBe(tween); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.remove()).toBe(tween); }); it('should not throw when parent is null', function () { var tween = createTween(); tween.parent = null; expect(function () { tween.remove(); }).not.toThrow(); }); }); describe('stop', function () { it('should set state to PENDING_REMOVE when active', function () { var tween = createTween(); tween.setActiveState(); tween.stop(); expect(tween.state).toBe(TWEEN_CONST.PENDING_REMOVE); }); it('should dispatch a stop event', function () { var tween = createTween(); var dispatched = false; tween.setActiveState(); tween.dispatchEvent = function () { dispatched = true; }; tween.stop(); expect(dispatched).toBe(true); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.stop()).toBe(tween); }); it('should not dispatch when already in REMOVED state', function () { var tween = createTween(); var callCount = 0; tween.setRemovedState(); tween.dispatchEvent = function () { callCount++; }; tween.stop(); expect(callCount).toBe(0); }); it('should not dispatch when already in PENDING_REMOVE state', function () { var tween = createTween(); var callCount = 0; tween.setPendingRemoveState(); tween.dispatchEvent = function () { callCount++; }; tween.stop(); expect(callCount).toBe(0); }); it('should not dispatch when in DESTROYED state', function () { var tween = createTween(); var callCount = 0; tween.setDestroyedState(); tween.dispatchEvent = function () { callCount++; }; tween.stop(); expect(callCount).toBe(0); }); it('should not throw when parent is null', function () { var tween = createTween(); tween.parent = null; expect(function () { tween.stop(); }).not.toThrow(); }); }); describe('updateLoopCountdown', function () { it('should decrease countdown by delta', function () { var tween = createTween(); tween.countdown = 1000; tween.updateLoopCountdown(100); expect(tween.countdown).toBeCloseTo(900); }); it('should set state to ACTIVE when countdown reaches zero', function () { var tween = createTween(); tween.countdown = 100; tween.updateLoopCountdown(100); expect(tween.state).toBe(TWEEN_CONST.ACTIVE); }); it('should set state to ACTIVE when countdown goes below zero', function () { var tween = createTween(); tween.countdown = 50; tween.updateLoopCountdown(100); expect(tween.state).toBe(TWEEN_CONST.ACTIVE); }); it('should dispatch a loop event when countdown expires', function () { var tween = createTween(); var dispatched = false; tween.countdown = 100; tween.dispatchEvent = function () { dispatched = true; }; tween.updateLoopCountdown(100); expect(dispatched).toBe(true); }); it('should not change state when countdown is still positive', function () { var tween = createTween(); tween.setLoopDelayState(); tween.countdown = 500; tween.updateLoopCountdown(100); expect(tween.state).toBe(TWEEN_CONST.LOOP_DELAY); }); }); describe('updateStartCountdown', function () { it('should decrease countdown by delta', function () { var tween = createTween(); tween.countdown = 1000; tween.updateStartCountdown(200); expect(tween.countdown).toBeCloseTo(800); }); it('should return the delta unchanged when countdown is still positive', function () { var tween = createTween(); tween.countdown = 1000; var result = tween.updateStartCountdown(200); expect(result).toBe(200); }); it('should set state to ACTIVE (via setActiveState which resets hasStarted) when countdown expires', function () { var tween = createTween(); tween.countdown = 100; tween.updateStartCountdown(100); // setActiveState() is called internally and resets hasStarted to false expect(tween.hasStarted).toBe(false); expect(tween.state).toBe(TWEEN_CONST.ACTIVE); }); it('should set state to ACTIVE when countdown expires', function () { var tween = createTween(); tween.countdown = 100; tween.updateStartCountdown(100); expect(tween.state).toBe(TWEEN_CONST.ACTIVE); }); it('should return zero delta when countdown expires', function () { var tween = createTween(); tween.countdown = 100; var result = tween.updateStartCountdown(100); expect(result).toBe(0); }); it('should dispatch a start event when countdown expires', function () { var tween = createTween(); var dispatched = false; tween.countdown = 100; tween.dispatchEvent = function () { dispatched = true; }; tween.updateStartCountdown(100); expect(dispatched).toBe(true); }); it('should not set hasStarted when countdown is still positive', function () { var tween = createTween(); tween.countdown = 500; tween.hasStarted = false; tween.updateStartCountdown(100); expect(tween.hasStarted).toBe(false); }); }); describe('updateCompleteDelay', function () { it('should decrease countdown by delta', function () { var tween = createTween(); tween.countdown = 1000; tween.updateCompleteDelay(300); expect(tween.countdown).toBeCloseTo(700); }); it('should call onCompleteHandler when countdown expires', function () { var tween = createTween(); var called = false; tween.countdown = 100; tween.onCompleteHandler = function () { called = true; }; tween.updateCompleteDelay(100); expect(called).toBe(true); }); it('should not call onCompleteHandler when countdown is still positive', function () { var tween = createTween(); var called = false; tween.countdown = 500; tween.onCompleteHandler = function () { called = true; }; tween.updateCompleteDelay(100); expect(called).toBe(false); }); }); describe('setCallback', function () { it('should set a valid callback type', function () { var tween = createTween(); var fn = function () {}; tween.setCallback('onComplete', fn, []); expect(tween.callbacks.onComplete.func).toBe(fn); }); it('should store params with the callback', function () { var tween = createTween(); var fn = function () {}; var params = [ 1, 2, 3 ]; tween.setCallback('onComplete', fn, params); expect(tween.callbacks.onComplete.params).toBe(params); }); it('should default params to an empty array when not provided', function () { var tween = createTween(); var fn = function () {}; tween.setCallback('onStart', fn); expect(Array.isArray(tween.callbacks.onStart.params)).toBe(true); expect(tween.callbacks.onStart.params.length).toBe(0); }); it('should return the tween instance for chaining', function () { var tween = createTween(); expect(tween.setCallback('onStart', function () {})).toBe(tween); }); it('should not set an invalid callback type', function () { var tween = createTween(); var fn = function () {}; tween.setCallback('onInvalid', fn, []); expect(tween.callbacks.hasOwnProperty('onInvalid')).toBe(false); }); it('should replace a previously set callback', function () { var tween = createTween(); var fn1 = function () {}; var fn2 = function () {}; tween.setCallback('onLoop', fn1, []); tween.setCallback('onLoop', fn2, []); expect(tween.callbacks.onLoop.func).toBe(fn2); }); it('should handle all valid callback types', function () { var tween = createTween(); var types = BaseTween.TYPES; for (var i = 0; i < types.length; i++) { var fn = function () {}; tween.setCallback(types[i], fn, []); expect(tween.callbacks[types[i]].func).toBe(fn); } }); }); describe('setPendingState', function () { it('should set state to PENDING', function () { var tween = createTween(); tween.setActiveState(); tween.setPendingState(); expect(tween.state).toBe(TWEEN_CONST.PENDING); }); }); describe('setActiveState', function () { it('should set state to ACTIVE', function () { var tween = createTween(); tween.setActiveState(); expect(tween.state).toBe(TWEEN_CONST.ACTIVE); }); it('should reset hasStarted to false', function () { var tween = createTween(); tween.hasStarted = true; tween.setActiveState(); expect(tween.hasStarted).toBe(false); }); }); describe('setLoopDelayState', function () { it('should set state to LOOP_DELAY', function () { var tween = createTween(); tween.setLoopDelayState(); expect(tween.state).toBe(TWEEN_CONST.LOOP_DELAY); }); }); describe('setCompleteDelayState', function () { it('should set state to COMPLETE_DELAY', function () { var tween = createTween(); tween.setCompleteDelayState(); expect(tween.state).toBe(TWEEN_CONST.COMPLETE_DELAY); }); }); describe('setStartDelayState', function () { it('should set state to START_DELAY', function () { var tween = createTween(); tween.setStartDelayState(); expect(tween.state).toBe(TWEEN_CONST.START_DELAY); }); it('should set countdown to startDelay', function () { var tween = createTween(); tween.startDelay = 750; tween.setStartDelayState(); expect(tween.countdown).toBe(750); }); it('should reset hasStarted to false', function () { var tween = createTween(); tween.hasStarted = true; tween.setStartDelayState(); expect(tween.hasStarted).toBe(false); }); }); describe('setPendingRemoveState', function () { it('should set state to PENDING_REMOVE', function () { var tween = createTween(); tween.setPendingRemoveState(); expect(tween.state).toBe(TWEEN_CONST.PENDING_REMOVE); }); }); describe('setRemovedState', function () { it('should set state to REMOVED', function () { var tween = createTween(); tween.setRemovedState(); expect(tween.state).toBe(TWEEN_CONST.REMOVED); }); }); describe('setFinishedState', function () { it('should set state to FINISHED', function () { var tween = createTween(); tween.setFinishedState(); expect(tween.state).toBe(TWEEN_CONST.FINISHED); }); }); describe('setDestroyedState', function () { it('should set state to DESTROYED', function () { var tween = createTween(); tween.setDestroyedState(); expect(tween.state).toBe(TWEEN_CONST.DESTROYED); }); }); describe('state query methods', function () { it('isPending should return true only when state is PENDING', function () { var tween = createTween(); expect(tween.isPending()).toBe(true); tween.setActiveState(); expect(tween.isPending()).toBe(false); }); it('isActive should return true only when state is ACTIVE', function () { var tween = createTween(); expect(tween.isActive()).toBe(false); tween.setActiveState(); expect(tween.isActive()).toBe(true); }); it('isLoopDelayed should return true only when state is LOOP_DELAY', function () { var tween = createTween(); expect(tween.isLoopDelayed()).toBe(false); tween.setLoopDelayState(); expect(tween.isLoopDelayed()).toBe(true); }); it('isCompleteDelayed should return true only when state is COMPLETE_DELAY', function () { var tween = createTween(); expect(tween.isCompleteDelayed()).toBe(false); tween.setCompleteDelayState(); expect(tween.isCompleteDelayed()).toBe(true); }); it('isStartDelayed should return true only when state is START_DELAY', function () { var tween = createTween(); expect(tween.isStartDelayed()).toBe(false); tween.setStartDelayState(); expect(tween.isStartDelayed()).toBe(true); }); it('isPendingRemove should return true only when state is PENDING_REMOVE', function () { var tween = createTween(); expect(tween.isPendingRemove()).toBe(false); tween.setPendingRemoveState(); expect(tween.isPendingRemove()).toBe(true); }); it('isRemoved should return true only when state is REMOVED', function () { var tween = createTween(); expect(tween.isRemoved()).toBe(false); tween.setRemovedState(); expect(tween.isRemoved()).toBe(true); }); it('isFinished should return true only when state is FINISHED', function () { var tween = createTween(); expect(tween.isFinished()).toBe(false); tween.setFinishedState(); expect(tween.isFinished()).toBe(true); }); it('isDestroyed should return true only when state is DESTROYED', function () { var tween = createTween(); expect(tween.isDestroyed()).toBe(false); tween.setDestroyedState(); expect(tween.isDestroyed()).toBe(true); }); it('only one state query method should return true at a time', function () { var tween = createTween(); tween.setActiveState(); expect(tween.isPending()).toBe(false); expect(tween.isActive()).toBe(true); expect(tween.isLoopDelayed()).toBe(false); expect(tween.isCompleteDelayed()).toBe(false); expect(tween.isStartDelayed()).toBe(false); expect(tween.isPendingRemove()).toBe(false); expect(tween.isRemoved()).toBe(false); expect(tween.isFinished()).toBe(false); expect(tween.isDestroyed()).toBe(false); }); }); describe('destroy', function () { it('should set state to DESTROYED', function () { var tween = createTween(); tween.destroy(); expect(tween.state).toBe(TWEEN_CONST.DESTROYED); }); it('should null out callbacks', function () { var tween = createTween(); tween.destroy(); expect(tween.callbacks).toBeNull(); }); it('should null out data', function () { var tween = createTween(); tween.destroy(); expect(tween.data).toBeNull(); }); it('should null out parent', function () { var tween = createTween(); tween.destroy(); expect(tween.parent).toBeNull(); }); it('should call destroy on each item in data', function () { var tween = createTween(); var destroyCalled = false; var fakeData = { destroy: function () { destroyCalled = true; } }; tween.data = [ fakeData ]; tween.destroy(); expect(destroyCalled).toBe(true); }); it('should handle an empty data array without throwing', function () { var tween = createTween(); tween.data = []; expect(function () { tween.destroy(); }).not.toThrow(); }); it('isDestroyed should return true after destroy', function () { var tween = createTween(); tween.destroy(); expect(tween.isDestroyed()).toBe(true); }); }); describe('TYPES static property', function () { it('should be an array', function () { expect(Array.isArray(BaseTween.TYPES)).toBe(true); }); it('should contain all expected callback type names', function () { var expected = [ 'onActive', 'onComplete', 'onLoop', 'onPause', 'onRepeat', 'onResume', 'onStart', 'onStop', 'onUpdate', 'onYoyo' ]; for (var i = 0; i < expected.length; i++) { expect(BaseTween.TYPES).toContain(expected[i]); } }); it('should have 10 entries', function () { expect(BaseTween.TYPES.length).toBe(10); }); }); });