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 library test.runner.browser.server; | 5 library test.runner.browser.server; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 | 10 |
11 import 'package:path/path.dart' as p; | 11 import 'package:path/path.dart' as p; |
12 import 'package:pool/pool.dart'; | 12 import 'package:pool/pool.dart'; |
13 import 'package:shelf/shelf.dart' as shelf; | 13 import 'package:shelf/shelf.dart' as shelf; |
14 import 'package:shelf/shelf_io.dart' as shelf_io; | 14 import 'package:shelf/shelf_io.dart' as shelf_io; |
15 import 'package:shelf_static/shelf_static.dart'; | 15 import 'package:shelf_static/shelf_static.dart'; |
16 import 'package:shelf_web_socket/shelf_web_socket.dart'; | 16 import 'package:shelf_web_socket/shelf_web_socket.dart'; |
17 | 17 |
18 import '../../backend/suite.dart'; | 18 import '../../backend/suite.dart'; |
19 import '../../backend/test_platform.dart'; | 19 import '../../backend/test_platform.dart'; |
20 import '../../util/io.dart'; | 20 import '../../util/io.dart'; |
21 import '../../util/path_handler.dart'; | 21 import '../../util/path_handler.dart'; |
22 import '../../util/one_off_handler.dart'; | 22 import '../../util/one_off_handler.dart'; |
23 import '../../utils.dart'; | 23 import '../../utils.dart'; |
24 import '../load_exception.dart'; | 24 import '../load_exception.dart'; |
25 import 'browser.dart'; | 25 import 'browser.dart'; |
26 import 'browser_manager.dart'; | 26 import 'browser_manager.dart'; |
27 import 'compiler_pool.dart'; | 27 import 'compiler_pool.dart'; |
28 import 'chrome.dart'; | 28 import 'chrome.dart'; |
| 29 import 'dartium.dart'; |
29 import 'firefox.dart'; | 30 import 'firefox.dart'; |
30 | 31 |
31 /// A server that serves JS-compiled tests to browsers. | 32 /// A server that serves JS-compiled tests to browsers. |
32 /// | 33 /// |
33 /// A test suite may be loaded for a given file using [loadSuite]. | 34 /// A test suite may be loaded for a given file using [loadSuite]. |
34 class BrowserServer { | 35 class BrowserServer { |
35 /// Starts the server. | 36 /// Starts the server. |
36 /// | 37 /// |
37 /// [root] is the root directory that the server should serve. It defaults to | 38 /// [root] is the root directory that the server should serve. It defaults to |
38 /// the working directory. | 39 /// the working directory. |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 for (var i = 0; i < segments.length; i++) { | 173 for (var i = 0; i < segments.length; i++) { |
173 if (segments[i] != "packages") continue; | 174 if (segments[i] != "packages") continue; |
174 return staticHandler( | 175 return staticHandler( |
175 shelfChange(request, path: p.url.joinAll(segments.take(i + 1)))); | 176 shelfChange(request, path: p.url.joinAll(segments.take(i + 1)))); |
176 } | 177 } |
177 | 178 |
178 return new shelf.Response.notFound("Not found."); | 179 return new shelf.Response.notFound("Not found."); |
179 }; | 180 }; |
180 } | 181 } |
181 | 182 |
182 /// A handler that serves wrapper HTML to bootstrap tests. | 183 /// A handler that serves wrapper files used to bootstrap tests. |
183 shelf.Response _wrapperHandler(shelf.Request request) { | 184 shelf.Response _wrapperHandler(shelf.Request request) { |
184 var path = p.fromUri(shelfUrl(request)); | 185 var path = p.fromUri(shelfUrl(request)); |
185 var withoutExtensions = p.withoutExtension(p.withoutExtension(path)); | 186 var withoutExtensions = p.withoutExtension(p.withoutExtension(path)); |
186 var base = p.basename(withoutExtensions); | 187 var base = p.basename(withoutExtensions); |
187 | 188 |
| 189 if (path.endsWith(".browser_test.dart")) { |
| 190 return new shelf.Response.ok(''' |
| 191 import "package:test/src/runner/browser/iframe_listener.dart"; |
| 192 |
| 193 import "$base" as test; |
| 194 |
| 195 void main() { |
| 196 IframeListener.start(() => test.main); |
| 197 } |
| 198 ''', headers: {'Content-Type': 'application/dart'}); |
| 199 } |
| 200 |
188 if (path.endsWith(".browser_test.html")) { | 201 if (path.endsWith(".browser_test.html")) { |
189 // TODO(nweiz): support user-authored HTML files. | 202 // TODO(nweiz): support user-authored HTML files. |
190 return new shelf.Response.ok(''' | 203 return new shelf.Response.ok(''' |
191 <!DOCTYPE html> | 204 <!DOCTYPE html> |
192 <html> | 205 <html> |
193 <head> | 206 <head> |
194 <title>${HTML_ESCAPE.convert(base)}.dart Test</title> | 207 <title>${HTML_ESCAPE.convert(base)}.dart Test</title> |
195 <script type="application/javascript" | 208 <script type="application/dart" |
196 src="${HTML_ESCAPE.convert(base)}.browser_test.dart.js"> | 209 src="${HTML_ESCAPE.convert(base)}.browser_test.dart"> |
197 </script> | 210 </script> |
| 211 <script src="packages/browser/dart.js"></script> |
198 </head> | 212 </head> |
199 </html> | 213 </html> |
200 ''', headers: {'Content-Type': 'text/html'}); | 214 ''', headers: {'Content-Type': 'text/html'}); |
201 } | 215 } |
202 | 216 |
203 return new shelf.Response.notFound('Not found.'); | 217 return new shelf.Response.notFound('Not found.'); |
204 } | 218 } |
205 | 219 |
206 /// Loads the test suite at [path] on the browser [browser]. | 220 /// Loads the test suite at [path] on the browser [browser]. |
207 /// | 221 /// |
208 /// This will start a browser to load the suite if one isn't already running. | 222 /// This will start a browser to load the suite if one isn't already running. |
209 /// Throws an [ArgumentError] if [browser] isn't a browser platform. | 223 /// Throws an [ArgumentError] if [browser] isn't a browser platform. |
210 Future<Suite> loadSuite(String path, TestPlatform browser) { | 224 Future<Suite> loadSuite(String path, TestPlatform browser) { |
211 if (!browser.isBrowser) { | 225 if (!browser.isBrowser) { |
212 throw new ArgumentError("$browser is not a browser."); | 226 throw new ArgumentError("$browser is not a browser."); |
213 } | 227 } |
214 | 228 |
215 return new Future.sync(() { | 229 return new Future.sync(() { |
216 if (_pubServeUrl != null) { | 230 if (_pubServeUrl != null) { |
217 var suitePrefix = p.relative(path, from: p.join(_root, 'test')) + | 231 var suitePrefix = p.relative(path, from: p.join(_root, 'test')) + |
218 '.browser_test'; | 232 '.browser_test'; |
219 var jsUrl = _pubServeUrl.resolve('$suitePrefix.dart.js'); | 233 var jsUrl = _pubServeUrl.resolve('$suitePrefix.dart.js'); |
220 return _pubServeSuite(path, jsUrl).then((_) => | 234 return _pubServeSuite(path, jsUrl).then((_) => |
221 _pubServeUrl.resolve('$suitePrefix.html')); | 235 _pubServeUrl.resolve('$suitePrefix.html')); |
222 } | 236 } |
223 | 237 |
224 return _compileSuite(path).then((_) { | 238 return new Future.sync(() => browser.isJS ? _compileSuite(path) : null) |
| 239 .then((_) { |
225 if (_closed) return null; | 240 if (_closed) return null; |
226 return url.resolveUri( | 241 return url.resolveUri( |
227 p.toUri(p.relative(path, from: _root) + ".browser_test.html")); | 242 p.toUri(p.relative(path, from: _root) + ".browser_test.html")); |
228 }); | 243 }); |
229 }).then((suiteUrl) { | 244 }).then((suiteUrl) { |
230 if (_closed) return null; | 245 if (_closed) return null; |
231 | 246 |
232 // TODO(nweiz): Don't start the browser until all the suites are compiled. | 247 // TODO(nweiz): Don't start the browser until all the suites are compiled. |
233 return _browserManagerFor(browser).then((browserManager) { | 248 return _browserManagerFor(browser).then((browserManager) { |
234 if (_closed) return null; | 249 if (_closed) return null; |
235 return browserManager.loadSuite(path, suiteUrl); | 250 return browserManager.loadSuite(path, suiteUrl); |
236 }); | 251 }).then((suite) => suite.change(platform: browser.name)); |
237 }); | 252 }); |
238 } | 253 } |
239 | 254 |
240 /// Loads a test suite at [path] from the `pub serve` URL [jsUrl]. | 255 /// Loads a test suite at [path] from the `pub serve` URL [jsUrl]. |
241 /// | 256 /// |
242 /// This ensures that only one suite is loaded at a time, and that any errors | 257 /// This ensures that only one suite is loaded at a time, and that any errors |
243 /// are exposed as [LoadException]s. | 258 /// are exposed as [LoadException]s. |
244 Future _pubServeSuite(String path, Uri jsUrl) { | 259 Future _pubServeSuite(String path, Uri jsUrl) { |
245 return _pubServePool.withResource(() { | 260 return _pubServePool.withResource(() { |
246 var timer = new Timer(new Duration(seconds: 1), () { | 261 var timer = new Timer(new Duration(seconds: 1), () { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 if (completer.isCompleted) return; | 341 if (completer.isCompleted) return; |
327 completer.completeError(error, stackTrace); | 342 completer.completeError(error, stackTrace); |
328 }); | 343 }); |
329 | 344 |
330 return completer.future; | 345 return completer.future; |
331 } | 346 } |
332 | 347 |
333 /// Starts the browser identified by [browser] and has it load [url]. | 348 /// Starts the browser identified by [browser] and has it load [url]. |
334 Browser _newBrowser(Uri url, TestPlatform browser) { | 349 Browser _newBrowser(Uri url, TestPlatform browser) { |
335 switch (browser) { | 350 switch (browser) { |
| 351 case TestPlatform.dartium: return new Dartium(url); |
336 case TestPlatform.chrome: return new Chrome(url); | 352 case TestPlatform.chrome: return new Chrome(url); |
337 case TestPlatform.firefox: return new Firefox(url); | 353 case TestPlatform.firefox: return new Firefox(url); |
338 default: | 354 default: |
339 throw new ArgumentError("$browser is not a browser."); | 355 throw new ArgumentError("$browser is not a browser."); |
340 } | 356 } |
341 } | 357 } |
342 | 358 |
343 /// Closes the server and releases all its resources. | 359 /// Closes the server and releases all its resources. |
344 /// | 360 /// |
345 /// Returns a [Future] that completes once the server is closed and its | 361 /// Returns a [Future] that completes once the server is closed and its |
(...skipping 15 matching lines...) Expand all Loading... |
361 if (_pubServeUrl == null) { | 377 if (_pubServeUrl == null) { |
362 new Directory(_compiledDir).deleteSync(recursive: true); | 378 new Directory(_compiledDir).deleteSync(recursive: true); |
363 } else { | 379 } else { |
364 _http.close(); | 380 _http.close(); |
365 } | 381 } |
366 | 382 |
367 _closeCompleter.complete(); | 383 _closeCompleter.complete(); |
368 }).catchError(_closeCompleter.completeError); | 384 }).catchError(_closeCompleter.completeError); |
369 } | 385 } |
370 } | 386 } |
OLD | NEW |