| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library browser; | 4 library browser; |
| 5 | 5 |
| 6 import "dart:async"; | 6 import "dart:async"; |
| 7 import "dart:convert" show LineSplitter, UTF8; | 7 import "dart:convert" show LineSplitter, UTF8; |
| 8 import "dart:core"; | 8 import "dart:core"; |
| 9 import "dart:io"; | 9 import "dart:io"; |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 | 24 |
| 25 // This is called after the process is closed, before the done future | 25 // This is called after the process is closed, before the done future |
| 26 // is completed. | 26 // is completed. |
| 27 // Subclasses can use this to cleanup any browser specific resources | 27 // Subclasses can use this to cleanup any browser specific resources |
| 28 // (temp directories, profiles, etc). The function is expected to do | 28 // (temp directories, profiles, etc). The function is expected to do |
| 29 // it's work synchronously. | 29 // it's work synchronously. |
| 30 Function _cleanup; | 30 Function _cleanup; |
| 31 | 31 |
| 32 /** The version of the browser - normally set when starting a browser */ | 32 /** The version of the browser - normally set when starting a browser */ |
| 33 String version = ""; | 33 String version = ""; |
| 34 |
| 35 // The path to the browser executable. |
| 36 String _binary; |
| 37 |
| 34 /** | 38 /** |
| 35 * The underlying process - don't mess directly with this if you don't | 39 * The underlying process - don't mess directly with this if you don't |
| 36 * know what you are doing (this is an interactive process that needs | 40 * know what you are doing (this is an interactive process that needs |
| 37 * special threatment to not leak). | 41 * special threatment to not leak). |
| 38 */ | 42 */ |
| 39 Process process; | 43 Process process; |
| 40 | 44 |
| 41 Function logger; | 45 Function logger; |
| 42 | 46 |
| 43 /** | 47 /** |
| 44 * Id of the browser | 48 * Id of the browser |
| 45 */ | 49 */ |
| 46 String id; | 50 String id; |
| 47 | 51 |
| 48 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ | 52 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ |
| 49 bool debugPrint = false; | 53 bool debugPrint = false; |
| 50 | 54 |
| 51 // This future returns when the process exits. It is also the return value | 55 // This future returns when the process exits. It is also the return value |
| 52 // of close() | 56 // of close() |
| 53 Future done; | 57 Future done; |
| 54 | 58 |
| 55 Browser(); | 59 Browser(); |
| 56 | 60 |
| 57 factory Browser.byName(String name, | 61 factory Browser.byName(String name, |
| 58 [Map globalConfiguration = const {}, | 62 String executablePath, |
| 59 bool checkedMode = false]) { | 63 [bool checkedMode = false]) { |
| 60 if (name == 'ff' || name == 'firefox') { | 64 var browser; |
| 61 return new Firefox(); | 65 if (name == 'firefox') { |
| 66 browser = new Firefox(); |
| 62 } else if (name == 'chrome') { | 67 } else if (name == 'chrome') { |
| 63 return new Chrome(); | 68 browser = new Chrome(); |
| 64 } else if (name == 'dartium') { | 69 } else if (name == 'dartium') { |
| 65 return new Dartium(globalConfiguration, checkedMode); | 70 browser = new Dartium(checkedMode); |
| 66 } else if (name == 'safari') { | 71 } else if (name == 'safari') { |
| 67 return new Safari(); | 72 browser = new Safari(); |
| 68 } else if (name.startsWith('ie')) { | 73 } else if (name.startsWith('ie')) { |
| 69 return new IE(); | 74 browser = new IE(); |
| 70 } else { | 75 } else { |
| 71 throw "Non supported browser"; | 76 throw "Non supported browser"; |
| 72 } | 77 } |
| 78 browser._binary = executablePath; |
| 79 return browser; |
| 73 } | 80 } |
| 74 | 81 |
| 75 static const List<String> SUPPORTED_BROWSERS = | 82 static const List<String> SUPPORTED_BROWSERS = |
| 76 const ['safari', 'ff', 'firefox', 'chrome', 'ie9', 'ie10', 'dartium']; | 83 const ['safari', 'ff', 'firefox', 'chrome', 'ie9', 'ie10', 'dartium']; |
| 77 | 84 |
| 78 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = const []; | 85 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = const []; |
| 79 | 86 |
| 80 // TODO(kustermann): add standard support for chrome on android | 87 // TODO(kustermann): add standard support for chrome on android |
| 81 static bool supportedBrowser(String name) { | 88 static bool supportedBrowser(String name) { |
| 82 return SUPPORTED_BROWSERS.contains(name); | 89 return SUPPORTED_BROWSERS.contains(name); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 } | 194 } |
| 188 | 195 |
| 189 String toString(); | 196 String toString(); |
| 190 | 197 |
| 191 /** Starts the browser loading the given url */ | 198 /** Starts the browser loading the given url */ |
| 192 Future<bool> start(String url); | 199 Future<bool> start(String url); |
| 193 } | 200 } |
| 194 | 201 |
| 195 class Safari extends Browser { | 202 class Safari extends Browser { |
| 196 /** | 203 /** |
| 197 * The binary used to run safari - changing this can be nececcary for | |
| 198 * testing or using non standard safari installation. | |
| 199 */ | |
| 200 static const String binary = "/Applications/Safari.app/Contents/MacOS/Safari"; | |
| 201 | |
| 202 /** | |
| 203 * We get the safari version by parsing a version file | 204 * We get the safari version by parsing a version file |
| 204 */ | 205 */ |
| 205 static const String versionFile = | 206 static const String versionFile = |
| 206 "/Applications/Safari.app/Contents/version.plist"; | 207 "/Applications/Safari.app/Contents/version.plist"; |
| 207 | 208 |
| 208 /** | 209 /** |
| 209 * Directories where safari stores state. We delete these if the deleteCache | 210 * Directories where safari stores state. We delete these if the deleteCache |
| 210 * is set | 211 * is set |
| 211 */ | 212 */ |
| 212 static const List<String> CACHE_DIRECTORIES = | 213 static const List<String> CACHE_DIRECTORIES = |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 _logEvent("Could not clear cache"); | 312 _logEvent("Could not clear cache"); |
| 312 return false; | 313 return false; |
| 313 } | 314 } |
| 314 // Get the version and log that. | 315 // Get the version and log that. |
| 315 return getVersion().then((version) { | 316 return getVersion().then((version) { |
| 316 _logEvent("Got version: $version"); | 317 _logEvent("Got version: $version"); |
| 317 return new Directory('').createTemp().then((userDir) { | 318 return new Directory('').createTemp().then((userDir) { |
| 318 _cleanup = () { userDir.deleteSync(recursive: true); }; | 319 _cleanup = () { userDir.deleteSync(recursive: true); }; |
| 319 _createLaunchHTML(userDir.path, url); | 320 _createLaunchHTML(userDir.path, url); |
| 320 var args = ["${userDir.path}/launch.html"]; | 321 var args = ["${userDir.path}/launch.html"]; |
| 321 return startBrowser(binary, args); | 322 return startBrowser(_binary, args); |
| 322 }); | 323 }); |
| 323 }).catchError((error) { | 324 }).catchError((error) { |
| 324 _logEvent("Running $binary --version failed with $error"); | 325 _logEvent("Running $_binary --version failed with $error"); |
| 325 return false; | 326 return false; |
| 326 }); | 327 }); |
| 327 }); | 328 }); |
| 328 }); | 329 }); |
| 329 } | 330 } |
| 330 | 331 |
| 331 String toString() => "Safari"; | 332 String toString() => "Safari"; |
| 332 | 333 |
| 333 // Delete the user specific browser cache and profile data. | 334 // Delete the user specific browser cache and profile data. |
| 334 // Safari only have one per user, and you can't specify one by command line. | 335 // Safari only have one per user, and you can't specify one by command line. |
| 335 static bool deleteCache = false; | 336 static bool deleteCache = false; |
| 336 | 337 |
| 337 } | 338 } |
| 338 | 339 |
| 339 | 340 |
| 340 class Chrome extends Browser { | 341 class Chrome extends Browser { |
| 341 String _binary; | |
| 342 String _version = "Version not found yet"; | 342 String _version = "Version not found yet"; |
| 343 | 343 |
| 344 Chrome() { | |
| 345 _binary = _getBinary(); | |
| 346 } | |
| 347 | |
| 348 String _getBinary() { | |
| 349 if (Platform.isWindows) { | |
| 350 return "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"; | |
| 351 } else if (Platform.isMacOS) { | |
| 352 return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; | |
| 353 } | |
| 354 assert(Platform.isLinux); | |
| 355 return 'google-chrome'; | |
| 356 } | |
| 357 | |
| 358 Map<String, String> _getEnvironment() => null; | 344 Map<String, String> _getEnvironment() => null; |
| 359 | 345 |
| 360 Future<bool> _getVersion() { | 346 Future<bool> _getVersion() { |
| 361 if (Platform.isWindows) { | 347 if (Platform.isWindows) { |
| 362 // The version flag does not work on windows. | 348 // The version flag does not work on windows. |
| 363 // See issue: | 349 // See issue: |
| 364 // https://code.google.com/p/chromium/issues/detail?id=158372 | 350 // https://code.google.com/p/chromium/issues/detail?id=158372 |
| 365 // The registry hack does not seem to work. | 351 // The registry hack does not seem to work. |
| 366 _version = "Can't get version on windows"; | 352 _version = "Can't get version on windows"; |
| 367 // We still validate that the binary exists so that we can give good | 353 // We still validate that the binary exists so that we can give good |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 }).catchError((e) { | 389 }).catchError((e) { |
| 404 _logEvent("Running $_binary --version failed with $e"); | 390 _logEvent("Running $_binary --version failed with $e"); |
| 405 return false; | 391 return false; |
| 406 }); | 392 }); |
| 407 } | 393 } |
| 408 | 394 |
| 409 String toString() => "Chrome"; | 395 String toString() => "Chrome"; |
| 410 } | 396 } |
| 411 | 397 |
| 412 class Dartium extends Chrome { | 398 class Dartium extends Chrome { |
| 413 final Map globalConfiguration; | |
| 414 final bool checkedMode; | 399 final bool checkedMode; |
| 415 | 400 |
| 416 Dartium(this.globalConfiguration, this.checkedMode); | 401 Dartium(this.checkedMode); |
| 417 | |
| 418 String _getBinary() { | |
| 419 return Locations.getDartiumLocation(globalConfiguration); | |
| 420 } | |
| 421 | 402 |
| 422 Map<String, String> _getEnvironment() { | 403 Map<String, String> _getEnvironment() { |
| 423 var environment = new Map<String,String>.from(Platform.environment); | 404 var environment = new Map<String,String>.from(Platform.environment); |
| 424 // By setting this environment variable, dartium will forward "print()" | 405 // By setting this environment variable, dartium will forward "print()" |
| 425 // calls in dart to the top-level javascript function "dartPrint()" if | 406 // calls in dart to the top-level javascript function "dartPrint()" if |
| 426 // available. | 407 // available. |
| 427 environment['DART_FORWARDING_PRINT'] = '1'; | 408 environment['DART_FORWARDING_PRINT'] = '1'; |
| 428 if (checkedMode) { | 409 if (checkedMode) { |
| 429 environment['DART_FLAGS'] = '--checked'; | 410 environment['DART_FLAGS'] = '--checked'; |
| 430 } | 411 } |
| 431 return environment; | 412 return environment; |
| 432 } | 413 } |
| 433 | 414 |
| 434 String toString() => "Dartium"; | 415 String toString() => "Dartium"; |
| 435 } | 416 } |
| 436 | 417 |
| 437 class IE extends Browser { | 418 class IE extends Browser { |
| 438 | |
| 439 static const String binary = | |
| 440 "c:\\Program Files\\Internet Explorer\\iexplore.exe"; | |
| 441 | |
| 442 Future<String> getVersion() { | 419 Future<String> getVersion() { |
| 443 var args = ["query", | 420 var args = ["query", |
| 444 "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer", | 421 "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer", |
| 445 "/v", | 422 "/v", |
| 446 "version"]; | 423 "version"]; |
| 447 return Process.run("reg", args).then((result) { | 424 return Process.run("reg", args).then((result) { |
| 448 if (result.exitCode == 0) { | 425 if (result.exitCode == 0) { |
| 449 // The string we get back looks like this: | 426 // The string we get back looks like this: |
| 450 // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer | 427 // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer |
| 451 // version REG_SZ 9.0.8112.16421 | 428 // version REG_SZ 9.0.8112.16421 |
| 452 var findString = "REG_SZ"; | 429 var findString = "REG_SZ"; |
| 453 var index = result.stdout.indexOf(findString); | 430 var index = result.stdout.indexOf(findString); |
| 454 if (index > 0) { | 431 if (index > 0) { |
| 455 return result.stdout.substring(index + findString.length).trim(); | 432 return result.stdout.substring(index + findString.length).trim(); |
| 456 } | 433 } |
| 457 } | 434 } |
| 458 return "Could not get the version of internet explorer"; | 435 return "Could not get the version of internet explorer"; |
| 459 }); | 436 }); |
| 460 } | 437 } |
| 461 | 438 |
| 462 Future<bool> start(String url) { | 439 Future<bool> start(String url) { |
| 463 _logEvent("Starting ie browser on: $url"); | 440 _logEvent("Starting ie browser on: $url"); |
| 464 return getVersion().then((version) { | 441 return getVersion().then((version) { |
| 465 _logEvent("Got version: $version"); | 442 _logEvent("Got version: $version"); |
| 466 return startBrowser(binary, [url]); | 443 return startBrowser(_binary, [url]); |
| 467 }); | 444 }); |
| 468 } | 445 } |
| 469 String toString() => "IE"; | 446 String toString() => "IE"; |
| 470 } | 447 } |
| 471 | 448 |
| 472 | 449 |
| 473 class AndroidBrowserConfig { | 450 class AndroidBrowserConfig { |
| 474 final String name; | 451 final String name; |
| 475 final String package; | 452 final String package; |
| 476 final String activity; | 453 final String activity; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 | 580 |
| 604 | 581 |
| 605 class Firefox extends Browser { | 582 class Firefox extends Browser { |
| 606 static const String enablePopUp = | 583 static const String enablePopUp = |
| 607 'user_pref("dom.disable_open_during_load", false);'; | 584 'user_pref("dom.disable_open_during_load", false);'; |
| 608 static const String disableDefaultCheck = | 585 static const String disableDefaultCheck = |
| 609 'user_pref("browser.shell.checkDefaultBrowser", false);'; | 586 'user_pref("browser.shell.checkDefaultBrowser", false);'; |
| 610 static const String disableScriptTimeLimit = | 587 static const String disableScriptTimeLimit = |
| 611 'user_pref("dom.max_script_run_time", 0);'; | 588 'user_pref("dom.max_script_run_time", 0);'; |
| 612 | 589 |
| 613 static String _binary = _getBinary(); | |
| 614 | |
| 615 Future _createPreferenceFile(var path) { | 590 Future _createPreferenceFile(var path) { |
| 616 var file = new File("${path.toString()}/user.js"); | 591 var file = new File("${path.toString()}/user.js"); |
| 617 var randomFile = file.openSync(mode: FileMode.WRITE); | 592 var randomFile = file.openSync(mode: FileMode.WRITE); |
| 618 randomFile.writeStringSync(enablePopUp); | 593 randomFile.writeStringSync(enablePopUp); |
| 619 randomFile.writeStringSync(disableDefaultCheck); | 594 randomFile.writeStringSync(disableDefaultCheck); |
| 620 randomFile.writeStringSync(disableScriptTimeLimit); | 595 randomFile.writeStringSync(disableScriptTimeLimit); |
| 621 randomFile.close(); | 596 randomFile.close(); |
| 622 } | 597 } |
| 623 | 598 |
| 624 // This is extracted to a function since we may need to support several | |
| 625 // locations. | |
| 626 static String _getWindowsBinary() { | |
| 627 return "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"; | |
| 628 } | |
| 629 | |
| 630 static String _getBinary() { | |
| 631 if (Platform.isWindows) return _getWindowsBinary(); | |
| 632 if (Platform.isLinux) return 'firefox'; | |
| 633 } | |
| 634 | |
| 635 Future<bool> start(String url) { | 599 Future<bool> start(String url) { |
| 636 _logEvent("Starting firefox browser on: $url"); | 600 _logEvent("Starting firefox browser on: $url"); |
| 637 // Get the version and log that. | 601 // Get the version and log that. |
| 638 return Process.run(_binary, ["--version"]).then((var versionResult) { | 602 return Process.run(_binary, ["--version"]).then((var versionResult) { |
| 639 if (versionResult.exitCode != 0) { | 603 if (versionResult.exitCode != 0) { |
| 640 _logEvent("Failed to firefox get version"); | 604 _logEvent("Failed to firefox get version"); |
| 641 _logEvent("Make sure $_binary is a valid program for running firefox"); | 605 _logEvent("Make sure $_binary is a valid program for running firefox"); |
| 642 return new Future.value(false); | 606 return new Future.value(false); |
| 643 } | 607 } |
| 644 version = versionResult.stdout; | 608 version = versionResult.stdout; |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 } | 993 } |
| 1030 return Future.wait(futures).then((values) { | 994 return Future.wait(futures).then((values) { |
| 1031 testingServer.httpServer.close(); | 995 testingServer.httpServer.close(); |
| 1032 testingServer.errorReportingServer.close(); | 996 testingServer.errorReportingServer.close(); |
| 1033 printDoubleReportingTests(); | 997 printDoubleReportingTests(); |
| 1034 return !values.contains(false); | 998 return !values.contains(false); |
| 1035 }); | 999 }); |
| 1036 } | 1000 } |
| 1037 | 1001 |
| 1038 Browser getInstance() { | 1002 Browser getInstance() { |
| 1039 var browser = | 1003 if (browserName == 'ff') browserName = 'firefox'; |
| 1040 new Browser.byName(browserName, globalConfiguration, checkedMode); | 1004 var path = Locations.getBrowserLocation(browserName, globalConfiguration); |
| 1005 var browser = new Browser.byName(browserName, path, checkedMode); |
| 1041 browser.logger = logger; | 1006 browser.logger = logger; |
| 1042 return browser; | 1007 return browser; |
| 1043 } | 1008 } |
| 1044 } | 1009 } |
| 1045 | 1010 |
| 1046 class BrowserTestingServer { | 1011 class BrowserTestingServer { |
| 1047 final Map globalConfiguration; | 1012 final Map globalConfiguration; |
| 1048 /// Interface of the testing server: | 1013 /// Interface of the testing server: |
| 1049 /// | 1014 /// |
| 1050 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch | 1015 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1359 Dart test driver, number of tests: <div id="number"></div><br> | 1324 Dart test driver, number of tests: <div id="number"></div><br> |
| 1360 Currently executing: <div id="currently_executing"></div><br> | 1325 Currently executing: <div id="currently_executing"></div><br> |
| 1361 Unhandled error: <div id="unhandled_error"></div> | 1326 Unhandled error: <div id="unhandled_error"></div> |
| 1362 <iframe id="embedded_iframe"></iframe> | 1327 <iframe id="embedded_iframe"></iframe> |
| 1363 </body> | 1328 </body> |
| 1364 </html> | 1329 </html> |
| 1365 """; | 1330 """; |
| 1366 return driverContent; | 1331 return driverContent; |
| 1367 } | 1332 } |
| 1368 } | 1333 } |
| OLD | NEW |