Bug 1258600 - Part3: Modify tests, r=smaug
authorKershaw Chang <kechang@mozilla.com>
Mon, 30 May 2016 08:48:00 +0200
changeset 340646 b7836822d08417b4134ae1a1f45a38d383971803
parent 340645 3f3fef6d6d9c845a4de04eba6639cae3d5027c97
child 340647 9143e6d98cdf0ec9825d76c048e4659e86b390d2
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1258600
milestone49.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 1258600 - Part3: Modify tests, r=smaug
dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html
dom/presentation/tests/mochitest/file_presentation_receiver.html
dom/presentation/tests/mochitest/mochitest.ini
dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html
dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html
dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.html
dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
dom/presentation/tests/mochitest/test_presentation_dc_sender.html
dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html
dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
@@ -118,16 +118,26 @@ mockSessionTransport.prototype = {
     }
     if (this._role === Ci.nsIPresentationService.ROLE_RECEIVER) {
       mockSessionTransportOfSender._callback.notifyData(data);
     }
   },
   close: function(reason) {
     sendAsyncMessage('data-transport-closed', reason);
     this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
+    if (this._role === Ci.nsIPresentationService.ROLE_CONTROLLER) {
+      if (mockSessionTransportOfReceiver._callback) {
+        mockSessionTransportOfReceiver._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
+      }
+    }
+    else if (this._role === Ci.nsIPresentationService.ROLE_RECEIVER) {
+      if (mockSessionTransportOfSender._callback) {
+        mockSessionTransportOfSender._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
+      }
+    }
   },
   simulateTransportReady: function() {
     this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
   },
 };
 
 const mockSessionTransportFactory = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
--- a/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
@@ -57,23 +57,23 @@ function testConnectionAvailable() {
       aReject();
     });
   });
 }
 
 function testConnectionReady() {
   return new Promise(function(aResolve, aReject) {
     info('Receiver: --- testConnectionReady ---');
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
-      ok(false, "Should not get |onstatechange| event.")
+    connection.onconnect = function() {
+      connection.onconnect = null;
+      ok(false, "Should not get |onconnect| event.")
       aReject();
     };
     if (connection.state === "connected") {
-      connection.onstatechange = null;
+      connection.onconnect = null;
       is(connection.state, "connected", "Receiver: Connection state should become connected.");
       aResolve();
     }
   });
 }
 
 function testIncomingMessage() {
   return new Promise(function(aResolve, aReject) {
@@ -100,34 +100,37 @@ function testSendMessage() {
       if (message.type === 'message-from-receiver-received') {
         window.removeEventListener('hashchange', hashchangeHandler);
         aResolve();
       }
     });
   });
 }
 
-function testTerminateConnection() {
+// Currently, PresentationSessionInfo::NotifyTransportClosed only set the state to
+// STATE_CLOSED. So, when sender call connection.terminate(), we can only get STATE_CLOSED
+// at receiver side. This should be fixed in bu 1210340.
+function testConnectionClosed() {
   return new Promise(function(aResolve, aReject) {
-    info('Receiver: --- testTerminateConnection ---');
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
-      is(connection.state, "terminated", "Receiver: Connection should be terminated.");
+    info('Receiver: --- testConnectionClosed ---');
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Receiver: Connection should be closed.");
       aResolve();
     };
-    connection.terminate();
+    command('forward-command', JSON.stringify({ name: 'ready-to-terminate' }));
   });
 }
 
 function runTests() {
   testConnectionAvailable()
   .then(testConnectionReady)
   .then(testIncomingMessage)
   .then(testSendMessage)
-  .then(testTerminateConnection)
+  .then(testConnectionClosed)
   .then(finish);
 }
 
 runTests();
 
 </script>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Test for B2G PresentationReceiver at receiver side</title>
+  </head>
+  <body>
+    <div id="content"></div>
+<script type="application/javascript;version=1.7">
+
+"use strict";
+
+function is(a, b, msg) {
+  if (a === b) {
+    alert('OK ' + msg);
+  } else {
+    alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
+  }
+}
+
+function ok(a, msg) {
+  alert((a ? 'OK ' : 'KO ') + msg);
+}
+
+function info(msg) {
+  alert('INFO ' + msg);
+}
+
+function command(name, data) {
+  alert('COMMAND ' + JSON.stringify({name: name, data: data}));
+}
+
+function finish() {
+  alert('DONE');
+}
+
+var connection;
+
+function testConnectionAvailable() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionAvailable ---');
+    ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
+    ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
+
+    navigator.presentation.receiver.connectionList
+    .then((aList) => {
+      is(aList.connections.length, 1, "Should get one conncetion.");
+      connection = aList.connections[0];
+      ok(connection.id, "Connection ID should be set: " + connection.id);
+      is(connection.state, "connected", "Connection state at receiver side should be connected.");
+      aResolve();
+    })
+    .catch((aError) => {
+      ok(false, "Receiver: Error occurred when getting the connection: " + aError);
+      finish();
+      aReject();
+    });
+  });
+}
+
+function testConnectionReady() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionReady ---');
+    connection.onconnect = function() {
+      connection.onconnect = null;
+      ok(false, "Should not get |onconnect| event.")
+      aReject();
+    };
+    if (connection.state === "connected") {
+      connection.onconnect = null;
+      is(connection.state, "connected", "Receiver: Connection state should become connected.");
+      aResolve();
+    }
+  });
+}
+
+function testConnectionWentaway() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testConnectionWentaway ---\n');
+    command('forward-command', JSON.stringify({ name: 'ready-to-remove-receiverFrame' }));
+  });
+}
+
+function runTests() {
+  testConnectionAvailable()
+  .then(testConnectionReady)
+  .then(testConnectionWentaway);
+}
+
+runTests();
+
+</script>
+  </body>
+</html>
--- a/dom/presentation/tests/mochitest/file_presentation_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_receiver.html
@@ -118,18 +118,18 @@ function testIncomingMessage() {
 
     command({ name: 'trigger-incoming-message',
               data: incomingMessage });
   });
 }
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Connection should be terminated.");
       aResolve();
     };
 
     connection.terminate();
   });
 }
 
--- a/dom/presentation/tests/mochitest/mochitest.ini
+++ b/dom/presentation/tests/mochitest/mochitest.ini
@@ -4,25 +4,31 @@ support-files =
   PresentationSessionChromeScript.js
   PresentationSessionChromeScript1UA.js
   file_presentation_1ua_receiver.html
   file_presentation_non_receiver_inner_iframe.html
   file_presentation_non_receiver.html
   file_presentation_receiver.html
   file_presentation_receiver_establish_connection_error.html
   file_presentation_receiver_inner_iframe.html
+  file_presentation_1ua_wentaway.html
+  test_presentation_1ua_connection_wentaway.js
 
 [test_presentation_dc_sender.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_dc_receiver.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_1ua_sender_and_receiver.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_1ua_sender_and_receiver_oop.html]
 skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
+[test_presentation_1ua_connection_wentaway_inproc.html]
+skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
+[test_presentation_1ua_connection_wentaway_oop.html]
+skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
 [test_presentation_device_info.html]
 [test_presentation_device_info_permission.html]
 [test_presentation_sender_startWithDevice.html]
 skip-if = toolkit == 'android' # Bug 1129785
 [test_presentation_tcp_sender_disconnect.html]
 skip-if = toolkit == 'android' # Bug 1129785
 [test_presentation_tcp_sender_establish_connection_error.html]
 skip-if = toolkit == 'android' # Bug 1129785
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
@@ -0,0 +1,185 @@
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+
+function debug(str) {
+  // info(str);
+}
+
+var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
+var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_wentaway.html');
+var request;
+var connection;
+var receiverIframe;
+
+function setup() {
+  SpecialPowers.addPermission("presentation",
+                              true, { url: receiverUrl,
+                                      originAttributes: {
+                                        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
+                                        inIsolatedMozBrowser: true }});
+
+  gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+    debug('Got message: device-prompt');
+    gScript.removeMessageListener('device-prompt', devicePromptHandler);
+    gScript.sendAsyncMessage('trigger-device-prompt-select');
+  });
+
+  gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+    debug('Got message: control-channel-established');
+    gScript.removeMessageListener('control-channel-established',
+                                  controlChannelEstablishedHandler);
+    receiverIframe = document.createElement('iframe');
+    receiverIframe.setAttribute("mozbrowser", "true");
+    receiverIframe.setAttribute("mozpresentation", receiverUrl);
+    var oop = location.pathname.indexOf('_inproc') == -1;
+    receiverIframe.setAttribute("remote", oop);
+
+    receiverIframe.setAttribute('src', receiverUrl);
+    receiverIframe.addEventListener("mozbrowserloadend", function mozbrowserloadendHander() {
+      receiverIframe.removeEventListener("mozbrowserloadend", mozbrowserloadendHander);
+      info("Receiver loaded.");
+      gScript.sendAsyncMessage("trigger-control-channel-open");
+    });
+
+    // This event is triggered when the iframe calls "alert".
+    receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
+      var message = evt.detail.message;
+      if (/^OK /.exec(message)) {
+        ok(true, message.replace(/^OK /, ""));
+      } else if (/^KO /.exec(message)) {
+        ok(false, message.replace(/^KO /, ""));
+      } else if (/^INFO /.exec(message)) {
+        info(message.replace(/^INFO /, ""));
+      } else if (/^COMMAND /.exec(message)) {
+        var command = JSON.parse(message.replace(/^COMMAND /, ""));
+        gScript.sendAsyncMessage(command.name, command.data);
+      } else if (/^DONE$/.exec(message)) {
+        receiverIframe.removeEventListener("mozbrowsershowmodalprompt",
+                                            receiverListener);
+        teardown();
+      }
+    }, false);
+
+    var promise = new Promise(function(aResolve, aReject) {
+      document.body.appendChild(receiverIframe);
+      aResolve(receiverIframe);
+    });
+
+    var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
+                           .getService(SpecialPowers.Ci.nsIObserverService);
+    obs.notifyObservers(promise, 'setup-request-promise', null);
+  });
+
+  gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
+    debug('Got message: promise-setup-ready');
+    gScript.removeMessageListener('promise-setup-ready',
+                                  promiseSetupReadyHandler);
+    gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
+  });
+
+  gScript.addMessageListener('offer-sent', function offerSentHandler() {
+    debug('Got message: offer-sent');
+    gScript.removeMessageListener('offer-sent', offerSentHandler);
+    gScript.sendAsyncMessage('trigger-on-offer');
+  });
+
+  gScript.addMessageListener('answer-sent', function answerSentHandler() {
+    debug('Got message: answer-sent');
+    gScript.removeMessageListener('answer-sent', answerSentHandler);
+    gScript.sendAsyncMessage('trigger-on-answer');
+  });
+
+  return Promise.resolve();
+}
+
+function testCreateRequest() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testCreateRequest ---');
+    request = new PresentationRequest("http://example.com");
+    request.getAvailability().then((aAvailability) => {
+      aAvailability.onchange = function() {
+        aAvailability.onchange = null;
+        ok(aAvailability.value, "Sender: Device should be available.");
+        aResolve();
+      }
+    }).catch((aError) => {
+      ok(false, "Sender: Error occurred when getting availability: " + aError);
+      teardown();
+      aReject();
+    });
+
+    gScript.sendAsyncMessage('trigger-device-add');
+  });
+}
+
+function testStartConnection() {
+  return new Promise(function(aResolve, aReject) {
+    request.start().then((aConnection) => {
+      connection = aConnection;
+      ok(connection, "Sender: Connection should be available.");
+      ok(connection.id, "Sender: Connection ID should be set.");
+      is(connection.state, "connecting", "Sender: The initial state should be connecting.");
+      connection.onconnect = function() {
+        connection.onconnect = null;
+        is(connection.state, "connected", "Connection should be connected.");
+        aResolve();
+      };
+    }).catch((aError) => {
+      ok(false, "Sender: Error occurred when establishing a connection: " + aError);
+      teardown();
+      aReject();
+    });
+  });
+}
+
+function testConnectionWentaway() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testConnectionWentaway ---');
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Sender: Connection should be closed.");
+      aResolve();
+    };
+    gScript.addMessageListener('ready-to-remove-receiverFrame', function onReadyToRemove() {
+      gScript.removeMessageListener('ready-to-remove-receiverFrame', onReadyToRemove);
+      receiverIframe.src = "http://example.com";
+    });
+  });
+}
+
+function teardown() {
+  gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
+    debug('Got message: teardown-complete');
+    gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
+    gScript.destroy();
+    SimpleTest.finish();
+  });
+
+  SpecialPowers.removePermission("presentation",
+                                 { url: receiverUrl,
+                                   originAttributes: {
+                                     appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
+                                     inIsolatedMozBrowser: true }});
+  gScript.sendAsyncMessage('teardown');
+}
+
+function runTests() {
+  setup().then(testCreateRequest)
+         .then(testStartConnection)
+         .then(testConnectionWentaway)
+         .then(teardown);
+}
+
+SpecialPowers.pushPermissions([
+  {type: 'presentation-device-manage', allow: false, context: document},
+  {type: 'presentation', allow: true, context: document},
+  {type: "browser", allow: true, context: document},
+], () => {
+  SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
+                                      ["dom.presentation.test.enabled", true],
+                                      ["dom.mozBrowserFramesEnabled", true],
+                                      ["dom.ipc.tabs.disabled", false],
+                                      ["dom.presentation.test.stage", 0]]},
+                            runTests);
+});
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <!-- Any copyright is dedicated to the Public Domain.
+    - http://creativecommons.org/publicdomain/zero/1.0/ -->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for B2G Presentation API when sender and receiver at the same side</title>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  </head>
+  <body>
+    <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
+      Test for PresentationConnectionClosedEvent with wentaway reason</a>
+    <script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
+<html>
+  <!-- Any copyright is dedicated to the Public Domain.
+    - http://creativecommons.org/publicdomain/zero/1.0/ -->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for B2G Presentation API when sender and receiver at the same side</title>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  </head>
+  <body>
+    <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
+      Test for PresentationConnectionClosedEvent with wentaway reason</a>
+    <script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
+    </script>
+  </body>
+</html>
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.html
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.html
@@ -124,18 +124,18 @@ function testCreateRequest() {
 
 function testStartConnection() {
   return new Promise(function(aResolve, aReject) {
     request.start().then((aConnection) => {
       connection = aConnection;
       ok(connection, "Sender: Connection should be available.");
       ok(connection.id, "Sender: Connection ID should be set.");
       is(connection.state, "connecting", "The initial state should be connecting.");
-      connection.onstatechange = function() {
-        connection.onstatechange = null;
+      connection.onconnect = function() {
+        connection.onconnect = null;
         is(connection.state, "connected", "Connection should be connected.");
         aResolve();
       };
     }).catch((aError) => {
       ok(false, "Sender: Error occurred when establishing a connection: " + aError);
       teardown();
       aReject();
     });
@@ -172,22 +172,25 @@ function testIncomingMessage() {
     });
     postMessageToIframe('trigger-message-from-receiver');
   });
 }
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
     info('Sender: --- testTerminateConnection ---');
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Sender: Connection should be terminated.");
       aResolve();
     };
-    connection.terminate();
+    gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
+      gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
+      connection.terminate();
+    });
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     debug('Got message: teardown-complete');
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
@@ -130,18 +130,18 @@ function testCreateRequest() {
 function testStartConnection() {
   return new Promise(function(aResolve, aReject) {
     request.start()
     .then((aConnection) => {
       connection = aConnection;
       ok(connection, "Sender: Connection should be available.");
       ok(connection.id, "Sender: Connection ID should be set.");
       is(connection.state, "connecting", "The initial state should be connecting.");
-      connection.onstatechange = function() {
-        connection.onstatechange = null;
+      connection.onconnect = function() {
+        connection.onconnect = null;
         is(connection.state, "connected", "Connection should be connected.");
         aResolve();
       };
     })
     .catch((aError) => {
       ok(false, "Sender: Error occurred when establishing a connection: " + aError);
       teardown();
       aReject();
@@ -177,22 +177,25 @@ function testIncomingMessage() {
     });
     postMessageToIframe('trigger-message-from-receiver');
   });
 }
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
     info('Sender: --- testTerminateConnection ---');
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Sender: Connection should be terminated.");
       aResolve();
     };
-    connection.terminate();
+    gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
+      gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
+      connection.terminate();
+    });
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
     SimpleTest.finish();
--- a/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
+++ b/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
@@ -108,18 +108,18 @@ function testStartConnection() {
         connection = aConnection;
         ok(connection, "Connection should be available.");
         ok(connection.id, "Connection ID should be set.");
         is(connection.state, "connecting", "The initial state should be connecting.");
 
         if (connectionFromEvent) {
           is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
         }
-        connection.onstatechange = function() {
-          connection.onstatechange = null;
+        connection.onconnect = function() {
+          connection.onconnect = null;
           is(connection.state, "connected", "Connection should be connected.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -158,18 +158,18 @@ function testIncomingMessage() {
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Connection should be terminated.");
       aResolve();
     };
 
     connection.terminate();
   });
 }
 
--- a/dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html
+++ b/dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html
@@ -104,18 +104,18 @@ function testStartConnectionWithDevice()
         connection = aConnection;
         ok(connection, "Connection should be available.");
         ok(connection.id, "Connection ID should be set.");
         is(connection.state, "connecting", "The initial state should be connecting.");
 
         if (connectionFromEvent) {
           is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
         }
-        connection.onstatechange = function() {
-          connection.onstatechange = null;
+        connection.onconnect = function() {
+          connection.onconnect = null;
           is(connection.state, "connected", "Connection should be connected.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
@@ -103,18 +103,18 @@ function testStartConnection() {
         connection = aConnection;
         ok(connection, "Connection should be available.");
         ok(connection.id, "Connection ID should be set.");
         is(connection.state, "connecting", "The initial state should be connecting.");
 
         if (connectionFromEvent) {
           is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
         }
-        connection.onstatechange = function() {
-          connection.onstatechange = null;
+        connection.onconnect = function() {
+          connection.onconnect = null;
           is(connection.state, "connected", "Connection should be connected.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -153,18 +153,18 @@ function testIncomingMessage() {
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Connection should be terminated.");
       aResolve();
     };
 
     connection.terminate();
   });
 }
 
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
@@ -84,18 +84,18 @@ function testStartConnection() {
     ok(!navigator.presentation.receiver, "Sender shouldn't get a presentation receiver instance.");
 
     navigator.presentation.defaultRequest.onconnectionavailable = function(aEvent) {
       navigator.presentation.defaultRequest.onconnectionavailable = null;
       connection = aEvent.connection;
       ok(connection, "|connectionavailable| event is fired with a connection.");
       ok(connection.id, "Connection ID should be set.");
       is(connection.state, "connecting", "The initial state should be connecting.");
-      connection.onstatechange = function() {
-        connection.onstatechange = null;
+      connection.onconnect = function() {
+        connection.onconnect = null;
         is(connection.state, "connected", "Connection should be connected.");
         aResolve();
       };
     };
 
     // Simulate the UA triggers |start()| of the default request.
     navigator.presentation.defaultRequest.start();
   });
@@ -103,18 +103,18 @@ function testStartConnection() {
 
 function testTerminateConnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onterminate = function() {
+      connection.onterminate = null;
       is(connection.state, "terminated", "Connection should be terminated.");
       aResolve();
     };
 
     connection.terminate();
   });
 }
 
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
@@ -88,18 +88,18 @@ function testStartConnection() {
     });
 
     request.start().then(
       function(aConnection) {
         connection = aConnection;
         ok(connection, "Connection should be available.");
         ok(connection.id, "Connection ID should be set.");
         is(connection.state, "connecting", "The initial state should be connecting.");
-        connection.onstatechange = function() {
-          connection.onstatechange = null;
+        connection.onconnect = function() {
+          connection.onconnect = null;
           is(connection.state, "connected", "Connection should be connected.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -110,18 +110,18 @@ function testStartConnection() {
 
 function testDisconnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onstatechange = function() {
-      connection.onstatechange = null;
+    connection.onclose = function() {
+      connection.onclose = null;
       is(connection.state, "closed", "Connection should be closed.");
       aResolve();
     };
 
     gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
   });
 }
 
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
@@ -100,18 +100,18 @@ function testStartConnectionUnexpectedCo
       gScript.removeMessageListener('offer-sent', offerSentHandler);
       ok(aIsValid, "A valid offer is sent out.");
       gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
     });
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onstatechange = function() {
-          aConnection.onstatechange = null;
+        aConnection.onterminate = function() {
+          aConnection.onterminate = null;
           is(aConnection.state, "terminated", "Connection should be terminated.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -148,18 +148,18 @@ function testStartConnectionUnexpectedCo
       gScript.removeMessageListener('offer-sent', offerSentHandler);
       ok(aIsValid, "A valid offer is sent out.");
       gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
     });
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onstatechange = function() {
-          aConnection.onstatechange = null;
+        aConnection.onterminate = function() {
+          aConnection.onterminate = null;
           is(aConnection.state, "terminated", "Connection should be terminated.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -207,18 +207,18 @@ function testStartConnectionUnexpectedCo
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onstatechange = function() {
-          aConnection.onstatechange = null;
+        aConnection.onterminate = function() {
+          aConnection.onterminate = null;
           is(aConnection.state, "terminated", "Connection should be terminated.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -266,18 +266,18 @@ function testStartConnectionUnexpectedCo
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onstatechange = function() {
-          aConnection.onstatechange = null;
+        aConnection.onterminate = function() {
+          aConnection.onterminate = null;
           is(aConnection.state, "terminated", "Connection should be terminated.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();
@@ -325,18 +325,18 @@ function testStartConnectionUnexpectedDa
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onstatechange = function() {
-          aConnection.onstatechange = null;
+        aConnection.onterminate = function() {
+          aConnection.onterminate = null;
           is(aConnection.state, "terminated", "Connection should be terminated.");
           aResolve();
         };
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
         aReject();