Unverified Commit 2e75f52a authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] refactor drive launch into separate service, split by...

[flutter_tools] refactor drive launch into separate service, split by mobile+desktop and web (#68451)

Overhaul of flutter drive in order to deliver a better experience, namely:

flutter run and flutter drive now share more flags, so code paths that were previously only testable on run are now testable on drive.
Removes web-initialize-platform as this is no longer used
flutter drive correctly sets up a logger that shows native exceptions, by connecting to the vm service.
VM service connection now provides access to memory info without launching devtools (only for debug/profile mode)
Web changes

Passes on the one test in the repo, otherwise the webdriver code has been isolated as much as possible

Additional NNBD related bug fixes:

No longer passes --enable-experiment to the test script. (FYI @blasten ). earlier we might have assumed that the flutter gallery benchmarks would be migrated along side the app and flutter driver, but only the app under test needs to be migrated. The test scripts should never be run with the experiment.
parent 1bd661f4
......@@ -95,7 +95,10 @@ Future<void> main(List<String> args) async {
DevicesCommand(),
DoctorCommand(verbose: verbose),
DowngradeCommand(),
DriveCommand(verboseHelp: verboseHelp),
DriveCommand(verboseHelp: verboseHelp,
fileSystem: globals.fs,
logger: globals.logger,
),
EmulatorsCommand(),
FormatCommand(),
GenerateCommand(),
......
......@@ -590,13 +590,17 @@ class AndroidDevice extends Device {
}
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
_logger.printTrace('$this startApp');
ProtocolDiscovery observatoryDiscovery;
if (debuggingOptions.debuggingEnabled) {
observatoryDiscovery = ProtocolDiscovery.observatory(
await getLogReader(),
// Avoid using getLogReader, which returns a singleton instance, because the
// observatory discovery will dipose at the end. creating a new logger here allows
// logs to be surfaced normally during `flutter drive`.
await AdbLogReader.createLogReader(
this,
_processManager,
),
portForwarder: portForwarder,
hostPort: debuggingOptions.hostVmServicePort,
devicePort: debuggingOptions.deviceVmServicePort,
......@@ -669,8 +673,6 @@ class AndroidDevice extends Device {
// Wait for the service protocol port here. This will complete once the
// device has printed "Observatory is listening on...".
_logger.printTrace('Waiting for observatory port to be available...');
// TODO(danrubel): Waiting for observatory services can be made common across all devices.
try {
Uri observatoryUri;
if (debuggingOptions.buildInfo.isDebug || debuggingOptions.buildInfo.isProfile) {
......
......@@ -22,9 +22,6 @@ import 'assets.dart';
import 'common.dart';
import 'localizations.dart';
/// Whether web builds should call the platform initialization logic.
const String kInitializePlatform = 'InitializePlatform';
/// Whether the application has web plugins.
const String kHasWebPlugins = 'HasWebPlugins';
......@@ -89,7 +86,6 @@ class WebEntrypointTarget extends Target {
@override
Future<void> build(Environment environment) async {
final String targetFile = environment.defines[kTargetFile];
final bool shouldInitializePlatform = environment.defines[kInitializePlatform] == 'true';
final bool hasPlugins = environment.defines[kHasWebPlugins] == 'true';
final Uri importUri = environment.fileSystem.file(targetFile).absolute.uri;
// TODO(jonahwilliams): support configuration of this file.
......@@ -137,9 +133,7 @@ import '$mainImport' as entrypoint;
Future<void> main() async {
registerPlugins(webPluginRegistry);
if ($shouldInitializePlatform) {
await ui.webOnlyInitializePlatform();
}
await ui.webOnlyInitializePlatform();
entrypoint.main();
}
''';
......@@ -152,9 +146,7 @@ import 'dart:ui' as ui;
import '$mainImport' as entrypoint;
Future<void> main() async {
if ($shouldInitializePlatform) {
await ui.webOnlyInitializePlatform();
}
await ui.webOnlyInitializePlatform();
entrypoint.main();
}
''';
......
......@@ -384,7 +384,6 @@ known, it can be explicitly provided to attach via the command-line, e.g.
final FlutterDevice flutterDevice = await FlutterDevice.create(
device,
flutterProject: flutterProject,
fileSystemRoots: stringsArg('filesystem-root'),
fileSystemScheme: stringArg('filesystem-scheme'),
target: stringArg('target'),
......
......@@ -25,12 +25,6 @@ class BuildWebCommand extends BuildSubCommand {
usesDartDefineOption();
addEnableExperimentation(hide: !verboseHelp);
addNullSafetyModeOptions(hide: !verboseHelp);
argParser.addFlag('web-initialize-platform',
defaultsTo: true,
negatable: true,
hide: true,
help: 'Whether to automatically invoke webOnlyInitializePlatform.',
);
argParser.addFlag('csp',
defaultsTo: false,
negatable: false,
......@@ -92,7 +86,6 @@ class BuildWebCommand extends BuildSubCommand {
flutterProject,
target,
buildInfo,
boolArg('web-initialize-platform'),
boolArg('csp'),
stringArg('pwa-strategy'),
boolArg('source-maps')
......
......@@ -466,7 +466,6 @@ class AppDomain extends Domain {
final FlutterDevice flutterDevice = await FlutterDevice.create(
device,
flutterProject: flutterProject,
target: target,
buildInfo: options.buildInfo,
platform: globals.platform,
......
......@@ -847,7 +847,6 @@ class DebuggingOptions {
this.disablePortPublication = false,
this.deviceVmServicePort,
this.ddsPort,
this.initializePlatform = true,
this.hostname,
this.port,
this.webEnableExposeUrl,
......@@ -862,7 +861,6 @@ class DebuggingOptions {
}) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, {
this.initializePlatform = true,
this.port,
this.hostname,
this.webEnableExposeUrl,
......@@ -913,8 +911,6 @@ class DebuggingOptions {
final bool purgePersistentCache;
final bool useTestFonts;
final bool verboseSystemLogs;
/// Whether to invoke webOnlyInitializePlatform in Flutter for web.
final bool initializePlatform;
final int hostVmServicePort;
final int deviceVmServicePort;
final bool disablePortPublication;
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:dds/dds.dart' as dds;
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../application_package.dart';
import '../base/common.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../device.dart';
import '../vmservice.dart';
import 'web_driver_service.dart';
class FlutterDriverFactory {
FlutterDriverFactory({
@required ApplicationPackageFactory applicationPackageFactory,
@required Logger logger,
@required ProcessUtils processUtils,
@required String dartSdkPath,
}) : _applicationPackageFactory = applicationPackageFactory,
_logger = logger,
_processUtils = processUtils,
_dartSdkPath = dartSdkPath;
final ApplicationPackageFactory _applicationPackageFactory;
final Logger _logger;
final ProcessUtils _processUtils;
final String _dartSdkPath;
/// Create a driver service for running `flutter drive`.
DriverService createDriverService(bool web) {
if (web) {
return WebDriverService(
processUtils: _processUtils,
dartSdkPath: _dartSdkPath,
);
}
return FlutterDriverService(
logger: _logger,
processUtils: _processUtils,
dartSdkPath: _dartSdkPath,
applicationPackageFactory: _applicationPackageFactory,
);
}
}
/// An interface for the `flutter driver` integration test operations.
abstract class DriverService {
/// Install and launch the application for the provided [device].
Future<void> start(
BuildInfo buildInfo,
Device device,
DebuggingOptions debuggingOptions,
bool ipv6, {
File applicationBinary,
String route,
String userIdentifier,
String mainPath,
Map<String, Object> platformArgs = const <String, Object>{},
});
/// Start the test file with the provided [arguments] and [environment], returning
/// the test process exit code.
Future<int> startTest(
String testFile,
List<String> arguments,
Map<String, String> environment, {
bool headless,
String chromeBinary,
String browserName,
bool androidEmulator,
int driverPort,
List<String> browserDimension,
});
/// Stop the running application and uninstall it from the device.
///
/// If [writeSkslOnExit] is non-null, will connect to the VM Service
/// and write SkSL to the file. This is only supported on mobile and
/// desktop devices.
Future<void> stop({
File writeSkslOnExit,
String userIdentifier,
});
}
/// An implementation of the driver service that connects to mobile and desktop
/// applications.
class FlutterDriverService extends DriverService {
FlutterDriverService({
@required ApplicationPackageFactory applicationPackageFactory,
@required Logger logger,
@required ProcessUtils processUtils,
@required String dartSdkPath,
@visibleForTesting VMServiceConnector vmServiceConnector = connectToVmService,
}) : _applicationPackageFactory = applicationPackageFactory,
_logger = logger,
_processUtils = processUtils,
_dartSdkPath = dartSdkPath,
_vmServiceConnector = vmServiceConnector;
static const int _kLaunchAttempts = 3;
final ApplicationPackageFactory _applicationPackageFactory;
final Logger _logger;
final ProcessUtils _processUtils;
final String _dartSdkPath;
final VMServiceConnector _vmServiceConnector;
Device _device;
ApplicationPackage _applicationPackage;
String _vmServiceUri;
vm_service.VmService _vmService;
@override
Future<void> start(
BuildInfo buildInfo,
Device device,
DebuggingOptions debuggingOptions,
bool ipv6, {
File applicationBinary,
String route,
String userIdentifier,
Map<String, Object> platformArgs = const <String, Object>{},
String mainPath,
}) async {
if (buildInfo.isRelease) {
throwToolExit(
'Flutter Driver (non-web) does not support running in release mode.\n'
'\n'
'Use --profile mode for testing application performance.\n'
'Use --debug (default) mode for testing correctness (with assertions).'
);
}
_device = device;
final TargetPlatform targetPlatform = await device.targetPlatform;
_applicationPackage = await _applicationPackageFactory.getPackageForPlatform(
targetPlatform,
buildInfo: buildInfo,
applicationBinary: applicationBinary,
);
int attempt = 0;
LaunchResult result;
bool prebuiltApplication = applicationBinary != null;
while (attempt < _kLaunchAttempts) {
result = await device.startApp(
_applicationPackage,
mainPath: mainPath,
route: route,
debuggingOptions: debuggingOptions,
platformArgs: platformArgs,
userIdentifier: userIdentifier,
prebuiltApplication: prebuiltApplication,
);
if (result != null && result.started) {
break;
}
// On attempts past 1, assume the application is built correctly and re-use it.
attempt += 1;
prebuiltApplication = true;
_logger.printError('Application failed to start on attempt: $attempt');
}
if (result == null || !result.started) {
throwToolExit('Application failed to start. Will not run test. Quitting.', exitCode: 1);
}
_vmServiceUri = result.observatoryUri.toString();
try {
await device.dds.startDartDevelopmentService(
result.observatoryUri,
debuggingOptions.ddsPort,
ipv6,
debuggingOptions.disableServiceAuthCodes,
);
_vmServiceUri = device.dds.uri.toString();
} on dds.DartDevelopmentServiceException {
// If there's another flutter_tools instance still connected to the target
// application, DDS will already be running remotely and this call will fail.
// This can be ignored to continue to use the existing remote DDS instance.
}
_vmService = await _vmServiceConnector(Uri.parse(_vmServiceUri), device: _device);
final DeviceLogReader logReader = await device.getLogReader(app: _applicationPackage);
logReader.logLines.listen(_logger.printStatus);
final vm_service.VM vm = await _vmService.getVM();
logReader.appPid = vm.pid;
}
@override
Future<int> startTest(
String testFile,
List<String> arguments,
Map<String, String> environment, {
bool headless,
String chromeBinary,
String browserName,
bool androidEmulator,
int driverPort,
List<String> browserDimension,
}) async {
return _processUtils.stream(<String>[
_dartSdkPath,
...arguments,
testFile,
'-rexpanded',
], environment: <String, String>{
'VM_SERVICE_URL': _vmServiceUri,
...environment,
});
}
@override
Future<void> stop({
File writeSkslOnExit,
String userIdentifier,
}) async {
if (writeSkslOnExit != null) {
final FlutterView flutterView = (await _vmService.getFlutterViews()).first;
final Map<String, Object> result = await _vmService.getSkSLs(
viewId: flutterView.id
);
await sharedSkSlWriter(_device, result, outputFile: writeSkslOnExit, logger: _logger);
}
try {
if (!await _device.stopApp(_applicationPackage, userIdentifier: userIdentifier)) {
_logger.printError('Failed to stop app');
}
} on Exception catch (err) {
_logger.printError('Failed to stop app due to unhandled error: $err');
}
try {
if (!await _device.uninstallApp(_applicationPackage, userIdentifier: userIdentifier)) {
_logger.printError('Failed to uninstall app');
}
} on Exception catch (err) {
_logger.printError('Failed to uninstall app due to unhandled error: $err');
}
await _device.dispose();
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:math' as math;
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:webdriver/async_io.dart' as async_io;
import '../base/common.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../convert.dart';
import '../device.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../resident_runner.dart';
import '../web/web_runner.dart';
import 'drive_service.dart';
/// An implementation of the driver service for web debug and release applications.
class WebDriverService extends DriverService {
WebDriverService({
@required ProcessUtils processUtils,
@required String dartSdkPath,
}) : _processUtils = processUtils,
_dartSdkPath = dartSdkPath;
final ProcessUtils _processUtils;
final String _dartSdkPath;
ResidentRunner _residentRunner;
Uri _webUri;
@override
Future<void> start(
BuildInfo buildInfo,
Device device,
DebuggingOptions debuggingOptions,
bool ipv6, {
File applicationBinary,
String route,
String userIdentifier,
String mainPath,
Map<String, Object> platformArgs = const <String, Object>{},
}) async {
final FlutterDevice flutterDevice = await FlutterDevice.create(
device,
target: mainPath,
buildInfo: buildInfo,
platform: globals.platform,
);
_residentRunner = webRunnerFactory.createWebRunner(
flutterDevice,
target: mainPath,
ipv6: ipv6,
debuggingOptions: debuggingOptions,
stayResident: false,
urlTunneller: null,
flutterProject: FlutterProject.current(),
);
final Completer<void> appStartedCompleter = Completer<void>.sync();
final int result = await _residentRunner.run(
appStartedCompleter: appStartedCompleter,
route: route,
);
_webUri = _residentRunner.uri;
if (result != 0) {
throwToolExit(null);
}
}
@override
Future<int> startTest(String testFile, List<String> arguments, Map<String, String> environment, {
bool headless,
String chromeBinary,
String browserName,
bool androidEmulator,
int driverPort,
List<String> browserDimension,
}) async {
async_io.WebDriver webDriver;
final Browser browser = _browserNameToEnum(browserName);
try {
webDriver = await async_io.createDriver(
uri: Uri.parse('http://localhost:$driverPort/'),
desired: getDesiredCapabilities(browser, headless, chromeBinary),
spec: async_io.WebDriverSpec.Auto
);
} on Exception catch (ex) {
throwToolExit(
'Unable to start WebDriver Session for Flutter for Web testing. \n'
'Make sure you have the correct WebDriver Server running at $driverPort. \n'
'Make sure the WebDriver Server matches option --browser-name. \n'
'$ex'
);
}
final bool isAndroidChrome = browser == Browser.androidChrome;
// Do not set the window size for android chrome browser.
if (!isAndroidChrome) {
assert(browserDimension.length == 2);
int x;
int y;
try {
x = int.parse(browserDimension[0]);
y = int.parse(browserDimension[1]);
} on FormatException catch (ex) {
throwToolExit('Dimension provided to --browser-dimension is invalid: $ex');
}
final async_io.Window window = await webDriver.window;
await window.setLocation(const math.Point<int>(0, 0));
await window.setSize(math.Rectangle<int>(0, 0, x, y));
}
final int result = await _processUtils.stream(<String>[
_dartSdkPath,
...arguments,
testFile,
'-rexpanded',
], environment: <String, String>{
'VM_SERVICE_URL': _webUri.toString(),
..._additionalDriverEnvironment(webDriver, browserName, androidEmulator),
...environment,
});
await webDriver.quit();
return result;
}
@override
Future<void> stop({File writeSkslOnExit, String userIdentifier}) async {
await _residentRunner.cleanupAtFinish();
}
Map<String, String> _additionalDriverEnvironment(async_io.WebDriver webDriver, String browserName, bool androidEmulator) {
return <String, String>{
'DRIVER_SESSION_ID': webDriver.id,
'DRIVER_SESSION_URI': webDriver.uri.toString(),
'DRIVER_SESSION_SPEC': webDriver.spec.toString(),
'DRIVER_SESSION_CAPABILITIES': json.encode(webDriver.capabilities),
'SUPPORT_TIMELINE_ACTION': (_browserNameToEnum(browserName) == Browser.chrome).toString(),
'FLUTTER_WEB_TEST': 'true',
'ANDROID_CHROME_ON_EMULATOR': (_browserNameToEnum(browserName) == Browser.androidChrome && androidEmulator).toString(),
};
}
}
/// A list of supported browsers.
enum Browser {
/// Chrome on Android: https://developer.chrome.com/multidevice/android/overview
androidChrome,
/// Chrome: https://www.google.com/chrome/
chrome,
/// Edge: https://www.microsoft.com/en-us/windows/microsoft-edge
edge,
/// Firefox: https://www.mozilla.org/en-US/firefox/
firefox,
/// Safari in iOS: https://www.apple.com/safari/
iosSafari,
/// Safari in macOS: https://www.apple.com/safari/
safari,
}
/// Returns desired capabilities for given [browser], [headless] and
/// [chromeBinary].
@visibleForTesting
Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [String chromeBinary]) {
switch (browser) {
case Browser.chrome:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ async_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
if (chromeBinary != null)
'binary': chromeBinary,
'w3c': false,
'args': <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',
if (headless) '--headless'
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
},
};
break;
case Browser.firefox:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[
if (headless) '-headless'
],
'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'}
}
};
break;
case Browser.edge:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'edge',
};
break;
case Browser.safari:
return <String, dynamic>{
'browserName': 'safari',
};
break;
case Browser.iosSafari:
return <String, dynamic>{
'platformName': 'ios',
'browserName': 'safari',
'safari:useSimulator': true
};
case Browser.androidChrome:
return <String, dynamic>{
'browserName': 'chrome',
'platformName': 'android',
'goog:chromeOptions': <String, dynamic>{
'androidPackage': 'com.android.chrome',
'args': <String>['--disable-fullscreen']
},
};
default:
throw UnsupportedError('Browser $browser not supported.');
}
}
/// Converts [browserName] string to [Browser]
Browser _browserNameToEnum(String browserName){
switch (browserName) {
case 'android-chrome': return Browser.androidChrome;
case 'chrome': return Browser.chrome;
case 'edge': return Browser.edge;
case 'firefox': return Browser.firefox;
case 'ios-safari': return Browser.iosSafari;
case 'safari': return Browser.safari;
}
throw UnsupportedError('Browser $browserName not supported');
}
......@@ -528,7 +528,6 @@ class _ResidentWebRunner extends ResidentWebRunner {
flutterProject,
target,
debuggingOptions.buildInfo,
debuggingOptions.initializePlatform,
false,
kNoneWorker,
true,
......@@ -596,7 +595,6 @@ class _ResidentWebRunner extends ResidentWebRunner {
flutterProject,
target,
debuggingOptions.buildInfo,
debuggingOptions.initializePlatform,
false,
kNoneWorker,
true,
......
......@@ -70,7 +70,6 @@ class FlutterDevice {
/// Create a [FlutterDevice] with optional code generation enabled.
static Future<FlutterDevice> create(
Device device, {
@required FlutterProject flutterProject,
@required String target,
@required BuildInfo buildInfo,
@required Platform platform,
......
......@@ -8,6 +8,7 @@ import 'package:vm_service/vm_service.dart' as vm_service;
import 'base/context.dart';
import 'base/io.dart' as io;
import 'base/logger.dart';
import 'build_info.dart';
import 'convert.dart';
import 'device.dart';
......@@ -806,9 +807,11 @@ bool isPauseEvent(String kind) {
// or delete it.
Future<String> sharedSkSlWriter(Device device, Map<String, Object> data, {
File outputFile,
Logger logger,
}) async {
logger ??= globals.logger;
if (data.isEmpty) {
globals.logger.printStatus(
logger.printStatus(
'No data was received. To ensure SkSL data can be generated use a '
'physical device then:\n'
' 1. Pass "--cache-sksl" as an argument to flutter run.\n'
......@@ -844,7 +847,7 @@ Future<String> sharedSkSlWriter(Device device, Map<String, Object> data, {
'data': data,
};
outputFile.writeAsStringSync(json.encode(manifest));
globals.logger.printStatus('Wrote SkSL data to ${outputFile.path}.');
logger.printStatus('Wrote SkSL data to ${outputFile.path}.');
return outputFile.path;
}
......
......@@ -26,7 +26,6 @@ Future<void> buildWeb(
FlutterProject flutterProject,
String target,
BuildInfo buildInfo,
bool initializePlatform,
bool csp,
String serviceWorkerStrategy,
bool sourceMaps,
......@@ -54,7 +53,6 @@ Future<void> buildWeb(
defines: <String, String>{
kBuildMode: getNameForBuildMode(buildInfo.mode),
kTargetFile: target,
kInitializePlatform: initializePlatform.toString(),
kHasWebPlugins: hasWebPlugins.toString(),
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
kCspMode: csp.toString(),
......
......@@ -54,7 +54,6 @@ void main() {
fileSystem.path.join('lib', 'main.dart'),
BuildInfo.debug,
false,
false,
null,
true,
), throwsToolExit());
......
......@@ -77,7 +77,6 @@ void main() {
..writeAsStringSync('void main() {}');
environment.defines[kTargetFile] = mainFile.path;
environment.defines[kHasWebPlugins] = 'true';
environment.defines[kInitializePlatform] = 'true';
await const WebEntrypointTarget().build(environment);
final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();
......@@ -86,9 +85,6 @@ void main() {
expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
expect(generated, contains('registerPlugins(webPluginRegistry);'));
// Platform
expect(generated, contains('if (true) {'));
// Main
expect(generated, contains('entrypoint.main();'));
......@@ -183,7 +179,6 @@ void main() {
environment.defines[kTargetFile] = mainFile.path;
environment.defines[kHasWebPlugins] = 'true';
environment.defines[kInitializePlatform] = 'true';
await const WebEntrypointTarget().build(environment);
final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();
......@@ -192,9 +187,6 @@ void main() {
expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
expect(generated, contains('registerPlugins(webPluginRegistry);'));
// Platform
expect(generated, contains('if (true) {'));
// Main
expect(generated, contains('entrypoint.main();'));
......@@ -210,7 +202,6 @@ void main() {
..writeAsStringSync('void main() {}');
environment.defines[kTargetFile] = mainFile.path;
environment.defines[kHasWebPlugins] = 'false';
environment.defines[kInitializePlatform] = 'true';
await const WebEntrypointTarget().build(environment);
final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();
......@@ -218,32 +209,6 @@ void main() {
// Plugins
expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
expect(generated, isNot(contains('registerPlugins(webPluginRegistry);')));
// Platform
expect(generated, contains('if (true) {'));
// Main
expect(generated, contains('entrypoint.main();'));
}));
test('WebEntrypointTarget generates an entrypoint with plugins and without init platform', () => testbed.run(() async {
final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
..createSync(recursive: true)
..writeAsStringSync('void main() {}');
environment.defines[kTargetFile] = mainFile.path;
environment.defines[kHasWebPlugins] = 'true';
environment.defines[kInitializePlatform] = 'false';
await const WebEntrypointTarget().build(environment);
final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();
// Plugins
expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
expect(generated, contains('registerPlugins(webPluginRegistry);'));
// Platform
expect(generated, contains('if (false) {'));
// Main
expect(generated, contains('entrypoint.main();'));
}));
......@@ -282,7 +247,6 @@ void main() {
..writeAsStringSync('void main() {}');
environment.defines[kTargetFile] = mainFile.path;
environment.defines[kHasWebPlugins] = 'false';
environment.defines[kInitializePlatform] = 'false';
await const WebEntrypointTarget().build(environment);
final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();
......@@ -291,9 +255,6 @@ void main() {
expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
expect(generated, isNot(contains('registerPlugins(webPluginRegistry);')));
// Platform
expect(generated, contains('if (false) {'));
// Main
expect(generated, contains('entrypoint.main();'));
}));
......
......@@ -55,7 +55,7 @@ void main() {
testWithoutContext('Install and uninstall are no-ops that report success', () async {
final FakeDesktopDevice device = setUpDesktopDevice();
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
expect(await device.uninstallApp(package), true);
expect(await device.isAppInstalled(package), true);
......@@ -71,7 +71,7 @@ void main() {
group('Starting and stopping application', () {
testWithoutContext('Stop without start is a successful no-op', () async {
final FakeDesktopDevice device = setUpDesktopDevice();
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
expect(await device.stopApp(package), true);
});
......@@ -89,7 +89,7 @@ void main() {
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager, fileSystem: fileSystem);
final String executableName = device.executablePathForDevice(null, BuildMode.debug);
fileSystem.file(executableName).writeAsStringSync('\n');
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
......@@ -103,7 +103,7 @@ void main() {
testWithoutContext('Null executable path fails gracefully', () async {
final BufferLogger logger = BufferLogger.test();
final DesktopDevice device = setUpDesktopDevice(nullExecutablePathForDevice: true, logger: logger);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
......@@ -124,7 +124,7 @@ void main() {
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
......@@ -168,7 +168,7 @@ void main() {
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
......@@ -191,7 +191,6 @@ void main() {
purgePersistentCache: true,
useTestFonts: true,
verboseSystemLogs: true,
initializePlatform: true,
nullAssertions: true,
),
);
......@@ -217,7 +216,7 @@ void main() {
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final FakeApplicationPackage package = FakeApplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
......@@ -228,7 +227,6 @@ void main() {
BuildInfo.debug,
traceAllowlist: 'foo,bar',
cacheSkSL: true,
initializePlatform: true,
),
);
......@@ -325,7 +323,7 @@ class FakeDesktopDevice extends DesktopDevice {
}
}
class FakeAppplicationPackage extends Fake implements ApplicationPackage {}
class FakeApplicationPackage extends Fake implements ApplicationPackage {}
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
@override
String get name => 'Example';
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/drive/web_driver_service.dart';
import 'package:webdriver/sync_io.dart' as sync_io;
import '../../src/common.dart';
void main() {
testWithoutContext('getDesiredCapabilities Chrome with headless on', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ sync_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
'w3c': false,
'args': <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',
'--headless'
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
}
};
expect(getDesiredCapabilities(Browser.chrome, true), expected);
});
testWithoutContext('getDesiredCapabilities Chrome with headless off', () {
const String chromeBinary = 'random-binary';
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ sync_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
'binary': chromeBinary,
'w3c': false,
'args': <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',
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
}
};
expect(getDesiredCapabilities(Browser.chrome, false, chromeBinary), expected);
});
testWithoutContext('getDesiredCapabilities Firefox with headless on', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>['-headless'],
'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, true), expected);
});
testWithoutContext('getDesiredCapabilities Firefox with headless off', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[],
'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), expected);
});
testWithoutContext('getDesiredCapabilities Edge', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'edge',
};
expect(getDesiredCapabilities(Browser.edge, false), expected);
});
testWithoutContext('getDesiredCapabilities macOS Safari', () {
final Map<String, dynamic> expected = <String, dynamic>{
'browserName': 'safari',
};
expect(getDesiredCapabilities(Browser.safari, false), expected);
});
testWithoutContext('getDesiredCapabilities iOS Safari', () {
final Map<String, dynamic> expected = <String, dynamic>{
'platformName': 'ios',
'browserName': 'safari',
'safari:useSimulator': true
};
expect(getDesiredCapabilities(Browser.iosSafari, false), expected);
});
testWithoutContext('getDesiredCapabilities android chrome', () {
final Map<String, dynamic> expected = <String, dynamic>{
'browserName': 'chrome',
'platformName': 'android',
'goog:chromeOptions': <String, dynamic>{
'androidPackage': 'com.android.chrome',
'args': <String>['--disable-fullscreen']
},
};
expect(getDesiredCapabilities(Browser.androidChrome, false), expected);
});
}
......@@ -24,7 +24,6 @@ import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_cold.dart';
......@@ -2386,7 +2385,6 @@ void main() {
treeShakeIcons: false,
nullSafetyMode: NullSafetyMode.unsound,
),
flutterProject: FlutterProject.current(),
target: null,
platform: FakePlatform(operatingSystem: 'linux'),
)).generator as DefaultResidentCompiler;
......@@ -2421,7 +2419,6 @@ void main() {
treeShakeIcons: false,
extraFrontEndOptions: <String>['--enable-experiment=non-nullable'],
),
flutterProject: FlutterProject.current(),
target: null,
platform: FakePlatform(operatingSystem: 'linux'),
)).generator as DefaultResidentCompiler;
......@@ -2456,7 +2453,6 @@ void main() {
treeShakeIcons: false,
extraFrontEndOptions: <String>[],
),
flutterProject: FlutterProject.current(),
target: null, platform: null,
)).generator as DefaultResidentCompiler;
......
......@@ -4,7 +4,6 @@
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import '../src/common.dart';
import 'test_utils.dart';
......@@ -61,7 +60,7 @@ void main() {
final String outputFilePath = line.split(iosDebugMessage).last.trim();
expect(fileSystem.file(fileSystem.path.join(woringDirectory, outputFilePath)), exists);
expect(result.exitCode, 0);
}, skip: !const LocalPlatform().isMacOS); // Only supported on macOS
}, skip: true); // Extremely flaky due to https://github.com/flutter/flutter/issues/68144
testWithoutContext('--analyze-size is only supported in release mode', () async {
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
......
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