Bug 1462990 - Use async/await in mediasource mochitests draft
authorJan-Ivar Bruaroey <jib@mozilla.com>
Mon, 21 May 2018 16:40:13 -0400
changeset 801141 45949412c6084666e29f880c2c2576c9c7c61d11
parent 801140 48a9b8b74f1b45b089c5ce426aa8a001137b8b6d
push id111591
push userjbruaroey@mozilla.com
push dateTue, 29 May 2018 20:32:24 +0000
bugs1462990
milestone62.0a1
Bug 1462990 - Use async/await in mediasource mochitests MozReview-Commit-ID: AIr8CLyuGb7
dom/media/mediasource/test/.eslintrc.js
dom/media/mediasource/test/mediasource.js
dom/media/mediasource/test/test_AVC3_mp4.html
dom/media/mediasource/test/test_AudioChange_mp4.html
dom/media/mediasource/test/test_BufferingWait.html
dom/media/mediasource/test/test_BufferingWait_mp4.html
dom/media/mediasource/test/test_ChangeWhileWaitingOnMissingData_mp4.html
dom/media/mediasource/test/test_DrainOnMissingData_mp4.html
dom/media/mediasource/test/test_DurationChange.html
dom/media/mediasource/test/test_DurationUpdated.html
dom/media/mediasource/test/test_DurationUpdated_mp4.html
dom/media/mediasource/test/test_EndedEvent.html
dom/media/mediasource/test/test_Eviction_mp4.html
dom/media/mediasource/test/test_FrameSelection.html
dom/media/mediasource/test/test_FrameSelection_mp4.html
dom/media/mediasource/test/test_LiveSeekable.html
dom/media/mediasource/test/test_LoadedDataFired_mp4.html
dom/media/mediasource/test/test_MediaSource_flac_mp4.html
dom/media/mediasource/test/test_MediaSource_memory_reporting.html
dom/media/mediasource/test/test_MultipleInitSegments.html
dom/media/mediasource/test/test_MultipleInitSegments_mp4.html
dom/media/mediasource/test/test_OnEvents.html
dom/media/mediasource/test/test_PlayEvents.html
dom/media/mediasource/test/test_PlayEventsAutoPlaying.html
dom/media/mediasource/test/test_PlayEventsAutoPlaying2.html
dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html
dom/media/mediasource/test/test_SeekNoData_mp4.html
dom/media/mediasource/test/test_SeekToEnd_mp4.html
dom/media/mediasource/test/test_SeekToLastFrame_mp4.html
dom/media/mediasource/test/test_SeekTwice_mp4.html
dom/media/mediasource/test/test_SeekedEvent_mp4.html
dom/media/mediasource/test/test_Sequence_mp4.html
dom/media/mediasource/test/test_Threshold_mp4.html
dom/media/mediasource/test/test_TimestampOffset_mp4.html
dom/media/mediasource/test/test_TruncatedDuration.html
dom/media/mediasource/test/test_TruncatedDuration_mp4.html
dom/media/mediasource/test/test_WaitingOnMissingData.html
dom/media/mediasource/test/test_WaitingOnMissingDataEnded_mp4.html
dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html
dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html
--- a/dom/media/mediasource/test/.eslintrc.js
+++ b/dom/media/mediasource/test/.eslintrc.js
@@ -5,17 +5,22 @@ module.exports = {
   "extends": "plugin:mozilla/mochitest-test",
   // Globals from mediasource.js. We use false to indicate they should not
   // be overwritten in scripts.
   "globals": {
     "addMSEPrefs": false,
     "fetchAndLoad": false,
     "fetchAndLoadAsync": false,
     "fetchWithXHR": false,
+    "logEvents": false,
     "loadSegment": false,
+    "must_not_reject": false,
+    "must_not_throw": false,
+    "must_reject": false,
+    "must_throw": false,
     "once": false,
     "range": false,
     "runWithMSE": false,
     "waitUntilTime": false
   },
   // Use const/let instead of var for tighter scoping, avoiding redeclaration
   "rules": {
     "array-bracket-spacing": ["error", "always"],
--- a/dom/media/mediasource/test/mediasource.js
+++ b/dom/media/mediasource/test/mediasource.js
@@ -56,16 +56,47 @@ async function fetchWithXHR(uri, onLoadF
 function range(start, end) {
   const rv = [];
   for (let i = start; i < end; ++i) {
     rv.push(i);
   }
   return rv;
 }
 
+function must_throw(f, msg, error = true) {
+  try {
+    f();
+    ok(!error, msg);
+  } catch (e) {
+    ok(error, msg);
+    if (error === true) {
+      ok(false, `Please provide name of expected error! Got ${e.name}: ${e.message}.`);
+    } else if (e.name != error) {
+      throw e;
+    }
+  }
+}
+
+async function must_reject(f, msg, error = true) {
+  try {
+    await f();
+    ok(!error, msg);
+  } catch (e) {
+    ok(error, msg);
+    if (error === true) {
+      ok(false, `Please provide name of expected error! Got ${e.name}: ${e.message}.`);
+    } else if (e.name != error) {
+      throw e;
+    }
+  }
+}
+
+const must_not_throw = (f, msg) => must_throw(f, msg, false);
+const must_not_reject = (f, msg) => must_reject(f, msg, false);
+
 async function once(target, name, cb) {
   let result = await new Promise(r => target.addEventListener(name, r, {once: true}));
   if (cb) {
     result = await cb();
   }
   return result;
 }
 
@@ -77,17 +108,17 @@ function timeRangeToString(r) {
   return str;
 }
 
 async function loadSegment(sb, typedArrayOrArrayBuffer) {
   const typedArray = (typedArrayOrArrayBuffer instanceof ArrayBuffer) ? new Uint8Array(typedArrayOrArrayBuffer)
                                                                       : typedArrayOrArrayBuffer;
   info(`Loading buffer: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
   const beforeBuffered = timeRangeToString(sb.buffered);
-  const p = once(sb, 'update');
+  const p = once(sb, "update");
   sb.appendBuffer(typedArray);
   await p;
   const afterBuffered = timeRangeToString(sb.buffered);
   info(`SourceBuffer buffered ranges grew from ${beforeBuffered} to ${afterBuffered}`);
 }
 
 async function fetchAndLoad(sb, prefix, chunks, suffix) {
 
@@ -147,8 +178,17 @@ async function waitUntilTime(target, tar
       if (target.currentTime >= targetTime) {
         target.removeEventListener("waiting", onwaiting);
         resolve();
       }
     });
   });
   ok(true, "Reached target time of: " + targetTime);
 }
+
+// Log events for debugging.
+
+function logEvents(el) {
+  [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+   "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+   "waiting", "pause", "durationchange", "seeking",
+   "seeked" ].forEach(type => el.addEventListener(type, e => info(`got ${e.type} event`)));
+}
--- a/dom/media/mediasource/test/test_AVC3_mp4.html
+++ b/dom/media/mediasource/test/test_AVC3_mp4.html
@@ -7,38 +7,33 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
 
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
 
-    fetchAndLoad(videosb, "avc3/init", [ "" ], ".mp4")
-    .then(function() {
-      const promises = [];
-      promises.push(fetchAndLoad(videosb, "avc3/segment", range(1, 2), ".m4s"));
-      promises.push(once(el, "loadeddata"));
-      return Promise.all(promises);
-    }).then(function() {
-      is(videosb.buffered.length, 1, "continuous buffered range");
-      ok(true, "got loadeddata");
-      ms.endOfStream();
-      return once(ms, "sourceended");
-    }).then(function() {
-      ok(true, "endOfStream completed");
-      // Now ensure that we can play to the end.
-      el.play();
-      once(el, "ended").then(SimpleTest.finish.bind(SimpleTest));
-    });
-  });
+  await fetchAndLoad(videosb, "avc3/init", [ "" ], ".mp4");
+  const p = once(el, "loadeddata");
+  await fetchAndLoad(videosb, "avc3/segment", range(1, 2), ".m4s");
+  await p;
+  is(videosb.buffered.length, 1, "continuous buffered range");
+  ok(true, "got loadeddata");
+  ms.endOfStream();
+  await once(ms, "sourceended");
+  ok(true, "endOfStream completed");
+  // Now ensure that we can play to the end.
+  el.play();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_AudioChange_mp4.html
+++ b/dom/media/mediasource/test/test_AudioChange_mp4.html
@@ -9,62 +9,41 @@
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 // This test checks loading a stereo segment, followed by a 5.1 segment plays without error.
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    // Log events for debugging.
-    const events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
-                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
-                     "waiting", "pause", "durationchange", "seeking", "seeked" ];
-    function logEvent(e) {
-      info("got " + e.type + " event");
-    }
-    events.forEach(function(e) {
-      el.addEventListener(e, logEvent);
-    });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  logEvents(el);
 
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    el.addEventListener("error", function(e) {
-      ok(false, "should not fire '" + e.type + "' event");
-      SimpleTest.finish();
-    });
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const loadedmetadataPromises = [];
-    loadedmetadataPromises.push(fetchAndLoad(audiosb, "aac20-48000-64000-", [ "init" ], ".mp4"));
-    loadedmetadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(loadedmetadataPromises)
-    .then(function() {
-      ok(true, "got loadedmetadata event");
-      const canplayPromises = [];
-      canplayPromises.push(once(el, "loadeddata"));
-      canplayPromises.push(once(el, "canplay"));
-      canplayPromises.push(fetchAndLoad(audiosb, "aac20-48000-64000-", [ "1" ], ".m4s"));
-      return Promise.all(canplayPromises);
-    })
-    .then(function() {
-      ok(true, "got canplay event");
-      el.play();
-      return fetchAndLoad(audiosb, "aac51-48000-128000-", [ "init" ], ".mp4");
-    })
-    .then(fetchAndLoad.bind(null, audiosb, "aac51-48000-128000-", [ "2" ], ".m4s"))
-    .then(function() {
-      ms.endOfStream();
-      return once(el, "ended");
-    })
-    .then(function() {
-      ok(el.currentTime >= 6, "played to the end");
-      SimpleTest.finish();
-    });
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  el.addEventListener("error", e => {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(audiosb, "aac20-48000-64000-", [ "init" ], ".mp4");
+  await p;
+  ok(true, "got loadedmetadata event");
+  p = Promise.all([ once(el, "loadeddata"), once(el, "canplay") ]);
+  await fetchAndLoad(audiosb, "aac20-48000-64000-", [ "1" ], ".m4s");
+  await p;
+  ok(true, "got canplay event");
+  el.play();
+  await fetchAndLoad(audiosb, "aac51-48000-128000-", [ "init" ], ".mp4");
+  await fetchAndLoad(audiosb, "aac51-48000-128000-", [ "2" ], ".m4s");
+  ms.endOfStream();
+  await once(el, "ended");
+  ok(el.currentTime >= 6, "played to the end");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_BufferingWait.html
+++ b/dom/media/mediasource/test/test_BufferingWait.html
@@ -6,52 +6,47 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let receivedSourceOpen = false;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
-    receivedSourceOpen = true;
-    const sb = ms.addSourceBuffer("video/webm");
-    ok(sb, "Create a SourceBuffer");
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  ms.addEventListener("sourceopen", () => ok(false, "No more sourceopen"));
+  const sb = ms.addSourceBuffer("video/webm");
+  ok(sb, "Create a SourceBuffer");
 
-    fetchWithXHR("seek.webm", function(arrayBuffer) {
-      sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-      loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 0, 318))()
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 318, 25523 - 318)))
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 25523, 46712 - 25523)))
-      /* Note - Missing |46712, 67833 - 46712| segment here corresponding to (0.8, 1.2] */
-      /* Note - Missing |67833, 88966 - 67833| segment here corresponding to (1.2, 1.6]  */
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 88966)))
-      .then(function() {
-        // 0.767 is the time of the last video sample +- 40ms.
-        const promise = waitUntilTime(v, .767 - 0.04);
-        info("Playing video. It should play for a bit, then fire 'waiting'");
-        v.play();
-        return promise;
-      }).then(function() {
-        window.firstStop = Date.now();
-        loadSegment(sb, new Uint8Array(arrayBuffer, 46712, 67833 - 46712));
-        return waitUntilTime(v, 1.167 - 0.04);
-      }).then(function() {
-        const waitDuration = (Date.now() - window.firstStop) / 1000;
-        ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration);
-        SimpleTest.finish();
-        /* If we allow the rest of the stream to be played, we get stuck at
-           around 2s. See bug 1093133.
-        once(v, 'ended', SimpleTest.finish.bind(SimpleTest));
-        return loadSegment(sb, new Uint8Array(arrayBuffer, 67833, 88966 - 67833));
-        */
-      });
-    });
+  const arrayBuffer = await fetchWithXHR("seek.webm");
+  sb.addEventListener("error", e => {
+    ok(false, "Got Error: " + e);
+    SimpleTest.finish();
   });
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 0, 318));
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 318, 25523 - 318));
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 25523, 46712 - 25523));
+  /* Note - Missing |46712, 67833 - 46712| segment here corresponding to (0.8, 1.2] */
+  /* Note - Missing |67833, 88966 - 67833| segment here corresponding to (1.2, 1.6]  */
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 88966));
+  // 0.767 is the time of the last video sample +- 40ms.
+  info("Playing video. It should play for a bit, then fire 'waiting'");
+  v.play();
+  await waitUntilTime(v, .767 - 0.04);
+  const firstStop = Date.now();
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 46712, 67833 - 46712));
+  await waitUntilTime(v, 1.167 - 0.04);
+  const waitDuration = (Date.now() - firstStop) / 1000;
+  ok(waitDuration < 15, `Should not spend inordinate amount of time buffering: ${waitDuration}`);
+  SimpleTest.finish();
+  /* If we allow the rest of the stream to be played, we get stuck at
+     around 2s. See bug 1093133.
+  await once(v, "ended");
+  SimpleTest.finish();
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 67833, 88966 - 67833));
+  */
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_BufferingWait_mp4.html
+++ b/dom/media/mediasource/test/test_BufferingWait_mp4.html
@@ -6,49 +6,44 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let receivedSourceOpen = false;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
-    receivedSourceOpen = true;
-    const sb = ms.addSourceBuffer("video/mp4");
-    ok(sb, "Create a SourceBuffer");
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  ms.addEventListener("sourceopen", () => ok(false, "No more sourceopen"));
+  const sb = ms.addSourceBuffer("video/mp4");
+  ok(sb, "Create a SourceBuffer");
 
-    sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-    fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop", [ "1" ], ".m4s"))
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop", [ "2" ], ".m4s"))
-    /* Note - Missing |bipbop3| segment here corresponding to (1.62, 2.41] */
-    /* Note - Missing |bipbop4| segment here corresponding to (2.41, 3.20]  */
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop", [ "5" ], ".m4s"))
-    .then(function() {
-      // last audio sample has a start time of 1.578956s
-      const promise = waitUntilTime(v, 1.57895);
-      info("Playing video. It should play for a bit, then fire 'waiting'");
-      v.play();
-      return promise;
-    }).then(function() {
-      window.firstStop = Date.now();
-      fetchAndLoad(sb, "bipbop/bipbop", [ "3" ], ".m4s");
-      // last audio sample has a start time of 2.368435
-      return waitUntilTime(v, 2.36843);
-    }).then(function() {
-      const waitDuration = (Date.now() - window.firstStop) / 1000;
-      ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration);
-      once(v, "ended", SimpleTest.finish.bind(SimpleTest));
-      return fetchAndLoad(sb, "bipbop/bipbop", [ "4" ], ".m4s");
-    }).then(function() {
-      ms.endOfStream();
-    });
+  sb.addEventListener("error", e => {
+    ok(false, "Got Error: " + e);
+    SimpleTest.finish();
   });
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "1" ], ".m4s");
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "2" ], ".m4s");
+  /* Note - Missing |bipbop3| segment here corresponding to (1.62, 2.41] */
+  /* Note - Missing |bipbop4| segment here corresponding to (2.41, 3.20]  */
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "5" ], ".m4s");
+  // last audio sample has a start time of 1.578956s
+  info("Playing video. It should play for a bit, then fire 'waiting'");
+  v.play();
+  await waitUntilTime(v, 1.57895);
+  const firstStop = Date.now();
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "3" ], ".m4s");
+  // last audio sample has a start time of 2.368435
+  await waitUntilTime(v, 2.36843);
+  const waitDuration = (Date.now() - firstStop) / 1000;
+  ok(waitDuration < 15, `Should not spend inordinate amount of time buffering: ${waitDuration}`);
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "4" ], ".m4s");
+  ms.endOfStream();
+  await once(v, "ended");
+  SimpleTest.finish();
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_ChangeWhileWaitingOnMissingData_mp4.html
+++ b/dom/media/mediasource/test/test_ChangeWhileWaitingOnMissingData_mp4.html
@@ -6,40 +6,32 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const sb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop_480_624kbps-video", range(1, 3), ".m4s"))
-    .then(function() {
-      el.play();
-      // let seek to the last audio frame.
-      // The seek will complete and then playback will stall.
-      el.currentTime = 1.532517;
-      return Promise.all([ once(el, "seeked"), once(el, "waiting") ]);
-    })
-    .then(function() {
-      info("seek completed");
-      return fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4");
-    })
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop", range(1, 4), ".m4s"))
-    .then(function() {
-      ms.endOfStream();
-      return once(el, "ended");
-    }).then(function() {
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const sb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", range(1, 3), ".m4s");
+  el.play();
+  // let seek to the last audio frame.
+  // The seek will complete and then playback will stall.
+  el.currentTime = 1.532517;
+  await Promise.all([ once(el, "seeked"), once(el, "waiting") ]);
+  info("seek completed");
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop", range(1, 4), ".m4s");
+  ms.endOfStream();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_DrainOnMissingData_mp4.html
+++ b/dom/media/mediasource/test/test_DrainOnMissingData_mp4.html
@@ -6,55 +6,44 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(function() {
-      // Set appendWindowEnd to ensure we only have about 6 frames worth.
-      // We must feed at least 6 frames to pass the MDSM pre-roll.
-      videosb.appendWindowEnd = .4;
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", [ "1" ], ".m4s");
-    })
-    .then(function() {
-      info("Invoking play()");
-      const promises = [];
-      promises.push(once(el, "playing"));
-      el.play();
-      return Promise.all(promises);
-    })
-    .then(function() {
-      info("got playing");
-      return once(el, "waiting");
-    }).then(function() {
-      info("got waiting");
-      info("Loading more data");
-      // Waiting will be fired on the last frame +- 40ms.
-      isfuzzy(el.currentTime, videosb.buffered.end(0) - 1 / 30,
-              0.04, "Got a waiting event at " + el.currentTime);
-      videosb.appendWindowEnd = 1;
-      const p = once(el, "ended");
-      const loads = fetchAndLoad(videosb, "bipbop/bipbop_video", [ 1 ], ".m4s");
-      loads.then(() => ms.endOfStream());
-      return p;
-    }).then(function() {
-      // These fuzz factors are bigger than they should be. We should investigate
-      // and fix them in bug 1137574.
-      is(el.duration, 0.801666, "Video has correct duration: " + el.duration);
-      is(el.currentTime, el.duration, "Video has correct currentTime.");
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  // Set appendWindowEnd to ensure we only have about 6 frames worth.
+  // We must feed at least 6 frames to pass the MDSM pre-roll.
+  videosb.appendWindowEnd = .4;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "1" ], ".m4s");
+  info("Invoking play()");
+  const p = once(el, "playing");
+  await el.play();
+  await p;
+  info("got playing");
+  await once(el, "waiting");
+  info("got waiting");
+  info("Loading more data");
+  // Waiting will be fired on the last frame +- 40ms.
+  isfuzzy(el.currentTime, videosb.buffered.end(0) - 1 / 30,
+          0.04, `Got a waiting event at ${el.currentTime}`);
+  videosb.appendWindowEnd = 1;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ 1 ], ".m4s");
+  ms.endOfStream();
+  await once(el, "ended");
+  // These fuzz factors are bigger than they should be. We should investigate
+  // and fix them in bug 1137574.
+  is(el.duration, 0.801666, "Video has correct duration: " + el.duration);
+  is(el.currentTime, el.duration, "Video has correct currentTime.");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_DurationChange.html
+++ b/dom/media/mediasource/test/test_DurationChange.html
@@ -7,108 +7,65 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-    fetchWithXHR("seek.webm", function(arrayBuffer) {
-      sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
-      const promises = [];
-      promises.push(once(v, "loadedmetadata"));
-      promises.push(once(sb, "updateend"));
-      Promise.all(promises)
-      .then(function() {
-        is(v.duration, ms.duration, "video duration is mediasource one");
-        try {
-          ms.duration = 0;
-        } catch (e) { ok(false, "must not throw as operation is valid"); }
-        is(v.duration, 0, "reducing duration with no data buffered is valid");
-        sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
-        // Adding more data will fire durationchange.
-        once(sb, "updateend")
-        .then(function() {
-          ok(true, "got updateend");
-          // XXX: Duration should be exactly 4.0, see bug 1065207.
-          ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
-          let error = false;
-          try {
-            ms.duration = 0;
-          } catch (e) {
-            ok(true, "must use remove for range removal");
-            is(e.name, "InvalidStateError", "Error is InvalidStateError");
-            error = true;
-          }
-          ok(error, "got an error");
-          ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
-          try {
-            ms.duration = 10;
-          } catch (e) { ok(false, "must not throw as setting duration past data is valid"); }
-          is(v.duration, 10, "extending duration is always valid");
-          // The last sample has a start time of 3.967000s and a end time of 4.001 (see bug 1065207).
-          try {
-            ms.duration = 3.967000;
-          } catch (e) { ok(false, "setting duration with >= highest frame presentation time is valid"); }
-          is(v.duration, sb.buffered.end(0), "duration is the highest end time reported by the buffered attribute ");
-          try {
-            ms.duration = 3.97;
-          } catch (e) { ok(false, "setting duration with >= highest frame presentation time is valid"); }
-          is(v.duration, sb.buffered.end(0), "duration is the highest end time reported by the buffered attribute ");
-          error = false;
-          try {
-            ms.duration = 3.96;
-          } catch (e) {
-            ok(true, "setting duration with < highest frame presentation time is not valid");
-            is(e.name, "InvalidStateError", "Error is InvalidStateError");
-            error = true;
-          }
-          ok(error, "got an error");
-          is(v.duration, sb.buffered.end(0), "duration is the highest end time reported by the buffered attribute ");
-          error = false;
-          try {
-            ms.duration = -1;
-          } catch (e) {
-            ok(true, "can't set a negative duration");
-            is(e.name, "TypeError", "Error is TypeError");
-            error = true;
-          }
-          ok(error, "got an error");
-          sb.remove(sb.buffered.end(0), Infinity);
-          is(sb.updating, true, "updating is true");
-          error = false;
-          try {
-            ms.duration = Infinity;
-          } catch (e) {
-            ok(true, "setting the duration while updating is not allowed");
-            is(e.name, "InvalidStateError", "Error is InvalidStateError");
-            error = true;
-          }
-          ok(error, "got an error");
-          error = false;
-          try {
-            sb.abort();
-          } catch (e) {
-            ok(true, "Can't use abort while range removal is in progress");
-            is(e.name, "InvalidStateError", "Error is InvalidStateError");
-            error = true;
-          }
-          ok(error, "got an error");
-          is(v.duration, sb.buffered.end(0), "duration is the highest end time reported by the buffered attribute ");
-          once(sb, "updateend", () => ms.endOfStream());
-        });
-      });
-    });
-  });
-  ms.addEventListener("sourceended", function() {
-    SimpleTest.finish();
-  });
+  const arrayBuffer = await fetchWithXHR("seek.webm");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
+  await Promise.all([ once(v, "loadedmetadata"), once(sb, "updateend") ]);
+  is(v.duration, ms.duration, "video duration is mediasource one");
+  must_not_throw(() => ms.duration = 0, "duration = 0 is valid initially");
+  is(v.duration, 0, "reducing duration with no data buffered is valid");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
+  // Adding more data will fire durationchange.
+  await once(sb, "updateend");
+  ok(true, "got updateend");
+  // XXX: Duration should be exactly 4.0, see bug 1065207.
+  ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
+  must_throw(() => ms.duration = 0,
+             "Must use remove for range removal",
+             "InvalidStateError");
+  ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
+  must_not_throw(() => ms.duration = 10, "setting duration past data is valid");
+  is(v.duration, 10, "extending duration is always valid");
+  // The last sample has a start time of 3.967000s and a end time of 4.001 (see bug 1065207).
+  must_not_throw(() => ms.duration = 3.967000,
+                 "setting duration with >= highest frame presentation time is valid");
+  is(v.duration, sb.buffered.end(0),
+     "duration is the highest end time reported by the buffered attribute ");
+  must_not_throw(() => ms.duration = 3.97,
+                 "setting duration with >= highest frame presentation time is valid");
+  is(v.duration, sb.buffered.end(0),
+     "duration is the highest end time reported by the buffered attribute ");
+  must_throw(() => ms.duration = 3.96,
+             "setting duration with < highest frame presentation time is not valid",
+             "InvalidStateError");
+  is(v.duration, sb.buffered.end(0),
+     "duration is the highest end time reported by the buffered attribute ");
+  must_throw(() => ms.duration = -1, "can't set a negative duration", "TypeError");
+  sb.remove(sb.buffered.end(0), Infinity);
+  is(sb.updating, true, "updating is true");
+  must_throw(() => ms.duration = Infinity,
+             "setting the duration while updating is not allowed",
+             "InvalidStateError");
+  must_throw(() => sb.abort(),
+             "Can't use abort while range removal is in progress",
+             "InvalidStateError");
+  is(v.duration, sb.buffered.end(0),
+     "duration is the highest end time reported by the buffered attribute ");
+  await once(sb, "updateend");
+  ms.endOfStream();
+  await once(ms, "sourceended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_DurationUpdated.html
+++ b/dom/media/mediasource/test/test_DurationUpdated.html
@@ -7,54 +7,42 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let durationChangeCount = 0;
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
+  let durationChangeCount = 0;
+  v.addEventListener("durationchange", () => durationChangeCount++);
 
-    v.addEventListener("durationchange", function() {
-      durationChangeCount++;
-    });
+  const arrayBuffer = await fetchWithXHR("seek.webm");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
 
-    fetchWithXHR("seek.webm", function(arrayBuffer) {
-      sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
-      // Adding the first init segment will fire a durationchange.
-      const promises = [];
-      promises.push(once(sb, "updateend"));
-      promises.push(once(v, "loadedmetadata"));
-      Promise.all(promises)
-      .then(function() {
-        ok(true, "got loadedmetadata");
-        // Set mediasource duration to 0, so future appendBuffer
-        // will update the mediasource duration.
-        // Changing the duration will fire a durationchange.
-        ms.duration = 0;
-        sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
-        // Adding more data will fire durationchange.
-        once(sb, "updateend")
-        .then(function() {
-          ok(true, "got updateend");
-          // this will not fire durationchange as new duration == old duration
-          ms.endOfStream();
-        });
-      });
-    });
-  });
-  ms.addEventListener("sourceended", function() {
-    is(durationChangeCount, 3, "durationchange not fired as many times as expected");
-    // XXX: Duration should be exactly 4.0, see bug 1065207.
-    ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
-    SimpleTest.finish();
-  });
+  // Adding the first init segment will fire a durationchange.
+  await Promise.all([ once(sb, "updateend"), once(v, "loadedmetadata") ]);
+  ok(true, "got loadedmetadata");
+  // Set mediasource duration to 0, so future appendBuffer
+  // will update the mediasource duration.
+  // Changing the duration will fire a durationchange.
+  ms.duration = 0;
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
+  // Adding more data will fire durationchange.
+  await once(sb, "updateend");
+  ok(true, "got updateend");
+  // this will not fire durationchange as new duration == old duration
+  ms.endOfStream();
+  await once(ms, "sourceended");
+  is(durationChangeCount, 3, "durationchange not fired as many times as expected");
+  // XXX: Duration should be exactly 4.0, see bug 1065207.
+  ok(Math.abs(v.duration - 4) <= 0.002, "Video has correct duration");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_DurationUpdated_mp4.html
+++ b/dom/media/mediasource/test/test_DurationUpdated_mp4.html
@@ -7,53 +7,41 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let durationChangeCount = 0;
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/mp4");
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/mp4");
+  let durationChangeCount = 0;
+  v.addEventListener("durationchange", () => durationChangeCount++);
 
-    v.addEventListener("durationchange", function() {
-      durationChangeCount++;
-    });
+  const arrayBuffer = await fetchWithXHR("bipbop/bipbop2s.mp4");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 1395));
 
-    fetchWithXHR("bipbop/bipbop2s.mp4", function(arrayBuffer) {
-      sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 1395));
-      // Adding the first init segment will fire a durationchange.
-      const promises = [];
-      promises.push(once(sb, "updateend"));
-      promises.push(once(v, "loadedmetadata"));
-      Promise.all(promises)
-      .then(function() {
-        ok(true, "got loadedmetadata");
-        // Set mediasource duration to 0, so future appendBuffer
-        // will update the mediasource duration.
-        // Changing the duration will fire a durationchange.
-        ms.duration = 0;
-        sb.appendBuffer(new Uint8Array(arrayBuffer, 1395));
-        // Adding more data will fire durationchange.
-        once(sb, "updateend")
-        .then(function() {
-          ok(true, "got updateend");
-          // this will not fire durationchange as new duration == old duration
-          ms.endOfStream();
-        });
-      });
-    });
-  });
-  ms.addEventListener("sourceended", function() {
-    is(durationChangeCount, 3, "durationchange not fired as many times as expected");
-    is(v.duration, 1.696666, "Video has correct duration");
-    SimpleTest.finish();
-  });
+  // Adding the first init segment will fire a durationchange.
+  await Promise.all([ once(sb, "updateend"), once(v, "loadedmetadata") ]);
+  ok(true, "got loadedmetadata");
+  // Set mediasource duration to 0, so future appendBuffer
+  // will update the mediasource duration.
+  // Changing the duration will fire a durationchange.
+  ms.duration = 0;
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 1395));
+  // Adding more data will fire durationchange.
+  await once(sb, "updateend");
+  ok(true, "got updateend");
+  // this will not fire durationchange as new duration == old duration
+  ms.endOfStream();
+  await once(ms, "sourceended");
+  is(durationChangeCount, 3, "durationchange not fired as many times as expected");
+  is(v.duration, 1.696666, "Video has correct duration");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_EndedEvent.html
+++ b/dom/media/mediasource/test/test_EndedEvent.html
@@ -7,27 +7,25 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
-  once(ms, "sourceopen").then(function() {
-    const sb = ms.addSourceBuffer("video/webm");
-    fetchWithXHR("seek.webm", (buf) => sb.appendBuffer(new Uint8Array(buf)));
-    sb.addEventListener("updateend", () => ms.endOfStream());
+runWithMSE(async (ms, el) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
+  sb.appendBuffer(new Uint8Array(await fetchWithXHR("seek.webm")));
+  sb.addEventListener("updateend", () => ms.endOfStream());
 
-    // Test 'ended' is fired when seeking to the end of the media
-    // once the duration is known.
-    ms.onsourceended = () => {
-      el.currentTime = el.duration;
-    };
-    el.addEventListener("ended", SimpleTest.finish.bind(null));
-  });
+  // Test "ended" is fired when seeking to the end of the media
+  // once the duration is known.
+  ms.onsourceended = () => el.currentTime = el.duration;
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_Eviction_mp4.html
+++ b/dom/media/mediasource/test/test_Eviction_mp4.html
@@ -10,73 +10,54 @@
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 // We fill up the source buffer with audio data until the buffer is full.
 // We ensure that QuotaExceededError is thrown once the buffer is full.
 // We then seek to half the content. By that time, another appendBuffer must succeed
 // as the auto-eviction would succeed (removing all data prior currentTime)
 
-// Fill up the SourceBuffer by appending data repeatedly via doAppendDataFunc until
-// an exception is thrown.
-function fillUpSourceBuffer(sourceBuffer, doAppendDataFunc, onCaughtExceptionCallback) {
-  // We are appending data repeatedly in sequence mode, there should be no gaps.
-  ok(sourceBuffer.buffered.length <= 1, "there should be no gap in buffered ranges.");
-  try {
-    doAppendDataFunc();
-  } catch (ex) {
-    onCaughtExceptionCallback(ex);
-    return;
-  }
-  once(sourceBuffer, "updateend", () => {
-    fillUpSourceBuffer(sourceBuffer, doAppendDataFunc, onCaughtExceptionCallback);
-  });
-}
-
 addMSEPrefs(
   [ "media.mediasource.eviction_threshold.audio", 524288 ],
   [ "media.dormant-on-pause-timeout-ms", -1 ] // FIXME: bug 1319292
 );
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    audiosb.mode = "sequence";
-    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4")
-    .then(function() {
-      fetchWithXHR("bipbop/bipbop_audio1.m4s", function(audioBuffer) {
-        fillUpSourceBuffer(audiosb,
-          function() { // doAppendDataFunc
-            audiosb.appendBuffer(audioBuffer);
-          },
-          function(ex1) { // onCaughtExceptionCallback
-            is(ex1.name, "QuotaExceededError", "QuotaExceededError thrown");
-            is(audiosb.buffered.end(0), el.duration, "Duration is end of buffered range");
-            const seekTime = audiosb.buffered.end(0) / 2;
-            el.currentTime = seekTime;
-            once(el, "seeked", () => {
-              dump("dump: seeked to " + seekTime);
-              is(el.currentTime, seekTime, "correctly seeked to " + seekTime);
-              try {
-                audiosb.appendBuffer(audioBuffer);
-              } catch (ex2) {
-                ok(false, "Shouldn't throw another time when data can be evicted");
-                el.mozDumpDebugInfo();
-                SimpleTest.finish();
-                return;
-              }
-              once(audiosb, "update", () => {
-                ok(true, "appendBuffer succeeded");
-                SimpleTest.finish();
-              });
-            });
-          });
-      });
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  audiosb.mode = "sequence";
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  const audioBuffer = await fetchWithXHR("bipbop/bipbop_audio1.m4s");
+
+  await must_reject(async () => {
+    // We are appending data repeatedly in sequence mode, there should be no gaps.
+    while (true) {
+      ok(audiosb.buffered.length <= 1, "there should be no gap in buffered ranges.");
+      audiosb.appendBuffer(audioBuffer);
+      await once(audiosb, "updateend");
+    }
+  },
+  "Fill up SourceBuffer by appending data until an exception is thrown.",
+  "QuotaExceededError");
+
+  is(audiosb.buffered.end(0), el.duration, "Duration is end of buffered range");
+  const seekTime = audiosb.buffered.end(0) / 2;
+  el.currentTime = seekTime;
+  await once(el, "seeked");
+  dump("dump: seeked to " + seekTime);
+  is(el.currentTime, seekTime, "correctly seeked to " + seekTime);
+  try {
+    audiosb.appendBuffer(audioBuffer);
+    await once(audiosb, "update");
+    ok(true, "appendBuffer succeeded");
+  } catch (ex) {
+    ok(false, "Shouldn't throw another time when data can be evicted");
+    el.mozDumpDebugInfo();
+  }
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_FrameSelection.html
+++ b/dom/media/mediasource/test/test_FrameSelection.html
@@ -7,72 +7,58 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-const updateCount = 0;
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-const targets = [ { currentTime: 3, videoWidth: 160, videoHeight: 120 },
-                  { currentTime: 2, videoWidth: 160, videoHeight: 120 },
-                  { currentTime: 0, videoWidth: 320, videoHeight: 240 } ];
-let target;
+  let arrayBuffer = await fetchWithXHR("seek.webm");
+  let p = once(v, "loadedmetadata");
+  // Append entire file covering range [0, 4].
+  sb.appendBuffer(new Uint8Array(arrayBuffer));
+  await p;
+  is(v.currentTime, 0, "currentTime has correct initial value");
+  is(v.videoWidth, 320, "videoWidth has correct initial value");
+  is(v.videoHeight, 240, "videoHeight has correct initial value");
 
-let lowResBuffer;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
+  arrayBuffer = await fetchWithXHR("seek_lowres.webm");
+  // Append initialization segment.
+  info("Appending low-res init segment");
+  p = once(sb, "updateend");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438));
+  await p;
 
-    fetchWithXHR("seek.webm")
-    .then(function(arrayBuffer) {
-      const p = once(v, "loadedmetadata");
-      // Append entire file covering range [0, 4].
-      sb.appendBuffer(new Uint8Array(arrayBuffer));
-      return p;
-    }).then(function() {
-      is(v.currentTime, 0, "currentTime has correct initial value");
-      is(v.videoWidth, 320, "videoWidth has correct initial value");
-      is(v.videoHeight, 240, "videoHeight has correct initial value");
-      return fetchWithXHR("seek_lowres.webm");
-    }).then(function(arrayBuffer) {
-      // Append initialization segment.
-      const p = once(sb, "updateend");
-      info("Appending low-res init segment");
-      sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438));
-      lowResBuffer = arrayBuffer;
-      return p;
-    }).then(function() {
-      const p = once(sb, "updateend");
-      info("Appending low-res range [2,4]");
-      // Append media segment covering range [2, 4].
-      sb.appendBuffer(new Uint8Array(lowResBuffer, 51003));
-      return p;
-    }).then(function() {
-      ms.endOfStream();
-      const p = Promise.all([ once(v, "seeked"), once(v, "resize") ]);
-      info("Seeking to t=3");
-      v.currentTime = 3;
-      return p;
-    }).then(function() {
-      is(v.currentTime, 3, "Video currentTime at target");
-      is(v.videoWidth, 160, "videoWidth has correct low-res value");
-      is(v.videoHeight, 120, "videoHeight has correct low-res value");
+  info("Appending low-res range [2,4]");
+  // Append media segment covering range [2, 4].
+  p = once(sb, "updateend");
+  sb.appendBuffer(new Uint8Array(arrayBuffer, 51003));
+  await p;
+
+  ms.endOfStream();
 
-      const p = Promise.all([ once(v, "seeked"), once(v, "resize") ]);
-      info("Seeking to t=1");
-      v.currentTime = 1;
-      return p;
-    }).then(function() {
-      is(v.currentTime, 1, "Video currentTime at target");
-      is(v.videoWidth, 320, "videoWidth has correct high-res value");
-      is(v.videoHeight, 240, "videoHeight has correct high-res value");
-      SimpleTest.finish();
-    });
-  });
+  info("Seeking to t=3");
+  p = Promise.all([ once(v, "seeked"), once(v, "resize") ]);
+  v.currentTime = 3;
+  await p;
+  is(v.currentTime, 3, "Video currentTime at target");
+  is(v.videoWidth, 160, "videoWidth has correct low-res value");
+  is(v.videoHeight, 120, "videoHeight has correct low-res value");
+
+  info("Seeking to t=1");
+  p = Promise.all([ once(v, "seeked"), once(v, "resize") ]);
+  v.currentTime = 1;
+  await p;
+  is(v.currentTime, 1, "Video currentTime at target");
+  is(v.videoWidth, 320, "videoWidth has correct high-res value");
+  is(v.videoHeight, 240, "videoHeight has correct high-res value");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_FrameSelection_mp4.html
+++ b/dom/media/mediasource/test/test_FrameSelection_mp4.html
@@ -9,64 +9,41 @@
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 // This test loads partial video, plays and waits until playback stalls.
 // It then loads only 3 frames of a video at higher resolution.
 
-let receivedSourceOpen = false;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
-    receivedSourceOpen = true;
-    const sb = ms.addSourceBuffer("video/mp4");
-    ok(sb, "Create a SourceBuffer");
-
-    // Log events for debugging.
-    const events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
-                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
-                     "waiting", "pause", "durationchange", "seeking", "seeked" ];
-    function logEvent(e) {
-      info("got " + e.type + " event");
-    }
-    events.forEach(function(e) {
-      v.addEventListener(e, logEvent);
-    });
-
-    sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-    fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4")
-    .then(function() {
-      const promises = [];
-      promises.push(fetchAndLoad(sb, "bipbop/bipbop", range(1, 3), ".m4s"));
-      promises.push(once(v, "loadeddata"));
-      return Promise.all(promises);
-    }).then(function() {
-      is(sb.buffered.length, 1, "continuous range");
-      v.play();
-      // We have nothing to play, waiting will be fired.
-      return waitUntilTime(v, 1.5);
-    }).then(function() {
-      return fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4");
-    }).then(function() {
-      sb.timestampOffset = 1.601666; // End of the video track buffered - time of first video sample (0.095).
-      sb.appendWindowEnd = 1.796677; // Only allow room for three extra video frames (we need 3 as this video has b-frames).
-      return fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "1" ], ".m4s");
-    }).then(function() {
-      ms.endOfStream();
-      const promises = [];
-      promises.push(once(ms, "sourceended"));
-      promises.push(once(v, "playing"));
-      promises.push(once(v, "ended"));
-      return Promise.all(promises);
-    }).then(function() {
-      if (v.width, 640, "has proper width");
-      if (v.height, 480, "has proper height");
-      SimpleTest.finish();
-    });
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  ms.addEventListener("sourceopen", () => ok(false, "No more sourceopen"));
+  const sb = ms.addSourceBuffer("video/mp4");
+  ok(sb, "Create a SourceBuffer");
+  logEvents(v);
+  sb.addEventListener("error", function(e) {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4");
+  const p = once(v, "loadeddata");
+  await fetchAndLoad(sb, "bipbop/bipbop", range(1, 3), ".m4s");
+  await p;
+  is(sb.buffered.length, 1, "continuous range");
+  v.play();
+  // We have nothing to play, waiting will be fired.
+  await waitUntilTime(v, 1.5);
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4");
+  sb.timestampOffset = 1.601666; // End of the video track buffered - time of first video sample (0.095).
+  sb.appendWindowEnd = 1.796677; // Only allow room for three extra video frames (we need 3 as this video has b-frames).
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "1" ], ".m4s");
+  ms.endOfStream();
+  await Promise.all([ once(ms, "sourceended"), once(v, "playing"), once(v, "ended") ]);
+  if (v.width, 640, "has proper width");
+  if (v.height, 480, "has proper height");
+  SimpleTest.finish();
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_LiveSeekable.html
+++ b/dom/media/mediasource/test/test_LiveSeekable.html
@@ -7,74 +7,70 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
-    // Load data with a +2 offset so that we can distinguish buffered range start
-    // and seekable range start.
-    sb.timestampOffset = 2;
-    const promises = [];
-    promises.push(fetchAndLoad(sb, "seek", [ "" ], ".webm"));
-    promises.push(once(v, "loadedmetadata"));
-    Promise.all(promises)
-    .then(function() {
-      ms.duration = Infinity;
-      sb.abort();
-      is(sb.buffered.length, 1, "continuous buffered range");
-      is(sb.buffered.start(0), 2, "buffered range start at timestamp offset");
-      is(sb.buffered.end(0), 6.001, "buffered range end at original duration + timestamp offset");
-      is(v.seekable.length, 1, "continuous seekable range");
-      is(v.seekable.start(0), 0, "seekable range start at 0");
-      is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-      // LiveSeekableRange.start < buffered.start
-      ms.setLiveSeekableRange(1, 5);
-      is(v.seekable.length, 1, "continuous seekable range");
-      is(v.seekable.start(0), 1, "seekable range start at live range start");
-      is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
+  // Load data with a +2 offset so that we can distinguish buffered range start
+  // and seekable range start.
+  sb.timestampOffset = 2;
+  const p = once(v, "loadedmetadata");
+  await fetchAndLoad(sb, "seek", [ "" ], ".webm");
+  await p;
+  ms.duration = Infinity;
+  sb.abort();
+  is(sb.buffered.length, 1, "continuous buffered range");
+  is(sb.buffered.start(0), 2, "buffered range start at timestamp offset");
+  is(sb.buffered.end(0), 6.001, "buffered range end at original duration + timestamp offset");
+  is(v.seekable.length, 1, "continuous seekable range");
+  is(v.seekable.start(0), 0, "seekable range start at 0");
+  is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
+
+  // LiveSeekableRange.start < buffered.start
+  ms.setLiveSeekableRange(1, 5);
+  is(v.seekable.length, 1, "continuous seekable range");
+  is(v.seekable.start(0), 1, "seekable range start at live range start");
+  is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
 
-      ms.clearLiveSeekableRange();
-      ok(v.seekable.length, 1, "continuous seekable range");
-      is(v.seekable.start(0), 0, "seekable range start at 0");
-      is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
+  ms.clearLiveSeekableRange();
+  ok(v.seekable.length, 1, "continuous seekable range");
+  is(v.seekable.start(0), 0, "seekable range start at 0");
+  is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
 
-      // LiveSeekableRange.end > buffered.end
-      ms.setLiveSeekableRange(1, 8);
-      is(v.seekable.start(0), 1, "seekable range start at live range start");
-      is(v.seekable.end(0), 8, "seekable range end at live range end");
+  // LiveSeekableRange.end > buffered.end
+  ms.setLiveSeekableRange(1, 8);
+  is(v.seekable.start(0), 1, "seekable range start at live range start");
+  is(v.seekable.end(0), 8, "seekable range end at live range end");
 
-      // LiveSeekableRange.start > buffered.start
-      // LiveSeekableRange.end < buffered.end
-      ms.setLiveSeekableRange(3, 5);
-      is(v.seekable.start(0), sb.buffered.start(0), "seekable range start at buffered start");
-      is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at live range end");
+  // LiveSeekableRange.start > buffered.start
+  // LiveSeekableRange.end < buffered.end
+  ms.setLiveSeekableRange(3, 5);
+  is(v.seekable.start(0), sb.buffered.start(0), "seekable range start at buffered start");
+  is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at live range end");
 
-      // LiveSeekableRange.start > buffered.end
-      ms.setLiveSeekableRange(8, 10);
-      is(v.seekable.start(0), sb.buffered.start(0), "seekable range start at buffered start");
-      is(v.seekable.end(0), 10, "seekable range end at live range end");
+  // LiveSeekableRange.start > buffered.end
+  ms.setLiveSeekableRange(8, 10);
+  is(v.seekable.start(0), sb.buffered.start(0), "seekable range start at buffered start");
+  is(v.seekable.end(0), 10, "seekable range end at live range end");
 
-      // LiveSeekableRange.end < buffered.start
-      ms.setLiveSeekableRange(0, 2);
-      is(v.seekable.start(0), 0, "seekable range start at live range start");
-      is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
+  // LiveSeekableRange.end < buffered.start
+  ms.setLiveSeekableRange(0, 2);
+  is(v.seekable.start(0), 0, "seekable range start at live range start");
+  is(v.seekable.end(0), sb.buffered.end(0), "seekable range end at buffered end");
 
-      try {
-        ms.setLiveSeekableRange(2, 0);
-        ok(false, "start > end");
-      } catch (e) { ok(true, "must thow if start > end"); }
+  must_throw(() => ms.setLiveSeekableRange(2, 0),
+             "must thow if start > end",
+             "TypeError");
 
-      SimpleTest.finish();
-    });
-  });
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_LoadedDataFired_mp4.html
+++ b/dom/media/mediasource/test/test_LoadedDataFired_mp4.html
@@ -7,64 +7,51 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
   el.addEventListener("loadeddata", function() {
     ok(el.buffered.length > 0, "data is buffered");
     is(el.buffered.start(0), 0, "must fire loadeddata when data has been loaded");
     is(el.currentTime, 0, "must fire loadeddata at start");
   });
   el.addEventListener("playing", function() {
     ok(el.buffered.length > 0, "data is buffered");
     is(el.buffered.start(0), 0, "must fire playing when data has been loaded");
     ok(el.currentTime >= 0, "must have started playback");
   });
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const loadedmetadataPromises = [];
-    loadedmetadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    loadedmetadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(loadedmetadataPromises)
-    .then(function() {
-      videosb.appendWindowStart = 2;
-      videosb.appendWindowEnd = 4;
-      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      // Load [2.4, 3.968344). 2.4 as it's the first keyframe after 2s and
-      // 3.968344 as the last frame ends after 4s.
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 8), ".m4s");
-    })
-    .then(function() {
-      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      // test that appendWindowEnd did its job.
-      ok(el.buffered.start(0) >= 2, "no data can be found prior appendWindowStart");
-      ok(el.buffered.end(el.buffered.length - 1) <= 4, "no data can be found beyond appendWindowEnd");
-      el.play();
-      return once(el, "play");
-    })
-    .then(function() {
-      videosb.appendWindowStart = 0;
-      const playingPromises = [];
-      // Load [0, 3.971666).
-      playingPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 8), ".m4s"));
-      // playback can only start now.
-      playingPromises.push(once(el, "playing"));
-      return Promise.all(playingPromises);
-    })
-    .then(function() {
-      ok(true, "playing");
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await p;
+  videosb.appendWindowStart = 2;
+  videosb.appendWindowEnd = 4;
+  is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  // Load [2.4, 3.968344). 2.4 as it's the first keyframe after 2s and
+  // 3.968344 as the last frame ends after 4s.
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 8), ".m4s");
+  is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  // test that appendWindowEnd did its job.
+  ok(el.buffered.start(0) >= 2, "no data can be found prior appendWindowStart");
+  ok(el.buffered.end(el.buffered.length - 1) <= 4, "no data can be found beyond appendWindowEnd");
+  el.play();
+  await once(el, "play");
+  videosb.appendWindowStart = 0;
+  p = once(el, "playing");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 8), ".m4s");
+  await p;
+  ok(true, "playing");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_MediaSource_flac_mp4.html
+++ b/dom/media/mediasource/test/test_MediaSource_flac_mp4.html
@@ -6,32 +6,28 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    is(ms.readyState, "open", "MediaSource must be in open state after sourceopen");
-    const sb = ms.addSourceBuffer("audio/mp4; codecs=\"flac\"");
-    ok(sb, "Create a SourceBuffer");
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  is(ms.readyState, "open", "MediaSource must be in open state after sourceopen");
+  const sb = ms.addSourceBuffer("audio/mp4; codecs=\"flac\"");
+  ok(sb, "Create a SourceBuffer");
 
-    fetchAndLoad(sb, "flac/IS", [ "" ], ".mp4")
-    .then(fetchAndLoad.bind(null, sb, "flac/0000", range(1, 3), ".m4s"))
-    .then(function() {
-      el.play();
-      ms.endOfStream();
-      return once(el, "ended");
-    }).then(function() {
-      SimpleTest.finish();
-    });
-  });
+  await fetchAndLoad(sb, "flac/IS", [ "" ], ".mp4");
+  await fetchAndLoad(sb, "flac/0000", range(1, 3), ".m4s");
+  el.play();
+  ms.endOfStream();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_MediaSource_memory_reporting.html
+++ b/dom/media/mediasource/test/test_MediaSource_memory_reporting.html
@@ -7,48 +7,41 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
+runWithMSE(async (ms, v) => {
+  // Load a webm video and play it.
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
+  await fetchAndLoad(sb, "seek", [ "" ], ".webm");
+  const p = once(v, "ended");
+  ms.endOfStream();
+  v.play();
+  await p;
+
   // Test that memory reporting works once we've played a video.
-  once(v, "ended", () => {
-    // Grab a memory report.
-    const mgr = SpecialPowers.Cc["@mozilla.org/memory-reporter-manager;1"]
+  // Grab a memory report.
+  const mgr = SpecialPowers.Cc["@mozilla.org/memory-reporter-manager;1"]
       .getService(SpecialPowers.Ci.nsIMemoryReporterManager);
 
-    let amount = 0;
-    let resourcePathSeen = false;
-    const handleReport = function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) {
-      if (aPath == "explicit/media/resources") {
-        resourcePathSeen = true;
-        amount += aAmount;
-      }
-    };
+  let amount;
+  const handleReport = (aProcess, aPath, aKind, aUnits, aAmount) => {
+    if (aPath == "explicit/media/resources") {
+      amount = (amount || 0) + aAmount;
+    }
+  };
 
-    const finished = function() {
-      ok(true, "Yay didn't crash!");
-      ok(resourcePathSeen, "Got media resources amount");
-      ok(amount > 0, "Non-zero amount reported for media resources");
-      SimpleTest.finish();
-    };
-
-    mgr.getReports(handleReport, null, finished, null, /* anonymized = */ false);
-  });
-
-  // Load a webm video and play it.
-  ms.addEventListener("sourceopen", () => {
-    const sb = ms.addSourceBuffer("video/webm");
-    fetchAndLoad(sb, "seek", [ "" ], ".webm").then(function() {
-      ms.endOfStream();
-      v.play();
-    });
-  });
+  await new Promise(r => mgr.getReports(handleReport, null, r, null, /* anonymized = */ false));
+  ok(true, "Yay didn't crash!");
+  ok(amount !== undefined, "Got media resources amount");
+  ok(amount > 0, "Non-zero amount reported for media resources");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_MultipleInitSegments.html
+++ b/dom/media/mediasource/test/test_MultipleInitSegments.html
@@ -8,46 +8,42 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
-    fetchWithXHR("seek_lowres.webm", function(seek_lowres) {
-      fetchWithXHR("seek.webm", function(seek) {
-        const data = [
-          [ seek_lowres, 0, 438 ],     // lowres init segment
-          [ seek_lowres, 438, 25950 ], // lowres media segment 0-1
-          [ seek, 0, 318 ],            // init segment
-          [ seek, 46712, 67833 ]       // media segment 0.8-1.201
-        ];
-        const length = data.map(d => d[2] - d[1]).reduce((a, b) => a + b);
-        const arrayBuffer = new Uint8Array(length);
-        let pos = 0;
-        data.forEach(function(d) {
-          const buffer = new Uint8Array(d[0], d[1], d[2] - d[1]);
-          arrayBuffer.set(buffer, pos);
-          pos += buffer.byteLength;
-        });
-        loadSegment.bind(null, sb, arrayBuffer)().then(function() {
-          // Since we are passing multiple segments in one buffer,
-          // the first durationchange event from parsing the init
-          // segment will be fired before updateend.
-          v.addEventListener("durationchange", function() {
-            ok(v.duration, 1.201);
-            SimpleTest.finish();
-          });
-          ms.endOfStream();
-        });
-      });
-    });
-  });
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
+  const seek_lowres = await fetchWithXHR("seek_lowres.webm");
+  const seek = await fetchWithXHR("seek.webm");
+  const data = [
+    [ seek_lowres, 0, 438 ],     // lowres init segment
+    [ seek_lowres, 438, 25950 ], // lowres media segment 0-1
+    [ seek, 0, 318 ],            // init segment
+    [ seek, 46712, 67833 ]       // media segment 0.8-1.201
+  ];
+  const length = data.map(d => d[2] - d[1]).reduce((a, b) => a + b, 0);
+  const arrayBuffer = new Uint8Array(length);
+  let pos = 0;
+  for (const d of data) {
+    const buffer = new Uint8Array(d[0], d[1], d[2] - d[1]);
+    arrayBuffer.set(buffer, pos);
+    pos += buffer.byteLength;
+  }
+  await loadSegment(sb, arrayBuffer);
+  // Since we are passing multiple segments in one buffer,
+  // the first durationchange event from parsing the init
+  // segment will be fired before updateend.
+  const p = once(v, "durationchange");
+  ms.endOfStream();
+  await p;
+  ok(v.duration, 1.201);
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_MultipleInitSegments_mp4.html
+++ b/dom/media/mediasource/test/test_MultipleInitSegments_mp4.html
@@ -8,45 +8,37 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/mp4");
-    fetchWithXHR("bipbop/bipbop_videoinit.mp4", function(init) {
-      init = new Uint8Array(init);
-      fetchWithXHR("bipbop/bipbop_video1.m4s", function(segment1) {
-        segment1 = new Uint8Array(segment1);
-        fetchWithXHR("bipbop/bipbop_video2.m4s", function(segment2) {
-          segment2 = new Uint8Array(segment2);
-          const data = [ init, segment1, init, segment2 ];
-          const length = data.map(d => d.byteLength).reduce((a, b) => a + b);
-          const arrayBuffer = new Uint8Array(length);
-          let pos = 0;
-          data.forEach(function(buffer) {
-            arrayBuffer.set(buffer, pos);
-            pos += buffer.byteLength;
-          });
-          loadSegment.bind(null, sb, arrayBuffer)().then(function() {
-            // Since we are passing multiple segments in one buffer,
-            // the first durationchange event from parsing the init
-            // segment will be fired before updateend.
-            v.addEventListener("durationchange", function() {
-              ok(v.duration, 1.601666);
-              SimpleTest.finish();
-            });
-            ms.endOfStream();
-          });
-        });
-      });
-    });
-  });
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/mp4");
+  const init = new Uint8Array(await fetchWithXHR("bipbop/bipbop_videoinit.mp4"));
+  const segment1 = new Uint8Array(await fetchWithXHR("bipbop/bipbop_video1.m4s"));
+  const segment2 = new Uint8Array(await fetchWithXHR("bipbop/bipbop_video2.m4s"));
+  const data = [ init, segment1, init, segment2 ];
+  const length = data.map(d => d.byteLength).reduce((a, b) => a + b, 0);
+  const arrayBuffer = new Uint8Array(length);
+  let pos = 0;
+  for (const buffer of data) {
+    arrayBuffer.set(buffer, pos);
+    pos += buffer.byteLength;
+  }
+  await loadSegment(sb, arrayBuffer);
+  // Since we are passing multiple segments in one buffer,
+  // the first durationchange event from parsing the init
+  // segment will be fired before updateend.
+  const p = once(v, "durationchange");
+  ms.endOfStream();
+  await p;
+  ok(v.duration, 1.601666);
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_OnEvents.html
+++ b/dom/media/mediasource/test/test_OnEvents.html
@@ -7,59 +7,36 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, v) {
-  function initEvent(e) {
-    v["got" + e] = false;
-  }
-  function receiveEvent(e) {
-    v["got" + e] = true;
-  }
+runWithMSE(async (ms, v) => {
+  const receiveEvent = e => v["got" + e] = true;
+
   const msevents = [ "onsourceopen", "onsourceended" ];
-  msevents.forEach(function(e) {
-    initEvent(e);
-    ms[e] = function() { receiveEvent(e); };
-  });
+  msevents.forEach(e => ms[e] = () => receiveEvent(e));
 
   const sblistevents = [ "onaddsourcebuffer", "onremovesourcebuffer" ];
-  sblistevents.forEach(function(e) {
-    initEvent(e);
-    ms.sourceBuffers[e] = function() { receiveEvent(e); };
-  });
+  sblistevents.forEach(e => ms.sourceBuffers[e] = () => receiveEvent(e));
 
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-    const sbevents = [ "onupdatestart", "onupdate", "onupdateend", "onabort" ];
-    sbevents.forEach(function(e) {
-      initEvent(e);
-      sb[e] = function() { receiveEvent(e); };
-    });
+  const sbevents = [ "onupdatestart", "onupdate", "onupdateend", "onabort" ];
+  sbevents.forEach(e => sb[e] = () => receiveEvent(e));
 
-    fetchAndLoad(sb, "seek", [ "" ], ".webm")
-    .then(function() {
-      fetchWithXHR("seek.webm")
-      .then(function(arrayBuffer) {
-        sb.appendBuffer(arrayBuffer);
-        ms.removeSourceBuffer(sb); // will fire abort and removesourcebuffer
-        ms.endOfStream(); // will fire sourceended
-        once(ms, "sourceended").then(function() {
-          const events = [ "onsourceopen", "onsourceended", "onupdatestart", "onupdate", "onupdateend", "onabort", "onaddsourcebuffer", "onremovesourcebuffer" ];
-          events.forEach(function(e) {
-            ok(v["got" + e], "got " + e);
-          });
-          SimpleTest.finish();
-        });
-      });
-    });
-  });
+  await fetchAndLoad(sb, "seek", [ "" ], ".webm");
+  sb.appendBuffer(await fetchWithXHR("seek.webm"));
+  ms.removeSourceBuffer(sb); // will fire abort and removesourcebuffer
+  ms.endOfStream(); // will fire sourceended
+  await once(ms, "sourceended");
+  [ ...msevents, ...sbevents, ...sblistevents ].forEach(e => ok(v["got" + e], "got " + e));
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_PlayEvents.html
+++ b/dom/media/mediasource/test/test_PlayEvents.html
@@ -16,151 +16,100 @@ SimpleTest.waitForExplicitFinish();
 // 1. Load 1.6s of data and ensure that canplay event is fired.
 // 2. Load data to have a complete buffered range from 0 to duration and ensure that canplaythrough is fired.
 // 3. Seek to an area with no buffered data, and ensure that readyState goes back to HAVE_METADATA
 // 4. Load 1.6s of data at the seek position and ensure that canplay is fired and that readyState is now HAVE_FUTURE_DATA
 // 5. Start playing video and check that once it reaches a position with no data, readyState goes back to HAVE_CURRENT_DATA and waiting event is fired.
 // 6. Add 1.6s of data once video element fired waiting, that canplay is fired once readyState is HAVE_FUTURE_DATA.
 // 7. Finally load data to the end and ensure that canplaythrough is fired and that readyState is now HAVE_ENOUGH_DATA
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    // Log events for debugging.
-    const events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
-                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
-                     "waiting", "pause", "durationchange", "seeking", "seeked" ];
-    function logEvent(e) {
-      info("got " + e.type + " event");
-    }
-    events.forEach(function(e) {
-      el.addEventListener(e, logEvent);
-    });
-
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    el.addEventListener("error", function(e) {
-      ok(false, "should not fire '" + e + "' event");
-    });
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const metadataPromises = [];
-    metadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    metadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(metadataPromises)
-    .then(function() {
-      ok(true, "got loadedmetadata event");
-      const canplayPromises = [];
-      canplayPromises.push(once(el, "loadeddata"));
-      canplayPromises.push(once(el, "canplay"));
-      canplayPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s"));
-      return Promise.all(canplayPromises);
-    })
-    .then(function() {
-      ok(true, "got canplay event");
-      // set element duration to 3.203333s. We do so in order to guarantee that
-      // the end of the buffered range will be equal to duration, causing
-      // canplaythrough to be fired later.
-      ms.duration = 3.203333;
-      return once(el, "durationchange");
-    })
-    .then(function() {
-      ok(true, "got durationchange event");
-      const promises = [];
-      promises.push(once(el, "canplaythrough"));
-      // Load [0.801666, 3.203333]
-      promises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s"));
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got canplaythrough event");
-      // set element duration to 9.203333s, this value is set to coincide with
-      // data added later (we now have an empty range from 6s to 9.203333s).
-      ms.duration = 9.203333;
-      return once(el, "durationchange");
-    })
-    .then(function() {
-      ok(true, "got durationchange event");
-      // An arbitrary value, so we are guaranteed to be in a range with no data.
-      el.currentTime = 6;
-      videosb.timestampOffset = 6;
-      ok(el.seeking, "seeking started");
-      return once(el, "seeking");
-    })
-    .then(function() {
-      ok(true, "got seeking event");
-      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      const promises = [];
-      promises.push(once(el, "seeked"));
-      promises.push(once(el, "canplay"));
-      // Load [6+0, 6+1.601666)
-      promises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s"));
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got seeked and canplay event");
-      is(el.currentTime, 6, "seeked to 6s");
-      is(el.readyState, el.HAVE_FUTURE_DATA, "readyState is HAVE_FUTURE_DATA");
-      const promises = [];
-      promises.push(once(el, "canplaythrough"));
-      // Load [6+1.60166, 6+3.203333]
-      promises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s"));
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got canplaythrough event");
-      // set element duration to 19.805s, this value is set to coincide with
-      // data added later (we now have an empty range from 15 to 19.805).
-      ms.duration = 19.805;
-      return once(el, "durationchange");
-    })
-    .then(function() {
-      ok(true, "got durationchange event");
-      el.currentTime = 15;
-      videosb.timestampOffset = 15;
-      ok(el.seeking, "seeking started");
-      return once(el, "seeking");
-    })
-    .then(function() {
-      ok(true, "got seeking event");
-      const promises = [];
-      promises.push(once(el, "seeked"));
-      // Load [15+0, 15+1.601666)
-      promises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s"));
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got seeked event");
-      // Load [15+1.60166, 15+3.203333]
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s");
-    })
-    .then(function() {
-      ok(true, "data loaded");
-      // Playback we play for a little while then stall.
-      const promises = [];
-      promises.push(once(el, "playing"));
-      promises.push(once(el, "waiting"));
-      el.play();
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got playing and waiting event");
-      // Playback has stalled, readyState is back to HAVE_CURRENT_DATA.
-      is(el.readyState, el.HAVE_CURRENT_DATA, "readyState is HAVE_CURRENT_DATA");
-      const promises = [];
-      promises.push(once(el, "playing"));
-      promises.push(once(el, "canplay"));
-      promises.push(once(el, "canplaythrough"));
-      // Load [15+3.203333, 15+4.805)
-      // Our final buffered range will now be [0, 3.203333)[6, 9.203333)[15, 19.805)
-      promises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 7), ".m4s"));
-      return Promise.all(promises);
-    })
-    .then(function() {
-      ok(true, "got playing, canplay and canplaythrough event");
-      SimpleTest.finish();
-    });
+  await once(ms, "sourceopen");
+  logEvents(el);
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  el.addEventListener("error", e => {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await p;
+  ok(true, "got loadedmetadata event");
+  p = Promise.all([ once(el, "loadeddata"), once(el, "canplay") ]);
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s");
+  await p;
+  ok(true, "got canplay event");
+  // set element duration to 3.203333s. We do so in order to guarantee that
+  // the end of the buffered range will be equal to duration, causing
+  // canplaythrough to be fired later.
+  ms.duration = 3.203333;
+  await once(el, "durationchange");
+  ok(true, "got durationchange event");
+  // Load [0.801666, 3.203333]
+  p = once(el, "canplaythrough");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s");
+  await p;
+  ok(true, "got canplaythrough event");
+  // set element duration to 9.203333s, this value is set to coincide with
+  // data added later (we now have an empty range from 6s to 9.203333s).
+  ms.duration = 9.203333;
+  await once(el, "durationchange");
+  ok(true, "got durationchange event");
+  // An arbitrary value, so we are guaranteed to be in a range with no data.
+  el.currentTime = 6;
+  videosb.timestampOffset = 6;
+  ok(el.seeking, "seeking started");
+  await once(el, "seeking");
+  ok(true, "got seeking event");
+  is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  // Load [6+0, 6+1.601666)
+  p = Promise.all([ once(el, "seeked"), once(el, "canplay") ]);
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s");
+  await p;
+  ok(true, "got seeked and canplay event");
+  is(el.currentTime, 6, "seeked to 6s");
+  is(el.readyState, el.HAVE_FUTURE_DATA, "readyState is HAVE_FUTURE_DATA");
+  // Load [6+1.60166, 6+3.203333]
+  p = once(el, "canplaythrough");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s");
+  await p;
+  ok(true, "got canplaythrough event");
+  // set element duration to 19.805s, this value is set to coincide with
+  // data added later (we now have an empty range from 15 to 19.805).
+  ms.duration = 19.805;
+  await once(el, "durationchange");
+  ok(true, "got durationchange event");
+  el.currentTime = 15;
+  videosb.timestampOffset = 15;
+  ok(el.seeking, "seeking started");
+  await once(el, "seeking");
+  ok(true, "got seeking event");
+  // Load [15+0, 15+1.601666)
+  p = once(el, "seeked");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s");
+  await p;
+  ok(true, "got seeked event");
+  // Load [15+1.60166, 15+3.203333]
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(3, 5), ".m4s");
+  ok(true, "data loaded");
+  // Playback we play for a little while then stall.
+  p = Promise.all([ once(el, "playing"), once(el, "waiting") ]);
+  el.play();
+  await p;
+  ok(true, "got playing and waiting event");
+  // Playback has stalled, readyState is back to HAVE_CURRENT_DATA.
+  is(el.readyState, el.HAVE_CURRENT_DATA, "readyState is HAVE_CURRENT_DATA");
+  // Load [15+3.203333, 15+4.805)
+  // Our final buffered range will now be [0, 3.203333)[6, 9.203333)[15, 19.805)
+  p = Promise.all([ once(el, "playing"), once(el, "canplay"), once(el, "canplaythrough") ]);
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 7), ".m4s");
+  await p;
+  ok(true, "got playing, canplay and canplaythrough event");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_PlayEventsAutoPlaying.html
+++ b/dom/media/mediasource/test/test_PlayEventsAutoPlaying.html
@@ -11,67 +11,48 @@
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 // This test checks that readyState is properly set and the appropriate events are being fired accordingly:
 // 1. Ensure that play/playing aren't fired before any media data been added.
 // 2. Load 1.6s of data and ensure that canplay, play and playing events are fired.
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
   el.autoplay = true;
-  const eventCounts = { play: 0, playing: 0};
-  function ForbiddenEvents(e) {
-    const v = e.target;
-    ok(v.readyState >= v.HAVE_FUTURE_DATA, "Must not have received event too early");
+  const eventCounts = { play: 0, playing: 0 };
+  await once(ms, "sourceopen");
+  logEvents(el);
+  ok(true, "Receive a sourceopen event");
+
+  const forbiddenEvents = e => {
+    ok(el.readyState >= el.HAVE_FUTURE_DATA, "Must not have received event too early");
     is(eventCounts[e.type], 0, "event should have only be fired once");
     eventCounts[e.type]++;
-  }
-  once(ms, "sourceopen").then(function() {
-    // Log events for debugging.
-    const events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
-                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
-                     "waiting", "pause", "durationchange", "seeking", "seeked" ];
-    function logEvent(e) {
-      info("got " + e.type + " event");
-    }
-    events.forEach(function(e) {
-      el.addEventListener(e, logEvent);
-    });
-    el.addEventListener("play", ForbiddenEvents);
-    el.addEventListener("playing", ForbiddenEvents);
+  };
+  el.addEventListener("play", forbiddenEvents);
+  el.addEventListener("playing", forbiddenEvents);
 
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    el.addEventListener("error", function(e) {
-      ok(false, "should not fire '" + e + "' event");
-    });
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const metadataPromises = [];
-    metadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    metadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(metadataPromises)
-    .then(function() {
-      ok(true, "got loadedmetadata event");
-      const playedThroughPromises = [];
-      playedThroughPromises.push(once(el, "loadeddata"));
-      playedThroughPromises.push(once(el, "canplay"));
-      playedThroughPromises.push(once(el, "play"));
-      playedThroughPromises.push(once(el, "playing"));
-      playedThroughPromises.push(once(el, "ended"));
-      // We're only adding 1.6s worth of data, not enough for readyState to change to HAVE_ENOUGH_DATA
-      // So we end the media source so that all the playable data is available.
-      playedThroughPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s")
-                                 .then(() => ms.endOfStream()));
-      return Promise.all(playedThroughPromises);
-    })
-    .then(function() {
-      ok(true, "got all required event");
-      SimpleTest.finish();
-    });
+  const videosb = ms.addSourceBuffer("video/mp4");
+  el.addEventListener("error", e => {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await p;
+  ok(true, "got loadedmetadata event");
+  // We're only adding 1.6s worth of data, not enough for readyState to change to HAVE_ENOUGH_DATA
+  // So we end the media source so that all the playable data is available.
+  p = Promise.all([ "loadeddata", "canplay", "play", "playing", "ended" ].map(e => once(el, e)));
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 3), ".m4s");
+  ms.endOfStream();
+  await p;
+  ok(true, "got all required event");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_PlayEventsAutoPlaying2.html
+++ b/dom/media/mediasource/test/test_PlayEventsAutoPlaying2.html
@@ -11,66 +11,48 @@
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 // This test checks that readyState is properly set and the appropriate events are being fired accordingly:
 // 1. Ensure that play/playing aren't fired before any media data been added.
 // 2. Load more than 10s of data and ensure that canplay, play and playing events are fired.
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
   el.autoplay = true;
-  const eventCounts = { play: 0, playing: 0};
-  function ForbiddenEvents(e) {
-    const v = e.target;
-    ok(v.readyState >= v.HAVE_FUTURE_DATA, "Must not have received event too early");
+  const eventCounts = { play: 0, playing: 0 };
+  await once(ms, "sourceopen");
+  logEvents(el);
+  ok(true, "Receive a sourceopen event");
+
+  const forbiddenEvents = e => {
+    ok(el.readyState >= el.HAVE_FUTURE_DATA, "Must not have received event too early");
     is(eventCounts[e.type], 0, "event should have only be fired once");
     eventCounts[e.type]++;
-  }
-  once(ms, "sourceopen").then(function() {
-    // Log events for debugging.
-    const events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
-                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
-                     "waiting", "pause", "durationchange", "seeking", "seeked" ];
-    function logEvent(e) {
-      info("got " + e.type + " event");
-    }
-    events.forEach(function(e) {
-      el.addEventListener(e, logEvent);
-    });
-    el.addEventListener("play", ForbiddenEvents);
-    el.addEventListener("playing", ForbiddenEvents);
+  };
+  el.addEventListener("play", forbiddenEvents);
+  el.addEventListener("playing", forbiddenEvents);
 
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    el.addEventListener("error", function(e) {
-      ok(false, "should not fire '" + e + "' event");
-    });
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const metadataPromises = [];
-    metadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    metadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(metadataPromises)
-    .then(function() {
-      ok(true, "got loadedmetadata event");
-      const playingPromises = [];
-      // We shift the timestamps slightly to create a small gaps at the start.
-      // one that should normally be ignored.
-      videosb.timestampOffset = 0.1;
-      playingPromises.push(once(el, "loadeddata"));
-      playingPromises.push(once(el, "canplay"));
-      playingPromises.push(once(el, "play"));
-      playingPromises.push(once(el, "playing"));
-      playingPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 14), ".m4s"));
-      return Promise.all(playingPromises);
-    })
-    .then(function() {
-      ok(true, "got all required event");
-      SimpleTest.finish();
-    });
+  const videosb = ms.addSourceBuffer("video/mp4");
+  el.addEventListener("error", e => {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await p;
+  ok(true, "got loadedmetadata event");
+  // We shift the timestamps slightly to create a small gaps at the start.
+  // one that should normally be ignored.
+  videosb.timestampOffset = 0.1;
+  p = Promise.all([ "loadeddata", "canplay", "play", "playing" ].map(e => once(el, e)));
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 14), ".m4s");
+  await p;
+  ok(true, "got all required event");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html
+++ b/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html
@@ -6,50 +6,39 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let receivedSourceOpen = false;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
-    receivedSourceOpen = true;
-    const sb = ms.addSourceBuffer("video/mp4");
-    ok(sb, "Create a SourceBuffer");
-
-    sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-    fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4")
-    .then(function() {
-      const promises = [];
-      promises.push(fetchAndLoad(sb, "bipbop/bipbop", range(1, 3), ".m4s"));
-      promises.push(once(v, "loadeddata"));
-      return Promise.all(promises);
-    }).then(function() {
-      // clear the entire sourcebuffer.
-      sb.remove(0, 5);
-      return once(sb, "updateend");
-    }).then(function() {
-      v.play();
-      // We have nothing to play, waiting will be fired.
-      return once(v, "waiting");
-    }).then(function() {
-      const promises = [];
-      promises.push(once(v, "playing"));
-      promises.push(fetchAndLoad(sb, "bipbop/bipbop", range(1, 4), ".m4s"));
-      return Promise.all(promises);
-    }).then(function() {
-      ms.endOfStream();
-      const promises = [];
-      promises.push(once(ms, "sourceended"));
-      promises.push(once(v, "ended"));
-      return Promise.all(promises);
-    }).then(SimpleTest.finish.bind(SimpleTest));
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  ms.addEventListener("sourceopen", () => ok(false, "No more sourceopen"));
+  const sb = ms.addSourceBuffer("video/mp4");
+  ok(sb, "Create a SourceBuffer");
+  sb.addEventListener("error", e => {
+    ok(false, "Got Error: " + e);
+    SimpleTest.finish();
   });
+  await fetchAndLoad(sb, "bipbop/bipbop", [ "init" ], ".mp4");
+  let p = once(v, "loadeddata");
+  await fetchAndLoad(sb, "bipbop/bipbop", range(1, 3), ".m4s");
+  await p;
+  // clear the entire sourcebuffer.
+  sb.remove(0, 5);
+  await once(sb, "updateend");
+  v.play();
+  // We have nothing to play, waiting will be fired.
+  await once(v, "waiting");
+  p = once(v, "playing");
+  await fetchAndLoad(sb, "bipbop/bipbop", range(1, 4), ".m4s");
+  await p;
+  ms.endOfStream();
+  await Promise.all([ once(ms, "sourceended"), once(v, "ended") ]);
+  SimpleTest.finish(SimpleTest);
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_SeekNoData_mp4.html
+++ b/dom/media/mediasource/test/test_SeekNoData_mp4.html
@@ -7,65 +7,51 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-// Avoid making trouble for people who fix rounding bugs.
-function fuzzyEquals(a, b) {
-  return Math.abs(a - b) < 0.01;
-}
-
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    el.addEventListener("error", function(e) {
-      ok(false, "should not fire '" + e + "' event");
-    });
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    try {
-      el.currentTime = 3;
-    } catch (e) {
-      ok(false, "should not throw '" + e + "' exception");
-    }
-    is(el.currentTime, 3, "currentTime is default playback start position");
-    is(el.seeking, false, "seek not started with HAVE_NOTHING");
-    const metadataPromises = [];
-    metadataPromises.push(fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4"));
-    metadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    metadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(metadataPromises)
-    .then(function() {
-      const p = once(el, "seeking");
-      el.play();
-      el.currentTime = 5;
-      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      is(el.seeking, true, "seek not started with HAVE_METADATA");
-      is(el.currentTime, 5, "currentTime is seek position");
-      return p;
-    })
-    .then(function() {
-      ok(true, "Got seeking event");
-      const seekedPromises = [];
-      seekedPromises.push(once(el, "seeked"));
-      seekedPromises.push(fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(5, 9), ".m4s"));
-      seekedPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", range(6, 10), ".m4s"));
-      return Promise.all(seekedPromises);
-    })
-    .then(function() {
-      ok(true, "Got seeked event");
-      ok(el.currentTime >= 5, "Time >= 5");
-      once(el, "ended").then(SimpleTest.finish.bind(SimpleTest));
-      ms.endOfStream();
-    });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  el.addEventListener("error", e => {
+    ok(false, `should not fire ${e.type} event`);
+    SimpleTest.finish();
   });
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  must_not_throw(() => el.currentTime = 3, "setting currentTime is valid");
+  is(el.currentTime, 3, "currentTime is default playback start position");
+  is(el.seeking, false, "seek not started with HAVE_NOTHING");
+  await Promise.all([
+    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4"),
+    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"),
+    once(el, "loadedmetadata")
+  ]);
+  const p = once(el, "seeking");
+  el.play();
+  el.currentTime = 5;
+  is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  is(el.seeking, true, "seek not started with HAVE_METADATA");
+  is(el.currentTime, 5, "currentTime is seek position");
+  await p;
+  ok(true, "Got seeking event");
+  await Promise.all([
+    once(el, "seeked"),
+    fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(5, 9), ".m4s"),
+    fetchAndLoad(videosb, "bipbop/bipbop_video", range(6, 10), ".m4s")
+  ]);
+  ok(true, "Got seeked event");
+  ok(el.currentTime >= 5, "Time >= 5");
+  ms.endOfStream();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_SeekToEnd_mp4.html
+++ b/dom/media/mediasource/test/test_SeekToEnd_mp4.html
@@ -7,51 +7,49 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
 
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
 
-    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 6), ".m4s"))
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4"))
-    .then(function() {
-      is(videosb.buffered.length, 1, "continuous buffered range");
-      // Ensure we have at least 2s less audio than video.
-      audiosb.appendWindowEnd = videosb.buffered.end(0) - 2;
-      return fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 6), ".m4s");
-    }).then(function() {
-      ms.endOfStream();
-      return Promise.all([ once(el, "durationchange"), once(ms, "sourceended") ]);
-    }).then(function() {
-      ok(true, "endOfStream completed");
-      // Seek to the middle of the gap where audio is missing. As we are in readyState = ended
-      // seeking must complete.
-      el.currentTime = videosb.buffered.end(0) / 2 + audiosb.buffered.end(0) / 2;
-      ok(el.currentTime - audiosb.buffered.end(0) > 1, "gap is big enough");
-      is(el.buffered.length, 1, "continuous buffered range");
-      is(el.buffered.end(0), videosb.buffered.end(0), "buffered range end is aligned with longest track");
-      ok(el.seeking, "element is now seeking");
-      ok(el.currentTime >= el.buffered.start(0) && el.currentTime <= el.buffered.end(0), "seeking time is in buffered range");
-      ok(el.currentTime > audiosb.buffered.end(0), "seeking point is not buffered in audio track");
-      return once(el, "seeked");
-    }).then(function() {
-      ok(true, "we have successfully seeked");
-      // Now ensure that we can play to the end, even though we are missing data in one track.
-      el.play();
-      once(el, "ended").then(SimpleTest.finish.bind(SimpleTest));
-    });
-  });
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 6), ".m4s");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  is(videosb.buffered.length, 1, "continuous buffered range");
+  // Ensure we have at least 2s less audio than video.
+  audiosb.appendWindowEnd = videosb.buffered.end(0) - 2;
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 6), ".m4s");
+  ms.endOfStream();
+  await Promise.all([ once(el, "durationchange"), once(ms, "sourceended") ]);
+  ok(true, "endOfStream completed");
+  // Seek to the middle of the gap where audio is missing. As we are in readyState = ended
+  // seeking must complete.
+  el.currentTime = videosb.buffered.end(0) / 2 + audiosb.buffered.end(0) / 2;
+  ok(el.currentTime - audiosb.buffered.end(0) > 1, "gap is big enough");
+  is(el.buffered.length, 1, "continuous buffered range");
+  is(el.buffered.end(0), videosb.buffered.end(0),
+     "buffered range end is aligned with longest track");
+  ok(el.seeking, "element is now seeking");
+  ok(el.currentTime >= el.buffered.start(0) && el.currentTime <= el.buffered.end(0),
+     "seeking time is in buffered range");
+  ok(el.currentTime > audiosb.buffered.end(0),
+     "seeking point is not buffered in audio track");
+  await once(el, "seeked");
+  ok(true, "we have successfully seeked");
+  // Now ensure that we can play to the end, even though we are missing data in one track.
+  el.play();
+  await once(el, "ended");
+  SimpleTest.finish(SimpleTest);
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_SeekToLastFrame_mp4.html
+++ b/dom/media/mediasource/test/test_SeekToLastFrame_mp4.html
@@ -6,35 +6,29 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const sb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop_480_624kbps-video", range(1, 3), ".m4s"))
-    .then(function() {
-      el.play();
-      // let seek to the last audio frame.
-      el.currentTime = 1.532517;
-      return once(el, "seeked");
-    })
-    .then(function() {
-      ok(true, "seek completed");
-      ms.endOfStream();
-      return once(el, "ended");
-    }).then(function() {
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const sb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", [ "init" ], ".mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop_480_624kbps-video", range(1, 3), ".m4s");
+  el.play();
+  // let seek to the last audio frame.
+  el.currentTime = 1.532517;
+  await once(el, "seeked");
+  ok(true, "seek completed");
+  ms.endOfStream();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_SeekTwice_mp4.html
+++ b/dom/media/mediasource/test/test_SeekTwice_mp4.html
@@ -7,48 +7,39 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-// Avoid making trouble for people who fix rounding bugs.
-function fuzzyEquals(a, b) {
-  return Math.abs(a - b) < 0.01;
-}
-
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s"))
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(6, 12), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 6), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(7, 14), ".m4s"))
-    .then(function() {
-      const p = once(el, "seeking");
-      el.play();
-      el.currentTime = 4.5; // Seek to a gap in the video
-      return p;
-    }).then(function() {
-      ok(true, "Got seeking event");
-      const p = once(el, "seeked");
-      el.currentTime = 6; // Seek past the gap.
-      return p;
-    }).then(function() {
-      ok(true, "Got seeked event");
-      ok(el.currentTime >= 6, "Time >= 6");
-      once(el, "ended").then(SimpleTest.finish.bind(SimpleTest));
-      ms.endOfStream();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(6, 12), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 6), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(7, 14), ".m4s");
+  let p = once(el, "seeking");
+  el.play();
+  el.currentTime = 4.5; // Seek to a gap in the video
+  await p;
+  ok(true, "Got seeking event");
+  p = once(el, "seeked");
+  el.currentTime = 6; // Seek past the gap.
+  await p;
+  ok(true, "Got seeked event");
+  ok(el.currentTime >= 6, "Time >= 6");
+  ms.endOfStream();
+  await once(el, "ended");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_SeekedEvent_mp4.html
+++ b/dom/media/mediasource/test/test_SeekedEvent_mp4.html
@@ -7,72 +7,42 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  el._seeked = false;
-  el._loadeddata = false;
-  el._playing = false;
-  el.addEventListener("seeked", function() {
-    ok(true, "got seeked event");
-    is(el._loadeddata, false, "can't have received loadeddata prior seeked");
-    is(el._playing, false, "can't be playing prior seeked");
-    el._seeked = true;
-  });
-  el.addEventListener("loadeddata", function() {
-    ok(true, "got loadeddata event");
-    is(el._seeked, true, "must have received seeked prior loadeddata");
-    is(el._playing, false, "can't be playing prior playing");
-    el._loadeddata = true;
-  });
-  el.addEventListener("playing", function() {
-    ok(true, "got playing");
-    is(el._seeked, true, "must have received seeked prior playing");
-    is(el._loadeddata, true, "must have received loadeddata prior playing");
-    el._playing = true;
-  });
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
-    const metadataPromises = [];
-    metadataPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"));
-    metadataPromises.push(once(el, "loadedmetadata"));
-    Promise.all(metadataPromises)
-    .then(function() {
-      el.play();
-      videosb.timestampOffset = 2;
-      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      // Load [2, 3.606).
-      const playPromises = [];
-      playPromises.push(once(el, "play"));
-      playPromises.push(fetchAndLoad(videosb, "bipbop/bipbop_video", [ "1" ], ".m4s"));
-      return Promise.all(playPromises);
-    })
-    .then(function() {
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", [ "2" ], ".m4s");
-    })
-    .then(function() {
-      // TODO: readyState should be at least HAVE_CURRENTDATA, see bug 1367993.
-      ok(el.readyState >= el.HAVE_METADATA, "readyState is HAVE_METADATA");
-      el.currentTime = 2;
-      const seekedAndPlayingPromises = [];
-      seekedAndPlayingPromises.push(once(el, "seeked"));
-      seekedAndPlayingPromises.push(once(el, "playing"));
-      return Promise.all(seekedAndPlayingPromises);
-    })
-    .then(function() {
-      ok(true, "completed seek");
-      SimpleTest.finish();
-    });
-  });
+  const events = [ "seeked", "loadeddata", "playing" ];
+  let eventCount = 0;
+  events.forEach(type => el.addEventListener(type,
+      () => is(events[eventCount++], type, "events must come in order")));
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+  let p = once(el, "loadedmetadata");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await p;
+  el.play();
+  videosb.timestampOffset = 2;
+  is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  // Load [2, 3.606).
+  p = once(el, "play");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "1" ], ".m4s");
+  await p;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "2" ], ".m4s");
+  // TODO: readyState should be at least HAVE_CURRENTDATA, see bug 1367993.
+  ok(el.readyState >= el.HAVE_METADATA, "readyState is HAVE_METADATA");
+  el.currentTime = 2;
+  await Promise.all([ once(el, "seeked"), once(el, "playing") ]);
+  ok(true, "completed seek");
+  is(eventCount, events.length, "Received expected number of events");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_Sequence_mp4.html
+++ b/dom/media/mediasource/test/test_Sequence_mp4.html
@@ -6,34 +6,32 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-let receivedSourceOpen = false;
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    ok(true, "Receive a sourceopen event");
-    ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
-    receivedSourceOpen = true;
-    const sb = ms.addSourceBuffer("video/mp4");
-    ok(sb, "Create a SourceBuffer");
-    sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-    sb.mode = "sequence";
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  ms.addEventListener("sourceopen", () => ok(false, "No more sourceopen"));
+  const sb = ms.addSourceBuffer("video/mp4");
+  ok(sb, "Create a SourceBuffer");
+  sb.addEventListener("error", e => {
+    ok(false, "Got Error: " + e);
+    SimpleTest.finish();
+  });
+  sb.mode = "sequence";
 
-    fetchAndLoad(sb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop_video", [ "5" ], ".m4s"))
-    .then(fetchAndLoad.bind(null, sb, "bipbop/bipbop_video", [ "2" ], ".m4s"))
-    .then(function() {
-      is(v.buffered.length, 1, "Continuous buffered range");
-      is(v.buffered.start(0), 0, "Buffered range starts at 0");
-      ok(sb.timestampOffset > 0, "SourceBuffer.timestampOffset set to allow continuous range");
-      SimpleTest.finish();
-    });
-  });
+  await fetchAndLoad(sb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(sb, "bipbop/bipbop_video", [ "5" ], ".m4s");
+  await fetchAndLoad(sb, "bipbop/bipbop_video", [ "2" ], ".m4s");
+  is(v.buffered.length, 1, "Continuous buffered range");
+  is(v.buffered.start(0), 0, "Buffered range starts at 0");
+  ok(sb.timestampOffset > 0, "SourceBuffer.timestampOffset set to allow continuous range");
+  SimpleTest.finish();
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_Threshold_mp4.html
+++ b/dom/media/mediasource/test/test_Threshold_mp4.html
@@ -7,78 +7,67 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
-
+runWithMSE(async (ms, el) => {
   const threshold = 0.5; // gap threshold in seconds.
   const fuzz = 0.000001; // fuzz when comparing double.
 
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    const vchunks = [ {start: 0, end: 3.203333}, { start: 3.203333, end: 6.406666} ];
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  const vchunks = [ {start: 0, end: 3.203333}, { start: 3.203333, end: 6.406666} ];
 
-    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 5), ".m4s"))
-    .then(function() {
-      // We will insert a gap of threshold
-      videosb.timestampOffset = threshold;
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
-    }).then(function() {
-      // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
-      // has notified it of available data. Make sure that we get 'playing' before
-      // we starting waiting for 'waiting'.
-      info("Invoking play()");
-      const p = once(el, "playing");
-      el.play();
-      return p;
-    }).then(function() {
-      return once(el, "waiting");
-    }).then(function() {
-      // We're waiting for data after the start of the last frame.
-      // 0.033333 is the duration of the last frame.
-      ok(el.currentTime >= vchunks[1].end - 0.033333 + threshold - fuzz
-         && el.currentTime <= vchunks[1].end + threshold + fuzz, "skipped the gap properly: " + el.currentTime + " " + (vchunks[1].end + threshold));
-      is(el.buffered.length, 2, "buffered range has right length");
-      // Now we test that seeking will succeed despite the gap.
-      el.currentTime = el.buffered.end(0) + (threshold / 2);
-      return once(el, "seeked");
-    }).then(function() {
-      // Now we test that we don't pass the gap.
-      // Clean up our sourcebuffer by removing all data.
-      videosb.timestampOffset = 0;
-      videosb.remove(0, Infinity);
-      el.currentTime = 0;
-      el.pause();
-      return once(videosb, "updateend");
-    }).then(function() {
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 5), ".m4s");
-    }).then(function() {
-      // We will insert a gap of threshold + 1ms
-      videosb.timestampOffset = threshold + 1 / 1000;
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
-    }).then(function() {
-      info("Invoking play()");
-      const p = once(el, "playing");
-      el.play();
-      return p;
-    }).then(function() {
-      return once(el, "waiting");
-    }).then(function() {
-      // We're waiting for data after the start of the last frame.
-      // 0.033333 is the duration of the last frame.
-      ok(el.currentTime >= vchunks[0].end - 0.033333 - fuzz
-         && el.currentTime <= vchunks[0].end + fuzz, "stopped at the gap properly: " + el.currentTime + " " + vchunks[0].end);
-      SimpleTest.finish();
-    });
-  });
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 5), ".m4s");
+  // We will insert a gap of threshold
+  videosb.timestampOffset = threshold;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
+  // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
+  // has notified it of available data. Make sure that we get 'playing' before
+  // we starting waiting for 'waiting'.
+  info("Invoking play()");
+  let p = once(el, "playing");
+  el.play();
+  await p;
+  await once(el, "waiting");
+  // We're waiting for data after the start of the last frame.
+  // 0.033333 is the duration of the last frame.
+  ok((el.currentTime >= vchunks[1].end - 0.033333 + threshold - fuzz &&
+      el.currentTime <= vchunks[1].end + threshold + fuzz),
+     `skipped the gap properly: ${el.currentTime} ${vchunks[1].end + threshold}`);
+  is(el.buffered.length, 2, "buffered range has right length");
+  // Now we test that seeking will succeed despite the gap.
+  el.currentTime = el.buffered.end(0) + (threshold / 2);
+  await once(el, "seeked");
+  // Now we test that we don't pass the gap.
+  // Clean up our sourcebuffer by removing all data.
+  videosb.timestampOffset = 0;
+  videosb.remove(0, Infinity);
+  el.currentTime = 0;
+  el.pause();
+  await once(videosb, "updateend");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 5), ".m4s");
+  // We will insert a gap of threshold + 1ms
+  videosb.timestampOffset = threshold + 1 / 1000;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
+  info("Invoking play()");
+  p = once(el, "playing");
+  el.play();
+  await p;
+  await once(el, "waiting");
+  // We're waiting for data after the start of the last frame.
+  // 0.033333 is the duration of the last frame.
+  ok((el.currentTime >= vchunks[0].end - 0.033333 - fuzz &&
+      el.currentTime <= vchunks[0].end + fuzz),
+     `stopped at the gap properly: ${el.currentTime} ${vchunks[0].end}`);
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_TimestampOffset_mp4.html
+++ b/dom/media/mediasource/test/test_TimestampOffset_mp4.html
@@ -7,80 +7,71 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-function range(start, end) {
-  const rv = [];
-  for (let i = start; i < end; ++i) {
-    rv.push(i);
-  }
-  return rv;
-}
+runWithMSE(async (ms, el) => {
 
-const eps = 0.01;
-runWithMSE(function(ms, el) {
+  const eps = 0.01;
 
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    // We divide the video into 3 chunks:
-    // chunk 0: segments 1-4
-    // chunk 1: segments 5-8
-    // chunk 2: segments 9-13
-    // We then fill the timeline so that it seamlessly plays the chunks in order 0, 2, 1.
-    const vchunks = [ {start: 0, end: 3.2033}, { start: 3.2033, end: 6.4066}, { start: 6.4066, end: 10.01} ];
-    const firstvoffset = vchunks[2].end - vchunks[2].start; // Duration of chunk 2
-    const secondvoffset = -(vchunks[1].end - vchunks[1].start); // -(Duration of chunk 1)
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  // We divide the video into 3 chunks:
+  // chunk 0: segments 1-4
+  // chunk 1: segments 5-8
+  // chunk 2: segments 9-13
+  // We then fill the timeline so that it seamlessly plays the chunks in order 0, 2, 1.
+  const vchunks = [ {start: 0, end: 3.2033},
+                    { start: 3.2033, end: 6.4066},
+                    { start: 6.4066, end: 10.01} ];
+  const firstvoffset = vchunks[2].end - vchunks[2].start; // Duration of chunk 2
+  const secondvoffset = -(vchunks[1].end - vchunks[1].start); // -(Duration of chunk 1)
 
-    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 5), ".m4s"))
-    .then(function() {
-      is(videosb.buffered.length, 1, "No discontinuity");
-      isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "Chunk start");
-      isfuzzy(videosb.buffered.end(0), vchunks[0].end, eps, "Chunk end");
-      videosb.timestampOffset = firstvoffset;
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
-    })
-    .then(function(data) {
-      is(videosb.buffered.length, 2, "One discontinuity");
-      isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "First Chunk start");
-      isfuzzy(videosb.buffered.end(0), vchunks[0].end, eps, "First chunk end");
-      isfuzzy(videosb.buffered.start(1), vchunks[1].start + firstvoffset, eps, "Second chunk start");
-      isfuzzy(videosb.buffered.end(1), vchunks[1].end + firstvoffset, eps, "Second chunk end");
-      videosb.timestampOffset = secondvoffset;
-      return fetchAndLoad(videosb, "bipbop/bipbop_video", range(9, 14), ".m4s");
-    })
-    .then(function() {
-      is(videosb.buffered.length, 1, "No discontinuity (end)");
-      isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "Chunk start");
-      isfuzzy(videosb.buffered.end(0), vchunks[2].end, eps, "Chunk end");
-      audiosb.timestampOffset = 3;
-    }).then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4"))
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(1, 12), ".m4s"))
-    .then(function() {
-      is(audiosb.buffered.length, 1, "No audio discontinuity");
-      isfuzzy(audiosb.buffered.start(0), 3, eps, "Audio starts at 3");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 5), ".m4s");
+  is(videosb.buffered.length, 1, "No discontinuity");
+  isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "Chunk start");
+  isfuzzy(videosb.buffered.end(0), vchunks[0].end, eps, "Chunk end");
+  videosb.timestampOffset = firstvoffset;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(5, 9), ".m4s");
+  is(videosb.buffered.length, 2, "One discontinuity");
+  isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "First Chunk start");
+  isfuzzy(videosb.buffered.end(0), vchunks[0].end, eps, "First chunk end");
+  isfuzzy(videosb.buffered.start(1), vchunks[1].start + firstvoffset, eps, "Second chunk start");
+  isfuzzy(videosb.buffered.end(1), vchunks[1].end + firstvoffset, eps, "Second chunk end");
+  videosb.timestampOffset = secondvoffset;
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(9, 14), ".m4s");
+  is(videosb.buffered.length, 1, "No discontinuity (end)");
+  isfuzzy(videosb.buffered.start(0), vchunks[0].start, eps, "Chunk start");
+  isfuzzy(videosb.buffered.end(0), vchunks[2].end, eps, "Chunk end");
+  audiosb.timestampOffset = 3;
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 12), ".m4s");
+  is(audiosb.buffered.length, 1, "No audio discontinuity");
+  isfuzzy(audiosb.buffered.start(0), 3, eps, "Audio starts at 3");
 
-      // Trim the rest of the audio.
-      audiosb.remove(videosb.buffered.end(0), Infinity);
-      videosb.remove(videosb.buffered.end(0), Infinity);
-      return Promise.all([ audiosb.updating ? once(audiosb, "updateend") : Promise.resolve(),
-        videosb.updating ? once(videosb, "updateend") : Promise.resolve() ]);
-    }).then(function() {
-      info("waiting for play to complete");
-      el.play();
-      el.currentTime = el.buffered.start(0);
-      ms.endOfStream();
-      Promise.all([ once(el, "ended"), once(el, "seeked") ]).then(SimpleTest.finish.bind(SimpleTest));
-    });
-  });
+  // Trim the rest of the audio.
+  audiosb.remove(videosb.buffered.end(0), Infinity);
+  videosb.remove(videosb.buffered.end(0), Infinity);
+  if (audiosb.updating) {
+    await once(audiosb, "updateend");
+  }
+  if (videosb.updating) {
+    await once(videosb, "updateend");
+  }
+  info("waiting for play to complete");
+  el.play();
+  el.currentTime = el.buffered.start(0);
+  ms.endOfStream();
+  await Promise.all([ once(el, "ended"), once(el, "seeked") ]);
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_TruncatedDuration.html
+++ b/dom/media/mediasource/test/test_TruncatedDuration.html
@@ -15,60 +15,41 @@
 // We then shorten the video to 1/3rd of its original size by modifying the
 // mediasource.duration attribute.
 // We ensure that the buffered range immediately reflect the truncation
 // and that we've seeked to the new end of the media as per W3C spec and
 // video.currentTime got updated.
 
 SimpleTest.waitForExplicitFinish();
 
-function round(n) {
-  return Math.round(n * 1000) / 1000;
-}
+const round = n => Math.round(n * 1000) / 1000;
+
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/webm");
 
-function do_seeking(e) {
-  const v = e.target;
-  v.removeEventListener("seeking", do_seeking);
-  SimpleTest.finish();
-}
-
-function do_seeked(e) {
-  const v = e.target;
-  v.removeEventListener("seeked", do_seeked);
+  sb.appendBuffer(new Uint8Array(await fetchWithXHR("seek.webm")));
+  await once(sb, "updateend");
+  v.currentTime = v.duration / 2;
+  is(v.currentTime, v.duration / 2, "current time was updated");
+  ok(v.seeking, "seeking is true");
+  await once(v, "seeked");
   const duration = round(v.duration / 3);
-  is(v._sb.updating, false, "sourcebuffer isn't updating");
-  v._sb.remove(duration, Infinity);
-  once(v._sb, "updateend", function() {
-    v._ms.duration = duration;
-    // frames aren't truncated, so duration may be slightly more.
-    isfuzzy(v.duration, duration, 1 / 30, "element duration was updated");
-    v._sb.abort(); // this shouldn't abort updating the duration (bug 1130826).
-    ok(v.seeking, "seeking is true");
-    // test playback position was updated (bug 1130839).
-    is(v.currentTime, v.duration, "current time was updated");
-    is(v._sb.buffered.length, 1, "One buffered range");
-    // Truncated mediasource duration will cause the video element to seek.
-    v.addEventListener("seeking", do_seeking);
-  });
-}
-
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/webm");
-    v._sb = sb;
-    v._ms = ms;
-
-    fetchWithXHR("seek.webm", function(arrayBuffer) {
-      sb.appendBuffer(new Uint8Array(arrayBuffer));
-      once(sb, "updateend", function() {
-        v.currentTime = v.duration / 2;
-        is(v.currentTime, v.duration / 2, "current time was updated");
-        ok(v.seeking, "seeking is true");
-        v.addEventListener("seeked", do_seeked);
-      });
-    });
-  });
+  is(sb.updating, false, "sourcebuffer isn't updating");
+  sb.remove(duration, Infinity);
+  await once(sb, "updateend");
+  ms.duration = duration;
+  // frames aren't truncated, so duration may be slightly more.
+  isfuzzy(v.duration, duration, 1 / 30, "element duration was updated");
+  sb.abort(); // this shouldn't abort updating the duration (bug 1130826).
+  ok(v.seeking, "seeking is true");
+  // test playback position was updated (bug 1130839).
+  is(v.currentTime, v.duration, "current time was updated");
+  is(sb.buffered.length, 1, "One buffered range");
+  // Truncated mediasource duration will cause the video element to seek.
+  await once(v, "seeking");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_TruncatedDuration_mp4.html
+++ b/dom/media/mediasource/test/test_TruncatedDuration_mp4.html
@@ -14,66 +14,46 @@
 // of the video.
 // We then shorten the video to 1/3rd of its original size.
 // We ensure that the buffered range immediately reflect the truncation
 // and that we've seeked to the new end of the media as per W3C spec and
 // video.currentTime got updated.
 
 SimpleTest.waitForExplicitFinish();
 
-function round(n) {
-  return Math.round(n * 1000) / 1000;
-}
+const round = n => Math.round(n * 1000) / 1000;
+
+runWithMSE(async (ms, v) => {
+  await once(ms, "sourceopen");
+  const sb = ms.addSourceBuffer("video/mp4");
 
-function do_seeking(e) {
-  const v = e.target;
-  v.removeEventListener("seeking", do_seeking);
-  SimpleTest.finish();
-}
-
-function do_seeked(e) {
-  const v = e.target;
-  v.removeEventListener("seeked", do_seeked);
+  sb.appendBuffer(new Uint8Array(await fetchWithXHR("bipbop/bipbop2s.mp4")));
+  await once(sb, "updateend");
+  // mp4 metadata states 10s when we only have 1.6s worth of video.
+  sb.remove(sb.buffered.end(0), Infinity);
+  await once(sb, "updateend");
+  ms.duration = sb.buffered.end(0);
+  is(v.duration, ms.duration, "current time updated with mediasource duration");
+  v.currentTime = v.duration / 2;
+  is(v.currentTime, v.duration / 2, "current time was updated");
+  ok(v.seeking, "seeking is true");
+  await once(v, "seeked");
   const duration = round(v.duration / 3);
-  is(v._sb.updating, false, "sourcebuffer isn't updating");
-  v._sb.remove(duration, Infinity);
-  once(v._sb, "updateend", function() {
-    v._ms.duration = duration;
-    // frames aren't truncated, so duration may be slightly more.
-    isfuzzy(v.duration, duration, 1 / 30, "element duration was updated");
-    v._sb.abort(); // this shouldn't abort updating the duration (bug 1130826).
-    ok(v.seeking, "seeking is true");
-    // test playback position was updated (bug 1130839).
-    is(v.currentTime, v.duration, "current time was updated");
-    is(v._sb.buffered.length, 1, "One buffered range");
-    // Truncated mediasource duration will cause the video element to seek.
-    v.addEventListener("seeking", do_seeking);
-  });
-}
-
-runWithMSE(function(ms, v) {
-  ms.addEventListener("sourceopen", function() {
-    const sb = ms.addSourceBuffer("video/mp4");
-    v._sb = sb;
-    v._ms = ms;
-
-    fetchWithXHR("bipbop/bipbop2s.mp4", function(arrayBuffer) {
-      sb.appendBuffer(new Uint8Array(arrayBuffer));
-      once(sb, "updateend", function() {
-        // mp4 metadata states 10s when we only have 1.6s worth of video.
-        sb.remove(sb.buffered.end(0), Infinity);
-        once(sb, "updateend", function() {
-          ms.duration = sb.buffered.end(0);
-          is(v.duration, ms.duration, "current time updated with mediasource duration");
-          v.currentTime = v.duration / 2;
-          is(v.currentTime, v.duration / 2, "current time was updated");
-          ok(v.seeking, "seeking is true");
-          v.addEventListener("seeked", do_seeked);
-        });
-      });
-    });
-  });
+  is(sb.updating, false, "sourcebuffer isn't updating");
+  sb.remove(duration, Infinity);
+  await once(sb, "updateend");
+  ms.duration = duration;
+  // frames aren't truncated, so duration may be slightly more.
+  isfuzzy(v.duration, duration, 1 / 30, "element duration was updated");
+  sb.abort(); // this shouldn't abort updating the duration (bug 1130826).
+  ok(v.seeking, "seeking is true");
+  // test playback position was updated (bug 1130839).
+  is(v.currentTime, v.duration, "current time was updated");
+  is(sb.buffered.length, 1, "One buffered range");
+  // Truncated mediasource duration will cause the video element to seek.
+  await once(v, "seeking");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_WaitingOnMissingData.html
+++ b/dom/media/mediasource/test/test_WaitingOnMissingData.html
@@ -6,58 +6,55 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const sb = ms.addSourceBuffer("video/webm");
-    fetchWithXHR("seek.webm", function(arrayBuffer) {
-      sb.addEventListener("error", (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
-      loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 0, 318))()
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 318, 25223 - 318)))
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 25223, 46712 - 25223)))
-      /* Note - Missing |46712, 67833 - 46712| segment here */
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 67833, 88966 - 67833)))
-      .then(loadSegment.bind(null, sb, new Uint8Array(arrayBuffer, 88966)))
-      .then(function() {
-        // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
-        // has notified it of available data. Make sure that we get 'playing' before
-        // we starting waiting for 'waiting'.
-        info("Invoking play()");
-        const p = once(el, "playing");
-        el.play();
-        return p;
-      }).then(function() {
-        ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
-        const p = once(el, "waiting");
-        el.play();
-        return p;
-      }).then(function() {
-        // currentTime is based on the current video frame, so if the audio ends just before
-        // the next video frame, currentTime can be up to 1 frame's worth earlier than
-        // min(audioEnd, videoEnd).
-        // 0.0465 is the length of the last audio frame.
-        ok(el.currentTime >= (sb.buffered.end(0) - 0.0465),
-           "Got a waiting event at " + el.currentTime);
-        info("Loading more data");
-        const p = once(el, "ended");
-        loadSegment(sb, new Uint8Array(arrayBuffer, 46712, 67833 - 46712)).then(() => ms.endOfStream());
-        return p;
-      }).then(function() {
-        // These fuzz factors are bigger than they should be. We should investigate
-        // and fix them in bug 1137574.
-        isfuzzy(el.duration, 4.001, 0.1, "Video has correct duration: " + el.duration);
-        isfuzzy(el.currentTime, el.duration, 0.1, "Video has correct currentTime.");
-        SimpleTest.finish();
-      });
-    });
+runWithMSE(async (ms, el) => {
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const sb = ms.addSourceBuffer("video/webm");
+  sb.addEventListener("error", e => {
+    ok(false, "Got Error: " + e);
+    SimpleTest.finish();
   });
+  const arrayBuffer = await fetchWithXHR("seek.webm");
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 0, 318));
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 318, 25223 - 318));
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 25223, 46712 - 25223));
+  /* Note - Missing |46712, 67833 - 46712| segment here */
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 67833, 88966 - 67833));
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 88966));
+  // HTMLMediaElement fires "waiting" if somebody invokes |play()| before the MDSM
+  // has notified it of available data. Make sure that we get "playing" before
+  // we starting waiting for "waiting".
+  info("Invoking play()");
+  let p = once(el, "playing");
+  el.play();
+  await p;
+  ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
+  p = once(el, "waiting");
+  el.play();
+  await p;
+  // currentTime is based on the current video frame, so if the audio ends just before
+  // the next video frame, currentTime can be up to 1 frame's worth earlier than
+  // min(audioEnd, videoEnd).
+  // 0.0465 is the length of the last audio frame.
+  ok(el.currentTime >= (sb.buffered.end(0) - 0.0465),
+     `Got a waiting event at ${el.currentTime}`);
+  info("Loading more data");
+  p = once(el, "ended");
+  await loadSegment(sb, new Uint8Array(arrayBuffer, 46712, 67833 - 46712));
+  ms.endOfStream();
+  await p;
+  // These fuzz factors are bigger than they should be. We should investigate
+  // and fix them in bug 1137574.
+  isfuzzy(el.duration, 4.001, 0.1, "Video has correct duration: " + el.duration);
+  isfuzzy(el.currentTime, el.duration, 0.1, "Video has correct currentTime.");
+  SimpleTest.finish();
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_WaitingOnMissingDataEnded_mp4.html
+++ b/dom/media/mediasource/test/test_WaitingOnMissingDataEnded_mp4.html
@@ -6,48 +6,42 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    el.addEventListener("ended", function() {
-      ok(false, "ended should never fire");
-      SimpleTest.finish();
-    });
-    const videosb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 5), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(6, 8), ".m4s"))
-    .then(function() {
-      is(el.buffered.length, 2, "discontinuous buffered range");
-      ms.endOfStream();
-      return Promise.all([ once(el, "durationchange"), once(ms, "sourceended") ]);
-    }).then(function() {
-      // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
-      // has notified it of available data. Make sure that we get 'playing' before
-      // we starting waiting for 'waiting'.
-      info("Invoking play()");
-      el.play();
-      return once(el, "playing");
-    }).then(function() {
-      ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
-      return once(el, "waiting");
-    }).then(function() {
-      // waiting is fired when we start to play the last frame.
-      // 0.033334 is the duration of the last frame, + 0.000001 of fuzz.
-      // the next video frame, currentTime can be up to 1 frame's worth earlier than end of video.
-      isfuzzy(el.currentTime, videosb.buffered.end(0), 0.033334, "waiting was fired on gap");
-      SimpleTest.finish();
-    });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  el.addEventListener("ended", function() {
+    ok(false, "ended should never fire");
+    SimpleTest.finish();
   });
+  const videosb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 5), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(6, 8), ".m4s");
+  is(el.buffered.length, 2, "discontinuous buffered range");
+  ms.endOfStream();
+  await Promise.all([ once(el, "durationchange"), once(ms, "sourceended") ]);
+  // HTMLMediaElement fires "waiting" if somebody invokes |play()| before the MDSM
+  // has notified it of available data. Make sure that we get "playing" before
+  // we starting waiting for "waiting".
+  info("Invoking play()");
+  el.play();
+  await once(el, "playing");
+  ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
+  await once(el, "waiting");
+  // waiting is fired when we start to play the last frame.
+  // 0.033334 is the duration of the last frame, + 0.000001 of fuzz.
+  // the next video frame, currentTime can be up to 1 frame's worth earlier than end of video.
+  isfuzzy(el.currentTime, videosb.buffered.end(0), 0.033334, "waiting was fired on gap");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html
+++ b/dom/media/mediasource/test/test_WaitingOnMissingData_mp4.html
@@ -6,60 +6,56 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s"))
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(6, 12), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 6), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(7, 14), ".m4s"))
-    .then(function() {
-      // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
-      // has notified it of available data. Make sure that we get 'playing' before
-      // we starting waiting for 'waiting'.
-      info("Invoking play()");
-      const p = once(el, "playing");
-      el.play();
-      return p;
-    }).then(function() {
-      ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
-      const p = once(el, "waiting");
-      el.play();
-      return p;
-    }).then(function() {
-      // currentTime is based on the current video frame, so if the audio ends just before
-      // the next video frame, currentTime can be up to 1 frame's worth earlier than
-      // min(audioEnd, videoEnd).
-      // 0.0465 is the length of the last audio frame.
-      ok(el.currentTime >= (Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 0.0465),
-          "Got a waiting event at " + el.currentTime);
-      info("Loading more data");
-      const p = once(el, "ended");
-      const loads = Promise.all([ fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ 5 ], ".m4s"),
-        fetchAndLoad(videosb, "bipbop/bipbop_video", [ 6 ], ".m4s") ]);
-      loads.then(() => ms.endOfStream());
-      return p;
-    }).then(function() {
-      // These fuzz factors are bigger than they should be. We should investigate
-      // and fix them in bug 1137574.
-      isfuzzy(el.duration, 10.1, 0.1, "Video has correct duration: " + el.duration);
-      isfuzzy(el.currentTime, el.duration, 0.1, "Video has correct currentTime.");
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(6, 12), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 6), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(7, 14), ".m4s");
+  // HTMLMediaElement fires "waiting" if somebody invokes |play()| before the MDSM
+  // has notified it of available data. Make sure that we get "playing" before
+  // we starting waiting for "waiting".
+  info("Invoking play()");
+  let p = once(el, "playing");
+  el.play();
+  await p;
+  ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
+  p = once(el, "waiting");
+  el.play();
+  await p;
+  // currentTime is based on the current video frame, so if the audio ends just before
+  // the next video frame, currentTime can be up to 1 frame's worth earlier than
+  // min(audioEnd, videoEnd).
+  // 0.0465 is the length of the last audio frame.
+  ok(el.currentTime >= (Math.min(audiosb.buffered.end(0), videosb.buffered.end(0)) - 0.0465),
+     `Got a waiting event at ${el.currentTime}`);
+  info("Loading more data");
+  p = once(el, "ended");
+  await Promise.all([
+    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ 5 ], ".m4s"),
+    fetchAndLoad(videosb, "bipbop/bipbop_video", [ 6 ], ".m4s")
+  ]);
+  ms.endOfStream();
+  await p;
+  // These fuzz factors are bigger than they should be. We should investigate
+  // and fix them in bug 1137574.
+  isfuzzy(el.duration, 10.1, 0.1, "Video has correct duration: " + el.duration);
+  isfuzzy(el.currentTime, el.duration, 0.1, "Video has correct currentTime.");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html
+++ b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html
@@ -6,51 +6,43 @@
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function(ms, el) {
+runWithMSE(async (ms, el) => {
   el.controls = true;
-  once(ms, "sourceopen").then(function() {
-    ok(true, "Receive a sourceopen event");
-    const audiosb = ms.addSourceBuffer("audio/mp4");
-    const videosb = ms.addSourceBuffer("video/mp4");
-    // ensure tracks end at approximately the same time to ensure ended event is
-    // always fired (bug 1233639).
-    audiosb.appendWindowEnd = 3.9;
-    videosb.appendWindowEnd = 3.9;
-    fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4")
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", [ "init" ], ".mp4"))
-    .then(fetchAndLoad.bind(null, audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s"))
-    .then(fetchAndLoad.bind(null, videosb, "bipbop/bipbop_video", range(1, 6), ".m4s"))
-    .then(function() {
-      // HTMLMediaElement fires 'waiting' if somebody invokes |play()| before the MDSM
-      // has notified it of available data. Make sure that we get 'playing' before
-      // we starting waiting for 'waiting'.
-      info("Invoking play()");
-      const p = once(el, "playing");
-      el.play();
-      return p;
-    }).then(function() {
-      ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
-      const p = once(el, "waiting");
-      el.play();
-      return p;
-    }).then(function() {
-      const p = once(el, "ended");
-      ms.endOfStream();
-      return p;
-    }).then(function() {
-      is(el.duration, 3.854512, "Video has correct duration: " + el.duration);
-      is(el.currentTime, el.duration, "Video has correct currentTime.");
-      SimpleTest.finish();
-    });
-  });
+  await once(ms, "sourceopen");
+  ok(true, "Receive a sourceopen event");
+  const audiosb = ms.addSourceBuffer("audio/mp4");
+  const videosb = ms.addSourceBuffer("video/mp4");
+  // ensure tracks end at approximately the same time to ensure ended event is
+  // always fired (bug 1233639).
+  audiosb.appendWindowEnd = 3.9;
+  videosb.appendWindowEnd = 3.9;
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", [ "init" ], ".mp4");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", [ "init" ], ".mp4");
+  await fetchAndLoad(audiosb, "bipbop/bipbop_audio", range(1, 5), ".m4s");
+  await fetchAndLoad(videosb, "bipbop/bipbop_video", range(1, 6), ".m4s");
+  // HTMLMediaElement fires "waiting" if somebody invokes |play()| before the MDSM
+  // has notified it of available data. Make sure that we get "playing" before
+  // we starting waiting for "waiting".
+  info("Invoking play()");
+  let p = once(el, "playing");
+  el.play();
+  await p;
+  ok(true, "Video playing. It should play for a bit, then fire 'waiting'");
+  await once(el, "waiting");
+  p = once(el, "ended");
+  ms.endOfStream();
+  await p;
+  is(el.duration, 3.854512, "Video has correct duration: " + el.duration);
+  is(el.currentTime, el.duration, "Video has correct currentTime.");
+  SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>