Bug 1208373 - Check that we don't get "ended" event for tracks after calling stop(). r?jib draft
authorAndreas Pehrson <pehrsons@gmail.com>
Thu, 12 May 2016 13:50:34 +0200
changeset 376725 081f423177574ecf38af670a25775e3d82549c77
parent 375957 1828937da9493b2cd54862b9c520b2ba5c7db92b
child 376726 4a4c3d223e52922f932e116d1f12fa7fd931366f
push id20652
push userpehrsons@gmail.com
push dateWed, 08 Jun 2016 15:10:47 +0000
reviewersjib
bugs1208373
milestone50.0a1
Bug 1208373 - Check that we don't get "ended" event for tracks after calling stop(). r?jib MozReview-Commit-ID: K9gOZtUNQ5K
dom/media/tests/mochitest/head.js
dom/media/tests/mochitest/mediaStreamPlayback.js
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -585,16 +585,38 @@ function createOneShotEventWrapper(wrapp
   obj[onx] = e => {
     info(wrapper + ': "on' + event + '" event fired');
     e.wrapper = wrapper;
     wrapper[onx](e);
     wrapper[onx] = unexpected;
   };
 }
 
+/**
+ * Returns a promise that resolves when `target` has raised an event with the
+ * given name. Cancel the returned promise by passing in a `cancelPromise` and
+ * resolve it.
+ *
+ * @param {object} target
+ *        The target on which the event should occur.
+ * @param {string} name
+ *        The name of the event that should occur.
+ * @param {promise} cancelPromise
+ *        A promise that on resolving rejects the returned promise,
+ *        so we can avoid logging results after a test has finished.
+ */
+function haveEvent(target, name, cancelPromise) {
+  var listener;
+  var p = Promise.race([
+    (cancelPromise || new Promise()).then(e => Promise.reject(e)),
+    new Promise(resolve => target.addEventListener(name, listener = resolve))
+  ]);
+  p.then(() => target.removeEventListener(name, listener));
+  return p;
+};
 
 /**
  * This class executes a series of functions in a continuous sequence.
  * Promise-bearing functions are executed after the previous promise completes.
  *
  * @constructor
  * @param {object} framework
  *        A back reference to the framework which makes use of the class. It is
--- a/dom/media/tests/mochitest/mediaStreamPlayback.js
+++ b/dom/media/tests/mochitest/mediaStreamPlayback.js
@@ -50,27 +50,37 @@ MediaStreamPlayback.prototype = {
     var elem = this.mediaElement;
     var waitForEnded = () => new Promise(resolve => {
       elem.addEventListener('ended', function ended() {
         elem.removeEventListener('ended', ended);
         resolve();
       });
     });
 
-    // TODO (bug 910249) Also check that all the tracks are local.
-    this.mediaStream.getTracks().forEach(t => t.stop());
+    var noTrackEnded = Promise.all(this.mediaStream.getTracks().map(t => {
+      let onNextLoop = wait(0);
+      let p = Promise.race([
+        onNextLoop,
+        haveEvent(t, "ended", onNextLoop)
+          .then(() => Promise.reject("Unexpected ended event for track " + t.id),
+                () => Promise.resolve())
+      ]);
+      t.stop();
+      return p;
+    }));
 
     // XXX (bug 1208316) When we implement MediaStream.active, do not stop
     // the stream. We just do it now so the media element will raise 'ended'.
     if (!this.mediaStream.stop) {
       return;
     }
     this.mediaStream.stop();
     return timeout(waitForEnded(), ENDED_TIMEOUT_LENGTH, "ended event never fired")
-             .then(() => ok(true, "ended event successfully fired"));
+             .then(() => ok(true, "ended event successfully fired"))
+             .then(() => noTrackEnded);
   },
 
   /**
    * Starts media with a media stream, runs it until a canplaythrough and
    * timeupdate event fires, and stops the media.
    *
    * @param {Boolean} isResume specifies if this media element is being resumed
    *                           from a previous run