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 unittest.runner.browser.chrome; | 5 library unittest.runner.browser.chrome; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:io'; | 8 import 'dart:io'; |
9 | 9 |
10 import '../../util/io.dart'; | 10 import '../../util/io.dart'; |
(...skipping 27 matching lines...) Expand all Loading... | |
38 /// A future that completes when the browser process has started. | 38 /// A future that completes when the browser process has started. |
39 /// | 39 /// |
40 /// This is used to ensure that [close] works regardless of when it's called. | 40 /// This is used to ensure that [close] works regardless of when it's called. |
41 Future get _onProcessStarted => _onProcessStartedCompleter.future; | 41 Future get _onProcessStarted => _onProcessStartedCompleter.future; |
42 final _onProcessStartedCompleter = new Completer(); | 42 final _onProcessStartedCompleter = new Completer(); |
43 | 43 |
44 /// Starts a new instance of Chrome open to the given [url], which may be a | 44 /// Starts a new instance of Chrome open to the given [url], which may be a |
45 /// [Uri] or a [String]. | 45 /// [Uri] or a [String]. |
46 /// | 46 /// |
47 /// If [executable] is passed, it's used as the Chrome executable. Otherwise | 47 /// If [executable] is passed, it's used as the Chrome executable. Otherwise |
48 /// `"google-chrome"` will be looked up on the system PATH. | 48 /// the default executable name for the current OS will be used. |
49 Chrome(url, {String executable}) { | 49 Chrome(url, {String executable}) { |
50 if (executable == null) executable = "google-chrome"; | 50 if (executable == null) executable = _defaultExecutable(); |
51 | 51 |
52 // Don't return a Future here because there's no need for the caller to wait | 52 // Don't return a Future here because there's no need for the caller to wait |
53 // for the process to actually start. They should just wait for the HTTP | 53 // for the process to actually start. They should just wait for the HTTP |
54 // request instead. | 54 // request instead. |
55 withTempDir((dir) { | 55 withTempDir((dir) { |
56 _dir = dir; | 56 _dir = dir; |
57 return Process.start(executable, [ | 57 return Process.start(executable, [ |
58 "--user-data-dir=$_dir", | 58 "--user-data-dir=$_dir", |
59 url.toString(), | 59 url.toString(), |
60 "--disable-extensions", | 60 "--disable-extensions", |
61 "--disable-popup-blocking", | 61 "--disable-popup-blocking", |
62 "--bwsi", | 62 "--bwsi", |
63 "--no-first-run" | 63 "--no-first-run", |
64 "--no-default-browser-check", | |
65 "--disable-default-apps", | |
66 "--disable-translate" | |
64 ]).then((process) { | 67 ]).then((process) { |
65 _process = process; | 68 _process = process; |
66 _onProcessStartedCompleter.complete(); | 69 _onProcessStartedCompleter.complete(); |
67 | 70 |
68 // TODO(nweiz): the browser's standard output is almost always useless | 71 // TODO(nweiz): the browser's standard output is almost always useless |
69 // noise, but we should allow the user to opt in to seeing it. | 72 // noise, but we should allow the user to opt in to seeing it. |
70 return _process.exitCode; | 73 return _process.exitCode; |
71 }); | 74 }); |
72 }).then((exitCode) { | 75 }).then((exitCode) { |
73 if (exitCode != 0) throw "Chrome failed with exit code $exitCode."; | 76 if (exitCode != 0) throw "Chrome failed with exit code $exitCode."; |
74 }).then(_onExitCompleter.complete) | 77 }).then(_onExitCompleter.complete) |
75 .catchError(_onExitCompleter.completeError); | 78 .catchError(_onExitCompleter.completeError); |
76 } | 79 } |
77 | 80 |
78 /// Kills the browser process. | 81 /// Kills the browser process. |
79 /// | 82 /// |
80 /// Returns the same [Future] as [onExit], except that it won't emit | 83 /// Returns the same [Future] as [onExit], except that it won't emit |
81 /// exceptions. | 84 /// exceptions. |
82 Future close() { | 85 Future close() { |
83 _onProcessStarted.then((_) => _process.kill()); | 86 _onProcessStarted.then((_) => _process.kill()); |
84 | 87 |
85 // Swallow exceptions. The user should explicitly use [onExit] for these. | 88 // Swallow exceptions. The user should explicitly use [onExit] for these. |
86 return onExit.catchError((_) {}); | 89 return onExit.catchError((_) {}); |
87 } | 90 } |
91 | |
92 /// Return the default executable for the current operating system. | |
93 String _defaultExecutable() { | |
94 if (Platform.isMacOS) { | |
95 return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'; | |
96 } | |
97 if (!Platform.isWindows) return 'google-chrome'; | |
98 | |
99 // Chrome could be installed in several places on Windows. The only way to | |
100 // find it is to check. | |
101 var prefixes = [ | |
102 Platform.environment['LOCALAPPDATA'], | |
103 Platform.environment['PROGRAMFILES'], | |
104 Platform.environment['PROGRAMFILES(X86)'] | |
105 ]; | |
106 var suffix = r'Google\Chrome\Application\chrome.exe'; | |
107 | |
108 for (var prefix in prefixes) { | |
109 if (prefix == null) continue; | |
110 | |
111 var path = p.join(prefix, suffix); | |
kevmoo
2015/03/05 23:10:00
spoke too soon: pkg/path is not imported here
nweiz
2015/03/06 01:38:19
Done.
| |
112 if (new File(p.join(prefix, suffix)).existsSync()) return path; | |
113 } | |
114 | |
115 // Fall back on looking it up on the path. This probably won't work, but at | |
116 // least it will fail with a useful error message. | |
117 return "chrome.exe"; | |
118 } | |
88 } | 119 } |
OLD | NEW |