2015-03-26 06:43:41 +02:00
|
|
|
import Component from '../../src/js/component.js';
|
2015-05-04 01:12:38 +02:00
|
|
|
import * as Dom from '../../src/js/utils/dom.js';
|
|
|
|
import * as Events from '../../src/js/utils/events.js';
|
|
|
|
import * as browser from '../../src/js/utils/browser.js';
|
2015-03-26 06:43:41 +02:00
|
|
|
import document from 'global/document';
|
2015-05-17 00:59:46 +02:00
|
|
|
import TestHelpers from './test-helpers.js';
|
2015-03-26 06:43:41 +02:00
|
|
|
|
2015-11-06 23:42:19 +02:00
|
|
|
class TestComponent1 extends Component {}
|
|
|
|
class TestComponent2 extends Component {}
|
|
|
|
class TestComponent3 extends Component {}
|
|
|
|
class TestComponent4 extends Component {}
|
|
|
|
TestComponent1.prototype.options_ = {
|
|
|
|
children: [
|
|
|
|
'testComponent2',
|
|
|
|
'testComponent3'
|
|
|
|
]
|
|
|
|
};
|
|
|
|
Component.registerComponent('TestComponent1', TestComponent1);
|
|
|
|
Component.registerComponent('TestComponent2', TestComponent2);
|
|
|
|
Component.registerComponent('TestComponent3', TestComponent3);
|
|
|
|
Component.registerComponent('TestComponent4', TestComponent4);
|
|
|
|
|
2015-03-26 06:43:41 +02:00
|
|
|
q.module('Component', {
|
2014-12-03 21:31:39 +02:00
|
|
|
'setup': function() {
|
|
|
|
this.clock = sinon.useFakeTimers();
|
|
|
|
},
|
|
|
|
'teardown': function() {
|
|
|
|
this.clock.restore();
|
|
|
|
}
|
|
|
|
});
|
2012-12-11 03:40:12 +03:00
|
|
|
|
2013-01-18 04:33:53 +03:00
|
|
|
var getFakePlayer = function(){
|
|
|
|
return {
|
|
|
|
// Fake player requries an ID
|
2014-02-07 03:54:35 +03:00
|
|
|
id: function(){ return 'player_1'; },
|
|
|
|
reportUserActivity: function(){}
|
2013-02-09 01:14:36 +03:00
|
|
|
};
|
2013-01-18 04:33:53 +03:00
|
|
|
};
|
|
|
|
|
2012-12-11 03:40:12 +03:00
|
|
|
test('should create an element', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2012-12-11 03:40:12 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(comp.el().nodeName);
|
2012-12-11 03:40:12 +03:00
|
|
|
});
|
|
|
|
|
2012-12-31 08:45:50 +03:00
|
|
|
test('should add a child component', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer());
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2013-02-09 01:14:36 +03:00
|
|
|
var child = comp.addChild('component');
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(comp.children().length === 1);
|
|
|
|
ok(comp.children()[0] === child);
|
|
|
|
ok(comp.el().childNodes[0] === child.el());
|
|
|
|
ok(comp.getChild('component') === child);
|
|
|
|
ok(comp.getChildById(child.id()) === child);
|
2012-12-31 08:45:50 +03:00
|
|
|
});
|
|
|
|
|
2016-02-04 20:42:49 +02:00
|
|
|
test('should add a child component to an index', function(){
|
|
|
|
var comp = new Component(getFakePlayer());
|
|
|
|
|
|
|
|
var child = comp.addChild('component');
|
|
|
|
|
|
|
|
ok(comp.children().length === 1);
|
|
|
|
ok(comp.children()[0] === child);
|
|
|
|
|
|
|
|
var child0 = comp.addChild('component', {}, 0);
|
|
|
|
ok(comp.children().length === 2);
|
|
|
|
ok(comp.children()[0] === child0);
|
|
|
|
ok(comp.children()[1] === child);
|
|
|
|
|
|
|
|
var child1 = comp.addChild('component', {}, '2');
|
|
|
|
ok(comp.children().length === 3);
|
|
|
|
ok(comp.children()[2] === child1);
|
|
|
|
|
|
|
|
var child2 = comp.addChild('component', {}, undefined);
|
|
|
|
ok(comp.children().length === 4);
|
|
|
|
ok(comp.children()[3] === child2);
|
|
|
|
|
|
|
|
var child3 = comp.addChild('component', {}, -1);
|
|
|
|
ok(comp.children().length === 5);
|
|
|
|
ok(comp.children()[3] === child3);
|
|
|
|
ok(comp.children()[4] === child2);
|
|
|
|
});
|
|
|
|
|
2015-11-06 23:42:19 +02:00
|
|
|
test('addChild should throw if the child does not exist', function() {
|
|
|
|
var comp = new Component(getFakePlayer());
|
|
|
|
|
|
|
|
throws(function() {
|
2016-02-04 20:42:49 +02:00
|
|
|
comp.addChild('non-existent-child');
|
2015-11-06 23:42:19 +02:00
|
|
|
}, new Error('Component Non-existent-child does not exist'), 'addChild threw');
|
2016-02-04 20:42:49 +02:00
|
|
|
|
2015-11-06 23:42:19 +02:00
|
|
|
});
|
|
|
|
|
2016-02-04 20:42:49 +02:00
|
|
|
|
2014-03-18 22:49:59 +03:00
|
|
|
test('should init child components from options', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {
|
2013-01-11 00:06:12 +03:00
|
|
|
children: {
|
2015-04-23 00:26:37 +02:00
|
|
|
'component': {}
|
2013-01-11 00:06:12 +03:00
|
|
|
}
|
|
|
|
});
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(comp.children().length === 1);
|
|
|
|
ok(comp.el().childNodes.length === 1);
|
|
|
|
});
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2014-03-18 22:49:59 +03:00
|
|
|
test('should init child components from simple children array', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {
|
2014-03-18 22:49:59 +03:00
|
|
|
children: [
|
|
|
|
'component',
|
|
|
|
'component',
|
|
|
|
'component'
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
ok(comp.children().length === 3);
|
|
|
|
ok(comp.el().childNodes.length === 3);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should init child components from children array of objects', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {
|
2014-03-18 22:49:59 +03:00
|
|
|
children: [
|
2014-05-06 03:11:14 +03:00
|
|
|
{ 'name': 'component' },
|
|
|
|
{ 'name': 'component' },
|
|
|
|
{ 'name': 'component' }
|
2014-03-18 22:49:59 +03:00
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
ok(comp.children().length === 3);
|
|
|
|
ok(comp.el().childNodes.length === 3);
|
|
|
|
});
|
|
|
|
|
2013-01-16 19:09:56 +03:00
|
|
|
test('should do a deep merge of child options', function(){
|
2013-01-26 04:36:40 +03:00
|
|
|
// Create a default option for component
|
2015-03-11 03:01:11 +02:00
|
|
|
Component.prototype.options_ = {
|
2013-01-26 04:36:40 +03:00
|
|
|
'example': {
|
2013-01-16 19:09:56 +03:00
|
|
|
'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
|
|
|
|
'childTwo': {},
|
|
|
|
'childThree': {}
|
|
|
|
}
|
2013-02-09 01:14:36 +03:00
|
|
|
};
|
2013-01-16 19:09:56 +03:00
|
|
|
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {
|
2013-01-26 04:36:40 +03:00
|
|
|
'example': {
|
2013-01-16 19:09:56 +03:00
|
|
|
'childOne': { 'foo': 'baz', 'abc': '123' },
|
2014-10-30 22:18:18 +02:00
|
|
|
'childThree': false,
|
2013-01-16 19:09:56 +03:00
|
|
|
'childFour': {}
|
|
|
|
}
|
2013-01-26 04:36:40 +03:00
|
|
|
});
|
2013-01-16 19:09:56 +03:00
|
|
|
|
2015-06-05 02:33:34 +02:00
|
|
|
var mergedOptions = comp.options_;
|
2013-01-26 04:36:40 +03:00
|
|
|
var children = mergedOptions['example'];
|
2013-01-16 19:09:56 +03:00
|
|
|
|
2015-05-17 00:59:46 +02:00
|
|
|
strictEqual(children['childOne']['foo'], 'baz', 'value three levels deep overridden');
|
|
|
|
strictEqual(children['childOne']['asdf'], 'fdsa', 'value three levels deep maintained');
|
|
|
|
strictEqual(children['childOne']['abc'], '123', 'value three levels deep added');
|
2013-01-16 19:09:56 +03:00
|
|
|
ok(children['childTwo'], 'object two levels deep maintained');
|
2015-05-17 00:59:46 +02:00
|
|
|
strictEqual(children['childThree'], false, 'object two levels deep removed');
|
2013-01-16 19:09:56 +03:00
|
|
|
ok(children['childFour'], 'object two levels deep added');
|
2013-01-26 04:36:40 +03:00
|
|
|
|
2015-05-17 00:59:46 +02:00
|
|
|
strictEqual(Component.prototype.options_['example']['childOne']['foo'], 'bar', 'prototype options were not overridden');
|
2013-01-26 04:36:40 +03:00
|
|
|
|
|
|
|
// Reset default component options to none
|
2015-03-11 03:01:11 +02:00
|
|
|
Component.prototype.options_ = null;
|
2013-01-16 19:09:56 +03:00
|
|
|
});
|
|
|
|
|
2015-11-06 23:42:19 +02:00
|
|
|
test('should init child components from component options', function(){
|
|
|
|
let testComp = new TestComponent1(TestHelpers.makePlayer(), {
|
|
|
|
testComponent2: false,
|
|
|
|
testComponent4: {}
|
|
|
|
});
|
|
|
|
|
|
|
|
ok(!testComp.childNameIndex_.testComponent2, 'we do not have testComponent2');
|
|
|
|
ok(testComp.childNameIndex_.testComponent4, 'we have a testComponent4');
|
|
|
|
});
|
|
|
|
|
2014-10-28 20:45:32 +02:00
|
|
|
test('should allows setting child options at the parent options level', function(){
|
2014-10-30 22:18:18 +02:00
|
|
|
var parent, options;
|
2014-10-28 20:45:32 +02:00
|
|
|
|
2014-10-30 22:18:18 +02:00
|
|
|
// using children array
|
|
|
|
options = {
|
2014-10-28 20:45:32 +02:00
|
|
|
'children': [
|
2014-10-30 22:18:18 +02:00
|
|
|
'component',
|
|
|
|
'nullComponent'
|
2014-10-28 20:45:32 +02:00
|
|
|
],
|
|
|
|
// parent-level option for child
|
|
|
|
'component': {
|
|
|
|
'foo': true
|
2014-10-30 22:18:18 +02:00
|
|
|
},
|
|
|
|
'nullComponent': false
|
|
|
|
};
|
2014-10-28 20:45:32 +02:00
|
|
|
|
2014-10-30 22:18:18 +02:00
|
|
|
try {
|
2015-03-11 03:01:11 +02:00
|
|
|
parent = new Component(getFakePlayer(), options);
|
2014-10-30 22:18:18 +02:00
|
|
|
} catch(err) {
|
|
|
|
ok(false, 'Child with `false` option was initialized');
|
|
|
|
}
|
2015-06-05 02:33:34 +02:00
|
|
|
equal(parent.children()[0].options_['foo'], true, 'child options set when children array is used');
|
2015-11-06 23:42:19 +02:00
|
|
|
equal(parent.children().length, 1, 'we should only have one child');
|
2014-10-28 20:45:32 +02:00
|
|
|
|
2014-10-30 22:18:18 +02:00
|
|
|
// using children object
|
|
|
|
options = {
|
2014-10-28 20:45:32 +02:00
|
|
|
'children': {
|
|
|
|
'component': {
|
|
|
|
'foo': false
|
2014-10-30 22:18:18 +02:00
|
|
|
},
|
|
|
|
'nullComponent': {}
|
2014-10-28 20:45:32 +02:00
|
|
|
},
|
|
|
|
// parent-level option for child
|
|
|
|
'component': {
|
|
|
|
'foo': true
|
2014-10-30 22:18:18 +02:00
|
|
|
},
|
|
|
|
'nullComponent': false
|
|
|
|
};
|
2014-10-28 20:45:32 +02:00
|
|
|
|
2014-10-30 22:18:18 +02:00
|
|
|
try {
|
2015-03-11 03:01:11 +02:00
|
|
|
parent = new Component(getFakePlayer(), options);
|
2014-10-30 22:18:18 +02:00
|
|
|
} catch(err) {
|
|
|
|
ok(false, 'Child with `false` option was initialized');
|
|
|
|
}
|
2015-06-05 02:33:34 +02:00
|
|
|
equal(parent.children()[0].options_['foo'], true, 'child options set when children object is used');
|
2015-11-06 23:42:19 +02:00
|
|
|
equal(parent.children().length, 1, 'we should only have one child');
|
2014-10-28 20:45:32 +02:00
|
|
|
});
|
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
test('should dispose of component and children', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer());
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
// Add a child
|
2013-02-09 01:14:36 +03:00
|
|
|
var child = comp.addChild('Component');
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(comp.children().length === 1);
|
2012-12-31 08:45:50 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
// Add a listener
|
|
|
|
comp.on('click', function(){ return true; });
|
2015-05-17 00:59:46 +02:00
|
|
|
var el = comp.el();
|
|
|
|
var data = Dom.getElData(el);
|
2012-12-11 03:40:12 +03:00
|
|
|
|
2013-07-19 00:39:14 +03:00
|
|
|
var hasDisposed = false;
|
2014-02-07 04:11:33 +03:00
|
|
|
var bubbles = null;
|
|
|
|
comp.on('dispose', function(event){
|
|
|
|
hasDisposed = true;
|
|
|
|
bubbles = event.bubbles;
|
|
|
|
});
|
2013-07-19 00:39:14 +03:00
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
comp.dispose();
|
2012-12-11 03:40:12 +03:00
|
|
|
|
2013-07-19 00:39:14 +03:00
|
|
|
ok(hasDisposed, 'component fired dispose event');
|
2014-02-07 04:11:33 +03:00
|
|
|
ok(bubbles === false, 'dispose event does not bubble');
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(!comp.children(), 'component children were deleted');
|
|
|
|
ok(!comp.el(), 'component element was deleted');
|
|
|
|
ok(!child.children(), 'child children were deleted');
|
|
|
|
ok(!child.el(), 'child element was deleted');
|
2015-05-17 00:59:46 +02:00
|
|
|
ok(!Dom.hasElData(el), 'listener data nulled');
|
|
|
|
ok(!Object.getOwnPropertyNames(data).length, 'original listener data object was emptied');
|
2012-12-11 03:40:12 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should add and remove event listeners to element', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2012-12-11 03:40:12 +03:00
|
|
|
|
|
|
|
// No need to make this async because we're triggering events inline.
|
|
|
|
// We're going to trigger the event after removing the listener,
|
|
|
|
// So if we get extra asserts that's a problem.
|
2013-01-11 00:06:12 +03:00
|
|
|
expect(2);
|
2012-12-11 03:40:12 +03:00
|
|
|
|
|
|
|
var testListener = function(){
|
|
|
|
ok(true, 'fired event once');
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(this === comp, 'listener has the component as context');
|
2012-12-11 03:40:12 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
comp.on('test-event', testListener);
|
|
|
|
comp.trigger('test-event');
|
|
|
|
comp.off('test-event', testListener);
|
|
|
|
comp.trigger('test-event');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should trigger a listener once using one()', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2012-12-11 03:40:12 +03:00
|
|
|
|
|
|
|
expect(1);
|
|
|
|
|
|
|
|
var testListener = function(){
|
|
|
|
ok(true, 'fired event once');
|
|
|
|
};
|
|
|
|
|
|
|
|
comp.one('test-event', testListener);
|
|
|
|
comp.trigger('test-event');
|
|
|
|
comp.trigger('test-event');
|
2012-12-31 08:45:50 +03:00
|
|
|
});
|
2013-01-11 00:06:12 +03:00
|
|
|
|
2015-06-05 19:36:59 +02:00
|
|
|
test('should be possible to pass data when you trigger an event', function () {
|
|
|
|
var comp = new Component(getFakePlayer(), {});
|
|
|
|
var data1 = 'Data1';
|
|
|
|
var data2 = {txt: 'Data2'};
|
|
|
|
expect(3);
|
|
|
|
|
|
|
|
var testListener = function(evt, hash){
|
|
|
|
ok(true, 'fired event once');
|
|
|
|
deepEqual(hash.d1, data1);
|
|
|
|
deepEqual(hash.d2, data2);
|
|
|
|
};
|
|
|
|
|
|
|
|
comp.one('test-event', testListener);
|
|
|
|
comp.trigger('test-event', {d1: data1, d2: data2});
|
|
|
|
comp.trigger('test-event');
|
|
|
|
});
|
|
|
|
|
2014-10-28 20:16:56 +02:00
|
|
|
test('should add listeners to other components and remove them', function(){
|
|
|
|
var player = getFakePlayer(),
|
2015-03-11 03:01:11 +02:00
|
|
|
comp1 = new Component(player),
|
|
|
|
comp2 = new Component(player),
|
2014-10-28 20:16:56 +02:00
|
|
|
listenerFired = 0,
|
|
|
|
testListener;
|
|
|
|
|
|
|
|
testListener = function(){
|
|
|
|
equal(this, comp1, 'listener has the first component as context');
|
|
|
|
listenerFired++;
|
|
|
|
};
|
|
|
|
|
|
|
|
comp1.on(comp2, 'test-event', testListener);
|
|
|
|
comp2.trigger('test-event');
|
|
|
|
equal(listenerFired, 1, 'listener was fired once');
|
|
|
|
|
|
|
|
listenerFired = 0;
|
|
|
|
comp1.off(comp2, 'test-event', testListener);
|
|
|
|
comp2.trigger('test-event');
|
|
|
|
equal(listenerFired, 0, 'listener was not fired after being removed');
|
|
|
|
|
|
|
|
// this component is disposed first
|
|
|
|
listenerFired = 0;
|
|
|
|
comp1.on(comp2, 'test-event', testListener);
|
|
|
|
comp1.dispose();
|
|
|
|
comp2.trigger('test-event');
|
|
|
|
equal(listenerFired, 0, 'listener was removed when this component was disposed first');
|
|
|
|
comp1.off = function(){ throw 'Comp1 off called'; };
|
|
|
|
comp2.dispose();
|
|
|
|
ok(true, 'this component removed dispose listeners from other component');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should add listeners to other components and remove when them other component is disposed', function(){
|
|
|
|
var player = getFakePlayer(),
|
2015-03-11 03:01:11 +02:00
|
|
|
comp1 = new Component(player),
|
|
|
|
comp2 = new Component(player),
|
2014-10-28 20:16:56 +02:00
|
|
|
listenerFired = 0,
|
|
|
|
testListener;
|
|
|
|
|
|
|
|
testListener = function(){
|
|
|
|
equal(this, comp1, 'listener has the first component as context');
|
|
|
|
listenerFired++;
|
|
|
|
};
|
|
|
|
|
|
|
|
comp1.on(comp2, 'test-event', testListener);
|
|
|
|
comp2.dispose();
|
|
|
|
comp2.off = function(){ throw 'Comp2 off called'; };
|
|
|
|
comp1.dispose();
|
|
|
|
ok(true, 'this component removed dispose listener from this component that referenced other component');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should add listeners to other components that are fired once', function(){
|
|
|
|
var player = getFakePlayer(),
|
2015-03-11 03:01:11 +02:00
|
|
|
comp1 = new Component(player),
|
|
|
|
comp2 = new Component(player),
|
2014-10-28 20:16:56 +02:00
|
|
|
listenerFired = 0,
|
|
|
|
testListener;
|
|
|
|
|
|
|
|
testListener = function(){
|
|
|
|
equal(this, comp1, 'listener has the first component as context');
|
|
|
|
listenerFired++;
|
|
|
|
};
|
|
|
|
|
|
|
|
comp1.one(comp2, 'test-event', testListener);
|
|
|
|
comp2.trigger('test-event');
|
|
|
|
equal(listenerFired, 1, 'listener was executed once');
|
|
|
|
comp2.trigger('test-event');
|
|
|
|
equal(listenerFired, 1, 'listener was executed only once');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should add listeners to other element and remove them', function(){
|
|
|
|
var player = getFakePlayer(),
|
2015-03-11 03:01:11 +02:00
|
|
|
comp1 = new Component(player),
|
2014-10-28 20:16:56 +02:00
|
|
|
el = document.createElement('div'),
|
|
|
|
listenerFired = 0,
|
|
|
|
testListener;
|
|
|
|
|
|
|
|
testListener = function(){
|
|
|
|
equal(this, comp1, 'listener has the first component as context');
|
|
|
|
listenerFired++;
|
|
|
|
};
|
|
|
|
|
|
|
|
comp1.on(el, 'test-event', testListener);
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'test-event');
|
2014-10-28 20:16:56 +02:00
|
|
|
equal(listenerFired, 1, 'listener was fired once');
|
|
|
|
|
|
|
|
listenerFired = 0;
|
|
|
|
comp1.off(el, 'test-event', testListener);
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'test-event');
|
2014-10-28 20:16:56 +02:00
|
|
|
equal(listenerFired, 0, 'listener was not fired after being removed from other element');
|
|
|
|
|
|
|
|
// this component is disposed first
|
|
|
|
listenerFired = 0;
|
|
|
|
comp1.on(el, 'test-event', testListener);
|
|
|
|
comp1.dispose();
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'test-event');
|
2014-10-28 20:16:56 +02:00
|
|
|
equal(listenerFired, 0, 'listener was removed when this component was disposed first');
|
|
|
|
comp1.off = function(){ throw 'Comp1 off called'; };
|
|
|
|
try {
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'dispose');
|
2014-10-28 20:16:56 +02:00
|
|
|
} catch(e) {
|
|
|
|
ok(false, 'listener was not removed from other element');
|
|
|
|
}
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'dispose');
|
2014-10-28 20:16:56 +02:00
|
|
|
ok(true, 'this component removed dispose listeners from other element');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should add listeners to other components that are fired once', function(){
|
|
|
|
var player = getFakePlayer(),
|
2015-03-11 03:01:11 +02:00
|
|
|
comp1 = new Component(player),
|
2014-10-28 20:16:56 +02:00
|
|
|
el = document.createElement('div'),
|
|
|
|
listenerFired = 0,
|
|
|
|
testListener;
|
|
|
|
|
|
|
|
testListener = function(){
|
|
|
|
equal(this, comp1, 'listener has the first component as context');
|
|
|
|
listenerFired++;
|
|
|
|
};
|
|
|
|
|
|
|
|
comp1.one(el, 'test-event', testListener);
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'test-event');
|
2014-10-28 20:16:56 +02:00
|
|
|
equal(listenerFired, 1, 'listener was executed once');
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(el, 'test-event');
|
2014-10-28 20:16:56 +02:00
|
|
|
equal(listenerFired, 1, 'listener was executed only once');
|
|
|
|
});
|
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
test('should trigger a listener when ready', function(){
|
2015-07-30 21:38:01 +02:00
|
|
|
let initListenerFired;
|
|
|
|
let methodListenerFired;
|
|
|
|
let syncListenerFired;
|
2013-01-11 00:06:12 +03:00
|
|
|
|
2015-07-30 21:38:01 +02:00
|
|
|
let comp = new Component(getFakePlayer(), {}, function(){
|
|
|
|
initListenerFired = true;
|
|
|
|
});
|
2013-01-11 00:06:12 +03:00
|
|
|
|
2015-07-30 21:38:01 +02:00
|
|
|
comp.ready(function(){
|
|
|
|
methodListenerFired = true;
|
|
|
|
});
|
2013-01-11 00:06:12 +03:00
|
|
|
|
|
|
|
comp.triggerReady();
|
|
|
|
|
2015-07-30 21:38:01 +02:00
|
|
|
comp.ready(function(){
|
|
|
|
syncListenerFired = true;
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
ok(!initListenerFired, 'init listener should NOT fire synchronously');
|
|
|
|
ok(!methodListenerFired, 'method listener should NOT fire synchronously');
|
|
|
|
ok(syncListenerFired, 'sync listener SHOULD fire synchronously if after ready');
|
|
|
|
|
2015-05-22 06:46:36 +02:00
|
|
|
this.clock.tick(1);
|
2015-07-30 21:38:01 +02:00
|
|
|
ok(initListenerFired, 'init listener should fire asynchronously');
|
|
|
|
ok(methodListenerFired, 'method listener should fire asynchronously');
|
|
|
|
|
|
|
|
// Listeners should only be fired once and then removed
|
|
|
|
initListenerFired = false;
|
|
|
|
methodListenerFired = false;
|
|
|
|
syncListenerFired = false;
|
2013-01-11 00:06:12 +03:00
|
|
|
|
|
|
|
comp.triggerReady();
|
2015-05-22 06:46:36 +02:00
|
|
|
this.clock.tick(1);
|
2015-07-30 21:38:01 +02:00
|
|
|
|
|
|
|
ok(!initListenerFired, 'init listener should be removed');
|
|
|
|
ok(!methodListenerFired, 'method listener should be removed');
|
|
|
|
ok(!syncListenerFired, 'sync listener should be removed');
|
2013-01-11 00:06:12 +03:00
|
|
|
});
|
|
|
|
|
2015-07-23 17:28:34 +02:00
|
|
|
test('should not retrigger a listener when the listener calls triggerReady', function(){
|
|
|
|
var timesCalled = 0;
|
|
|
|
var selfTriggered = false;
|
|
|
|
|
|
|
|
var readyListener = function(){
|
|
|
|
timesCalled++;
|
|
|
|
|
|
|
|
// Don't bother calling again if we have
|
|
|
|
// already failed
|
|
|
|
if (!selfTriggered) {
|
|
|
|
selfTriggered = true;
|
|
|
|
comp.triggerReady();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-29 18:28:02 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2015-07-23 17:28:34 +02:00
|
|
|
|
|
|
|
comp.ready(readyListener);
|
|
|
|
comp.triggerReady();
|
|
|
|
|
2015-09-29 18:28:02 +02:00
|
|
|
this.clock.tick(100);
|
|
|
|
|
2015-07-23 17:28:34 +02:00
|
|
|
equal(timesCalled, 1, 'triggerReady from inside a ready handler does not result in an infinite loop');
|
|
|
|
});
|
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
test('should add and remove a CSS class', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2013-01-11 00:06:12 +03:00
|
|
|
|
|
|
|
comp.addClass('test-class');
|
|
|
|
ok(comp.el().className.indexOf('test-class') !== -1);
|
|
|
|
comp.removeClass('test-class');
|
|
|
|
ok(comp.el().className.indexOf('test-class') === -1);
|
2015-11-10 00:43:17 +02:00
|
|
|
comp.toggleClass('test-class');
|
|
|
|
ok(comp.el().className.indexOf('test-class') !== -1);
|
|
|
|
comp.toggleClass('test-class');
|
|
|
|
ok(comp.el().className.indexOf('test-class') === -1);
|
2013-01-11 00:06:12 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should show and hide an element', function(){
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2013-01-11 00:06:12 +03:00
|
|
|
|
|
|
|
comp.hide();
|
2014-12-22 19:38:54 +02:00
|
|
|
ok(comp.hasClass('vjs-hidden') === true);
|
2013-01-11 00:06:12 +03:00
|
|
|
comp.show();
|
2014-12-22 19:38:54 +02:00
|
|
|
ok(comp.hasClass('vjs-hidden') === false);
|
2013-01-11 00:06:12 +03:00
|
|
|
});
|
|
|
|
|
2014-09-02 21:37:42 +03:00
|
|
|
test('dimension() should treat NaN and null as zero', function() {
|
2014-08-26 01:41:33 +03:00
|
|
|
var comp, width, height, newWidth, newHeight;
|
|
|
|
width = 300;
|
|
|
|
height = 150;
|
|
|
|
|
2015-03-11 03:01:11 +02:00
|
|
|
comp = new Component(getFakePlayer(), {}),
|
2014-08-26 01:41:33 +03:00
|
|
|
// set component dimension
|
|
|
|
|
|
|
|
comp.dimensions(width, height);
|
|
|
|
|
|
|
|
newWidth = comp.dimension('width', null);
|
|
|
|
|
2014-09-02 21:37:42 +03:00
|
|
|
notEqual(newWidth, width, 'new width and old width are not the same');
|
|
|
|
equal(newWidth, comp, 'we set a value, so, return value is component');
|
|
|
|
equal(comp.width(), 0, 'the new width is zero');
|
2014-08-26 01:41:33 +03:00
|
|
|
|
|
|
|
newHeight = comp.dimension('height', NaN);
|
|
|
|
|
2014-09-02 21:37:42 +03:00
|
|
|
notEqual(newHeight, height, 'new height and old height are not the same');
|
|
|
|
equal(newHeight, comp, 'we set a value, so, return value is component');
|
|
|
|
equal(comp.height(), 0, 'the new height is zero');
|
2014-08-26 01:41:33 +03:00
|
|
|
|
2014-09-02 21:37:42 +03:00
|
|
|
comp.width(width);
|
2014-08-26 01:41:33 +03:00
|
|
|
newWidth = comp.dimension('width', undefined);
|
|
|
|
|
|
|
|
equal(newWidth, width, 'we did not set the width with undefined');
|
|
|
|
});
|
|
|
|
|
2013-01-11 00:06:12 +03:00
|
|
|
test('should change the width and height of a component', function(){
|
|
|
|
var container = document.createElement('div');
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer(), {});
|
2013-01-11 00:06:12 +03:00
|
|
|
var el = comp.el();
|
|
|
|
var fixture = document.getElementById('qunit-fixture');
|
|
|
|
|
|
|
|
fixture.appendChild(container);
|
|
|
|
container.appendChild(el);
|
|
|
|
// Container of el needs dimensions or the component won't have dimensions
|
2013-02-09 01:14:36 +03:00
|
|
|
container.style.width = '1000px';
|
|
|
|
container.style.height = '1000px';
|
2013-01-11 00:06:12 +03:00
|
|
|
|
|
|
|
comp.width('50%');
|
|
|
|
comp.height('123px');
|
|
|
|
|
|
|
|
ok(comp.width() === 500, 'percent values working');
|
2015-05-17 00:59:46 +02:00
|
|
|
var compStyle = TestHelpers.getComputedStyle(el, 'width');
|
2013-04-13 02:51:04 +03:00
|
|
|
ok(compStyle === comp.width() + 'px', 'matches computed style');
|
2013-01-11 00:06:12 +03:00
|
|
|
ok(comp.height() === 123, 'px values working');
|
|
|
|
|
|
|
|
comp.width(321);
|
|
|
|
ok(comp.width() === 321, 'integer values working');
|
2013-03-09 11:39:28 +03:00
|
|
|
|
|
|
|
comp.width('auto');
|
|
|
|
comp.height('auto');
|
|
|
|
ok(comp.width() === 1000, 'forced width was removed');
|
|
|
|
ok(comp.height() === 0, 'forced height was removed');
|
2013-01-11 00:06:12 +03:00
|
|
|
});
|
2013-05-01 03:27:36 +03:00
|
|
|
|
2016-03-25 21:12:53 +02:00
|
|
|
test('should get the computed dimensions', function(){
|
|
|
|
const container = document.createElement('div');
|
|
|
|
const comp = new Component(getFakePlayer(), {});
|
|
|
|
const el = comp.el();
|
|
|
|
const fixture = document.getElementById('qunit-fixture');
|
|
|
|
|
|
|
|
const computedWidth = '500px';
|
|
|
|
const computedHeight = '500px';
|
|
|
|
|
|
|
|
fixture.appendChild(container);
|
|
|
|
container.appendChild(el);
|
|
|
|
// Container of el needs dimensions or the component won't have dimensions
|
|
|
|
container.style.width = '1000px';
|
|
|
|
container.style.height = '1000px';
|
|
|
|
|
|
|
|
comp.width('50%');
|
|
|
|
comp.height('50%');
|
|
|
|
|
|
|
|
equal(comp.currentWidth() + 'px', computedWidth, 'matches computed width');
|
|
|
|
equal(comp.currentHeight() + 'px', computedHeight, 'matches computed height');
|
|
|
|
|
|
|
|
equal(comp.currentDimension('width') + 'px', computedWidth, 'matches computed width');
|
|
|
|
equal(comp.currentDimension('height') + 'px', computedHeight, 'matches computed height');
|
|
|
|
|
|
|
|
equal(comp.currentDimensions()['width'] + 'px', computedWidth, 'matches computed width');
|
|
|
|
equal(comp.currentDimensions()['height'] + 'px', computedHeight, 'matches computed width');
|
|
|
|
|
|
|
|
});
|
2013-05-01 03:27:36 +03:00
|
|
|
|
|
|
|
test('should use a defined content el for appending children', function(){
|
2015-04-14 22:08:32 +02:00
|
|
|
class CompWithContent extends Component {}
|
|
|
|
|
2013-05-01 03:27:36 +03:00
|
|
|
CompWithContent.prototype.createEl = function(){
|
|
|
|
// Create the main componenent element
|
2015-05-04 01:12:38 +02:00
|
|
|
var el = Dom.createEl('div');
|
2013-05-01 03:27:36 +03:00
|
|
|
// Create the element where children will be appended
|
2015-05-04 01:12:38 +02:00
|
|
|
this.contentEl_ = Dom.createEl('div', { 'id': 'contentEl' });
|
2013-05-01 03:27:36 +03:00
|
|
|
el.appendChild(this.contentEl_);
|
|
|
|
return el;
|
|
|
|
};
|
|
|
|
|
|
|
|
var comp = new CompWithContent(getFakePlayer());
|
|
|
|
var child = comp.addChild('component');
|
|
|
|
|
|
|
|
ok(comp.children().length === 1);
|
|
|
|
ok(comp.el().childNodes[0]['id'] === 'contentEl');
|
|
|
|
ok(comp.el().childNodes[0].childNodes[0] === child.el());
|
|
|
|
|
|
|
|
comp.removeChild(child);
|
|
|
|
|
|
|
|
ok(comp.children().length === 0, 'Length should now be zero');
|
|
|
|
ok(comp.el().childNodes[0]['id'] === 'contentEl', 'Content El should still exist');
|
|
|
|
ok(comp.el().childNodes[0].childNodes[0] !== child.el(), 'Child el should be removed.');
|
|
|
|
});
|
2013-08-10 00:29:22 +03:00
|
|
|
|
|
|
|
test('should emit a tap event', function(){
|
2015-02-12 22:01:20 +02:00
|
|
|
expect(3);
|
2013-08-10 00:29:22 +03:00
|
|
|
|
|
|
|
// Fake touch support. Real touch support isn't needed for this test.
|
2015-05-04 01:12:38 +02:00
|
|
|
var origTouch = browser.TOUCH_ENABLED;
|
|
|
|
browser.TOUCH_ENABLED = true;
|
2013-08-10 00:29:22 +03:00
|
|
|
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer());
|
2015-02-12 22:01:20 +02:00
|
|
|
var singleTouch = {};
|
2014-02-06 04:58:30 +03:00
|
|
|
|
2013-08-10 00:29:22 +03:00
|
|
|
comp.emitTapEvents();
|
|
|
|
comp.on('tap', function(){
|
|
|
|
ok(true, 'Tap event emitted');
|
|
|
|
});
|
2014-05-07 03:22:29 +03:00
|
|
|
|
|
|
|
// A touchstart followed by touchend should trigger a tap
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchstart', touches: [{}]});
|
2014-05-07 03:22:29 +03:00
|
|
|
comp.trigger('touchend');
|
|
|
|
|
|
|
|
// A touchmove with a lot of movement should not trigger a tap
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchstart', touches: [
|
2014-05-07 03:22:29 +03:00
|
|
|
{ pageX: 0, pageY: 0 }
|
|
|
|
]});
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchmove', touches: [
|
2014-05-07 03:22:29 +03:00
|
|
|
{ pageX: 100, pageY: 100 }
|
|
|
|
]});
|
2013-08-10 00:29:22 +03:00
|
|
|
comp.trigger('touchend');
|
|
|
|
|
2014-05-07 03:22:29 +03:00
|
|
|
// A touchmove with not much movement should still allow a tap
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchstart', touches: [
|
2014-05-07 03:22:29 +03:00
|
|
|
{ pageX: 0, pageY: 0 }
|
|
|
|
]});
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchmove', touches: [
|
2015-01-27 22:45:33 +02:00
|
|
|
{ pageX: 7, pageY: 7 }
|
2014-05-07 03:22:29 +03:00
|
|
|
]});
|
2013-08-10 00:29:22 +03:00
|
|
|
comp.trigger('touchend');
|
|
|
|
|
2015-02-12 22:01:20 +02:00
|
|
|
// A touchmove with a lot of movement by modifying the exisiting touch object
|
|
|
|
// should not trigger a tap
|
|
|
|
singleTouch = { pageX: 0, pageY: 0 };
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchstart', touches: [singleTouch]});
|
2015-02-12 22:01:20 +02:00
|
|
|
singleTouch.pageX = 100;
|
|
|
|
singleTouch.pageY = 100;
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchmove', touches: [singleTouch]});
|
2015-02-12 22:01:20 +02:00
|
|
|
comp.trigger('touchend');
|
|
|
|
|
|
|
|
// A touchmove with not much movement by modifying the exisiting touch object
|
|
|
|
// should still allow a tap
|
|
|
|
singleTouch = { pageX: 0, pageY: 0 };
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchstart', touches: [singleTouch]});
|
2015-01-27 22:45:33 +02:00
|
|
|
singleTouch.pageX = 7;
|
|
|
|
singleTouch.pageY = 7;
|
2015-03-26 06:43:41 +02:00
|
|
|
Events.trigger(comp.el(), {type: 'touchmove', touches: [singleTouch]});
|
2015-02-12 22:01:20 +02:00
|
|
|
comp.trigger('touchend');
|
|
|
|
|
2013-08-10 00:29:22 +03:00
|
|
|
// Reset to orignial value
|
2015-05-04 01:12:38 +02:00
|
|
|
browser.TOUCH_ENABLED = origTouch;
|
2013-08-10 00:29:22 +03:00
|
|
|
});
|
2014-12-03 21:31:39 +02:00
|
|
|
|
|
|
|
test('should provide timeout methods that automatically get cleared on component disposal', function() {
|
|
|
|
expect(4);
|
|
|
|
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer());
|
2014-12-03 21:31:39 +02:00
|
|
|
var timeoutsFired = 0;
|
|
|
|
|
|
|
|
comp.setTimeout(function() {
|
|
|
|
timeoutsFired++;
|
|
|
|
equal(this, comp, 'Timeout fn has the component as its context');
|
|
|
|
ok(true, 'Timeout created and fired.');
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
var timeoutToClear = comp.setTimeout(function() {
|
|
|
|
timeoutsFired++;
|
|
|
|
ok(false, 'Timeout should have been manually cleared');
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
comp.setTimeout(function() {
|
|
|
|
timeoutsFired++;
|
|
|
|
ok(false, 'Timeout should have been disposed');
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
this.clock.tick(100);
|
|
|
|
|
|
|
|
ok(timeoutsFired === 1, 'One timeout should have fired by this point');
|
|
|
|
|
|
|
|
comp.clearTimeout(timeoutToClear);
|
|
|
|
|
|
|
|
this.clock.tick(500);
|
|
|
|
|
|
|
|
comp.dispose();
|
|
|
|
|
|
|
|
this.clock.tick(1000);
|
|
|
|
|
|
|
|
ok(timeoutsFired === 1, 'One timeout should have fired overall');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should provide interval methods that automatically get cleared on component disposal', function() {
|
|
|
|
expect(13);
|
|
|
|
|
2015-03-11 03:01:11 +02:00
|
|
|
var comp = new Component(getFakePlayer());
|
2014-12-03 21:31:39 +02:00
|
|
|
var intervalsFired = 0;
|
|
|
|
|
|
|
|
var interval = comp.setInterval(function() {
|
|
|
|
intervalsFired++;
|
|
|
|
equal(this, comp, 'Interval fn has the component as its context');
|
|
|
|
ok(true, 'Interval created and fired.');
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
comp.setInterval(function() {
|
|
|
|
intervalsFired++;
|
|
|
|
ok(false, 'Interval should have been disposed');
|
|
|
|
}, 1200);
|
|
|
|
|
|
|
|
this.clock.tick(500);
|
|
|
|
|
|
|
|
ok(intervalsFired === 5, 'Component interval fired 5 times');
|
|
|
|
|
|
|
|
comp.clearInterval(interval);
|
|
|
|
|
|
|
|
this.clock.tick(600);
|
|
|
|
|
|
|
|
ok(intervalsFired === 5, 'Interval was manually cleared');
|
|
|
|
|
|
|
|
comp.dispose();
|
|
|
|
|
|
|
|
this.clock.tick(1200);
|
|
|
|
|
|
|
|
ok(intervalsFired === 5, 'Interval was cleared when component was disposed');
|
|
|
|
});
|
2015-11-10 00:43:17 +02:00
|
|
|
|
|
|
|
test('$ and $$ functions', function() {
|
|
|
|
var comp = new Component(getFakePlayer());
|
|
|
|
var contentEl = document.createElement('div');
|
|
|
|
var children = [
|
|
|
|
document.createElement('div'),
|
|
|
|
document.createElement('div')
|
|
|
|
];
|
|
|
|
|
|
|
|
comp.contentEl_ = contentEl;
|
|
|
|
children.forEach(child => contentEl.appendChild(child));
|
|
|
|
|
|
|
|
strictEqual(comp.$('div'), children[0], '$ defaults to contentEl as scope');
|
|
|
|
strictEqual(comp.$$('div').length, children.length, '$$ defaults to contentEl as scope');
|
|
|
|
});
|