aboutsummaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2020-05-01 20:17:24 +1000
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2020-05-01 20:17:24 +1000
commit897bbfa075055097d64d42d7a32952bec9c75665 (patch)
tree648b309560000a18f51e689f13bd22ca16f468af /spec
parent9a17f412b894c21db7f81bcc910981443477957f (diff)
downloadsvg.js-897bbfa075055097d64d42d7a32952bec9c75665.tar.gz
svg.js-897bbfa075055097d64d42d7a32952bec9c75665.zip
added specs for animation files except runner, fixed a few things
Diffstat (limited to 'spec')
-rw-r--r--spec/RAFPlugin.js5
-rw-r--r--spec/spec/animation/Animator.js56
-rw-r--r--spec/spec/animation/Controller.js403
-rw-r--r--spec/spec/animation/Morphable.js227
-rw-r--r--spec/spec/animation/Queue.js24
-rw-r--r--spec/spec/animation/Timeline.js382
-rw-r--r--spec/spec/animation/easing.js26
7 files changed, 1057 insertions, 66 deletions
diff --git a/spec/RAFPlugin.js b/spec/RAFPlugin.js
index 3e82c70..c644ee4 100644
--- a/spec/RAFPlugin.js
+++ b/spec/RAFPlugin.js
@@ -20,9 +20,10 @@ function RAFPlugin (jasmine) {
throw new Error('You should pass a function to requestAnimationFrame')
}
- callbacks[index++] = fn
+ const i = index++
+ callbacks[i] = fn
- return index
+ return i
}
/**
diff --git a/spec/spec/animation/Animator.js b/spec/spec/animation/Animator.js
index 80f2eab..043beaa 100644
--- a/spec/spec/animation/Animator.js
+++ b/spec/spec/animation/Animator.js
@@ -3,21 +3,22 @@
import { Animator, Queue } from '../../../src/main.js'
import { getWindow } from '../../../src/utils/window.js'
-describe('Animator.js', function () {
+describe('Animator.js', () => {
- beforeEach(function () {
+ beforeEach(() => {
jasmine.RequestAnimationFrame.install(getWindow())
Animator.timeouts = new Queue()
Animator.frames = new Queue()
+ Animator.immediates = new Queue()
Animator.nextDraw = null
})
- afterEach(function () {
+ afterEach(() => {
jasmine.RequestAnimationFrame.uninstall(getWindow())
})
- describe('timeout()', function () {
- it('calls a function after a specific time', function () {
+ describe('timeout()', () => {
+ it('calls a function after a specific time', () => {
var spy = jasmine.createSpy('tester')
Animator.timeout(spy, 100)
@@ -29,8 +30,8 @@ describe('Animator.js', function () {
})
})
- describe('cancelTimeout()', function () {
- it('cancels a timeout which was created with timeout()', function () {
+ describe('cancelTimeout()', () => {
+ it('cancels a timeout which was created with timeout()', () => {
var spy = jasmine.createSpy('tester')
var id = Animator.timeout(spy, 100)
Animator.clearTimeout(id)
@@ -41,8 +42,8 @@ describe('Animator.js', function () {
})
})
- describe('frame()', function () {
- it('calls a function at the next animationFrame', function () {
+ describe('frame()', () => {
+ it('calls a function at the next animationFrame', () => {
var spy = jasmine.createSpy('tester')
Animator.frame(spy)
@@ -52,4 +53,41 @@ describe('Animator.js', function () {
})
})
+ describe('cancelFrame()', () => {
+ it('cancels a single frame which was created with frame()', () => {
+ var spy = jasmine.createSpy('tester')
+
+ const id = Animator.frame(spy)
+ Animator.cancelFrame(id)
+
+ expect(spy).not.toHaveBeenCalled()
+ jasmine.RequestAnimationFrame.tick()
+ expect(spy).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('immediate()', () => {
+ it('calls a function at the next animationFrame but after all frames are processed', () => {
+ var spy = jasmine.createSpy('tester')
+
+ Animator.immediate(spy)
+
+ expect(spy).not.toHaveBeenCalled()
+ jasmine.RequestAnimationFrame.tick()
+ expect(spy).toHaveBeenCalled()
+ })
+ })
+
+ describe('cancelImmediate()', () => {
+ it('cancels an immediate cakk which was created with immediate()', () => {
+ var spy = jasmine.createSpy('tester')
+
+ const id = Animator.immediate(spy)
+ Animator.cancelImmediate(id)
+
+ expect(spy).not.toHaveBeenCalled()
+ jasmine.RequestAnimationFrame.tick()
+ expect(spy).not.toHaveBeenCalled()
+ })
+ })
})
diff --git a/spec/spec/animation/Controller.js b/spec/spec/animation/Controller.js
new file mode 100644
index 0000000..b1d4b8f
--- /dev/null
+++ b/spec/spec/animation/Controller.js
@@ -0,0 +1,403 @@
+/* globals describe, expect, it, jasmine */
+
+import { easing, defaults } from '../../../src/main.js'
+import { Stepper, Ease, Controller, Spring, PID } from '../../../src/animation/Controller.js'
+
+const { any, createSpy } = jasmine
+
+describe('Controller.js', () => {
+
+ describe('easing', () => {
+ var easedValues = {
+ '-': 0.5,
+ '<>': 0.5,
+ '>': 0.7071,
+ '<': 0.2929
+ }
+
+ ;[ '-', '<>', '<', '>' ].forEach((el) => {
+ describe(el, () => {
+ it('is 0 at 0', () => {
+ expect(easing[el](0)).toBe(0)
+ })
+ it('is 1 at 1', () => {
+ expect(Math.round(easing[el](1) * 1000) / 1000).toBe(1) // we need to round cause for some reason at some point 1==0.999999999
+ })
+ it('is eased at 0.5', () => {
+ expect(easing[el](0.5)).toBeCloseTo(easedValues[el])
+ })
+ })
+ })
+
+ describe('beziere()', () => {
+ const b1 = easing.bezier(0.25, 0.25, 0.75, 0.75)
+ const b2 = easing.bezier(-0.25, -0.25, 0.75, 0.75)
+ const b3 = easing.bezier(0.5, 0.5, 2, 2)
+ const b4 = easing.bezier(1, 1, 2, 2)
+ const b5 = easing.bezier(-1, -1, -2, -2)
+
+ it('is 0 at 0', () => {
+ expect(b1(0)).toBe(0)
+ })
+
+ it('is 1 at 1', () => {
+ expect(b1(1)).toBe(1)
+ })
+
+ it('is eased at 0.5', () => {
+ expect(b1(0.5)).toBe(0.5)
+ expect(b2(0.5)).toBe(0.3125)
+ expect(b3(0.5)).toBe(1.0625)
+ expect(b4(0.5)).toBe(1.25)
+ expect(b5(0.5)).toBe(-1)
+ })
+
+ it('handles values bigger 1', () => {
+ expect(b1(1.5)).toBe(1.5)
+ expect(b2(1.5)).toBe(1.5)
+ expect(b3(1.5)).toBe(1.5)
+ expect(b4(1.5)).toBe(1)
+ expect(b5(1.5)).toBe(1.5)
+ })
+
+ it('handles values lower 0', () => {
+ expect(b1(-0.5)).toBe(-0.5)
+ expect(b2(-0.5)).toBe(-0.5)
+ expect(b3(-0.5)).toBe(-0.5)
+ expect(b4(-0.5)).toBe(-0.5)
+ expect(b5(-0.5)).toBe(0)
+ })
+ })
+
+ describe('steps()', () => {
+ const s1 = easing.steps(5)
+ const s2 = easing.steps(5, 'start')
+ const s3 = easing.steps(5, 'end')
+ const s4 = easing.steps(5, 'none')
+ const s5 = easing.steps(5, 'both')
+
+ it('is 0 at 0', () => {
+ expect(s1(0)).toBe(0)
+ expect(s1(0, true)).toBe(0)
+ expect(s2(0)).toBe(0.2)
+ expect(s2(0, true)).toBe(0)
+ expect(s3(0)).toBe(0)
+ expect(s3(0, true)).toBe(0)
+ expect(s4(0)).toBe(0)
+ expect(s4(0, true)).toBe(0)
+ expect(s5(0)).toBe(1 / 6)
+ expect(s5(0, true)).toBe(0)
+ })
+
+ it('also works at values < 0', () => {
+ expect(s1(-0.1)).toBe(-0.2)
+ expect(s1(-0.1, true)).toBe(-0.2)
+ expect(s2(-0.1)).toBe(0)
+ expect(s2(-0.1, true)).toBe(0)
+ expect(s3(-0.1)).toBe(-0.2)
+ expect(s3(-0.1, true)).toBe(-0.2)
+ expect(s4(-0.1)).toBe(-0.25)
+ expect(s4(-0.1, true)).toBe(-0.25)
+ expect(s5(-0.1)).toBe(0)
+ expect(s5(-0.1, true)).toBe(0)
+ })
+
+ it('is 1 at 1', () => {
+ expect(s1(1)).toBe(1)
+ expect(s1(1, true)).toBe(0.8)
+ expect(s2(1)).toBe(1)
+ expect(s2(1, true)).toBe(1)
+ expect(s3(1)).toBe(1)
+ expect(s3(1, true)).toBe(0.8)
+ expect(s4(1)).toBe(1)
+ expect(s4(1, true)).toBe(1)
+ expect(s5(1)).toBe(1)
+ expect(s5(1, true)).toBe(5 / 6)
+ })
+
+ it('also works at values > 1', () => {
+ expect(s1(1.1)).toBe(1)
+ expect(s1(1.1, true)).toBe(1)
+ expect(s2(1.1)).toBe(1.2)
+ expect(s2(1.1, true)).toBe(1.2)
+ expect(s3(1.1)).toBe(1)
+ expect(s3(1.1, true)).toBe(1)
+ expect(s4(1.1)).toBe(1.25)
+ expect(s4(1.1, true)).toBe(1.25)
+ expect(s5(1.1)).toBe(1)
+ expect(s5(1.1, true)).toBe(1)
+ })
+
+ it('is eased at 0.1', () => {
+ expect(s1(0.1)).toBe(0)
+ expect(s1(0.1, true)).toBe(0)
+ expect(s2(0.1)).toBe(0.2)
+ expect(s2(0.1, true)).toBe(0)
+ expect(s3(0.1)).toBe(0)
+ expect(s3(0.1, true)).toBe(0)
+ expect(s4(0.1)).toBe(0)
+ expect(s4(0.1, true)).toBe(0)
+ expect(s5(0.1)).toBe(1 / 6)
+ expect(s5(0.1, true)).toBe(0)
+ })
+
+ it('is eased at 0.15', () => {
+ expect(s1(0.15)).toBe(0)
+ expect(s1(0.15, true)).toBe(0)
+ expect(s2(0.15)).toBe(0.2)
+ expect(s2(0.15, true)).toBe(0)
+ expect(s3(0.15)).toBe(0)
+ expect(s3(0.15, true)).toBe(0)
+ expect(s4(0.15)).toBe(0)
+ expect(s4(0.15, true)).toBe(0)
+ expect(s5(0.15)).toBe(1 / 6)
+ expect(s5(0.15, true)).toBe(0)
+ })
+
+ it('is eased at 0.2', () => {
+ expect(s1(0.2)).toBe(0.2)
+ expect(s1(0.2, true)).toBe(0.2)
+ expect(s2(0.2)).toBe(0.4)
+ expect(s2(0.2, true)).toBe(0.4)
+ expect(s3(0.2)).toBe(0.2)
+ expect(s3(0.2, true)).toBe(0.2)
+ expect(s4(0.2)).toBe(0.25)
+ expect(s4(0.2, true)).toBe(0.25)
+ expect(s5(0.2)).toBe(1 / 3)
+ expect(s5(0.2, true)).toBe(1 / 3)
+ })
+
+ it('is eased at 0.25', () => {
+ expect(s1(0.25)).toBe(0.2)
+ expect(s1(0.25, true)).toBe(0.2)
+ expect(s2(0.25)).toBe(0.4)
+ expect(s2(0.25, true)).toBe(0.4)
+ expect(s3(0.25)).toBe(0.2)
+ expect(s3(0.25, true)).toBe(0.2)
+ expect(s4(0.25)).toBe(0.25)
+ expect(s4(0.25, true)).toBe(0.25)
+ expect(s5(0.25)).toBe(1 / 3)
+ expect(s5(0.25, true)).toBe(1 / 3)
+ })
+ })
+ })
+
+ describe('Stepper', () => {
+ it('has a done() method', () => {
+ const stepper = new Stepper()
+ expect(stepper).toEqual(any(Stepper))
+ expect(stepper.done()).toBe(false)
+ })
+ })
+
+ describe('Ease', () => {
+ describe('()', () => {
+ it('wraps the default easing function by default', () => {
+ const ease = new Ease()
+ expect(ease.ease).toBe(easing[defaults.timeline.ease])
+ })
+
+ it('wraps an easing function found in "easing"', () => {
+ const ease = new Ease('-')
+ expect(ease.ease).toBe(easing['-'])
+ })
+
+ it('wraps a a custom easing function', () => {
+ const ease = new Ease(easing['-'])
+ expect(ease.ease).toBe(easing['-'])
+ })
+ })
+
+ describe('step()', () => {
+ it('provides an eased value to a position', () => {
+ let ease = new Ease(easing['-'])
+ expect(ease.step(2, 4, 0.5)).toBe(3)
+
+ ease = new Ease(() => 3)
+ expect(ease.step(2, 4, 0.5)).toBe(8)
+
+ ease = new Ease()
+ expect(ease.step(2, 4, 0.5)).toBeCloseTo(3.414, 3)
+ })
+
+ it('jumps to "to" value at pos 1 if from is not a number', () => {
+ const ease = new Ease('-')
+ expect(ease.step('Hallo', 'Welt', 0.999)).toBe('Hallo')
+ expect(ease.step('Hallo', 'Welt', 1)).toBe('Welt')
+ })
+ })
+ })
+
+ describe('Controller', () => {
+ describe('()', () => {
+ it('constructs a controller with the given stepper function set', () => {
+ const spy = createSpy()
+ const controller = new Controller(spy)
+ expect(controller).toEqual(any(Controller))
+ expect(controller.stepper).toBe(spy)
+ })
+ })
+
+ describe('step()', () => {
+ it('runs the stepper with current value, target value, dt and context', () => {
+ const spy = createSpy().and.returnValue('foo')
+ const controller = new Controller(spy)
+ expect(controller.step(10, 20, 30, 'bar')).toBe('foo')
+ expect(spy).toHaveBeenCalledWith(10, 20, 30, 'bar')
+ })
+ })
+
+ describe('done()', () => {
+ it('returns given values "done" property', () => {
+ const spy = createSpy()
+ const controller = new Controller(spy)
+ expect(controller.done({ done: 'yes' })).toBe('yes')
+ })
+ })
+ })
+
+ describe('Spring', () => {
+ describe('()', () => {
+ it('creates a spring with default duration and overshoot', () => {
+ const spring = new Spring()
+ expect(spring).toEqual(any(Spring))
+ expect(spring.duration()).toBe(500)
+ expect(spring.overshoot()).toBe(0)
+ })
+
+ it('creates a spring with given duration and overshoot', () => {
+ const spring = new Spring(100, 10)
+ expect(spring).toEqual(any(Spring))
+ expect(spring.duration()).toBe(100)
+ expect(spring.overshoot()).toBe(10)
+ })
+ })
+
+ describe('duration()', () => {
+ it('gets and sets a new duration for the spring controller', () => {
+ const spring = new Spring().duration(100)
+ expect(spring.duration()).toBe(100)
+ })
+ })
+
+ describe('overshoot()', () => {
+ it('gets and sets a new overshoot for the spring controller', () => {
+ const spring = new Spring().overshoot(10)
+ expect(spring.overshoot()).toBe(10)
+ })
+ })
+
+ describe('step()', () => {
+ it('calculates the new spring position', () => {
+ const spring = new Spring()
+ expect(spring.step(0, 100, 16, {})).toBeCloseTo(0.793, 3)
+ })
+
+ it('returns current if current is a string', () => {
+ const spring = new Spring()
+ expect(spring.step('Hallo', 'Welt', 16, {})).toBe('Hallo')
+ })
+
+ it('returns current if dt is 0', () => {
+ const spring = new Spring()
+ expect(spring.step(0, 100, 0, {})).toBe(0)
+ })
+
+ it('is done if dt is infinity and returns target', () => {
+ const spring = new Spring()
+ const context = {}
+ expect(spring.step(0, 100, Infinity, context)).toBe(100)
+ expect(spring.done(context)).toBe(true)
+ })
+
+ it('uses dt of 16 if it is over 100', () => {
+ const spring = new Spring()
+ expect(spring.step(0, 100, 101, {})).toBe(spring.step(0, 100, 16, {}))
+ })
+ })
+ })
+
+ describe('PID', () => {
+ describe('()', () => {
+ it('creates a PID controller with default values', () => {
+ const pid = new PID()
+ expect(pid).toEqual(any(PID))
+ expect(pid.p()).toBe(0.1)
+ expect(pid.i()).toBe(0.01)
+ expect(pid.d()).toBe(0)
+ expect(pid.windup()).toBe(1000)
+ })
+
+ it('creates a PID controller with given values', () => {
+ const pid = new PID(1, 2, 3, 4)
+ expect(pid).toEqual(any(PID))
+ expect(pid.p()).toBe(1)
+ expect(pid.i()).toBe(2)
+ expect(pid.d()).toBe(3)
+ expect(pid.windup()).toBe(4)
+ })
+ })
+
+ describe('p()', () => {
+ it('gets and sets the p parameter of the controller', () => {
+ const pid = new PID().p(100)
+ expect(pid.p()).toBe(100)
+ })
+ })
+
+ describe('i()', () => {
+ it('gets and sets the i parameter of the controller', () => {
+ const pid = new PID().i(100)
+ expect(pid.i()).toBe(100)
+ })
+ })
+
+ describe('d()', () => {
+ it('gets and sets the d parameter of the controller', () => {
+ const pid = new PID().d(100)
+ expect(pid.d()).toBe(100)
+ })
+ })
+
+ describe('windup()', () => {
+ it('gets and sets the windup parameter of the controller', () => {
+ const pid = new PID().windup(100)
+ expect(pid.windup()).toBe(100)
+ })
+ })
+
+ describe('step()', () => {
+ it('returns current if current is a string', () => {
+ const pid = new PID()
+ expect(pid.step('Hallo', 'Welt', 16, {})).toBe('Hallo')
+ })
+
+ it('returns current if dt is 0', () => {
+ const pid = new PID()
+ expect(pid.step(0, 100, 0, {})).toBe(0)
+ })
+
+ it('is done if dt is infinity and returns target', () => {
+ const pid = new PID()
+ const context = {}
+ expect(pid.step(0, 100, Infinity, context)).toBe(100)
+ expect(pid.done(context)).toBe(true)
+ })
+
+ it('caculates a new value', () => {
+ const pid = new PID()
+ expect(pid.step(0, 100, 16, {})).toBe(20)
+ })
+
+ it('uses antiwindup to restrict i power', () => {
+ const pid = new PID(0, 5, 0, 100)
+ expect(pid.step(0, 100, 1000, {})).toBe(500)
+ })
+
+ it('doesnt uses antiwindup if disabled', () => {
+ const pid = new PID(0, 5, 0, false)
+ expect(pid.step(0, 100, 1000, {})).toBe(500000)
+ })
+ })
+ })
+})
diff --git a/spec/spec/animation/Morphable.js b/spec/spec/animation/Morphable.js
index 4b0e2f1..c1f27e8 100644
--- a/spec/spec/animation/Morphable.js
+++ b/spec/spec/animation/Morphable.js
@@ -1,13 +1,27 @@
/* globals describe, expect, it, jasmine */
import { Morphable, NonMorphable, ObjectBag, Color, Box, Matrix, PointArray, PathArray, TransformBag, Number as SVGNumber, Array as SVGArray } from '../../../src/main.js'
+import { Stepper, easing, Ease } from '../../../src/animation/Controller.js'
const { objectContaining, arrayContaining, any } = jasmine
-describe('Morphable.js', function () {
- describe('constructors', function () {
+describe('Morphable.js', () => {
+ describe('()', () => {
+ it('sets a default stepper', () => {
+ const morpher = new Morphable()
+ expect(morpher.stepper().ease).toBe(easing['-'])
+ })
+
+ it('sets the passed stepper', () => {
+ const ease = new Ease()
+ const morpher = new Morphable(ease)
+ expect(morpher.stepper()).toBe(ease)
+ })
+ })
+
+ describe('constructors', () => {
- it('Morphable with SVGNumber', function () {
+ it('Morphable with SVGNumber', () => {
var morpher = new Morphable().from(10).to(5)
expect(morpher).toEqual(any(Morphable))
@@ -16,7 +30,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).valueOf()).toBe(7.5)
})
- it('Morphable with String', function () {
+ it('Morphable with String', () => {
var morpher = new Morphable().from('foo').to('bar')
expect(morpher).toEqual(any(Morphable))
@@ -26,7 +40,7 @@ describe('Morphable.js', function () {
expect(morpher.at(1).valueOf()).toBe('bar')
})
- it('Morphable with Object', function () {
+ it('Morphable with Object', () => {
var morpher = new Morphable().from({ a: 5, b: 10 }).to({ a: 10, b: 20 })
expect(morpher).toEqual(any(Morphable))
@@ -35,7 +49,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).valueOf()).toEqual(objectContaining({ a: 7.5, b: 15 }))
})
- it('Creates a morphable out of an SVGNumber', function () {
+ it('Creates a morphable out of an SVGNumber', () => {
var morpher = new SVGNumber(5).to(10)
expect(morpher).toEqual(any(Morphable))
@@ -44,7 +58,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).valueOf()).toBe(7.5)
})
- it('Creates a morphable out of an Color', function () {
+ it('Creates a morphable out of an Color', () => {
var morpher = new Color('#fff').to('#000')
expect(morpher).toEqual(any(Morphable))
@@ -53,7 +67,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).toHex()).toBe('#808080')
})
- it('Creates a morphable out of an Box', function () {
+ it('Creates a morphable out of an Box', () => {
var morpher = new Box(1, 2, 3, 4).to([ 5, 6, 7, 8 ])
expect(morpher).toEqual(any(Morphable))
@@ -62,7 +76,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5)).toEqual(objectContaining({ x: 3, y: 4, width: 5, height: 6 }))
})
- it('Creates a morphable out of an Matrix', function () {
+ it('Creates a morphable out of an Matrix', () => {
var morpher = new Matrix(1, 2, 3, 4, 5, 6).to([ 3, 4, 5, 6, 7, 8 ])
expect(morpher).toEqual(any(Morphable))
@@ -71,7 +85,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5)).toEqual(objectContaining(new Matrix(2, 3, 4, 5, 6, 7)))
})
- it('Creates a morphable out of an Array', function () {
+ it('Creates a morphable out of an SVGArray', () => {
var morpher = new SVGArray([ 1, 2, 3, 4, 5, 6 ]).to([ 3, 4, 5, 6, 7, 8 ])
expect(morpher).toEqual(any(Morphable))
@@ -80,7 +94,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 2, 3, 4, 5, 6, 7 ]))
})
- it('Creates a morphable out of an PointArray', function () {
+ it('Creates a morphable out of an PointArray', () => {
var morpher = new PointArray([ 1, 2, 3, 4, 5, 6 ]).to([ 3, 4, 5, 6, 7, 8 ])
expect(morpher).toEqual(any(Morphable))
@@ -89,7 +103,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 2, 3, 4, 5, 6, 7 ]))
})
- it('Creates a morphable out of an PathArray', function () {
+ it('Creates a morphable out of an PathArray', () => {
var morpher = new PathArray([ 'M', 1, 2, 'L', 3, 4, 'L', 5, 6 ]).to([ 'M', 3, 4, 'L', 5, 6, 'L', 7, 8 ])
expect(morpher).toEqual(any(Morphable))
@@ -98,17 +112,17 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5).toArray()).toEqual(arrayContaining([ 'M', 2, 3, 'L', 4, 5, 'L', 6, 7 ]))
})
- it('Creates a morphable out of an NonMorphable', function () {
- var morpher = new NonMorphable('foo').to('bar')
+ it('creates a morphable from unmorphable types', () => {
+ var morpher = new Morphable().from('Hallo').to('Welt')
expect(morpher).toEqual(any(Morphable))
expect(morpher.type()).toBe(NonMorphable)
expect(morpher.at(0.5)).toEqual(any(NonMorphable))
- expect(morpher.at(0.5).valueOf()).toBe('foo')
- expect(morpher.at(1).valueOf()).toBe('bar')
+ expect(morpher.at(0.5).valueOf()).toBe('Hallo')
+ expect(morpher.at(1).valueOf()).toBe('Welt')
})
- it('Creates a morphable out of an TransformBag', function () {
+ it('Creates a morphable out of an TransformBag', () => {
var morpher = new TransformBag({ rotate: 0, translateX: 0 })
.to({ rotate: 50, translateX: 20 })
@@ -119,7 +133,7 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5)).toEqual(objectContaining({ rotate: 25, translateX: 10 }))
})
- it('Creates a morphable out of an ObjectBag', function () {
+ it('Creates a morphable out of an ObjectBag', () => {
var morpher = new ObjectBag({ a: 5, b: 10 }).to({ a: 10, b: 20 })
expect(morpher).toEqual(any(Morphable))
@@ -127,41 +141,200 @@ describe('Morphable.js', function () {
expect(morpher.at(0.5)).toEqual(any(Object))
expect(morpher.at(0.5).valueOf()).toEqual(objectContaining({ a: 7.5, b: 15 }))
})
+
+ it('creates a morphable from a color string', () => {
+ var morpher = new Morphable().from('#fff').to('#000')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(Color)
+ expect(morpher.at(0.5)).toEqual(any(Color))
+ expect(morpher.at(0.5).toHex()).toBe('#808080')
+
+ morpher = new Morphable().from('rgb(255,255,255)').to('rgb(0,0,0)')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(Color)
+ expect(morpher.at(0.5)).toEqual(any(Color))
+ expect(morpher.at(0.5).toHex()).toBe('#808080')
+ })
+
+ it('creates a morphable from path string', () => {
+ var morpher = new Morphable().from('M 0 0 L 10 10').to('M 0 0 L 20 20')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(PathArray)
+ expect(morpher.at(0.5)).toEqual(any(PathArray))
+ expect(morpher.at(0.5).toString()).toBe('M0 0L15 15 ')
+ })
+
+ it('creates a morphable from number string', () => {
+ var morpher = new Morphable().from('10').to('20')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(SVGNumber)
+ expect(morpher.at(0.5)).toEqual(any(SVGNumber))
+ expect(morpher.at(0.5).toString()).toBe('15')
+
+ morpher = new Morphable().from('10px').to('20px')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(SVGNumber)
+ expect(morpher.at(0.5)).toEqual(any(SVGNumber))
+ expect(morpher.at(0.5).toString()).toBe('15px')
+ })
+
+ it('creates a morphable from delimited string', () => {
+ var morpher = new Morphable().from(' 0 1, 2 , 3 ').to('4,5,6,7')
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(SVGArray)
+ expect(morpher.at(0.5)).toEqual(any(SVGArray))
+ expect(morpher.at(0.5)).toEqual([ 2, 3, 4, 5 ])
+ })
+
+ it('creates a morphable from an array', () => {
+ var morpher = new Morphable().from([ 0, 1, 2, 3 ]).to([ 4, 5, 6, 7 ])
+
+ expect(morpher).toEqual(any(Morphable))
+ expect(morpher.type()).toBe(SVGArray)
+ expect(morpher.at(0.5)).toEqual(any(SVGArray))
+ expect(morpher.at(0.5)).toEqual([ 2, 3, 4, 5 ])
+ })
+
+ it('converts the to-color to the from-type', () => {
+ var morpher = new Color('#fff').to(new Color(1, 2, 3, 'hsl'))
+ expect(new Color(morpher.from()).space).toBe('rgb')
+ expect(morpher.at(0.5).space).toBe('rgb')
+ })
+
+ it('converts the from-color to the to-type', () => {
+ const morpher = new Morphable().to(new Color(1, 2, 3, 'hsl')).from('#fff')
+ expect(new Color(morpher.from()).space).toBe('hsl')
+ expect(morpher.at(0.5).space).toBe('hsl')
+ })
})
- describe('from()', function () {
- it('sets the type of the runner', function () {
+ describe('from()', () => {
+ it('sets the type of the runner', () => {
var morpher = new Morphable().from(5)
expect(morpher.type()).toBe(SVGNumber)
})
- it('sets the from attribute to an array representation of the morphable type', function () {
+ it('sets the from attribute to an array representation of the morphable type', () => {
var morpher = new Morphable().from(5)
expect(morpher.from()).toEqual(arrayContaining([ 5 ]))
})
})
- describe('type()', function () {
- it('sets the type of the runner', function () {
+ describe('type()', () => {
+ it('sets the type of the runner', () => {
var morpher = new Morphable().type(SVGNumber)
expect(morpher._type).toBe(SVGNumber)
})
- it('gets the type of the runner', function () {
+ it('gets the type of the runner', () => {
var morpher = new Morphable().type(SVGNumber)
expect(morpher.type()).toBe(SVGNumber)
})
})
- describe('to()', function () {
- it('sets the type of the runner', function () {
+ describe('to()', () => {
+ it('sets the type of the runner', () => {
var morpher = new Morphable().to(5)
expect(morpher.type()).toBe(SVGNumber)
})
- it('sets the from attribute to an array representation of the morphable type', function () {
+ it('sets the from attribute to an array representation of the morphable type', () => {
var morpher = new Morphable().to(5)
expect(morpher.to()).toEqual(arrayContaining([ 5 ]))
})
})
+
+ describe('stepper()', () => {
+ it('sets and gets the stepper of the Morphable', () => {
+ const stepper = new Stepper()
+ const morpher = new Morphable().stepper(stepper)
+ expect(morpher.stepper()).toBe(stepper)
+ })
+ })
+
+ describe('NonMorphable', () => {
+ describe('()', () => {
+ it('wraps any type into a NonMorphable from an array', () => {
+ const non = new NonMorphable([ 5 ])
+ expect(non.valueOf()).toBe(5)
+ })
+
+ it('wraps any type into a NonMorphable from any type', () => {
+ expect(new NonMorphable(5).valueOf()).toBe(5)
+ expect(new NonMorphable('Hello').valueOf()).toBe('Hello')
+ })
+ })
+
+ describe('toArray()', () => {
+ it('returns array representation of NonMorphable', () => {
+ expect(new NonMorphable(5).toArray()).toEqual([ 5 ])
+ expect(new NonMorphable('Hello').toArray()).toEqual([ 'Hello' ])
+ })
+ })
+ })
+
+ describe('TransformBag', () => {
+ describe('()', () => {
+ it('creates an object which holds transformations for morphing by passing array', () => {
+ const bag = new TransformBag([ 0, 1, 2, 3, 4, 5, 6, 7 ])
+ expect(bag.toArray()).toEqual([ 0, 1, 2, 3, 4, 5, 6, 7 ])
+ })
+
+ it('creates an object which holds transformations for morphing by passing object', () => {
+ const bag = new TransformBag({
+ scaleX: 0,
+ scaleY: 1,
+ shear: 2,
+ rotate: 3,
+ translateX: 4,
+ translateY: 5,
+ originX: 6,
+ originY: 7
+ })
+
+ expect(bag.toArray()).toEqual([ 0, 1, 2, 3, 4, 5, 6, 7 ])
+ })
+ })
+
+ describe('toArray()', () => {
+ it('creates an array out of the transform values', () => {
+ const bag = new TransformBag([ 0, 1, 2, 3, 4, 5, 6, 7 ])
+ expect(bag.toArray()).toEqual([ 0, 1, 2, 3, 4, 5, 6, 7 ])
+ })
+ })
+ })
+
+ describe('ObjectBag', () => {
+ describe('()', () => {
+ it('wraps an object into a morphable object by passing an array', () => {
+ const bag = new ObjectBag([ 'foo', 1, 'bar', 2, 'baz', 3 ])
+ expect(bag.values).toEqual([ 'foo', 1, 'bar', 2, 'baz', 3 ])
+ })
+
+ it('wraps an object into a morphable object by passing an object', () => {
+ const bag = new ObjectBag({ foo: 1, bar: 2, baz: 3 })
+ expect(bag.values).toEqual([ 'bar', 2, 'baz', 3, 'foo', 1 ])
+ })
+ })
+
+ describe('toArray()', () => {
+ it('creates an array out of the object', () => {
+ const bag = new ObjectBag({ foo: 1, bar: 2, baz: 3 })
+ expect(bag.toArray()).toEqual([ 'bar', 2, 'baz', 3, 'foo', 1 ])
+ })
+ })
+
+ describe('valueOf()', () => {
+ it('create an object from the stored values', () => {
+ const bag = new ObjectBag({ foo: 1, bar: 2, baz: 3 })
+ expect(bag.valueOf()).toEqual({ foo: 1, bar: 2, baz: 3 })
+ })
+ })
+ })
})
diff --git a/spec/spec/animation/Queue.js b/spec/spec/animation/Queue.js
index 4282bf9..8386405 100644
--- a/spec/spec/animation/Queue.js
+++ b/spec/spec/animation/Queue.js
@@ -47,6 +47,18 @@ describe('Queue.js', function () {
expect(queue.first()).toBe(1)
expect(queue.last()).toBe(3)
})
+
+ it('adds an item to the end of the queue', function () {
+ var queue = new Queue()
+ queue.push(1)
+ const item = queue.push(2)
+ queue.push(3)
+ queue.remove(item)
+ queue.push(item)
+
+ expect(queue.first()).toBe(1)
+ expect(queue.last()).toBe(2)
+ })
})
describe('remove ()', function () {
@@ -61,6 +73,18 @@ describe('Queue.js', function () {
expect(queue.last()).toBe(2)
expect(queue.first()).toBe(1)
})
+
+ it('removes the given item from the queue', function () {
+ var queue = new Queue()
+ var item = queue.push(1)
+ queue.push(2)
+ queue.push(3)
+
+ queue.remove(item)
+
+ expect(queue.last()).toBe(3)
+ expect(queue.first()).toBe(2)
+ })
})
describe('shift ()', function () {
diff --git a/spec/spec/animation/Timeline.js b/spec/spec/animation/Timeline.js
index 1acc663..f23e620 100644
--- a/spec/spec/animation/Timeline.js
+++ b/spec/spec/animation/Timeline.js
@@ -1,14 +1,204 @@
-/* globals describe, expect, it, beforeEach, container */
+/* globals describe, expect, it, beforeEach, afterEach, spyOn, container, jasmine */
-import { Timeline, SVG } from '../../../src/main.js'
+import { Timeline, SVG, Runner, Animator, Queue, Rect } from '../../../src/main.js'
+import { getWindow } from '../../../src/utils/window.js'
+
+const { createSpy, any } = jasmine
describe('Timeline.js', () => {
+ beforeEach(() => {
+ jasmine.RequestAnimationFrame.install(getWindow())
+ Animator.timeouts = new Queue()
+ Animator.frames = new Queue()
+ Animator.immediates = new Queue()
+ Animator.nextDraw = null
+ })
+
+ afterEach(() => {
+ getWindow().cancelAnimationFrame(Animator.nextDraw)
+ jasmine.RequestAnimationFrame.uninstall(getWindow())
+ })
+
+ describe('()', () => {
+ it('creates a new Timeline with a default timesource', () => {
+ const timeline = new Timeline()
+ expect(timeline.source()).toEqual(any(Function))
+ })
+
+ it('creates a new Timeline with the passed timesource', () => {
+ const source = createSpy()
+ const timeline = new Timeline(source)
+ expect(timeline.source()).toBe(source)
+ })
+ })
+
+ describe('schedule()', () => {
+ it('schedules a runner at the start of the queue with a default delay of 0', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner)
+ expect(timeline._runners[0].start).toEqual(0)
+ })
+
+ it('sets a reference of the timeline to the runner', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner)
+ expect(runner.timeline()).toBe(timeline)
+ })
+
+ it('schedules after when no when is past', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ timeline.schedule(runner)
+ expect(timeline._runners[1].start).toBe(1000)
+ })
+
+ it('schedules after when when is last', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'last')
+ expect(timeline._runners[1].start).toBe(1000)
+ })
+
+ it('schedules after when when is after', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'after')
+ expect(timeline._runners[1].start).toBe(1000)
+ })
+
+ it('starts the animation right away when there is no runner to schedule after and when is after', () => {
+ const timeline = new Timeline().time(100)
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'after')
+ expect(timeline._runners[0].start).toBe(100)
+ })
+
+ it('schedules with start of the last runner when when is with-last', () => {
+ const timeline = new Timeline().schedule(new Runner(1000), 200)
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'with-last')
+ expect(timeline._runners[1].start).toBe(200)
+ })
+
+ it('starts the animation right away when there is no runner to schedule after and when is after', () => {
+ const timeline = new Timeline().time(100)
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'with-last')
+ expect(timeline._runners[0].start).toBe(100)
+ })
+
+ it('respects passed delay', () => {
+ const timeline = new Timeline().schedule(new Runner(1000), 1000)
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'after')
+ expect(timeline._runners[1].start).toBe(2000)
+ })
+
+ it('schedules the runner absolutely with absolute', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'absolute')
+ expect(timeline._runners[1].start).toBe(0)
+ })
+
+ it('schedules the runner absolutely with start', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 0, 'start')
+ expect(timeline._runners[1].start).toBe(0)
+ })
+
+ it('schedules the runner relatively to old start with relative', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 100).schedule(runner, 100, 'relative')
+ expect(timeline._runners[0].start).toBe(200)
+ })
+
+ it('schedules the runner as absolute if this runner wasnt on the timeline', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 100, 'relative')
+ expect(timeline._runners[0].start).toBe(100)
+ })
+
+ it('throws if when is not supported', () => {
+ const timeline = new Timeline().schedule(new Runner(1000), 1000)
+ const runner = new Runner(1000)
+ expect(() => timeline.schedule(runner, 0, 'not supported')).toThrowError('Invalid value for the "when" parameter')
+ })
+
+ it('uses persist value of the runner of present', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000).persist(100)
+ timeline.schedule(runner)
+ expect(timeline._runners[0].persist).toBe(100)
+ })
+ })
+
+ describe('unschedule()', () => {
+ it('removes a runner from the timeline', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner).unschedule(runner)
+ expect(runner.timeline()).toBe(null)
+ expect(timeline._runners).toEqual([])
+ })
+ })
+
+ describe('getRunnerInfoById()', () => {
+ it('gets a runner by its id from the timeline', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ expect(timeline.schedule(runner).getRunnerInfoById(runner.id).runner).toBe(runner)
+ })
+
+ it('returns null of runner not found', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ expect(timeline.getRunnerInfoById(runner.id)).toBe(null)
+ })
+ })
+
+ describe('getLastRunnerInfo()', () => {
+ it('gets a runner by its id from the timeline', () => {
+ const timeline = new Timeline().schedule(new Runner(1000))
+ const runner = new Runner(1000)
+ expect(timeline.schedule(runner).getLastRunnerInfo().runner).toBe(runner)
+ })
+ })
+
+ describe('getEndTime()', () => {
+ it('returns the end time of the runner which started last', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ const runner2 = new Runner(100)
+ timeline.schedule(runner).schedule(runner2, 500, 'start')
+ expect(timeline.getEndTime()).toBe(600)
+ })
+
+ it('returns the timeline time if no runner is scheduled', () => {
+ const timeline = new Timeline().time(100)
+ expect(timeline.getEndTime()).toBe(100)
+ })
+ })
+
describe('getEndTimeOfTimeline', () => {
it('returns 0 if no runners are scheduled', () => {
const timeline = new Timeline()
const endTime = timeline.getEndTimeOfTimeline()
expect(endTime).toEqual(0)
})
+
+ it('returns the time all runners are finished', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ const runner2 = new Runner(100)
+ timeline.schedule(runner).schedule(runner2, 500, 'start')
+ expect(timeline.getEndTimeOfTimeline()).toBe(1000)
+ })
})
describe('finish - issue #964', () => {
@@ -114,4 +304,192 @@ describe('Timeline.js', () => {
expect(rect3.y()).toEqual(200)
})
})
+
+ describe('updateTime()', () => {
+ it('sets the time to the current time', () => {
+ const timeline = new Timeline(() => 200).play()
+ expect(timeline._lastSourceTime).toBe(200)
+ })
+ })
+
+ describe('stop()', () => {
+ it('sets the time to 0 and pauses the timeline', () => {
+ const timeline = new Timeline().time(100)
+ expect(timeline.stop().time()).toBe(0)
+ expect(timeline._paused).toBe(true)
+ })
+ })
+
+ describe('speed()', () => {
+ it('gets or sets the speed of the timeline', () => {
+ const timeline = new Timeline().speed(2)
+ expect(timeline.speed()).toBe(2)
+ })
+ })
+
+ describe('reverse()', () => {
+ it('reverses the timeline with no parameter given', () => {
+ const timeline = new Timeline().speed(2)
+ const spy = spyOn(timeline, 'speed').and.callThrough()
+ timeline.reverse()
+ expect(spy).toHaveBeenCalledWith(-2)
+ timeline.reverse()
+ expect(spy).toHaveBeenCalledWith(2)
+ })
+
+ it('reverses the timeline when true was passed', () => {
+ const timeline = new Timeline().speed(2)
+ const spy = spyOn(timeline, 'speed').and.callThrough()
+ timeline.reverse(true)
+ expect(spy).toHaveBeenCalledWith(-2)
+ })
+
+ it('plays normal direction when false was passed', () => {
+ const timeline = new Timeline().speed(-2)
+ const spy = spyOn(timeline, 'speed').and.callThrough()
+ timeline.reverse(false)
+ expect(spy).toHaveBeenCalledWith(2)
+ })
+ })
+
+ describe('seek()', () => {
+ it('seeks the time by a given delta', () => {
+ const timeline = new Timeline().time(100).seek(200)
+ expect(timeline.time()).toBe(300)
+ })
+ })
+
+ describe('time()', () => {
+ it('gets and sets the current time of the timeline', () => {
+ const timeline = new Timeline().time(100)
+ expect(timeline.time()).toBe(100)
+ })
+ })
+
+ describe('persist()', () => {
+ it('gets and sets the persist property of the timeline', () => {
+ const timeline = new Timeline().persist(true)
+ expect(timeline.persist()).toBe(true)
+ })
+ })
+
+ describe('source()', () => {
+ it('gets or sets the time source of the timeline', () => {
+ const source = () => 200
+ const timeline = new Timeline().source(source)
+ expect(timeline.source()).toBe(source)
+ })
+ })
+
+ describe('_stepFn', () => {
+ it('does a step in the timeline and runs all runners', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(16)
+ expect(runner.time()).toBe(16)
+ })
+
+ it('doenst run runners which start later', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner, 100).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(16)
+ expect(runner.time()).toBe(0)
+ })
+
+ it('reset runner if timeline was seeked backwards', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner)
+ const spy = spyOn(runner, 'reset').and.callThrough()
+ jasmine.RequestAnimationFrame.tick(1000)
+ timeline.seek(-1000)
+ expect(runner.time()).toBe(0)
+ expect(spy).toHaveBeenCalled()
+ })
+
+ it('doesnt run runners if they are not active', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000).active(false)
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(16)
+ expect(runner.time()).toBe(0)
+ })
+
+ it('unschedules runner if its finished', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000)
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1000)
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(runner.time()).toBe(1001)
+ expect(timeline.getRunnerInfoById(runner.id)).toBe(null)
+ })
+
+ it('does not unschedule if runner is persistent forever', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000).persist(true)
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1000)
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(runner.time()).toBe(1001)
+ expect(timeline.getRunnerInfoById(runner.id)).not.toBe(null)
+ })
+
+ it('does not unschedule if runner is persistent for a certain time', () => {
+ const timeline = new Timeline()
+ const runner = new Runner(1000).persist(100)
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1000)
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(runner.time()).toBe(1001)
+ expect(timeline.getRunnerInfoById(runner.id)).not.toBe(null)
+ })
+
+ it('fires finish if no runners left', () => {
+ const spy = createSpy()
+ const timeline = new Timeline().on('finished', spy)
+ const runner = new Runner(1000)
+ spy.calls.reset()
+ timeline.schedule(runner).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1000)
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(spy).toHaveBeenCalled()
+ })
+
+ it('continues if there are still runners left from us when going back in time', () => {
+ const spy = createSpy()
+ const timeline = new Timeline().on('finished', spy).time(1200).reverse(true)
+ const runner = new Runner(1000)
+ spy.calls.reset()
+ timeline.schedule(runner, 0).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(spy).not.toHaveBeenCalled()
+ })
+
+ it('finishes if time is backwards and 0', () => {
+ const spy = createSpy()
+ const timeline = new Timeline().on('finished', spy).reverse(true)
+ const runner = new Runner(1000)
+ spy.calls.reset()
+ timeline.schedule(runner, 0).play() // we have to play because its syncronous here
+ jasmine.RequestAnimationFrame.tick(1)
+ expect(spy).toHaveBeenCalled()
+ })
+ })
+
+ describe('Element', () => {
+ describe('timeline()', () => {
+ it('sets and gets the timeline of the element', () => {
+ const timeline = new Timeline()
+ const rect = new Rect().timeline(timeline)
+ expect(rect.timeline()).toBe(timeline)
+ })
+
+ it('creates a timeline on the fly when getting it', () => {
+ expect(new Rect().timeline()).toEqual(any(Timeline))
+ })
+ })
+ })
})
diff --git a/spec/spec/animation/easing.js b/spec/spec/animation/easing.js
deleted file mode 100644
index ab9f51c..0000000
--- a/spec/spec/animation/easing.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* globals describe, expect, it */
-
-import { easing } from '../../../src/main.js'
-
-describe('easing', () => {
- var easedValues = {
- '-': 0.5,
- '<>': 0.5,
- '>': 0.7071,
- '<': 0.2929
- }
-
- ;[ '-', '<>', '<', '>' ].forEach((el) => {
- describe(el, () => {
- it('is 0 at 0', () => {
- expect(easing[el](0)).toBe(0)
- })
- it('is 1 at 1', () => {
- expect(Math.round(easing[el](1) * 1000) / 1000).toBe(1) // we need to round cause for some reason at some point 1==0.999999999
- })
- it('is eased at 0.5', () => {
- expect(easing[el](0.5)).toBeCloseTo(easedValues[el])
- })
- })
- })
-})