summaryrefslogtreecommitdiff
path: root/javascript/videojs/test/unit/plugin-advanced.test.js
blob: bc7800a7f8bbf42ed8017bb54135755bdb5dd169 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* eslint-env qunit */
import sinon from 'sinon';
import Plugin from '../../src/js/plugin';
import TestHelpers from './test-helpers';

QUnit.module('Plugin: advanced', {

  beforeEach() {
    this.player = TestHelpers.makePlayer();
    const spy = this.spy = sinon.spy();

    class MockPlugin extends Plugin {

      constructor(...args) {
        super(...args);
        spy.apply(this, args);
      }
    }

    MockPlugin.VERSION = '1.0.0';

    this.MockPlugin = MockPlugin;
    Plugin.registerPlugin('mock', MockPlugin);
  },

  afterEach() {
    this.player.dispose();

    Object.keys(Plugin.getPlugins()).forEach(key => {
      if (key !== Plugin.BASE_PLUGIN_NAME) {
        Plugin.deregisterPlugin(key);
      }
    });
  }
});

QUnit.test('pre-setup interface', function(assert) {
  assert.strictEqual(typeof this.player.plugin, 'undefined', 'the base Plugin does not add a method to the player');
  assert.strictEqual(typeof this.player.mock, 'function', 'plugins are a factory function on a player');
  assert.ok(this.player.hasPlugin('mock'), 'player has the plugin available');
  assert.strictEqual(this.player.mock.dispose, undefined, 'class-based plugins are not populated on a player until the factory method creates them');
  assert.notOk(this.player.usingPlugin('mock'), 'the player is not using the plugin');
});

QUnit.test('setup', function(assert) {
  const instance = this.player.mock({foo: 'bar'}, 123);

  assert.strictEqual(this.spy.callCount, 1, 'plugin was set up once');
  assert.strictEqual(this.spy.firstCall.thisValue, instance, 'plugin constructor `this` value was the instance');
  assert.deepEqual(this.spy.firstCall.args, [this.player, {foo: 'bar'}, 123], 'plugin had the correct arguments');
  assert.ok(this.player.usingPlugin('mock'), 'player now recognizes that the plugin was set up');
  assert.ok(this.player.hasPlugin('mock'), 'player has the plugin available');
  assert.ok(instance instanceof this.MockPlugin, 'plugin instance has the correct constructor');
  assert.strictEqual(instance, this.player.mock(), 'factory is replaced by method returning the instance');
  assert.strictEqual(instance.player, this.player, 'instance has a reference to the player');
  assert.strictEqual(instance.name, 'mock', 'instance knows its name');
  assert.strictEqual(typeof instance.state, 'object', 'instance is stateful');
  assert.strictEqual(typeof instance.setState, 'function', 'instance is stateful');
  assert.strictEqual(typeof instance.off, 'function', 'instance is evented');
  assert.strictEqual(typeof instance.on, 'function', 'instance is evented');
  assert.strictEqual(typeof instance.one, 'function', 'instance is evented');
  assert.strictEqual(typeof instance.trigger, 'function', 'instance is evented');
  assert.strictEqual(typeof instance.dispose, 'function', 'instance has dispose method');
  assert.strictEqual(typeof instance.version, 'function', 'instance has version method');
  assert.strictEqual(instance.version(), '1.0.0', 'version function returns VERSION value');

  assert.throws(
    () => new Plugin(this.player),
    new Error('Plugin must be sub-classed; not directly instantiated.'),
    'the Plugin class cannot be directly instantiated'
  );
});

QUnit.test('log is added by default', function(assert) {
  const instance = this.player.mock();

  assert.strictEqual(typeof instance.log, 'function', 'log is a function');
  assert.strictEqual(typeof instance.log.debug, 'function', 'log.debug is a function');
  assert.strictEqual(typeof instance.log.error, 'function', 'log.error is a function');
  assert.strictEqual(typeof instance.log.history, 'function', 'log.history is a function');
  assert.strictEqual(typeof instance.log.levels, 'object', 'log.levels is a object');
  assert.strictEqual(typeof instance.log.warn, 'function', 'log.warn is a function');
});

QUnit.test('log will not clobber pre-existing log property', function(assert) {
  class MockLogPlugin extends Plugin {
    log() {}
  }

  MockLogPlugin.VERSION = '1.0.0';
  Plugin.registerPlugin('mockLog', MockLogPlugin);

  const instance = this.player.mockLog();

  assert.strictEqual(typeof instance.log, 'function', 'log is a function');
  assert.strictEqual(instance.log, MockLogPlugin.prototype.log, 'log was not overridden');
});

QUnit.test('all "pluginsetup" events', function(assert) {
  const setupSpy = sinon.spy();
  const events = [
    'beforepluginsetup',
    'beforepluginsetup:mock',
    'pluginsetup',
    'pluginsetup:mock'
  ];

  this.player.on(events, setupSpy);

  const instance = this.player.mock();

  events.forEach((type, i) => {
    const event = setupSpy.getCall(i).args[0];
    const hash = setupSpy.getCall(i).args[1];

    assert.strictEqual(event.type, type, `the "${type}" event was triggered`);
    assert.strictEqual(event.target, this.player.el_, 'the event has the correct target');

    assert.deepEqual(hash, {
      name: 'mock',

      // The "before" events have a `null` instance and the others have the
      // return value of the plugin factory.
      instance: i < 2 ? null : instance,
      plugin: this.MockPlugin
    }, 'the event hash object is correct');
  });
});

QUnit.test('defaultState static property is used to populate state', function(assert) {
  class DefaultStateMock extends Plugin {}
  DefaultStateMock.defaultState = {foo: 1, bar: 2};
  Plugin.registerPlugin('dsm', DefaultStateMock);

  const instance = this.player.dsm();

  assert.deepEqual(instance.state, {foo: 1, bar: 2}, 'the plugin state has default properties');
});

QUnit.test('dispose', function(assert) {
  const instance = this.player.mock();

  instance.dispose();

  assert.notOk(this.player.usingPlugin('mock'), 'player recognizes that the plugin is NOT set up');
  assert.ok(this.player.hasPlugin('mock'), 'player still has the plugin available');
  assert.strictEqual(typeof this.player.mock, 'function', 'instance is replaced by factory');
  assert.notStrictEqual(instance, this.player.mock, 'instance is replaced by factory');
  assert.strictEqual(instance.player, null, 'instance no longer has a reference to the player');
  assert.strictEqual(instance.state, null, 'state is now null');
});

QUnit.test('"dispose" event', function(assert) {
  const disposeSpy = sinon.spy();
  const instance = this.player.mock();

  instance.on('dispose', disposeSpy);
  instance.dispose();

  assert.strictEqual(disposeSpy.callCount, 1, 'the "dispose" event was triggered');

  const event = disposeSpy.firstCall.args[0];
  const hash = disposeSpy.firstCall.args[1];

  assert.strictEqual(event.type, 'dispose', 'the event has the correct type');
  assert.strictEqual(event.target, instance.eventBusEl_, 'the event has the correct target');

  assert.deepEqual(hash, {
    name: 'mock',
    instance,
    plugin: this.MockPlugin
  }, 'the event hash object is correct');
});

QUnit.test('arbitrary events', function(assert) {
  const fooSpy = sinon.spy();
  const instance = this.player.mock();

  instance.on('foo', fooSpy);
  instance.trigger('foo');

  const event = fooSpy.firstCall.args[0];
  const hash = fooSpy.firstCall.args[1];

  assert.strictEqual(fooSpy.callCount, 1, 'the "foo" event was triggered');
  assert.strictEqual(event.type, 'foo', 'the event has the correct type');
  assert.strictEqual(event.target, instance.eventBusEl_, 'the event has the correct target');

  assert.deepEqual(hash, {
    name: 'mock',
    instance,
    plugin: this.MockPlugin
  }, 'the event hash object is correct');
});

QUnit.test('handleStateChanged() method is automatically bound to the "statechanged" event', function(assert) {
  const spy = sinon.spy();

  class TestHandler extends Plugin {
    handleStateChanged(...args) {
      spy.apply(this, args);
    }
  }
  Plugin.registerPlugin('testHandler', TestHandler);

  const instance = this.player.testHandler();

  instance.setState({foo: 1});
  assert.strictEqual(spy.callCount, 1, 'the handleStateChanged listener was called');
  assert.strictEqual(spy.firstCall.args[0].type, 'statechanged', 'the event was "statechanged"');
  assert.strictEqual(typeof spy.firstCall.args[0].changes, 'object', 'the event included a changes object');
});