Skip to content

Commit d65bbbb

Browse files
committed
Make browser platforms customizable
See #391
1 parent 9aad31e commit d65bbbb

21 files changed

+585
-216
lines changed

lib/src/backend/platform_selector.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class PlatformSelector {
7676

7777
return _inner.evaluate((variable) {
7878
if (variable == platform.identifier) return true;
79+
if (variable == platform.parent?.identifier) return true;
7980
if (variable == os.identifier) return true;
8081
switch (variable) {
8182
case "dart-vm":

lib/src/runner/browser/browser.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ abstract class Browser {
105105
_process.then((process) => process.kill());
106106

107107
if (stackTrace == null) stackTrace = new Trace.current();
108+
if (_onExitCompleter.isCompleted) return;
108109
_onExitCompleter.completeError(
109110
new ApplicationException(
110111
"Failed to run $name: ${getErrorMessage(error)}."),

lib/src/runner/browser/browser_manager.dart

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '../../util/stack_trace_mapper.dart';
1515
import '../application_exception.dart';
1616
import '../configuration/suite.dart';
1717
import '../environment.dart';
18+
import '../executable_settings.dart';
1819
import '../plugin/platform_helpers.dart';
1920
import '../runner_suite.dart';
2021
import 'browser.dart';
@@ -93,12 +94,14 @@ class BrowserManager {
9394
/// [future]. If [debug] is true, starts the browser in debug mode, with its
9495
/// debugger interfaces on and detected.
9596
///
97+
/// The [settings] indicate how to invoke this browser's executable.
98+
///
9699
/// Returns the browser manager, or throws an [ApplicationException] if a
97100
/// connection fails to be established.
98-
static Future<BrowserManager> start(
99-
TestPlatform platform, Uri url, Future<WebSocketChannel> future,
101+
static Future<BrowserManager> start(TestPlatform platform, Uri url,
102+
Future<WebSocketChannel> future, ExecutableSettings settings,
100103
{bool debug: false}) {
101-
var browser = _newBrowser(url, platform, debug: debug);
104+
var browser = _newBrowser(url, platform, settings, debug: debug);
102105

103106
var completer = new Completer<BrowserManager>();
104107

@@ -128,26 +131,27 @@ class BrowserManager {
128131
});
129132
}
130133

131-
/// Starts the browser identified by [browser] and has it load [url].
134+
/// Starts the browser identified by [browser] using [settings] and has it load [url].
132135
///
133136
/// If [debug] is true, starts the browser in debug mode.
134-
static Browser _newBrowser(Uri url, TestPlatform browser,
137+
static Browser _newBrowser(
138+
Uri url, TestPlatform browser, ExecutableSettings settings,
135139
{bool debug: false}) {
136-
switch (browser) {
140+
switch (browser.root) {
137141
case TestPlatform.dartium:
138-
return new Dartium(url, debug: debug);
142+
return new Dartium(url, settings: settings, debug: debug);
139143
case TestPlatform.contentShell:
140-
return new ContentShell(url, debug: debug);
144+
return new ContentShell(url, settings: settings, debug: debug);
141145
case TestPlatform.chrome:
142-
return new Chrome(url, debug: debug);
146+
return new Chrome(url, settings: settings, debug: debug);
143147
case TestPlatform.phantomJS:
144-
return new PhantomJS(url, debug: debug);
148+
return new PhantomJS(url, settings: settings, debug: debug);
145149
case TestPlatform.firefox:
146-
return new Firefox(url);
150+
return new Firefox(url, settings: settings);
147151
case TestPlatform.safari:
148-
return new Safari(url);
152+
return new Safari(url, settings: settings);
149153
case TestPlatform.internetExplorer:
150-
return new InternetExplorer(url);
154+
return new InternetExplorer(url, settings: settings);
151155
default:
152156
throw new ArgumentError("$browser is not a browser.");
153157
}

lib/src/runner/browser/chrome.dart

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import 'dart:async';
66
import 'dart:io';
77

8-
import 'package:path/path.dart' as p;
9-
8+
import '../../backend/test_platform.dart';
109
import '../../util/io.dart';
10+
import '../executable_settings.dart';
1111
import 'browser.dart';
12+
import 'default_settings.dart';
1213

1314
// TODO(nweiz): move this into its own package?
1415
/// A class for running an instance of Chrome.
@@ -25,14 +26,10 @@ class Chrome extends Browser {
2526

2627
/// Starts a new instance of Chrome open to the given [url], which may be a
2728
/// [Uri] or a [String].
28-
///
29-
/// If [executable] is passed, it's used as the Chrome executable. Otherwise
30-
/// the default executable name for the current OS will be used.
31-
factory Chrome(url, {String executable, bool debug: false}) {
29+
factory Chrome(url, {ExecutableSettings settings, bool debug: false}) {
30+
settings ??= defaultSettings[TestPlatform.chrome];
3231
var remoteDebuggerCompleter = new Completer<Uri>.sync();
3332
return new Chrome._(() async {
34-
if (executable == null) executable = _defaultExecutable();
35-
3633
var tryPort = ([int port]) async {
3734
var dir = createTempDir();
3835
var args = [
@@ -45,7 +42,7 @@ class Chrome extends Browser {
4542
"--no-default-browser-check",
4643
"--disable-default-apps",
4744
"--disable-translate",
48-
];
45+
]..addAll(settings.arguments);
4946

5047
// Currently, Chrome doesn't provide any way of ensuring that this port
5148
// was successfully bound. It produces an error if the binding fails,
@@ -54,7 +51,7 @@ class Chrome extends Browser {
5451
// though.
5552
if (port != null) args.add("--remote-debugging-port=$port");
5653

57-
var process = await Process.start(executable, args);
54+
var process = await Process.start(settings.executable, args);
5855

5956
if (port != null) {
6057
remoteDebuggerCompleter.complete(
@@ -76,32 +73,4 @@ class Chrome extends Browser {
7673

7774
Chrome._(Future<Process> startBrowser(), this.remoteDebuggerUrl)
7875
: super(startBrowser);
79-
80-
/// Return the default executable for the current operating system.
81-
static String _defaultExecutable() {
82-
if (Platform.isMacOS) {
83-
return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
84-
}
85-
if (!Platform.isWindows) return 'google-chrome';
86-
87-
// Chrome could be installed in several places on Windows. The only way to
88-
// find it is to check.
89-
var prefixes = [
90-
Platform.environment['LOCALAPPDATA'],
91-
Platform.environment['PROGRAMFILES'],
92-
Platform.environment['PROGRAMFILES(X86)']
93-
];
94-
var suffix = r'Google\Chrome\Application\chrome.exe';
95-
96-
for (var prefix in prefixes) {
97-
if (prefix == null) continue;
98-
99-
var path = p.join(prefix, suffix);
100-
if (new File(p.join(prefix, suffix)).existsSync()) return path;
101-
}
102-
103-
// Fall back on looking it up on the path. This probably won't work, but at
104-
// least it will fail with a useful error message.
105-
return "chrome.exe";
106-
}
10776
}

lib/src/runner/browser/content_shell.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
import 'dart:async';
66
import 'dart:io';
77

8+
import '../../backend/test_platform.dart';
89
import '../../util/io.dart';
910
import '../../utils.dart';
1011
import '../application_exception.dart';
12+
import '../executable_settings.dart';
1113
import 'browser.dart';
14+
import 'default_settings.dart';
1215

1316
final _observatoryRegExp = new RegExp(r"^Observatory listening on ([^ ]+)");
1417
final _errorTimeout = const Duration(seconds: 10);
@@ -27,18 +30,18 @@ class ContentShell extends Browser {
2730

2831
final Future<Uri> remoteDebuggerUrl;
2932

30-
factory ContentShell(url, {String executable, bool debug: false}) {
33+
factory ContentShell(url, {ExecutableSettings settings, bool debug: false}) {
34+
settings ??= defaultSettings[TestPlatform.contentShell];
3135
var observatoryCompleter = new Completer<Uri>.sync();
3236
var remoteDebuggerCompleter = new Completer<Uri>.sync();
3337
return new ContentShell._(() {
34-
if (executable == null) executable = _defaultExecutable();
35-
3638
var tryPort = ([int port]) async {
37-
var args = ["--dump-render-tree", url.toString()];
39+
var args = ["--dump-render-tree", url.toString()]
40+
..addAll(settings.arguments);
3841
if (port != null) args.add("--remote-debugging-port=$port");
3942

40-
var process = await Process
41-
.start(executable, args, environment: {"DART_FLAGS": "--checked"});
43+
var process = await Process.start(settings.executable, args,
44+
environment: {"DART_FLAGS": "--checked"});
4245

4346
if (debug) {
4447
observatoryCompleter.complete(lineSplitter
@@ -111,8 +114,4 @@ class ContentShell extends Browser {
111114
ContentShell._(Future<Process> startBrowser(), this.observatoryUrl,
112115
this.remoteDebuggerUrl)
113116
: super(startBrowser);
114-
115-
/// Return the default executable for the current operating system.
116-
static String _defaultExecutable() =>
117-
Platform.isWindows ? "content_shell.exe" : "content_shell";
118117
}

lib/src/runner/browser/dartium.dart

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import 'dart:convert';
77
import 'dart:io';
88

99
import 'package:async/async.dart';
10-
import 'package:path/path.dart' as p;
1110

11+
import '../../backend/test_platform.dart';
1212
import '../../util/io.dart';
1313
import '../../utils.dart';
14+
import '../executable_settings.dart';
1415
import 'browser.dart';
16+
import 'default_settings.dart';
1517

1618
final _observatoryRegExp =
1719
new RegExp(r'Observatory listening (?:on|at) ([^ "]+)');
@@ -30,12 +32,11 @@ class Dartium extends Browser {
3032

3133
final Future<Uri> remoteDebuggerUrl;
3234

33-
factory Dartium(url, {String executable, bool debug: false}) {
35+
factory Dartium(url, {ExecutableSettings settings, bool debug: false}) {
36+
settings ??= defaultSettings[TestPlatform.dartium];
3437
var observatoryCompleter = new Completer<Uri>.sync();
3538
var remoteDebuggerCompleter = new Completer<Uri>.sync();
3639
return new Dartium._(() async {
37-
if (executable == null) executable = _defaultExecutable();
38-
3940
var tryPort = ([int port]) async {
4041
var dir = createTempDir();
4142
var args = [
@@ -48,7 +49,7 @@ class Dartium extends Browser {
4849
"--no-default-browser-check",
4950
"--disable-default-apps",
5051
"--disable-translate"
51-
];
52+
]..addAll(settings.arguments);
5253

5354
if (port != null) {
5455
args.add("--remote-debugging-port=$port");
@@ -62,8 +63,8 @@ class Dartium extends Browser {
6263
args.add("--vmodule=startup_browser_creator_impl=1");
6364
}
6465

65-
var process = await Process
66-
.start(executable, args, environment: {"DART_FLAGS": "--checked"});
66+
var process = await Process.start(settings.executable, args,
67+
environment: {"DART_FLAGS": "--checked"});
6768

6869
if (port != null) {
6970
// Dartium on Windows prints all standard IO to stderr, so we need to
@@ -124,47 +125,6 @@ class Dartium extends Browser {
124125
this.remoteDebuggerUrl)
125126
: super(startBrowser);
126127

127-
/// Starts a new instance of Dartium open to the given [url], which may be a
128-
/// [Uri] or a [String].
129-
///
130-
/// If [executable] is passed, it's used as the Dartium executable. Otherwise
131-
/// the default executable name for the current OS will be used.
132-
133-
/// Return the default executable for the current operating system.
134-
static String _defaultExecutable() {
135-
var dartium = _executableInEditor();
136-
if (dartium != null) return dartium;
137-
return Platform.isWindows ? "dartium.exe" : "dartium";
138-
}
139-
140-
static String _executableInEditor() {
141-
var dir = p.dirname(sdkDir);
142-
143-
if (Platform.isWindows) {
144-
if (!new File(p.join(dir, "DartEditor.exe")).existsSync()) return null;
145-
146-
var dartium = p.join(dir, "chromium\\chrome.exe");
147-
return new File(dartium).existsSync() ? dartium : null;
148-
}
149-
150-
if (Platform.isMacOS) {
151-
if (!new File(p.join(dir, "DartEditor.app/Contents/MacOS/DartEditor"))
152-
.existsSync()) {
153-
return null;
154-
}
155-
156-
var dartium =
157-
p.join(dir, "chromium/Chromium.app/Contents/MacOS/Chromium");
158-
return new File(dartium).existsSync() ? dartium : null;
159-
}
160-
161-
assert(Platform.isLinux);
162-
if (!new File(p.join(dir, "DartEditor")).existsSync()) return null;
163-
164-
var dartium = p.join(dir, "chromium", "chrome");
165-
return new File(dartium).existsSync() ? dartium : null;
166-
}
167-
168128
// TODO(nweiz): simplify this when sdk#23923 is fixed.
169129
/// Returns the Observatory URL for the Dartium executable with the given
170130
/// [stdout] stream, or `null` if the correct one couldn't be found.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
import 'dart:collection';
6+
7+
import '../../backend/test_platform.dart';
8+
import '../executable_settings.dart';
9+
10+
/// Default settings for starting browser executables.
11+
final defaultSettings = new UnmodifiableMapView({
12+
TestPlatform.chrome: new ExecutableSettings(
13+
linuxExecutable: 'google-chrome',
14+
macOSExecutable:
15+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
16+
windowsExecutable: r'Google\Chrome\Application\chrome.exe'),
17+
TestPlatform.contentShell: new ExecutableSettings(
18+
linuxExecutable: 'content_shell',
19+
macOSExecutable: 'content_shell',
20+
windowsExecutable: 'content_shell.exe'),
21+
TestPlatform.dartium: new ExecutableSettings(
22+
linuxExecutable: 'dartium',
23+
macOSExecutable: 'dartium',
24+
windowsExecutable: 'dartium.exe'),
25+
TestPlatform.firefox: new ExecutableSettings(
26+
linuxExecutable: 'firefox',
27+
macOSExecutable: '/Applications/Firefox.app/Contents/MacOS/firefox-bin',
28+
windowsExecutable: r'Mozilla Firefox\firefox.exe'),
29+
TestPlatform.internetExplorer: new ExecutableSettings(
30+
windowsExecutable: r'Internet Explorer\iexplore.exe'),
31+
TestPlatform.phantomJS: new ExecutableSettings(
32+
linuxExecutable: 'phantomjs',
33+
macOSExecutable: 'phantomjs',
34+
windowsExecutable: 'phantomjs.exe'),
35+
TestPlatform.safari: new ExecutableSettings(
36+
macOSExecutable: '/Applications/Safari.app/Contents/MacOS/Safari')
37+
});

0 commit comments

Comments
 (0)