Unverified Commit 47f54ace authored by Gustl22's avatar Gustl22 Committed by GitHub

feat(tools): Arbitrary browser flags (closes #65575) (#104935)

parent 08779f0d
...@@ -279,6 +279,7 @@ class DriveCommand extends RunCommandBase { ...@@ -279,6 +279,7 @@ class DriveCommand extends RunCommandBase {
packageConfig, packageConfig,
chromeBinary: stringArgDeprecated('chrome-binary'), chromeBinary: stringArgDeprecated('chrome-binary'),
headless: boolArgDeprecated('headless'), headless: boolArgDeprecated('headless'),
webBrowserFlags: stringsArg(FlutterOptions.kWebBrowserFlag),
browserDimension: stringArgDeprecated('browser-dimension')!.split(','), browserDimension: stringArgDeprecated('browser-dimension')!.split(','),
browserName: stringArgDeprecated('browser-name'), browserName: stringArgDeprecated('browser-name'),
driverPort: stringArgDeprecated('driver-port') != null driverPort: stringArgDeprecated('driver-port') != null
......
...@@ -202,9 +202,12 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -202,9 +202,12 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
@protected @protected
Future<DebuggingOptions> createDebuggingOptions(bool webMode) async { Future<DebuggingOptions> createDebuggingOptions(bool webMode) async {
final BuildInfo buildInfo = await getBuildInfo(); final BuildInfo buildInfo = await getBuildInfo();
final int? browserDebugPort = featureFlags.isWebEnabled && argResults!.wasParsed('web-browser-debug-port') final int? webBrowserDebugPort = featureFlags.isWebEnabled && argResults!.wasParsed('web-browser-debug-port')
? int.parse(stringArgDeprecated('web-browser-debug-port')!) ? int.parse(stringArgDeprecated('web-browser-debug-port')!)
: null; : null;
final List<String> webBrowserFlags = featureFlags.isWebEnabled
? stringsArg(FlutterOptions.kWebBrowserFlag)
: const <String>[];
if (buildInfo.mode.isRelease) { if (buildInfo.mode.isRelease) {
return DebuggingOptions.disabled( return DebuggingOptions.disabled(
buildInfo, buildInfo,
...@@ -216,7 +219,8 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -216,7 +219,8 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
webUseSseForInjectedClient: featureFlags.isWebEnabled && stringArgDeprecated('web-server-debug-injected-client-protocol') == 'sse', webUseSseForInjectedClient: featureFlags.isWebEnabled && stringArgDeprecated('web-server-debug-injected-client-protocol') == 'sse',
webEnableExposeUrl: featureFlags.isWebEnabled && boolArgDeprecated('web-allow-expose-url'), webEnableExposeUrl: featureFlags.isWebEnabled && boolArgDeprecated('web-allow-expose-url'),
webRunHeadless: featureFlags.isWebEnabled && boolArgDeprecated('web-run-headless'), webRunHeadless: featureFlags.isWebEnabled && boolArgDeprecated('web-run-headless'),
webBrowserDebugPort: browserDebugPort, webBrowserDebugPort: webBrowserDebugPort,
webBrowserFlags: webBrowserFlags,
enableImpeller: enableImpeller, enableImpeller: enableImpeller,
uninstallFirst: uninstallFirst, uninstallFirst: uninstallFirst,
); );
...@@ -253,7 +257,8 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -253,7 +257,8 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
webUseSseForInjectedClient: featureFlags.isWebEnabled && stringArgDeprecated('web-server-debug-injected-client-protocol') == 'sse', webUseSseForInjectedClient: featureFlags.isWebEnabled && stringArgDeprecated('web-server-debug-injected-client-protocol') == 'sse',
webEnableExposeUrl: featureFlags.isWebEnabled && boolArgDeprecated('web-allow-expose-url'), webEnableExposeUrl: featureFlags.isWebEnabled && boolArgDeprecated('web-allow-expose-url'),
webRunHeadless: featureFlags.isWebEnabled && boolArgDeprecated('web-run-headless'), webRunHeadless: featureFlags.isWebEnabled && boolArgDeprecated('web-run-headless'),
webBrowserDebugPort: browserDebugPort, webBrowserDebugPort: webBrowserDebugPort,
webBrowserFlags: webBrowserFlags,
webEnableExpressionEvaluation: featureFlags.isWebEnabled && boolArgDeprecated('web-enable-expression-evaluation'), webEnableExpressionEvaluation: featureFlags.isWebEnabled && boolArgDeprecated('web-enable-expression-evaluation'),
webLaunchUrl: featureFlags.isWebEnabled ? stringArgDeprecated('web-launch-url') : null, webLaunchUrl: featureFlags.isWebEnabled ? stringArgDeprecated('web-launch-url') : null,
vmserviceOutFile: stringArgDeprecated('vmservice-out-file'), vmserviceOutFile: stringArgDeprecated('vmservice-out-file'),
......
...@@ -785,6 +785,7 @@ class DebuggingOptions { ...@@ -785,6 +785,7 @@ class DebuggingOptions {
this.webUseSseForInjectedClient = true, this.webUseSseForInjectedClient = true,
this.webRunHeadless = false, this.webRunHeadless = false,
this.webBrowserDebugPort, this.webBrowserDebugPort,
this.webBrowserFlags = const <String>[],
this.webEnableExpressionEvaluation = false, this.webEnableExpressionEvaluation = false,
this.webLaunchUrl, this.webLaunchUrl,
this.vmserviceOutFile, this.vmserviceOutFile,
...@@ -805,6 +806,7 @@ class DebuggingOptions { ...@@ -805,6 +806,7 @@ class DebuggingOptions {
this.webUseSseForInjectedClient = true, this.webUseSseForInjectedClient = true,
this.webRunHeadless = false, this.webRunHeadless = false,
this.webBrowserDebugPort, this.webBrowserDebugPort,
this.webBrowserFlags = const <String>[],
this.webLaunchUrl, this.webLaunchUrl,
this.cacheSkSL = false, this.cacheSkSL = false,
this.traceAllowlist, this.traceAllowlist,
...@@ -871,6 +873,7 @@ class DebuggingOptions { ...@@ -871,6 +873,7 @@ class DebuggingOptions {
required this.webUseSseForInjectedClient, required this.webUseSseForInjectedClient,
required this.webRunHeadless, required this.webRunHeadless,
required this.webBrowserDebugPort, required this.webBrowserDebugPort,
required this.webBrowserFlags,
required this.webEnableExpressionEvaluation, required this.webEnableExpressionEvaluation,
required this.webLaunchUrl, required this.webLaunchUrl,
required this.vmserviceOutFile, required this.vmserviceOutFile,
...@@ -930,6 +933,9 @@ class DebuggingOptions { ...@@ -930,6 +933,9 @@ class DebuggingOptions {
/// The port the browser should use for its debugging protocol. /// The port the browser should use for its debugging protocol.
final int? webBrowserDebugPort; final int? webBrowserDebugPort;
/// Arbitrary browser flags.
final List<String> webBrowserFlags;
/// Enable expression evaluation for web target. /// Enable expression evaluation for web target.
final bool webEnableExpressionEvaluation; final bool webEnableExpressionEvaluation;
...@@ -983,6 +989,7 @@ class DebuggingOptions { ...@@ -983,6 +989,7 @@ class DebuggingOptions {
'webUseSseForInjectedClient': webUseSseForInjectedClient, 'webUseSseForInjectedClient': webUseSseForInjectedClient,
'webRunHeadless': webRunHeadless, 'webRunHeadless': webRunHeadless,
'webBrowserDebugPort': webBrowserDebugPort, 'webBrowserDebugPort': webBrowserDebugPort,
'webBrowserFlags': webBrowserFlags,
'webEnableExpressionEvaluation': webEnableExpressionEvaluation, 'webEnableExpressionEvaluation': webEnableExpressionEvaluation,
'webLaunchUrl': webLaunchUrl, 'webLaunchUrl': webLaunchUrl,
'vmserviceOutFile': vmserviceOutFile, 'vmserviceOutFile': vmserviceOutFile,
...@@ -1027,6 +1034,7 @@ class DebuggingOptions { ...@@ -1027,6 +1034,7 @@ class DebuggingOptions {
webUseSseForInjectedClient: (json['webUseSseForInjectedClient'] as bool?)!, webUseSseForInjectedClient: (json['webUseSseForInjectedClient'] as bool?)!,
webRunHeadless: (json['webRunHeadless'] as bool?)!, webRunHeadless: (json['webRunHeadless'] as bool?)!,
webBrowserDebugPort: json['webBrowserDebugPort'] as int?, webBrowserDebugPort: json['webBrowserDebugPort'] as int?,
webBrowserFlags: ((json['webBrowserFlags'] as List<dynamic>?)?.cast<String>())!,
webEnableExpressionEvaluation: (json['webEnableExpressionEvaluation'] as bool?)!, webEnableExpressionEvaluation: (json['webEnableExpressionEvaluation'] as bool?)!,
webLaunchUrl: json['webLaunchUrl'] as String?, webLaunchUrl: json['webLaunchUrl'] as String?,
vmserviceOutFile: json['vmserviceOutFile'] as String?, vmserviceOutFile: json['vmserviceOutFile'] as String?,
......
...@@ -97,6 +97,7 @@ abstract class DriverService { ...@@ -97,6 +97,7 @@ abstract class DriverService {
String? browserName, String? browserName,
bool? androidEmulator, bool? androidEmulator,
int? driverPort, int? driverPort,
List<String> webBrowserFlags,
List<String>? browserDimension, List<String>? browserDimension,
String? profileMemory, String? profileMemory,
}); });
...@@ -254,6 +255,7 @@ class FlutterDriverService extends DriverService { ...@@ -254,6 +255,7 @@ class FlutterDriverService extends DriverService {
String? browserName, String? browserName,
bool? androidEmulator, bool? androidEmulator,
int? driverPort, int? driverPort,
List<String> webBrowserFlags = const <String>[],
List<String>? browserDimension, List<String>? browserDimension,
String? profileMemory, String? profileMemory,
}) async { }) async {
......
...@@ -136,6 +136,7 @@ class WebDriverService extends DriverService { ...@@ -136,6 +136,7 @@ class WebDriverService extends DriverService {
String? browserName, String? browserName,
bool? androidEmulator, bool? androidEmulator,
int? driverPort, int? driverPort,
List<String> webBrowserFlags = const <String>[],
List<String>? browserDimension, List<String>? browserDimension,
String? profileMemory, String? profileMemory,
}) async { }) async {
...@@ -144,7 +145,12 @@ class WebDriverService extends DriverService { ...@@ -144,7 +145,12 @@ class WebDriverService extends DriverService {
try { try {
webDriver = await async_io.createDriver( webDriver = await async_io.createDriver(
uri: Uri.parse('http://localhost:$driverPort/'), uri: Uri.parse('http://localhost:$driverPort/'),
desired: getDesiredCapabilities(browser, headless, chromeBinary), desired: getDesiredCapabilities(
browser,
headless,
webBrowserFlags: webBrowserFlags,
chromeBinary: chromeBinary,
),
); );
} on SocketException catch (error) { } on SocketException catch (error) {
_logger.printTrace('$error'); _logger.printTrace('$error');
...@@ -234,10 +240,15 @@ enum Browser { ...@@ -234,10 +240,15 @@ enum Browser {
safari, safari,
} }
/// Returns desired capabilities for given [browser], [headless] and /// Returns desired capabilities for given [browser], [headless], [chromeBinary]
/// [chromeBinary]. /// and [webBrowserFlags].
@visibleForTesting @visibleForTesting
Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [String? chromeBinary]) { Map<String, dynamic> getDesiredCapabilities(
Browser browser,
bool? headless, {
List<String> webBrowserFlags = const <String>[],
String? chromeBinary,
}) {
switch (browser) { switch (browser) {
case Browser.chrome: case Browser.chrome:
return <String, dynamic>{ return <String, dynamic>{
...@@ -262,6 +273,7 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St ...@@ -262,6 +273,7 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St
'--no-sandbox', '--no-sandbox',
'--no-first-run', '--no-first-run',
if (headless!) '--headless', if (headless!) '--headless',
...webBrowserFlags,
], ],
'perfLoggingPrefs': <String, String>{ 'perfLoggingPrefs': <String, String>{
'traceCategories': 'traceCategories':
...@@ -278,6 +290,7 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St ...@@ -278,6 +290,7 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St
'moz:firefoxOptions' : <String, dynamic>{ 'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[ 'args': <String>[
if (headless!) '-headless', if (headless!) '-headless',
...webBrowserFlags,
], ],
'prefs': <String, dynamic>{ 'prefs': <String, dynamic>{
'dom.file.createInChild': true, 'dom.file.createInChild': true,
...@@ -313,7 +326,10 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St ...@@ -313,7 +326,10 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [St
'platformName': 'android', 'platformName': 'android',
'goog:chromeOptions': <String, dynamic>{ 'goog:chromeOptions': <String, dynamic>{
'androidPackage': 'com.android.chrome', 'androidPackage': 'com.android.chrome',
'args': <String>['--disable-fullscreen'], 'args': <String>[
'--disable-fullscreen',
...webBrowserFlags,
],
}, },
}; };
} }
......
...@@ -119,6 +119,7 @@ class FlutterOptions { ...@@ -119,6 +119,7 @@ class FlutterOptions {
static const String kAssumeInitializeFromDillUpToDate = 'assume-initialize-from-dill-up-to-date'; static const String kAssumeInitializeFromDillUpToDate = 'assume-initialize-from-dill-up-to-date';
static const String kFatalWarnings = 'fatal-warnings'; static const String kFatalWarnings = 'fatal-warnings';
static const String kUseApplicationBinary = 'use-application-binary'; static const String kUseApplicationBinary = 'use-application-binary';
static const String kWebBrowserFlag = 'web-browser-flag';
} }
/// flutter command categories for usage. /// flutter command categories for usage.
...@@ -270,6 +271,15 @@ abstract class FlutterCommand extends Command<void> { ...@@ -270,6 +271,15 @@ abstract class FlutterCommand extends Command<void> {
help: 'The URL to provide to the browser. Defaults to an HTTP URL with the host ' help: 'The URL to provide to the browser. Defaults to an HTTP URL with the host '
'name of "--web-hostname", the port of "--web-port", and the path set to "/".', 'name of "--web-hostname", the port of "--web-port", and the path set to "/".',
); );
argParser.addMultiOption(
FlutterOptions.kWebBrowserFlag,
help: 'Additional flag to pass to a browser instance at startup.\n'
'Chrome: https://www.chromium.org/developers/how-tos/run-chromium-with-flags/\n'
'Firefox: https://wiki.mozilla.org/Firefox/CommandLineOptions\n'
'Multiple flags can be passed by repeating "--${FlutterOptions.kWebBrowserFlag}" multiple times.',
valueHelp: '--foo=bar',
hide: !verboseHelp,
);
} }
void usesTargetOption() { void usesTargetOption() {
......
...@@ -659,6 +659,8 @@ class BrowserManager { ...@@ -659,6 +659,8 @@ class BrowserManager {
/// ///
/// The browser will start in headless mode if [headless] is true. /// The browser will start in headless mode if [headless] is true.
/// ///
/// Add arbitrary browser flags via [webBrowserFlags].
///
/// The [settings] indicate how to invoke this browser's executable. /// The [settings] indicate how to invoke this browser's executable.
/// ///
/// Returns the browser manager, or throws an [ApplicationException] if a /// Returns the browser manager, or throws an [ApplicationException] if a
...@@ -670,8 +672,13 @@ class BrowserManager { ...@@ -670,8 +672,13 @@ class BrowserManager {
Future<WebSocketChannel> future, { Future<WebSocketChannel> future, {
bool debug = false, bool debug = false,
bool headless = true, bool headless = true,
List<String> webBrowserFlags = const <String>[],
}) async { }) async {
final Chromium chrome = await chromiumLauncher.launch(url.toString(), headless: headless); final Chromium chrome = await chromiumLauncher.launch(
url.toString(),
headless: headless,
webBrowserFlags: webBrowserFlags,
);
final Completer<BrowserManager> completer = Completer<BrowserManager>(); final Completer<BrowserManager> completer = Completer<BrowserManager>();
unawaited(chrome.onExit.then((int? browserExitCode) { unawaited(chrome.onExit.then((int? browserExitCode) {
......
...@@ -164,11 +164,14 @@ class ChromiumLauncher { ...@@ -164,11 +164,14 @@ class ChromiumLauncher {
/// port is picked automatically. /// port is picked automatically.
/// ///
/// [skipCheck] does not attempt to make a devtools connection before returning. /// [skipCheck] does not attempt to make a devtools connection before returning.
///
/// [webBrowserFlags] add arbitrary browser flags.
Future<Chromium> launch(String url, { Future<Chromium> launch(String url, {
bool headless = false, bool headless = false,
int? debugPort, int? debugPort,
bool skipCheck = false, bool skipCheck = false,
Directory? cacheDir, Directory? cacheDir,
List<String> webBrowserFlags = const <String>[],
}) async { }) async {
if (currentCompleter.isCompleted) { if (currentCompleter.isCompleted) {
throwToolExit('Only one instance of chrome can be started.'); throwToolExit('Only one instance of chrome can be started.');
...@@ -215,6 +218,7 @@ class ChromiumLauncher { ...@@ -215,6 +218,7 @@ class ChromiumLauncher {
'--no-sandbox', '--no-sandbox',
'--window-size=2400,1800', '--window-size=2400,1800',
], ],
...webBrowserFlags,
url, url,
]; ];
......
...@@ -149,6 +149,7 @@ abstract class ChromiumDevice extends Device { ...@@ -149,6 +149,7 @@ abstract class ChromiumDevice extends Device {
.childDirectory('chrome-device'), .childDirectory('chrome-device'),
headless: debuggingOptions.webRunHeadless, headless: debuggingOptions.webRunHeadless,
debugPort: debuggingOptions.webBrowserDebugPort, debugPort: debuggingOptions.webBrowserDebugPort,
webBrowserFlags: debuggingOptions.webBrowserFlags,
); );
} }
_logger.sendEvent('app.webLaunchUrl', <String, Object>{'url': url, 'launched': launchChrome}); _logger.sendEvent('app.webLaunchUrl', <String, Object>{'url': url, 'launched': launchChrome});
......
...@@ -354,6 +354,7 @@ class FailingFakeDriverService extends Fake implements DriverService { ...@@ -354,6 +354,7 @@ class FailingFakeDriverService extends Fake implements DriverService {
String browserName, String browserName,
bool androidEmulator, bool androidEmulator,
int driverPort, int driverPort,
List<String> webBrowserFlags,
List<String> browserDimension, List<String> browserDimension,
String profileMemory, String profileMemory,
}) async => 1; }) async => 1;
......
...@@ -24,6 +24,18 @@ import 'package:webdriver/sync_io.dart' as sync_io; ...@@ -24,6 +24,18 @@ import 'package:webdriver/sync_io.dart' as sync_io;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
const List<String> kChromeArgs = <String>[
'--bwsi',
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
];
void main() { void main() {
testWithoutContext('getDesiredCapabilities Chrome with headless on', () { testWithoutContext('getDesiredCapabilities Chrome with headless on', () {
final Map<String, dynamic> expected = <String, dynamic>{ final Map<String, dynamic> expected = <String, dynamic>{
...@@ -36,15 +48,7 @@ void main() { ...@@ -36,15 +48,7 @@ void main() {
'chromeOptions': <String, dynamic>{ 'chromeOptions': <String, dynamic>{
'w3c': false, 'w3c': false,
'args': <String>[ 'args': <String>[
'--bwsi', ...kChromeArgs,
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
'--headless', '--headless',
], ],
'perfLoggingPrefs': <String, String>{ 'perfLoggingPrefs': <String, String>{
...@@ -71,17 +75,7 @@ void main() { ...@@ -71,17 +75,7 @@ void main() {
'chromeOptions': <String, dynamic>{ 'chromeOptions': <String, dynamic>{
'binary': chromeBinary, 'binary': chromeBinary,
'w3c': false, 'w3c': false,
'args': <String>[ 'args': kChromeArgs,
'--bwsi',
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
],
'perfLoggingPrefs': <String, String>{ 'perfLoggingPrefs': <String, String>{
'traceCategories': 'traceCategories':
'devtools.timeline,' 'devtools.timeline,'
...@@ -91,8 +85,41 @@ void main() { ...@@ -91,8 +85,41 @@ void main() {
}, },
}; };
expect(getDesiredCapabilities(Browser.chrome, false, chromeBinary), expected); expect(getDesiredCapabilities(Browser.chrome, false, chromeBinary: chromeBinary), expected);
});
testWithoutContext('getDesiredCapabilities Chrome with browser flags', () {
const List<String> webBrowserFlags = <String>[
'--autoplay-policy=no-user-gesture-required',
'--incognito',
'--auto-select-desktop-capture-source="Entire screen"',
];
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{
sync_io.LogType.browser: 'INFO',
sync_io.LogType.performance: 'ALL',
},
'chromeOptions': <String, dynamic>{
'w3c': false,
'args': <String>[
...kChromeArgs,
'--autoplay-policy=no-user-gesture-required',
'--incognito',
'--auto-select-desktop-capture-source="Entire screen"',
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing',
},
},
};
expect(getDesiredCapabilities(Browser.chrome, false, webBrowserFlags: webBrowserFlags), expected);
}); });
testWithoutContext('getDesiredCapabilities Firefox with headless on', () { testWithoutContext('getDesiredCapabilities Firefox with headless on', () {
...@@ -141,6 +168,36 @@ void main() { ...@@ -141,6 +168,36 @@ void main() {
expect(getDesiredCapabilities(Browser.firefox, false), expected); expect(getDesiredCapabilities(Browser.firefox, false), expected);
}); });
testWithoutContext('getDesiredCapabilities Firefox with browser flags', () {
const List<String> webBrowserFlags = <String>[
'-url=https://example.com',
'-private',
];
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[
'-url=https://example.com',
'-private',
],
'prefs': <String, dynamic>{
'dom.file.createInChild': true,
'dom.timeout.background_throttling_max_budget': -1,
'media.autoplay.default': 0,
'media.gmp-manager.url': '',
'media.gmp-provider.enabled': false,
'network.captive-portal-service.enabled': false,
'security.insecure_field_warning.contextual.enabled': false,
'test.currentTimeOffsetSeconds': 11491200,
},
'log': <String, String>{'level': 'trace'},
},
};
expect(getDesiredCapabilities(Browser.firefox, false, webBrowserFlags: webBrowserFlags), expected);
});
testWithoutContext('getDesiredCapabilities Edge', () { testWithoutContext('getDesiredCapabilities Edge', () {
final Map<String, dynamic> expected = <String, dynamic>{ final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true, 'acceptInsecureCerts': true,
...@@ -169,16 +226,24 @@ void main() { ...@@ -169,16 +226,24 @@ void main() {
}); });
testWithoutContext('getDesiredCapabilities android chrome', () { testWithoutContext('getDesiredCapabilities android chrome', () {
const List<String> webBrowserFlags = <String>[
'--autoplay-policy=no-user-gesture-required',
'--incognito',
];
final Map<String, dynamic> expected = <String, dynamic>{ final Map<String, dynamic> expected = <String, dynamic>{
'browserName': 'chrome', 'browserName': 'chrome',
'platformName': 'android', 'platformName': 'android',
'goog:chromeOptions': <String, dynamic>{ 'goog:chromeOptions': <String, dynamic>{
'androidPackage': 'com.android.chrome', 'androidPackage': 'com.android.chrome',
'args': <String>['--disable-fullscreen'], 'args': <String>[
'--disable-fullscreen',
'--autoplay-policy=no-user-gesture-required',
'--incognito',
],
}, },
}; };
expect(getDesiredCapabilities(Browser.androidChrome, false), expected); expect(getDesiredCapabilities(Browser.androidChrome, false, webBrowserFlags: webBrowserFlags), expected);
}); });
testUsingContext('WebDriverService starts and stops an app', () async { testUsingContext('WebDriverService starts and stops an app', () async {
......
...@@ -1307,7 +1307,14 @@ class TestChromiumLauncher implements ChromiumLauncher { ...@@ -1307,7 +1307,14 @@ class TestChromiumLauncher implements ChromiumLauncher {
bool get hasChromeInstance => _hasInstance; bool get hasChromeInstance => _hasInstance;
@override @override
Future<Chromium> launch(String url, {bool headless = false, int debugPort, bool skipCheck = false, Directory cacheDir}) async { Future<Chromium> launch(
String url, {
bool headless = false,
int debugPort,
bool skipCheck = false,
Directory cacheDir,
List<String> webBrowserFlags = const <String>[],
}) async {
return currentCompleter.future; return currentCompleter.future;
} }
......
...@@ -389,7 +389,14 @@ class TestChromiumLauncher implements ChromiumLauncher { ...@@ -389,7 +389,14 @@ class TestChromiumLauncher implements ChromiumLauncher {
bool get hasChromeInstance => _hasInstance; bool get hasChromeInstance => _hasInstance;
@override @override
Future<Chromium> launch(String url, {bool headless = false, int? debugPort, bool skipCheck = false, Directory? cacheDir}) async { Future<Chromium> launch(
String url, {
bool headless = false,
int? debugPort,
bool skipCheck = false,
Directory? cacheDir,
List<String> webBrowserFlags = const <String>[],
}) async {
return currentCompleter.future; return currentCompleter.future;
} }
......
...@@ -328,6 +328,32 @@ void main() { ...@@ -328,6 +328,32 @@ void main() {
); );
}); });
testWithoutContext('can launch chrome with arbitrary flags', () async {
processManager.addCommand(const FakeCommand(
command: <String>[
'example_chrome',
'--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0',
'--remote-debugging-port=12345',
...kChromeArgs,
'--autoplay-policy=no-user-gesture-required',
'--incognito',
'--auto-select-desktop-capture-source="Entire screen"',
'example_url',
],
stderr: kDevtoolsStderr,
));
await expectReturnsNormallyLater(chromeLauncher.launch(
'example_url',
skipCheck: true,
webBrowserFlags: <String>[
'--autoplay-policy=no-user-gesture-required',
'--incognito',
'--auto-select-desktop-capture-source="Entire screen"',
],
));
});
testWithoutContext('can launch chrome headless', () async { testWithoutContext('can launch chrome headless', () async {
processManager.addCommand(const FakeCommand( processManager.addCommand(const FakeCommand(
command: <String>[ command: <String>[
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment