Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:convert'; | 6 import 'dart:convert'; |
| 7 import 'dart:html'; | 7 import 'dart:html'; |
| 8 import 'dart:js' as js; | 8 import 'dart:js' as js; |
| 9 | 9 |
| 10 import 'package:stack_trace/stack_trace.dart'; | 10 import 'package:stack_trace/stack_trace.dart'; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 } else if (message['command'] == 'displayPause') { | 81 } else if (message['command'] == 'displayPause') { |
| 82 document.body.classes.add('paused'); | 82 document.body.classes.add('paused'); |
| 83 } else if (message['command'] == 'resume') { | 83 } else if (message['command'] == 'resume') { |
| 84 document.body.classes.remove('paused'); | 84 document.body.classes.remove('paused'); |
| 85 } else { | 85 } else { |
| 86 assert(message['command'] == 'closeSuite'); | 86 assert(message['command'] == 'closeSuite'); |
| 87 _iframes[message['id']].remove(); | 87 _iframes[message['id']].remove(); |
| 88 } | 88 } |
| 89 }); | 89 }); |
| 90 | 90 |
| 91 // Send periodic pings to the test runner so it can know when the browser is | |
| 92 // paused for debugging. | |
| 93 new Timer.periodic(new Duration(seconds: 1), | |
|
kevmoo
2016/02/17 16:22:48
const Duration?
| |
| 94 (_) => serverChannel.sink.add({"command": "ping"})); | |
| 95 | |
| 91 var play = document.querySelector("#play"); | 96 var play = document.querySelector("#play"); |
| 92 play.onClick.listen((_) { | 97 play.onClick.listen((_) { |
| 93 document.body.classes.remove('paused'); | 98 document.body.classes.remove('paused'); |
| 94 serverChannel.sink.add({"command": "resume"}); | 99 serverChannel.sink.add({"command": "resume"}); |
| 95 }); | 100 }); |
| 96 }, onError: (error, stackTrace) { | 101 }, onError: (error, stackTrace) { |
| 97 print("$error\n${new Trace.from(stackTrace).terse}"); | 102 print("$error\n${new Trace.from(stackTrace).terse}"); |
| 98 }); | 103 }); |
| 99 } | 104 } |
| 100 | 105 |
| 101 /// Creates a [MultiChannel] connection to the server, using a [WebSocket] as | 106 /// Creates a [MultiChannel] connection to the server, using a [WebSocket] as |
| 102 /// the underlying protocol. | 107 /// the underlying protocol. |
| 103 MultiChannel _connectToServer() { | 108 MultiChannel _connectToServer() { |
| 104 // The `managerUrl` query parameter contains the WebSocket URL of the remote | 109 // The `managerUrl` query parameter contains the WebSocket URL of the remote |
| 105 // [BrowserManager] with which this communicates. | 110 // [BrowserManager] with which this communicates. |
| 106 var currentUrl = Uri.parse(window.location.href); | 111 var currentUrl = Uri.parse(window.location.href); |
| 107 var webSocket = new WebSocket(currentUrl.queryParameters['managerUrl']); | 112 var webSocket = new WebSocket(currentUrl.queryParameters['managerUrl']); |
| 108 | 113 |
| 109 var inputController = new StreamController(sync: true); | 114 var controller = new StreamChannelController(sync: true); |
| 110 webSocket.onMessage.listen((message) { | 115 webSocket.onMessage.listen((message) { |
| 111 inputController.add(JSON.decode(message.data)); | 116 controller.local.sink.add(JSON.decode(message.data)); |
| 112 }); | 117 }); |
| 113 | 118 |
| 114 var outputController = new StreamController(sync: true); | 119 controller.local.stream.listen( |
| 115 outputController.stream.listen( | |
| 116 (message) => webSocket.send(JSON.encode(message))); | 120 (message) => webSocket.send(JSON.encode(message))); |
| 117 | 121 |
| 118 return new MultiChannel( | 122 return new MultiChannel(controller.foreign); |
| 119 new StreamChannel(inputController.stream, outputController.sink)); | |
| 120 } | 123 } |
| 121 | 124 |
| 122 /// Creates an iframe with `src` [url] and establishes a connection to it using | 125 /// Creates an iframe with `src` [url] and establishes a connection to it using |
| 123 /// `postMessage`. | 126 /// `postMessage`. |
| 124 /// | 127 /// |
| 125 /// [id] identifies the suite loaded in this iframe. | 128 /// [id] identifies the suite loaded in this iframe. |
| 126 StreamChannel _connectToIframe(String url, int id) { | 129 StreamChannel _connectToIframe(String url, int id) { |
| 127 var iframe = new IFrameElement(); | 130 var iframe = new IFrameElement(); |
| 128 _iframes[id] = iframe; | 131 _iframes[id] = iframe; |
| 129 iframe.src = url; | 132 iframe.src = url; |
| 130 document.body.children.add(iframe); | 133 document.body.children.add(iframe); |
| 131 | 134 |
| 132 var inputController = new StreamController(sync: true); | 135 var controller = new StreamChannelController(sync: true); |
| 133 var outputController = new StreamController(sync: true); | |
| 134 | 136 |
| 135 // Use this to avoid sending a message to the iframe before it's sent a | 137 // Use this to avoid sending a message to the iframe before it's sent a |
| 136 // message to us. This ensures that no messages get dropped on the floor. | 138 // message to us. This ensures that no messages get dropped on the floor. |
| 137 var readyCompleter = new Completer(); | 139 var readyCompleter = new Completer(); |
| 138 | 140 |
| 139 // TODO(nweiz): use MessageChannel once Firefox supports it | 141 // TODO(nweiz): use MessageChannel once Firefox supports it |
| 140 // (http://caniuse.com/#search=MessageChannel). | 142 // (http://caniuse.com/#search=MessageChannel). |
| 141 window.onMessage.listen((message) { | 143 window.onMessage.listen((message) { |
| 142 // A message on the Window can theoretically come from any website. It's | 144 // A message on the Window can theoretically come from any website. It's |
| 143 // very unlikely that a malicious site would care about hacking someone's | 145 // very unlikely that a malicious site would care about hacking someone's |
| 144 // unit tests, let alone be able to find the test server while it's | 146 // unit tests, let alone be able to find the test server while it's |
| 145 // running, but it's good practice to check the origin anyway. | 147 // running, but it's good practice to check the origin anyway. |
| 146 if (message.origin != window.location.origin) return; | 148 if (message.origin != window.location.origin) return; |
| 147 | 149 |
| 148 // TODO(nweiz): Stop manually checking href here once issue 22554 is | 150 // TODO(nweiz): Stop manually checking href here once issue 22554 is |
| 149 // fixed. | 151 // fixed. |
| 150 if (message.data["href"] != iframe.src) return; | 152 if (message.data["href"] != iframe.src) return; |
| 151 | 153 |
| 152 message.stopPropagation(); | 154 message.stopPropagation(); |
| 153 inputController.add(message.data["data"]); | 155 |
| 154 if (!readyCompleter.isCompleted) readyCompleter.complete(); | 156 // This message indicates that the iframe is actively listening for events. |
| 157 if (message.data["ready"] == true) { | |
| 158 readyCompleter.complete(); | |
| 159 } else { | |
| 160 controller.local.sink.add(message.data["data"]); | |
| 161 } | |
| 155 }); | 162 }); |
| 156 | 163 |
| 157 outputController.stream.listen((message) async { | 164 controller.local.stream.listen((message) async { |
| 158 await readyCompleter.future; | 165 await readyCompleter.future; |
| 159 iframe.contentWindow.postMessage(message, window.location.origin); | 166 |
| 167 // JSON-encode the message to work around sdk#25636, which caused the | |
| 168 // structured clone algorithm to be broken with Window.postMessage in | |
| 169 // 1.14.{0,1,2}. Once we no longer care about these Dartiums, stop encoding. | |
| 170 iframe.contentWindow.postMessage( | |
| 171 JSON.encode(message), window.location.origin); | |
| 160 }); | 172 }); |
| 161 | 173 |
| 162 return new StreamChannel(inputController.stream, outputController.sink); | 174 return controller.foreign; |
| 163 } | 175 } |
| OLD | NEW |