Bug 1188099 - (Part 4) Introduce mochitest coverage for speech global queue. r=smaug r=kdavis
☠☠ backed out by 25d448978f89 ☠ ☠
authorEitan Isaacson <eitan@monotonous.org>
Wed, 05 Aug 2015 10:25:42 -0700
changeset 288087 f89e9a209c6c24a35580d8d18bd78204f4ef175b
parent 288086 e5b42fb931a655c9db67c988321f3aa26b526d39
child 288088 78e2ba8842d481bbae413da71b4870d67741ada7
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, kdavis
bugs1188099
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1188099 - (Part 4) Introduce mochitest coverage for speech global queue. r=smaug r=kdavis
dom/media/webspeech/synth/test/common.js
dom/media/webspeech/synth/test/file_global_queue.html
dom/media/webspeech/synth/test/file_global_queue_cancel.html
dom/media/webspeech/synth/test/file_global_queue_pause.html
dom/media/webspeech/synth/test/file_indirect_service_events.html
dom/media/webspeech/synth/test/file_speech_cancel.html
dom/media/webspeech/synth/test/file_speech_queue.html
dom/media/webspeech/synth/test/mochitest.ini
dom/media/webspeech/synth/test/test_global_queue.html
dom/media/webspeech/synth/test/test_global_queue_cancel.html
dom/media/webspeech/synth/test/test_global_queue_pause.html
dom/media/webspeech/synth/test/test_indirect_service_events.html
dom/media/webspeech/synth/test/test_speech_cancel.html
dom/media/webspeech/synth/test/test_speech_queue.html
--- a/dom/media/webspeech/synth/test/common.js
+++ b/dom/media/webspeech/synth/test/common.js
@@ -1,18 +1,19 @@
 function synthTestQueue(aTestArgs, aEndFunc) {
   var utterances = [];
   for (var i in aTestArgs) {
     var uargs = aTestArgs[i][0];
-    var u = new SpeechSynthesisUtterance(uargs.text);
+    var win = uargs.win || window;
+    var u = new win.SpeechSynthesisUtterance(uargs.text);
 
-    delete uargs.text;
-
-    for (var attr in uargs)
-      u[attr] = uargs[attr];
+    if (uargs.args) {
+      for (var attr in uargs.args)
+        u[attr] = uargs.args[attr];
+    }
 
     function onend_handler(e) {
       is(e.target, utterances.shift(), "Target matches utterances");
       ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
 
       isnot(e.eventType, 'error', "Error in utterance");
 
       if (utterances.length) {
@@ -38,14 +39,32 @@ function synthTestQueue(aTestArgs, aEndF
     u.addEventListener('error', onend_handler);
 
     u.addEventListener(
       'error', function onerror_handler(e) {
         ok(false, "Error in speech utterance '" + e.target.text + "'");
       });
 
     utterances.push(u);
-    speechSynthesis.speak(u);
+    win.speechSynthesis.speak(u);
   }
 
   ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
   ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
 }
+
+function loadFrame(frameId) {
+  return new Promise(function(resolve, reject) {
+    var frame = document.getElementById(frameId);
+    frame.addEventListener('load', function (e) {
+      frame.contentWindow.document.title = frameId;
+      resolve(frame);
+    });
+    frame1.src = 'data:text/html,' + encodeURI('<html><head></head><body></body></html>');
+  });
+}
+
+function testSynthState(win, expectedState) {
+  for (var attr in expectedState) {
+    is(win.speechSynthesis[attr], expectedState[attr],
+      win.document.title + ": '" + attr + '" does not match');
+  }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_global_queue.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1188099: Global queue should correctly schedule utterances</title>
+  <script type="application/javascript">
+    window.SimpleTest = parent.SimpleTest;
+    window.info = parent.info;
+    window.is = parent.is;
+    window.isnot = parent.isnot;
+    window.ok = parent.ok;
+    window.todo = parent.todo;
+  </script>
+  <script type="application/javascript" src="common.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
+<iframe id="frame1"></iframe>
+<iframe id="frame2"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+  Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
+    var win1 = frame1.contentWindow;
+    var win2 = frame2.contentWindow;
+    var utterance1 = new win1.SpeechSynthesisUtterance("hello, losers");
+    var utterance2 = new win1.SpeechSynthesisUtterance("hello, losers three");
+    var utterance3 = new win2.SpeechSynthesisUtterance("hello, losers too");
+    var eventOrder = ['start1', 'end1', 'start3', 'end3', 'start2', 'end2'];
+    utterance1.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start1', 'start1');
+      testSynthState(win1, { speaking: true, pending: true });
+      testSynthState(win2, { speaking: true, pending: true });
+    });
+    utterance1.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end1', 'end1');
+    });
+    utterance3.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start3', 'start3');
+      testSynthState(win1, { speaking: true, pending: true });
+      testSynthState(win2, { speaking: true, pending: false });
+    });
+    utterance3.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end3', 'end3');
+    });
+    utterance2.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start2', 'start2');
+      testSynthState(win1, { speaking: true, pending: false });
+      testSynthState(win2, { speaking: true, pending: false });
+    });
+    utterance2.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end2', 'end2');
+      testSynthState(win1, { speaking: false, pending: false });
+      testSynthState(win2, { speaking: false, pending: false });
+      SimpleTest.finish();
+    });
+    win1.speechSynthesis.speak(utterance1);
+    win1.speechSynthesis.speak(utterance2);
+    win2.speechSynthesis.speak(utterance3);
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_global_queue_cancel.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1188099: Calling cancel() should work correctly with global queue</title>
+  <script type="application/javascript">
+    window.SimpleTest = parent.SimpleTest;
+    window.info = parent.info;
+    window.is = parent.is;
+    window.isnot = parent.isnot;
+    window.ok = parent.ok;
+    window.todo = parent.todo;
+  </script>
+  <script type="application/javascript" src="common.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
+<iframe id="frame1"></iframe>
+<iframe id="frame2"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+  Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
+    var win1 = frame1.contentWindow;
+    var win2 = frame2.contentWindow;
+
+    var utterance1 = new win1.SpeechSynthesisUtterance(
+      "u1: Donec ac nunc feugiat, posuere");
+    var utterance2 = new win1.SpeechSynthesisUtterance("u2: hello, losers too");
+    utterance2.lang = 'it-IT-noend';
+    var utterance3 = new win1.SpeechSynthesisUtterance("u3: hello, losers three");
+
+    var utterance4 = new win2.SpeechSynthesisUtterance("u4: hello, losers same!");
+    utterance4.lang = 'it-IT-noend';
+    var utterance5 = new win2.SpeechSynthesisUtterance("u5: hello, losers too");
+    utterance5.lang = 'it-IT-noend';
+
+    var eventOrder = ['start1', 'end1', 'start2', 'end2'];
+    utterance1.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start1', 'start1');
+      testSynthState(win1, { speaking: true, pending: true });
+      testSynthState(win2, { speaking: true, pending: true });
+      win2.speechSynthesis.cancel();
+
+    });
+    utterance1.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end1', 'end1');
+      testSynthState(win1, { pending: true });
+      testSynthState(win2, { pending: false });
+    });
+    utterance2.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start2', 'start2');
+      testSynthState(win1, { speaking: true, pending: true });
+      testSynthState(win2, { speaking: true, pending: false });
+      win1.speechSynthesis.cancel();
+    });
+    utterance2.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end2', 'end2');
+      testSynthState(win1, { speaking: false, pending: false });
+      testSynthState(win2, { speaking: false, pending: false });
+      SimpleTest.finish();
+    });
+
+    function wrongUtterance(e) {
+      ok(false, 'This shall not be uttered: "' + e.target.text + '"');
+    }
+
+    utterance3.addEventListener('start', wrongUtterance);
+    utterance4.addEventListener('start', wrongUtterance);
+    utterance5.addEventListener('start', wrongUtterance);
+
+    win1.speechSynthesis.speak(utterance1);
+    win1.speechSynthesis.speak(utterance2);
+    win1.speechSynthesis.speak(utterance3);
+    win2.speechSynthesis.speak(utterance4);
+    win2.speechSynthesis.speak(utterance5);
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_global_queue_pause.html
@@ -0,0 +1,128 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1188099: Calling pause() should work correctly with global queue</title>
+  <script type="application/javascript">
+    window.SimpleTest = parent.SimpleTest;
+    window.info = parent.info;
+    window.is = parent.is;
+    window.isnot = parent.isnot;
+    window.ok = parent.ok;
+    window.todo = parent.todo;
+  </script>
+  <script type="application/javascript" src="common.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
+<iframe id="frame1"></iframe>
+<iframe id="frame2"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+  Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
+    var win1 = frame1.contentWindow;
+    var win2 = frame2.contentWindow;
+
+    var utterance1 = new win1.SpeechSynthesisUtterance("Speak utterance 1.");
+    var utterance2 = new win2.SpeechSynthesisUtterance("Speak utterance 2.");
+    var utterance3 = new win1.SpeechSynthesisUtterance("Speak utterance 3.");
+    var utterance4 = new win2.SpeechSynthesisUtterance("Speak utterance 4.");
+    var eventOrder = ['start1', 'pause1', 'resume1', 'end1', 'start2', 'end2',
+      'start4', 'end4', 'start3', 'end3'];
+
+    utterance1.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start1', 'start1');
+      win1.speechSynthesis.pause();
+    });
+    utterance1.addEventListener('pause', function(e) {
+      info('pause??');
+      var expectedEvent = eventOrder.shift()
+      is(expectedEvent, 'pause1', 'pause1');
+      testSynthState(win1, { speaking: true, pending: false, paused: true});
+      testSynthState(win2, { speaking: true, pending: true, paused: false});
+
+      if (expectedEvent == 'pause1') {
+        win1.speechSynthesis.resume();
+      }
+    });
+    utterance1.addEventListener('resume', function(e) {
+      is(eventOrder.shift(), 'resume1', 'resume1');
+      testSynthState(win1, { speaking: true, pending: false, paused: false});
+      testSynthState(win2, { speaking: true, pending: true, paused: false});
+
+      win2.speechSynthesis.pause();
+
+      testSynthState(win1, { speaking: true, pending: false, paused: false});
+      // 1188099: currently, paused state is not gaurenteed to be immediate.
+      testSynthState(win2, { speaking: true, pending: true });
+    });
+    utterance1.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end1', 'end1');
+      testSynthState(win1, { speaking: false, pending: false, paused: false});
+      testSynthState(win2, { speaking: false, pending: true, paused: true});
+
+      win2.speechSynthesis.resume();
+    });
+
+    utterance2.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start2', 'start2');
+      testSynthState(win1, { speaking: true, pending: false, paused: false});
+      testSynthState(win2, { speaking: true, pending: false, paused: false});
+    });
+    utterance2.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end2', 'end2');
+      testSynthState(win1, { speaking: false, pending: false, paused: false});
+      testSynthState(win2, { speaking: false, pending: false, paused: false});
+
+      win1.speechSynthesis.pause();
+
+      testSynthState(win1, { speaking: false, pending: false, paused: true});
+      testSynthState(win2, { speaking: false, pending: false, paused: false});
+
+      win1.speechSynthesis.speak(utterance3);
+      win2.speechSynthesis.speak(utterance4);
+
+      testSynthState(win1, { speaking: false, pending: true, paused: true});
+      testSynthState(win2, { speaking: false, pending: true, paused: false});
+    });
+
+    utterance4.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start4', 'start4');
+      testSynthState(win1, { speaking: true, pending: true, paused: true});
+      testSynthState(win2, { speaking: true, pending: false, paused: false});
+
+      win1.speechSynthesis.resume();
+    });
+    utterance4.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end4', 'end4');
+      testSynthState(win1, { speaking: false, pending: true, paused: false});
+      testSynthState(win2, { speaking: false, pending: false, paused: false});
+    });
+
+    utterance3.addEventListener('start', function(e) {
+      is(eventOrder.shift(), 'start3', 'start3');
+      testSynthState(win1, { speaking: true, pending: false, paused: false});
+      testSynthState(win2, { speaking: true, pending: false, paused: false});
+    });
+
+    utterance3.addEventListener('end', function(e) {
+      is(eventOrder.shift(), 'end3', 'end3');
+      testSynthState(win1, { speaking: false, pending: false, paused: false});
+      testSynthState(win2, { speaking: false, pending: false, paused: false});
+
+      SimpleTest.finish();
+    });
+
+    win1.speechSynthesis.speak(utterance1);
+    win2.speechSynthesis.speak(utterance2);
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webspeech/synth/test/file_indirect_service_events.html
+++ b/dom/media/webspeech/synth/test/file_indirect_service_events.html
@@ -21,73 +21,82 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 1155034 **/
 
-function test_with_events() {
-  info('test_with_events');
-  var utterance = new SpeechSynthesisUtterance("never end, callback events");
-  utterance.lang = 'it-IT-noend';
+function testFunc(done_cb) {
+  function test_with_events() {
+    info('test_with_events');
+    var utterance = new SpeechSynthesisUtterance("never end, callback events");
+    utterance.lang = 'it-IT-noend';
+
+    utterance.addEventListener('start', function(e) {
+      info('start test_with_events');
+      speechSynthesis.pause();
+    // Wait to see if we get some bad events we didn't expect.
+    });
 
-  utterance.addEventListener('start', function(e) {
-    speechSynthesis.pause();
-  // Wait to see if we get some bad events we didn't expect.
-  });
+    utterance.addEventListener('pause', function(e) {
+      is(e.charIndex, 1, 'pause event charIndex matches service arguments');
+      is(e.elapsedTime, 1.5, 'pause event elapsedTime matches service arguments');
+      speechSynthesis.resume();
+    });
+
+    utterance.addEventListener('resume', function(e) {
+      is(e.charIndex, 1, 'resume event charIndex matches service arguments');
+      is(e.elapsedTime, 1.5, 'resume event elapsedTime matches service arguments');
+      speechSynthesis.cancel();
+    });
+
+    utterance.addEventListener('end', function(e) {
+      ok(e.charIndex, 1, 'resume event charIndex matches service arguments');
+      ok(e.elapsedTime, 1.5, 'end event elapsedTime matches service arguments');
+      test_no_events();
+    });
 
-  utterance.addEventListener('pause', function(e) {
-    is(e.charIndex, 1, 'pause event charIndex matches service arguments');
-    is(e.elapsedTime, 1.5, 'pause event elapsedTime matches service arguments');
-    speechSynthesis.resume();
-  });
+    info('start speak');
+    speechSynthesis.speak(utterance);
+  }
+
+  function forbiddenEvent(e) {
+    ok(false, 'no "' + e.type + '" event was explicitly dispatched from the service')
+  }
 
-  utterance.addEventListener('resume', function(e) {
-    is(e.charIndex, 1, 'resume event charIndex matches service arguments');
-    is(e.elapsedTime, 1.5, 'resume event elapsedTime matches service arguments');
-    speechSynthesis.cancel();
-  });
+  function test_no_events() {
+    info('test_no_events');
+    var utterance = new SpeechSynthesisUtterance("never end");
+    utterance.lang = "it-IT-noevents-noend";
+    utterance.addEventListener('start', function(e) {
+      speechSynthesis.pause();
+      // Wait to see if we get some bad events we didn't expect.
+      setTimeout(function() {
+        ok(true, 'didn\'t get any unwanted events');
+        utterance.removeEventListener('end', forbiddenEvent);
+        SpecialPowers.wrap(speechSynthesis).forceEnd();
+        done_cb();
+      }, 1000);
+    });
 
-  utterance.addEventListener('end', function(e) {
-    ok(e.charIndex, 1, 'resume event charIndex matches service arguments');
-    ok(e.elapsedTime, 1.5, 'end event elapsedTime matches service arguments');
-    test_no_events();
-  });
+    utterance.addEventListener('pause', forbiddenEvent);
+    utterance.addEventListener('end', forbiddenEvent);
 
-  speechSynthesis.speak(utterance);
+    speechSynthesis.speak(utterance);
+  }
+
+  test_with_events();
 }
 
-function test_no_events() {
-  var utterance = new SpeechSynthesisUtterance("never end");
-  utterance.lang = "it-IT-noevents-noend";
-  utterance.addEventListener('start', function(e) {
-    speechSynthesis.pause();
-    // Wait to see if we get some bad events we didn't expect.
-    setTimeout(function() {
-      SimpleTest.finish();
-    }, 1000);
-  });
-
-  utterance.addEventListener('pause', function(e) {
-    ok(false, 'no pause event was explicitly dispatched from the service')
-    speechSynthesis.resume();
-  });
-
-  utterance.addEventListener('resume', function(e) {
-    ok(false, 'no resume event was explicitly dispatched from the service')
-    speechSynthesis.cancel();
-  });
-
-  utterance.addEventListener('end', function(e) {
-    ok(false, 'no end event was explicitly dispatched from the service')
-  });
-
-  speechSynthesis.speak(utterance);
-}
-
-test_with_events();
+// Run test with no global queue, and then run it with a global queue.
+testFunc(function() {
+  SpecialPowers.pushPrefEnv(
+    { set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
+      testFunc(SimpleTest.finish)
+    });
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webspeech/synth/test/file_speech_cancel.html
+++ b/dom/media/webspeech/synth/test/file_speech_cancel.html
@@ -21,69 +21,80 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 1150315 **/
 
-var gotEndEvent = false;
-// A long utterance that we will interrupt.
-var utterance = new SpeechSynthesisUtterance("Donec ac nunc feugiat, posuere " +
-  "mauris id, pharetra velit. Donec fermentum orci nunc, sit amet maximus" +
-  "dui tincidunt ut. Sed ultricies ac nisi a laoreet. Proin interdum," +
-  "libero maximus hendrerit posuere, lorem risus egestas nisl, a" +
-  "ultricies massa justo eu nisi. Duis mattis nibh a ligula tincidunt" +
-  "tincidunt non eu erat. Sed bibendum varius vulputate. Cras leo magna," +
-  "ornare ac posuere vel, luctus id metus. Mauris nec quam ac augue" +
-  "consectetur bibendum. Integer a commodo tortor. Duis semper dolor eu" +
-  "facilisis facilisis. Etiam venenatis turpis est, quis tincidunt velit" +
-  "suscipit a. Cras semper orci in sapien rhoncus bibendum. Suspendisse" +
-  "eu ex lobortis, finibus enim in, condimentum quam. Maecenas eget dui" +
-  "ipsum. Aliquam tortor leo, interdum eget congue ut, tempor id elit.");
-utterance.addEventListener('start', function(e) {
-  ok(true, 'start utterance 1');
-  speechSynthesis.cancel();
-  speechSynthesis.speak(utterance2);
-});
+function testFunc(done_cb) {
+  var gotEndEvent = false;
+  // A long utterance that we will interrupt.
+  var utterance = new SpeechSynthesisUtterance("Donec ac nunc feugiat, posuere " +
+    "mauris id, pharetra velit. Donec fermentum orci nunc, sit amet maximus" +
+    "dui tincidunt ut. Sed ultricies ac nisi a laoreet. Proin interdum," +
+    "libero maximus hendrerit posuere, lorem risus egestas nisl, a" +
+    "ultricies massa justo eu nisi. Duis mattis nibh a ligula tincidunt" +
+    "tincidunt non eu erat. Sed bibendum varius vulputate. Cras leo magna," +
+    "ornare ac posuere vel, luctus id metus. Mauris nec quam ac augue" +
+    "consectetur bibendum. Integer a commodo tortor. Duis semper dolor eu" +
+    "facilisis facilisis. Etiam venenatis turpis est, quis tincidunt velit" +
+    "suscipit a. Cras semper orci in sapien rhoncus bibendum. Suspendisse" +
+    "eu ex lobortis, finibus enim in, condimentum quam. Maecenas eget dui" +
+    "ipsum. Aliquam tortor leo, interdum eget congue ut, tempor id elit.");
+  utterance.addEventListener('start', function(e) {
+    ok(true, 'start utterance 1');
+    speechSynthesis.cancel();
+    info('cancel!');
+    speechSynthesis.speak(utterance2);
+    info('speak??');
+  });
 
-var utterance2 = new SpeechSynthesisUtterance("Proin ornare neque vitae " +
-  "risus mattis rutrum. Suspendisse a velit ut est convallis aliquet." +
-  "Nullam ante elit, malesuada vel luctus rutrum, ultricies nec libero." +
-  "Praesent eu iaculis orci. Sed nisl diam, sodales ac purus et," +
-  "volutpat interdum tortor. Nullam aliquam porta elit et maximus. Cras" +
-  "risus lectus, elementum vel sodales vel, ultricies eget lectus." +
-  "Curabitur velit lacus, mollis vel finibus et, molestie sit amet" +
-  "sapien. Proin vitae dolor ac augue posuere efficitur ac scelerisque" +
-  "diam. Nulla sed odio elit.");
-utterance2.addEventListener('start', function() {
-  speechSynthesis.cancel();
-  speechSynthesis.speak(utterance3);
-});
-utterance2.addEventListener('end', function(e) {
-  gotEndEvent = true;
-});
+  var utterance2 = new SpeechSynthesisUtterance("Proin ornare neque vitae " +
+    "risus mattis rutrum. Suspendisse a velit ut est convallis aliquet." +
+    "Nullam ante elit, malesuada vel luctus rutrum, ultricies nec libero." +
+    "Praesent eu iaculis orci. Sed nisl diam, sodales ac purus et," +
+    "volutpat interdum tortor. Nullam aliquam porta elit et maximus. Cras" +
+    "risus lectus, elementum vel sodales vel, ultricies eget lectus." +
+    "Curabitur velit lacus, mollis vel finibus et, molestie sit amet" +
+    "sapien. Proin vitae dolor ac augue posuere efficitur ac scelerisque" +
+    "diam. Nulla sed odio elit.");
+  utterance2.addEventListener('start', function() {
+    info('start');
+    speechSynthesis.cancel();
+    speechSynthesis.speak(utterance3);
+  });
+  utterance2.addEventListener('end', function(e) {
+    gotEndEvent = true;
+  });
 
-var utterance3 = new SpeechSynthesisUtterance("Hello, world 3!");
-utterance3.addEventListener('start', function() {
-  ok(gotEndEvent, "didn't get start event for this utterance");
-});
-utterance3.addEventListener('end', function(e) {
-  SimpleTest.finish();
-});
+  var utterance3 = new SpeechSynthesisUtterance("Hello, world 3!");
+  utterance3.addEventListener('start', function() {
+    ok(gotEndEvent, "didn't get start event for this utterance");
+  });
+  utterance3.addEventListener('end', done_cb);
 
-// Speak/cancel while paused (Bug 1187105)
-speechSynthesis.pause();
-speechSynthesis.speak(new SpeechSynthesisUtterance("hello."));
-ok(speechSynthesis.pending, "paused speechSynthesis has an utterance queued.");
-speechSynthesis.cancel();
-ok(!speechSynthesis.pending, "paused speechSynthesis has no utterance queued.");
-speechSynthesis.resume();
+  // Speak/cancel while paused (Bug 1187105)
+  speechSynthesis.pause();
+  speechSynthesis.speak(new SpeechSynthesisUtterance("hello."));
+  ok(speechSynthesis.pending, "paused speechSynthesis has an utterance queued.");
+  speechSynthesis.cancel();
+  ok(!speechSynthesis.pending, "paused speechSynthesis has no utterance queued.");
+  speechSynthesis.resume();
 
-speechSynthesis.speak(utterance);
-ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
-ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
+  speechSynthesis.speak(utterance);
+  ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
+  ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
+}
+
+// Run test with no global queue, and then run it with a global queue.
+testFunc(function() {
+  SpecialPowers.pushPrefEnv(
+    { set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
+      testFunc(SimpleTest.finish)
+    });
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webspeech/synth/test/file_speech_queue.html
+++ b/dom/media/webspeech/synth/test/file_speech_queue.html
@@ -39,40 +39,47 @@ for (var voice of speechSynthesis.getVoi
 }
 
 ok(langUriMap['en-JM'], 'No English-Jamaican voice');
 ok(langUriMap['en-GB'], 'No English-British voice');
 ok(langUriMap['en-CA'], 'No English-Canadian voice');
 ok(langUriMap['fr-CA'], 'No French-Canadian voice');
 ok(langUriMap['es-MX'], 'No Spanish-Mexican voice');
 
-synthTestQueue(
-  [[{text: "Hello, world."},
-    { uri: langUriMap['en-JM'] }],
-   [{text: "Bonjour tout le monde .", lang: "fr", rate: 0.5, pitch: 0.75},
-    { uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}],
-   [{text: "How are you doing?", lang: "en-GB"},
-    { rate: 1, pitch: 1, uri: langUriMap['en-GB']}],
-   [{text: "¡hasta mañana!", lang: "es-MX"},
-    { uri: langUriMap['es-MX'] }]],
-  function () {
-    var test_data = [];
-    var voices = speechSynthesis.getVoices();
-    for (var voice of voices) {
-      if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) {
-        continue;
+function testFunc(done_cb) {
+  synthTestQueue(
+    [[{text: "Hello, world."},
+      { uri: langUriMap['en-JM'] }],
+     [{text: "Bonjour tout le monde .",
+       args: { lang: "fr", rate: 0.5, pitch: 0.75 }},
+      { uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}],
+     [{text: "How are you doing?", args: { lang: "en-GB" } },
+      { rate: 1, pitch: 1, uri: langUriMap['en-GB']}],
+     [{text: "¡hasta mañana!", args: { lang: "es-MX" } },
+      { uri: langUriMap['es-MX'] }]],
+    function () {
+      var test_data = [];
+      var voices = speechSynthesis.getVoices();
+      for (var voice of voices) {
+        if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) {
+          continue;
+        }
+        test_data.push([{text: "Hello world", args: { voice: voice} },
+                        {uri: voice.voiceURI}]);
       }
-      test_data.push([{text: "Hello world", voice: voice},
-                      {uri: voice.voiceURI}]);
-    }
+
+      synthTestQueue(test_data, done_cb);
+    });
+}
 
-    synthTestQueue(test_data,
-                   function () {
-                     SimpleTest.finish();
-                   });
-  });
-
+// Run test with no global queue, and then run it with a global queue.
+testFunc(function() {
+  SpecialPowers.pushPrefEnv(
+    { set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
+      testFunc(SimpleTest.finish)
+    });
+});
 
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webspeech/synth/test/mochitest.ini
+++ b/dom/media/webspeech/synth/test/mochitest.ini
@@ -2,14 +2,20 @@
 tags=msg
 support-files =
   common.js
   file_setup.html
   file_speech_queue.html
   file_speech_simple.html
   file_speech_cancel.html
   file_indirect_service_events.html
+  file_global_queue.html
+  file_global_queue_cancel.html
+  file_global_queue_pause.html
 
 [test_setup.html]
 [test_speech_queue.html]
 [test_speech_simple.html]
 [test_speech_cancel.html]
 [test_indirect_service_events.html]
+[test_global_queue.html]
+[test_global_queue_cancel.html]
+[test_global_queue_pause.html]
copy from dom/media/webspeech/synth/test/test_speech_queue.html
copy to dom/media/webspeech/synth/test/test_global_queue.html
--- a/dom/media/webspeech/synth/test/test_speech_queue.html
+++ b/dom/media/webspeech/synth/test/test_global_queue.html
@@ -1,33 +1,34 @@
 <!DOCTYPE HTML>
-<html lang="en-US">
+<html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=525444
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
+  <title>Test for Bug 1188099: Global queue should correctly schedule utterances</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
 <p id="display"></p>
 <iframe id="testFrame"></iframe>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 525444 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
+SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true],
+                                  ['media.webspeech.synth.force_global_queue', true]] },
+                          function() { document.getElementById("testFrame").src = "file_global_queue.html"; });
 
 </script>
 </pre>
 </body>
-</html>
+</html>
\ No newline at end of file
copy from dom/media/webspeech/synth/test/test_speech_queue.html
copy to dom/media/webspeech/synth/test/test_global_queue_cancel.html
--- a/dom/media/webspeech/synth/test/test_speech_queue.html
+++ b/dom/media/webspeech/synth/test/test_global_queue_cancel.html
@@ -1,33 +1,34 @@
 <!DOCTYPE HTML>
-<html lang="en-US">
+<html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=525444
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
+  <title>Test for Bug 1188099: Calling cancel() should work correctly with global queue</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
 <p id="display"></p>
 <iframe id="testFrame"></iframe>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 525444 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
+SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true],
+                                  ['media.webspeech.synth.force_global_queue', true]] },
+                          function() { document.getElementById("testFrame").src = "file_global_queue_cancel.html"; });
 
 </script>
 </pre>
 </body>
-</html>
+</html>
\ No newline at end of file
copy from dom/media/webspeech/synth/test/test_speech_queue.html
copy to dom/media/webspeech/synth/test/test_global_queue_pause.html
--- a/dom/media/webspeech/synth/test/test_speech_queue.html
+++ b/dom/media/webspeech/synth/test/test_global_queue_pause.html
@@ -1,33 +1,34 @@
 <!DOCTYPE HTML>
-<html lang="en-US">
+<html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=525444
+https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
+  <title>Test for Bug 1188099: Calling pause() should work correctly with global queue</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
 <p id="display"></p>
 <iframe id="testFrame"></iframe>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 525444 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
+SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true],
+                                  ['media.webspeech.synth.force_global_queue', true]] },
+                          function() { document.getElementById("testFrame").src = "file_global_queue_pause.html"; });
 
 </script>
 </pre>
 </body>
-</html>
+</html>
\ No newline at end of file
--- a/dom/media/webspeech/synth/test/test_indirect_service_events.html
+++ b/dom/media/webspeech/synth/test/test_indirect_service_events.html
@@ -19,15 +19,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 1155034 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_indirect_service_events.html"; });
+SpecialPowers.pushPrefEnv(
+  { set: [['media.webspeech.synth.enabled', true],
+          ['media.webspeech.synth.force_global_queue', false]] },
+  function() { document.getElementById("testFrame").src = "file_indirect_service_events.html"; });
+
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webspeech/synth/test/test_speech_cancel.html
+++ b/dom/media/webspeech/synth/test/test_speech_cancel.html
@@ -19,15 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 1150315 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_speech_cancel.html"; });
+SpecialPowers.pushPrefEnv(
+  { set: [['media.webspeech.synth.enabled', true],
+          ['media.webspeech.synth.force_global_queue', false]] },
+  function() { document.getElementById("testFrame").src = "file_speech_cancel.html"; });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webspeech/synth/test/test_speech_queue.html
+++ b/dom/media/webspeech/synth/test/test_speech_queue.html
@@ -19,15 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 525444 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
-                          function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
+SpecialPowers.pushPrefEnv(
+  { set: [['media.webspeech.synth.enabled', true],
+          ['media.webspeech.synth.force_global_queue', false]] },
+  function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
 
 </script>
 </pre>
 </body>
 </html>