text: var player, tech, el;
  
  import Html5 from '../../../src/js/tech/html5.js';
  import * as browser from '../../../src/js/utils/browser.js';
  import document from 'global/document';
  
  q.module('HTML5', {
    'setup': function() {
  
      el = document.createElement('div');
      el.innerHTML = '<div />';
  
      player = {
        id: function(){ return 'id'; },
        el: function(){ return el; },
        options_: {},
        options: function(){ return this.options_; },
        bufferedPercent: function() { return 0; },
        controls: function(){ return false; },
        usingNativeControls: function(){ return false; },
        on: function(){ return this; },
        off: function() { return this; },
        ready: function(){},
        addChild: function(){},
        trigger: function(){}
      };
      tech = new Html5({});
    },
    'teardown': function() {
      tech.dispose();
      el = null;
      player = null;
      tech = null;
    }
  });
  
  test('should detect whether the volume can be changed', function(){
    var testVid, ConstVolumeVideo;
    if (!{}['__defineSetter__']) {
      ok(true, 'your browser does not support this test, skipping it');
      return;
    }
    testVid = Html5.TEST_VID;
    ConstVolumeVideo = function(){
      this.volume = 1;
      this.__defineSetter__('volume', function(){});
    };
    Html5.TEST_VID = new ConstVolumeVideo();
  
    ok(!Html5.canControlVolume());
    Html5.TEST_VID = testVid;
  });
  
  test('test playbackRate', function() {
    var playbackRate;
  
    // Android 2.3 always returns 0 for playback rate
    if (!Html5.canControlPlaybackRate()) {
      ok('Playback rate is not supported');
      return;
    }
  
    tech.createEl();
  
    tech.el().playbackRate = 1.25;
    strictEqual(tech.playbackRate(), 1.25);
  
    tech['setPlaybackRate'](0.75);
    strictEqual(tech.playbackRate(), 0.75);
  });
  
  test('should export played', function() {
    tech.createEl();
    deepEqual(tech.played(), tech.el().played, 'returns the played attribute');
  });
  
  test('should remove the controls attribute when recreating the element', function() {
    var el;
    player.tagAttributes = {
      controls: true
    };
    // force custom controls so the test environment is equivalent on iOS
    player.options_['nativeControlsForTouch'] = false;
    el = tech.createEl();
  
    // On the iPhone controls are always true
    if (!browser.IS_IPHONE) {
      ok(!el.controls, 'controls attribute is absent');
    }
  
    ok(player.tagAttributes.controls, 'tag attribute is still present');
  });
  
  test('patchCanPlayType patches canplaytype with our function, conditionally', function() {
    // the patch runs automatically so we need to first unpatch
    Html5.unpatchCanPlayType();
  
    var oldAV = browser.ANDROID_VERSION,
        video = document.createElement('video'),
        canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType,
        patchedCanPlayType,
        unpatchedCanPlayType;
  
    browser.ANDROID_VERSION = 4.0;
    Html5.patchCanPlayType();
  
    notStrictEqual(video.canPlayType, canPlayType, 'original canPlayType and patched canPlayType should not be equal');
  
    patchedCanPlayType = video.canPlayType;
    unpatchedCanPlayType = Html5.unpatchCanPlayType();
  
    strictEqual(canPlayType, Html5.TEST_VID.constructor.prototype.canPlayType, 'original canPlayType and unpatched canPlayType should be equal');
    strictEqual(patchedCanPlayType, unpatchedCanPlayType, 'patched canPlayType and function returned from unpatch are equal');
  
    browser.ANDROID_VERSION = oldAV;
    Html5.unpatchCanPlayType();
  });
  
  test('should return maybe for HLS urls on Android 4.0 or above', function() {
    var oldAV = browser.ANDROID_VERSION,
        video = document.createElement('video');
  
    browser.ANDROID_VERSION = 4.0;
    Html5.patchCanPlayType();
  
    strictEqual(video.canPlayType('application/x-mpegurl'), 'maybe', 'android version 4.0 or above should be a maybe for x-mpegurl');
    strictEqual(video.canPlayType('application/x-mpegURL'), 'maybe', 'android version 4.0 or above should be a maybe for x-mpegURL');
    strictEqual(video.canPlayType('application/vnd.apple.mpegurl'), 'maybe', 'android version 4.0 or above should be a maybe for vnd.apple.mpegurl');
    strictEqual(video.canPlayType('application/vnd.apple.mpegURL'), 'maybe', 'android version 4.0 or above should be a maybe for vnd.apple.mpegurl');
  
    browser.ANDROID_VERSION = oldAV;
    Html5.unpatchCanPlayType();
  });
  
  test('should return a maybe for mp4 on OLD ANDROID', function() {
    var isOldAndroid = browser.IS_OLD_ANDROID,
        video = document.createElement('video');
  
    browser.IS_OLD_ANDROID = true;
    Html5.patchCanPlayType();
  
    strictEqual(video.canPlayType('video/mp4'), 'maybe', 'old android should return a maybe for video/mp4');
  
    browser.IS_OLD_ANDROID = isOldAndroid;
    Html5.unpatchCanPlayType();
  });
  
  test('error events may not set the errors property', function() {
    equal(tech.error(), undefined, 'no tech-level error');
    tech.trigger('error');
    ok(true, 'no error was thrown');
  });
  
  test('should have the source handler interface', function() {
    ok(Html5.registerSourceHandler, 'has the registerSourceHandler function');
  });
  
  test('native source handler canPlayType', function(){
    var result;
  
    // Stub the test video canPlayType (used in canPlayType) to control results
    var origCPT = Html5.TEST_VID.canPlayType;
    Html5.TEST_VID.canPlayType = function(type){
      if (type === 'video/mp4') {
        return 'maybe';
      }
      return '';
    };
  
    var canPlayType = Html5.nativeSourceHandler.canPlayType;
  
    equal(canPlayType('video/mp4'), 'maybe', 'Native source handler reported type support');
    equal(canPlayType('foo'), '', 'Native source handler handled bad type');
  
    // Reset test video canPlayType
    Html5.TEST_VID.canPlayType = origCPT;
  });
  
  test('native source handler canHandleSource', function(){
    var result;
  
    // Stub the test video canPlayType (used in canHandleSource) to control results
    var origCPT = Html5.TEST_VID.canPlayType;
    Html5.TEST_VID.canPlayType = function(type){
      if (type === 'video/mp4') {
        return 'maybe';
      }
      return '';
    };
  
    var canHandleSource = Html5.nativeSourceHandler.canHandleSource;
  
    equal(canHandleSource({ type: 'video/mp4', src: 'video.flv' }), 'maybe', 'Native source handler reported type support');
    equal(canHandleSource({ src: 'http://www.example.com/video.mp4' }), 'maybe', 'Native source handler reported extension support');
    equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo&token=bar' }), 'maybe', 'Native source handler reported extension support');
    equal(canHandleSource({ src: 'https://example.com/video.sd.mp4?s=foo' }), 'maybe', 'Native source handler reported extension support');
  
    // Test for issue videojs/video.js#1785 and other potential failures
    equal(canHandleSource({ src: '' }), '', 'Native source handler handled empty src');
    equal(canHandleSource({}), '', 'Native source handler handled empty object');
    equal(canHandleSource({ src: 'foo' }), '', 'Native source handler handled bad src');
    equal(canHandleSource({ type: 'foo' }), '', 'Native source handler handled bad type');
  
    // Reset test video canPlayType
    Html5.TEST_VID.canPlayType = origCPT;
  });
  
  if (Html5.supportsNativeTextTracks()) {
    test('add native textTrack listeners on startup', function() {
      let adds = [];
      let rems = [];
      let tt = {
        length: 0,
        addEventListener: (type, fn) => adds.push([type, fn]),
        removeEventListener: (type, fn) => rems.push([type, fn]),
      };
      let el = document.createElement('div');
      el.textTracks = tt;
  
      let htmlTech = new Html5({el});
  
      equal(adds[0][0], 'change', 'change event handler added');
      equal(adds[1][0], 'addtrack', 'addtrack event handler added');
      equal(adds[2][0], 'removetrack', 'removetrack event handler added');
    });
  
    test('remove all tracks from emulated list on dispose', function() {
      let adds = [];
      let rems = [];
      let tt = {
        length: 0,
        addEventListener: (type, fn) => adds.push([type, fn]),
        removeEventListener: (type, fn) => rems.push([type, fn]),
      };
      let el = document.createElement('div');
      el.textTracks = tt;
  
      let htmlTech = new Html5({el});
      htmlTech.dispose();
  
      equal(adds[0][0], 'change', 'change event handler added');
      equal(adds[1][0], 'addtrack', 'addtrack event handler added');
      equal(adds[2][0], 'removetrack', 'removetrack event handler added');
      equal(rems[0][0], 'change', 'change event handler removed');
      equal(rems[1][0], 'addtrack', 'addtrack event handler removed');
      equal(rems[2][0], 'removetrack', 'removetrack event handler removed');
      equal(adds[0][0], rems[0][0], 'change event handler removed');
      equal(adds[1][0], rems[1][0], 'addtrack event handler removed');
      equal(adds[2][0], rems[2][0], 'removetrack event handler removed');
    });
  }
  
  test('should fire makeup events when a video tag is initialized late', function(){
    let lateInit = Html5.prototype.handleLateInit_;
    let triggeredEvents = [];
    let mockHtml5 = {
      readyListeners: [],
      ready(listener){
        this.readyListeners.push(listener);
      },
      triggerReady(){
        this.readyListeners.forEach(function(listener){
          listener.call(this);
        }, this);
      },
      trigger(type){
        triggeredEvents.push(type);
      },
      on: function(){},
      off: function(){}
    };
  
    function resetMock() {
      triggeredEvents = {};
      mockHtml5.readyListeners = [];
    }
  
    function testStates(statesObject, expectedEvents) {
      lateInit.call(mockHtml5, statesObject);
      mockHtml5.triggerReady();
      deepEqual(triggeredEvents, expectedEvents, `wrong events triggered for networkState:${statesObject.networkState} and readyState:${statesObject.readyState || 'no readyState'}`);
  
      // reset mock
      triggeredEvents = [];
      mockHtml5.readyListeners = [];
    }
  
    // Network States
    testStates({ networkState: 0, readyState: 0 }, []);
    testStates({ networkState: 1, readyState: 0 }, ['loadstart']);
    testStates({ networkState: 2, readyState: 0 }, ['loadstart']);
    testStates({ networkState: 3, readyState: 0 }, []);
  
    // Ready States
    testStates({ networkState: 1, readyState: 0 }, ['loadstart']);
    testStates({ networkState: 1, readyState: 1 }, ['loadstart', 'loadedmetadata']);
    testStates({ networkState: 1, readyState: 2 }, ['loadstart', 'loadedmetadata', 'loadeddata']);
    testStates({ networkState: 1, readyState: 3 }, ['loadstart', 'loadedmetadata', 'loadeddata', 'canplay']);
    testStates({ networkState: 1, readyState: 4 }, ['loadstart', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough']);
  });
  