mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] refactor Chrome launch logic to remove globals/statics (#55160)
This commit is contained in:
parent
033b07c783
commit
f2761b6b04
@ -125,6 +125,7 @@ class WebAssetServer implements AssetReader {
|
|||||||
/// Unhandled exceptions will throw a [ToolExit] with the error and stack
|
/// Unhandled exceptions will throw a [ToolExit] with the error and stack
|
||||||
/// trace.
|
/// trace.
|
||||||
static Future<WebAssetServer> start(
|
static Future<WebAssetServer> start(
|
||||||
|
ChromiumLauncher chromiumLauncher,
|
||||||
String hostname,
|
String hostname,
|
||||||
int port,
|
int port,
|
||||||
UrlTunneller urlTunneller,
|
UrlTunneller urlTunneller,
|
||||||
@ -208,8 +209,8 @@ class WebAssetServer implements AssetReader {
|
|||||||
enableDebugExtension: true,
|
enableDebugExtension: true,
|
||||||
buildResults: const Stream<BuildResult>.empty(),
|
buildResults: const Stream<BuildResult>.empty(),
|
||||||
chromeConnection: () async {
|
chromeConnection: () async {
|
||||||
final Chrome chrome = await ChromeLauncher.connectedInstance;
|
final Chromium chromium = await chromiumLauncher.connectedInstance;
|
||||||
return chrome.chromeConnection;
|
return chromium.chromeConnection;
|
||||||
},
|
},
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
urlEncoder: urlTunneller,
|
urlEncoder: urlTunneller,
|
||||||
@ -562,6 +563,7 @@ class WebDevFS implements DevFS {
|
|||||||
@required this.enableDwds,
|
@required this.enableDwds,
|
||||||
@required this.entrypoint,
|
@required this.entrypoint,
|
||||||
@required this.expressionCompiler,
|
@required this.expressionCompiler,
|
||||||
|
@required this.chromiumLauncher,
|
||||||
this.testMode = false,
|
this.testMode = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -575,6 +577,7 @@ class WebDevFS implements DevFS {
|
|||||||
final bool enableDwds;
|
final bool enableDwds;
|
||||||
final bool testMode;
|
final bool testMode;
|
||||||
final ExpressionCompiler expressionCompiler;
|
final ExpressionCompiler expressionCompiler;
|
||||||
|
final ChromiumLauncher chromiumLauncher;
|
||||||
|
|
||||||
WebAssetServer webAssetServer;
|
WebAssetServer webAssetServer;
|
||||||
|
|
||||||
@ -632,6 +635,7 @@ class WebDevFS implements DevFS {
|
|||||||
@override
|
@override
|
||||||
Future<Uri> create() async {
|
Future<Uri> create() async {
|
||||||
webAssetServer = await WebAssetServer.start(
|
webAssetServer = await WebAssetServer.start(
|
||||||
|
chromiumLauncher,
|
||||||
hostname,
|
hostname,
|
||||||
port,
|
port,
|
||||||
urlTunneller,
|
urlTunneller,
|
||||||
|
@ -114,6 +114,7 @@ abstract class ResidentWebRunner extends ResidentRunner {
|
|||||||
StreamSubscription<vmservice.Event> _stdErrSub;
|
StreamSubscription<vmservice.Event> _stdErrSub;
|
||||||
bool _exited = false;
|
bool _exited = false;
|
||||||
WipConnection _wipConnection;
|
WipConnection _wipConnection;
|
||||||
|
ChromiumLauncher _chromiumLauncher;
|
||||||
|
|
||||||
vmservice.VmService get _vmService =>
|
vmservice.VmService get _vmService =>
|
||||||
_connectionResult?.debugConnection?.vmService;
|
_connectionResult?.debugConnection?.vmService;
|
||||||
@ -158,10 +159,6 @@ abstract class ResidentWebRunner extends ResidentRunner {
|
|||||||
'Failed to clean up temp directory: ${_generatedEntrypointDirectory.path}',
|
'Failed to clean up temp directory: ${_generatedEntrypointDirectory.path}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (ChromeLauncher.hasChromeInstance) {
|
|
||||||
final Chrome chrome = await ChromeLauncher.connectedInstance;
|
|
||||||
await chrome.close();
|
|
||||||
}
|
|
||||||
_exited = true;
|
_exited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,6 +391,10 @@ class _ResidentWebRunner extends ResidentWebRunner {
|
|||||||
? await globals.os.findFreePort()
|
? await globals.os.findFreePort()
|
||||||
: int.tryParse(debuggingOptions.port);
|
: int.tryParse(debuggingOptions.port);
|
||||||
|
|
||||||
|
if (device.device is ChromiumDevice) {
|
||||||
|
_chromiumLauncher = (device.device as ChromiumDevice).chromeLauncher;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await asyncGuard(() async {
|
return await asyncGuard(() async {
|
||||||
// Ensure dwds resources are cached. If the .packages file is missing then
|
// Ensure dwds resources are cached. If the .packages file is missing then
|
||||||
@ -419,6 +420,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
|
|||||||
enableDwds: _enableDwds,
|
enableDwds: _enableDwds,
|
||||||
entrypoint: globals.fs.file(target).uri,
|
entrypoint: globals.fs.file(target).uri,
|
||||||
expressionCompiler: expressionCompiler,
|
expressionCompiler: expressionCompiler,
|
||||||
|
chromiumLauncher: _chromiumLauncher,
|
||||||
);
|
);
|
||||||
final Uri url = await device.devFS.create();
|
final Uri url = await device.devFS.create();
|
||||||
if (debuggingOptions.buildInfo.isDebug) {
|
if (debuggingOptions.buildInfo.isDebug) {
|
||||||
@ -645,8 +647,8 @@ class _ResidentWebRunner extends ResidentWebRunner {
|
|||||||
Completer<DebugConnectionInfo> connectionInfoCompleter,
|
Completer<DebugConnectionInfo> connectionInfoCompleter,
|
||||||
Completer<void> appStartedCompleter,
|
Completer<void> appStartedCompleter,
|
||||||
}) async {
|
}) async {
|
||||||
if (device.device is ChromeDevice) {
|
if (_chromiumLauncher != null) {
|
||||||
final Chrome chrome = await ChromeLauncher.connectedInstance;
|
final Chromium chrome = await _chromiumLauncher.connectedInstance;
|
||||||
final ChromeTab chromeTab = await chrome.chromeConnection.getTab((ChromeTab chromeTab) {
|
final ChromeTab chromeTab = await chrome.chromeConnection.getTab((ChromeTab chromeTab) {
|
||||||
return !chromeTab.url.startsWith('chrome-extension');
|
return !chromeTab.url.startsWith('chrome-extension');
|
||||||
});
|
});
|
||||||
|
@ -14,12 +14,10 @@ import '../runner/flutter_command.dart';
|
|||||||
class DevicesCommand extends FlutterCommand {
|
class DevicesCommand extends FlutterCommand {
|
||||||
|
|
||||||
DevicesCommand() {
|
DevicesCommand() {
|
||||||
|
|
||||||
argParser.addFlag('machine',
|
argParser.addFlag('machine',
|
||||||
negatable: false,
|
negatable: false,
|
||||||
help: 'Output device information in machine readable structured JSON format',
|
help: 'Output device information in machine readable structured JSON format',
|
||||||
);
|
);
|
||||||
|
|
||||||
argParser.addOption(
|
argParser.addOption(
|
||||||
'timeout',
|
'timeout',
|
||||||
abbr: 't',
|
abbr: 't',
|
||||||
@ -60,7 +58,9 @@ class DevicesCommand extends FlutterCommand {
|
|||||||
|
|
||||||
final List<Device> devices = await deviceManager.refreshAllConnectedDevices(timeout: timeout);
|
final List<Device> devices = await deviceManager.refreshAllConnectedDevices(timeout: timeout);
|
||||||
|
|
||||||
if (devices.isEmpty) {
|
if (boolArg('machine')) {
|
||||||
|
await printDevicesAsJson(devices);
|
||||||
|
} else if (devices.isEmpty) {
|
||||||
final StringBuffer status = StringBuffer('No devices detected.');
|
final StringBuffer status = StringBuffer('No devices detected.');
|
||||||
status.writeln();
|
status.writeln();
|
||||||
status.writeln();
|
status.writeln();
|
||||||
@ -80,8 +80,6 @@ class DevicesCommand extends FlutterCommand {
|
|||||||
globals.printStatus('• $diagnostic', hangingIndent: 2);
|
globals.printStatus('• $diagnostic', hangingIndent: 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (boolArg('machine')) {
|
|
||||||
await printDevicesAsJson(devices);
|
|
||||||
} else {
|
} else {
|
||||||
globals.printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n');
|
globals.printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n');
|
||||||
await Device.printDevices(devices);
|
await Device.printDevices(devices);
|
||||||
@ -97,5 +95,4 @@ class DevicesCommand extends FlutterCommand {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,6 @@ import 'persistent_tool_state.dart';
|
|||||||
import 'reporting/reporting.dart';
|
import 'reporting/reporting.dart';
|
||||||
import 'run_hot.dart';
|
import 'run_hot.dart';
|
||||||
import 'version.dart';
|
import 'version.dart';
|
||||||
import 'web/chrome.dart';
|
|
||||||
import 'web/workflow.dart';
|
import 'web/workflow.dart';
|
||||||
import 'windows/visual_studio.dart';
|
import 'windows/visual_studio.dart';
|
||||||
import 'windows/visual_studio_validator.dart';
|
import 'windows/visual_studio_validator.dart';
|
||||||
@ -99,13 +98,6 @@ Future<T> runInContext<T>(
|
|||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
platform: globals.platform,
|
platform: globals.platform,
|
||||||
),
|
),
|
||||||
ChromeLauncher: () => ChromeLauncher(
|
|
||||||
fileSystem: globals.fs,
|
|
||||||
processManager: globals.processManager,
|
|
||||||
logger: globals.logger,
|
|
||||||
operatingSystemUtils: globals.os,
|
|
||||||
platform: globals.platform,
|
|
||||||
),
|
|
||||||
CocoaPods: () => CocoaPods(
|
CocoaPods: () => CocoaPods(
|
||||||
fileSystem: globals.fs,
|
fileSystem: globals.fs,
|
||||||
processManager: globals.processManager,
|
processManager: globals.processManager,
|
||||||
|
@ -90,7 +90,13 @@ class DeviceManager {
|
|||||||
featureFlags: featureFlags,
|
featureFlags: featureFlags,
|
||||||
),
|
),
|
||||||
WindowsDevices(),
|
WindowsDevices(),
|
||||||
WebDevices(),
|
WebDevices(
|
||||||
|
featureFlags: featureFlags,
|
||||||
|
fileSystem: globals.fs,
|
||||||
|
logger: globals.logger,
|
||||||
|
platform: globals.platform,
|
||||||
|
processManager: globals.processManager,
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
String _specifiedDeviceId;
|
String _specifiedDeviceId;
|
||||||
|
@ -35,6 +35,7 @@ import 'reporting/reporting.dart';
|
|||||||
import 'tester/flutter_tester.dart';
|
import 'tester/flutter_tester.dart';
|
||||||
import 'version.dart';
|
import 'version.dart';
|
||||||
import 'vscode/vscode_validator.dart';
|
import 'vscode/vscode_validator.dart';
|
||||||
|
import 'web/chrome.dart';
|
||||||
import 'web/web_validator.dart';
|
import 'web/web_validator.dart';
|
||||||
import 'web/workflow.dart';
|
import 'web/workflow.dart';
|
||||||
import 'windows/visual_studio_validator.dart';
|
import 'windows/visual_studio_validator.dart';
|
||||||
@ -82,10 +83,16 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
|
|||||||
if (globals.iosWorkflow.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform)
|
if (globals.iosWorkflow.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform)
|
||||||
GroupedValidator(<DoctorValidator>[XcodeValidator(xcode: globals.xcode, userMessages: userMessages), cocoapodsValidator]),
|
GroupedValidator(<DoctorValidator>[XcodeValidator(xcode: globals.xcode, userMessages: userMessages), cocoapodsValidator]),
|
||||||
if (webWorkflow.appliesToHostPlatform)
|
if (webWorkflow.appliesToHostPlatform)
|
||||||
WebValidator(
|
ChromeValidator(
|
||||||
chromeLauncher: globals.chromeLauncher,
|
chromiumLauncher: ChromiumLauncher(
|
||||||
platform: globals.platform,
|
browserFinder: findChromeExecutable,
|
||||||
fileSystem: globals.fs,
|
fileSystem: globals.fs,
|
||||||
|
logger: globals.logger,
|
||||||
|
operatingSystemUtils: globals.os,
|
||||||
|
platform: globals.platform,
|
||||||
|
processManager: globals.processManager,
|
||||||
|
),
|
||||||
|
platform: globals.platform,
|
||||||
),
|
),
|
||||||
if (linuxWorkflow.appliesToHostPlatform)
|
if (linuxWorkflow.appliesToHostPlatform)
|
||||||
LinuxDoctorValidator(
|
LinuxDoctorValidator(
|
||||||
|
@ -34,7 +34,6 @@ import 'persistent_tool_state.dart';
|
|||||||
import 'project.dart';
|
import 'project.dart';
|
||||||
import 'reporting/reporting.dart';
|
import 'reporting/reporting.dart';
|
||||||
import 'version.dart';
|
import 'version.dart';
|
||||||
import 'web/chrome.dart';
|
|
||||||
|
|
||||||
Artifacts get artifacts => context.get<Artifacts>();
|
Artifacts get artifacts => context.get<Artifacts>();
|
||||||
BuildSystem get buildSystem => context.get<BuildSystem>();
|
BuildSystem get buildSystem => context.get<BuildSystem>();
|
||||||
@ -183,8 +182,5 @@ PlistParser get plistParser => context.get<PlistParser>() ?? (
|
|||||||
));
|
));
|
||||||
PlistParser _plistInstance;
|
PlistParser _plistInstance;
|
||||||
|
|
||||||
/// The [ChromeLauncher] instance.
|
|
||||||
ChromeLauncher get chromeLauncher => context.get<ChromeLauncher>();
|
|
||||||
|
|
||||||
/// The global template renderer
|
/// The global template renderer
|
||||||
TemplateRenderer get templateRenderer => context.get<TemplateRenderer>();
|
TemplateRenderer get templateRenderer => context.get<TemplateRenderer>();
|
||||||
|
@ -555,7 +555,7 @@ class BrowserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The browser instance that this is connected to via [_channel].
|
/// The browser instance that this is connected to via [_channel].
|
||||||
final Chrome _browser;
|
final Chromium _browser;
|
||||||
|
|
||||||
// TODO(nweiz): Consider removing the duplication between this and
|
// TODO(nweiz): Consider removing the duplication between this and
|
||||||
// [_browser.name].
|
// [_browser.name].
|
||||||
@ -623,8 +623,16 @@ class BrowserManager {
|
|||||||
bool debug = false,
|
bool debug = false,
|
||||||
bool headless = true,
|
bool headless = true,
|
||||||
}) async {
|
}) async {
|
||||||
final Chrome chrome =
|
final ChromiumLauncher chromiumLauncher = ChromiumLauncher(
|
||||||
await globals.chromeLauncher.launch(url.toString(), headless: headless);
|
browserFinder: findChromeExecutable,
|
||||||
|
fileSystem: globals.fs,
|
||||||
|
operatingSystemUtils: globals.os,
|
||||||
|
logger: globals.logger,
|
||||||
|
platform: globals.platform,
|
||||||
|
processManager: globals.processManager,
|
||||||
|
);
|
||||||
|
final Chromium chrome =
|
||||||
|
await chromiumLauncher.launch(url.toString(), headless: headless);
|
||||||
|
|
||||||
final Completer<BrowserManager> completer = Completer<BrowserManager>();
|
final Completer<BrowserManager> completer = Completer<BrowserManager>();
|
||||||
|
|
||||||
|
@ -15,11 +15,13 @@ import '../base/io.dart';
|
|||||||
import '../base/logger.dart';
|
import '../base/logger.dart';
|
||||||
import '../base/os.dart';
|
import '../base/os.dart';
|
||||||
import '../convert.dart';
|
import '../convert.dart';
|
||||||
import '../globals.dart' as globals;
|
|
||||||
|
|
||||||
/// An environment variable used to override the location of chrome.
|
/// An environment variable used to override the location of Google Chrome.
|
||||||
const String kChromeEnvironment = 'CHROME_EXECUTABLE';
|
const String kChromeEnvironment = 'CHROME_EXECUTABLE';
|
||||||
|
|
||||||
|
/// An environment variable used to override the location of Microsoft Edge.
|
||||||
|
const String kEdgeEnvironment = 'EDGE_ENVIRONMENT';
|
||||||
|
|
||||||
/// The expected executable name on linux.
|
/// The expected executable name on linux.
|
||||||
const String kLinuxExecutable = 'google-chrome';
|
const String kLinuxExecutable = 'google-chrome';
|
||||||
|
|
||||||
@ -27,9 +29,14 @@ const String kLinuxExecutable = 'google-chrome';
|
|||||||
const String kMacOSExecutable =
|
const String kMacOSExecutable =
|
||||||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
||||||
|
|
||||||
/// The expected executable name on Windows.
|
/// The expected Chrome executable name on Windows.
|
||||||
const String kWindowsExecutable = r'Google\Chrome\Application\chrome.exe';
|
const String kWindowsExecutable = r'Google\Chrome\Application\chrome.exe';
|
||||||
|
|
||||||
|
/// The expected Edge executable name on Windows.
|
||||||
|
const String kWindowsEdgeExecutable = r'Microsoft\Edge\Application\msedge.exe';
|
||||||
|
|
||||||
|
typedef BrowserFinder = String Function(Platform, FileSystem);
|
||||||
|
|
||||||
/// Find the chrome executable on the current platform.
|
/// Find the chrome executable on the current platform.
|
||||||
///
|
///
|
||||||
/// Does not verify whether the executable exists.
|
/// Does not verify whether the executable exists.
|
||||||
@ -63,43 +70,73 @@ String findChromeExecutable(Platform platform, FileSystem fileSystem) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
/// Find the Microsoft Edge executable on the current platform.
|
||||||
void resetChromeForTesting() {
|
///
|
||||||
ChromeLauncher._currentCompleter = Completer<Chrome>();
|
/// Does not verify whether the executable exists.
|
||||||
|
String findEdgeExecutable(Platform platform, FileSystem fileSystem) {
|
||||||
|
if (platform.environment.containsKey(kEdgeEnvironment)) {
|
||||||
|
return platform.environment[kEdgeEnvironment];
|
||||||
|
}
|
||||||
|
if (platform.isWindows) {
|
||||||
|
/// The possible locations where the Edge executable can be located on windows.
|
||||||
|
final List<String> kWindowsPrefixes = <String>[
|
||||||
|
platform.environment['LOCALAPPDATA'],
|
||||||
|
platform.environment['PROGRAMFILES'],
|
||||||
|
platform.environment['PROGRAMFILES(X86)'],
|
||||||
|
];
|
||||||
|
final String windowsPrefix = kWindowsPrefixes.firstWhere((String prefix) {
|
||||||
|
if (prefix == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String path = fileSystem.path.join(prefix, kWindowsEdgeExecutable);
|
||||||
|
return fileSystem.file(path).existsSync();
|
||||||
|
}, orElse: () => '.');
|
||||||
|
return fileSystem.path.join(windowsPrefix, kWindowsEdgeExecutable);
|
||||||
|
}
|
||||||
|
// Not yet supported for macOS and Linux.
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
/// A launcher for Chromium browsers with devtools configured.
|
||||||
void launchChromeInstance(Chrome chrome) {
|
class ChromiumLauncher {
|
||||||
ChromeLauncher._currentCompleter.complete(chrome);
|
ChromiumLauncher({
|
||||||
}
|
|
||||||
|
|
||||||
/// Responsible for launching chrome with devtools configured.
|
|
||||||
class ChromeLauncher {
|
|
||||||
const ChromeLauncher({
|
|
||||||
@required FileSystem fileSystem,
|
@required FileSystem fileSystem,
|
||||||
@required Platform platform,
|
@required Platform platform,
|
||||||
@required ProcessManager processManager,
|
@required ProcessManager processManager,
|
||||||
@required OperatingSystemUtils operatingSystemUtils,
|
@required OperatingSystemUtils operatingSystemUtils,
|
||||||
@required Logger logger,
|
@required Logger logger,
|
||||||
|
@required BrowserFinder browserFinder,
|
||||||
}) : _fileSystem = fileSystem,
|
}) : _fileSystem = fileSystem,
|
||||||
_platform = platform,
|
_platform = platform,
|
||||||
_processManager = processManager,
|
_processManager = processManager,
|
||||||
_operatingSystemUtils = operatingSystemUtils,
|
_operatingSystemUtils = operatingSystemUtils,
|
||||||
_logger = logger;
|
_logger = logger,
|
||||||
|
_browserFinder = browserFinder,
|
||||||
|
_fileSystemUtils = FileSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
platform: platform,
|
||||||
|
);
|
||||||
|
|
||||||
final FileSystem _fileSystem;
|
final FileSystem _fileSystem;
|
||||||
final Platform _platform;
|
final Platform _platform;
|
||||||
final ProcessManager _processManager;
|
final ProcessManager _processManager;
|
||||||
final OperatingSystemUtils _operatingSystemUtils;
|
final OperatingSystemUtils _operatingSystemUtils;
|
||||||
final Logger _logger;
|
final Logger _logger;
|
||||||
|
final BrowserFinder _browserFinder;
|
||||||
|
final FileSystemUtils _fileSystemUtils;
|
||||||
|
|
||||||
static bool get hasChromeInstance => _currentCompleter.isCompleted;
|
bool get hasChromeInstance => _currentCompleter.isCompleted;
|
||||||
|
|
||||||
static Completer<Chrome> _currentCompleter = Completer<Chrome>();
|
Completer<Chromium> _currentCompleter = Completer<Chromium>();
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
void testLaunchChromium(Chromium chromium) {
|
||||||
|
_currentCompleter.complete(chromium);
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether we can locate the chrome executable.
|
/// Whether we can locate the chrome executable.
|
||||||
bool canFindChrome() {
|
bool canFindExecutable() {
|
||||||
final String chrome = findChromeExecutable(_platform, _fileSystem);
|
final String chrome = _browserFinder(_platform, _fileSystem);
|
||||||
try {
|
try {
|
||||||
return _processManager.canRun(chrome);
|
return _processManager.canRun(chrome);
|
||||||
} on ArgumentError {
|
} on ArgumentError {
|
||||||
@ -107,7 +144,10 @@ class ChromeLauncher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launch the chrome browser to a particular `host` page.
|
/// The executable this launcher will use.
|
||||||
|
String findExecutable() => _browserFinder(_platform, _fileSystem);
|
||||||
|
|
||||||
|
/// Launch a Chromium browser to a particular `host` page.
|
||||||
///
|
///
|
||||||
/// `headless` defaults to false, and controls whether we open a headless or
|
/// `headless` defaults to false, and controls whether we open a headless or
|
||||||
/// a `headfull` browser.
|
/// a `headfull` browser.
|
||||||
@ -116,13 +156,19 @@ class ChromeLauncher {
|
|||||||
/// 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.
|
||||||
Future<Chrome> 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,
|
||||||
|
}) 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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final String chromeExecutable = findChromeExecutable(_platform, _fileSystem);
|
final String chromeExecutable = _browserFinder(_platform, _fileSystem);
|
||||||
final Directory userDataDir = _fileSystem.systemTempDirectory.createTempSync('flutter_tools_chrome_device.');
|
final Directory userDataDir = _fileSystem.systemTempDirectory
|
||||||
|
.createTempSync('flutter_tools_chrome_device.');
|
||||||
|
|
||||||
if (cacheDir != null) {
|
if (cacheDir != null) {
|
||||||
// Seed data dir with previous state.
|
// Seed data dir with previous state.
|
||||||
@ -148,7 +194,12 @@ class ChromeLauncher {
|
|||||||
'--disable-default-apps',
|
'--disable-default-apps',
|
||||||
'--disable-translate',
|
'--disable-translate',
|
||||||
if (headless)
|
if (headless)
|
||||||
...<String>['--headless', '--disable-gpu', '--no-sandbox', '--window-size=2400,1800'],
|
...<String>[
|
||||||
|
'--headless',
|
||||||
|
'--disable-gpu',
|
||||||
|
'--no-sandbox',
|
||||||
|
'--window-size=2400,1800',
|
||||||
|
],
|
||||||
url,
|
url,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -180,12 +231,13 @@ class ChromeLauncher {
|
|||||||
return 'Failed to spawn stderr';
|
return 'Failed to spawn stderr';
|
||||||
});
|
});
|
||||||
final Uri remoteDebuggerUri = await _getRemoteDebuggerUrl(Uri.parse('http://localhost:$port'));
|
final Uri remoteDebuggerUri = await _getRemoteDebuggerUrl(Uri.parse('http://localhost:$port'));
|
||||||
return _connect(Chrome._(
|
return _connect(Chromium._(
|
||||||
port,
|
port,
|
||||||
ChromeConnection('localhost', port),
|
ChromeConnection('localhost', port),
|
||||||
url: url,
|
url: url,
|
||||||
process: process,
|
process: process,
|
||||||
remoteDebuggerUri: remoteDebuggerUri,
|
remoteDebuggerUri: remoteDebuggerUri,
|
||||||
|
chromiumLauncher: this,
|
||||||
), skipCheck);
|
), skipCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +269,7 @@ class ChromeLauncher {
|
|||||||
|
|
||||||
if (sourceLocalStorageDir.existsSync()) {
|
if (sourceLocalStorageDir.existsSync()) {
|
||||||
targetLocalStorageDir.createSync(recursive: true);
|
targetLocalStorageDir.createSync(recursive: true);
|
||||||
globals.fsUtils.copyDirectorySync(sourceLocalStorageDir, targetLocalStorageDir);
|
_fileSystemUtils.copyDirectorySync(sourceLocalStorageDir, targetLocalStorageDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,11 +288,11 @@ class ChromeLauncher {
|
|||||||
|
|
||||||
if (sourceLocalStorageDir.existsSync()) {
|
if (sourceLocalStorageDir.existsSync()) {
|
||||||
targetLocalStorageDir.createSync(recursive: true);
|
targetLocalStorageDir.createSync(recursive: true);
|
||||||
globals.fsUtils.copyDirectorySync(sourceLocalStorageDir, targetLocalStorageDir);
|
_fileSystemUtils.copyDirectorySync(sourceLocalStorageDir, targetLocalStorageDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Chrome> _connect(Chrome chrome, bool skipCheck) async {
|
Future<Chromium> _connect(Chromium chrome, bool skipCheck) async {
|
||||||
// The connection is lazy. Try a simple call to make sure the provided
|
// The connection is lazy. Try a simple call to make sure the provided
|
||||||
// connection is valid.
|
// connection is valid.
|
||||||
if (!skipCheck) {
|
if (!skipCheck) {
|
||||||
@ -256,7 +308,7 @@ class ChromeLauncher {
|
|||||||
return chrome;
|
return chrome;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Chrome> get connectedInstance => _currentCompleter.future;
|
Future<Chromium> get connectedInstance => _currentCompleter.future;
|
||||||
|
|
||||||
/// Returns the full URL of the Chrome remote debugger for the main page.
|
/// Returns the full URL of the Chrome remote debugger for the main page.
|
||||||
///
|
///
|
||||||
@ -281,27 +333,30 @@ class ChromeLauncher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class for managing an instance of Chrome.
|
/// A class for managing an instance of a Chromium browser.
|
||||||
class Chrome {
|
class Chromium {
|
||||||
Chrome._(
|
Chromium._(
|
||||||
this.debugPort,
|
this.debugPort,
|
||||||
this.chromeConnection, {
|
this.chromeConnection, {
|
||||||
this.url,
|
this.url,
|
||||||
Process process,
|
Process process,
|
||||||
this.remoteDebuggerUri,
|
this.remoteDebuggerUri,
|
||||||
}) : _process = process;
|
@required ChromiumLauncher chromiumLauncher,
|
||||||
|
}) : _process = process,
|
||||||
|
_chromiumLauncher = chromiumLauncher;
|
||||||
|
|
||||||
final String url;
|
final String url;
|
||||||
final int debugPort;
|
final int debugPort;
|
||||||
final Process _process;
|
final Process _process;
|
||||||
final ChromeConnection chromeConnection;
|
final ChromeConnection chromeConnection;
|
||||||
final Uri remoteDebuggerUri;
|
final Uri remoteDebuggerUri;
|
||||||
|
final ChromiumLauncher _chromiumLauncher;
|
||||||
|
|
||||||
Future<int> get onExit => _process.exitCode;
|
Future<int> get onExit => _process.exitCode;
|
||||||
|
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
if (ChromeLauncher.hasChromeInstance) {
|
if (_chromiumLauncher.hasChromeInstance) {
|
||||||
ChromeLauncher._currentCompleter = Completer<Chrome>();
|
_chromiumLauncher._currentCompleter = Completer<Chromium>();
|
||||||
}
|
}
|
||||||
chromeConnection.close();
|
chromeConnection.close();
|
||||||
_process?.kill();
|
_process?.kill();
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:platform/platform.dart';
|
||||||
|
import 'package:process/process.dart';
|
||||||
|
|
||||||
import '../application_package.dart';
|
import '../application_package.dart';
|
||||||
import '../base/file_system.dart';
|
import '../base/file_system.dart';
|
||||||
import '../base/io.dart';
|
import '../base/io.dart';
|
||||||
|
import '../base/logger.dart';
|
||||||
|
import '../base/os.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
import '../features.dart';
|
import '../features.dart';
|
||||||
import '../globals.dart' as globals;
|
|
||||||
import '../project.dart';
|
import '../project.dart';
|
||||||
import 'chrome.dart';
|
import 'chrome.dart';
|
||||||
|
|
||||||
@ -26,16 +29,29 @@ class WebApplicationPackage extends ApplicationPackage {
|
|||||||
Directory get webSourcePath => flutterProject.directory.childDirectory('web');
|
Directory get webSourcePath => flutterProject.directory.childDirectory('web');
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChromeDevice extends Device {
|
/// A web device that supports a chromium browser.
|
||||||
ChromeDevice() : super(
|
abstract class ChromiumDevice extends Device {
|
||||||
'chrome',
|
ChromiumDevice({
|
||||||
|
@required String name,
|
||||||
|
@required this.chromeLauncher,
|
||||||
|
@required FileSystem fileSystem,
|
||||||
|
@required Logger logger,
|
||||||
|
}) : _fileSystem = fileSystem,
|
||||||
|
_logger = logger,
|
||||||
|
super(
|
||||||
|
name,
|
||||||
category: Category.web,
|
category: Category.web,
|
||||||
platformType: PlatformType.web,
|
platformType: PlatformType.web,
|
||||||
ephemeral: false,
|
ephemeral: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final ChromiumLauncher chromeLauncher;
|
||||||
|
|
||||||
|
final FileSystem _fileSystem;
|
||||||
|
final Logger _logger;
|
||||||
|
|
||||||
/// The active chrome instance.
|
/// The active chrome instance.
|
||||||
Chrome _chrome;
|
Chromium _chrome;
|
||||||
|
|
||||||
// TODO(jonahwilliams): this is technically false, but requires some refactoring
|
// TODO(jonahwilliams): this is technically false, but requires some refactoring
|
||||||
// to allow hot mode restart only devices.
|
// to allow hot mode restart only devices.
|
||||||
@ -83,47 +99,11 @@ class ChromeDevice extends Device {
|
|||||||
Future<String> get emulatorId async => null;
|
Future<String> get emulatorId async => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isSupported() => featureFlags.isWebEnabled && globals.chromeLauncher.canFindChrome();
|
bool isSupported() => chromeLauncher.canFindExecutable();
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => 'Chrome';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();
|
DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> get sdkNameAndVersion async => _sdkNameAndVersion ??= await _computeSdkNameAndVersion();
|
|
||||||
|
|
||||||
String _sdkNameAndVersion;
|
|
||||||
Future<String> _computeSdkNameAndVersion() async {
|
|
||||||
if (!isSupported()) {
|
|
||||||
return 'unknown';
|
|
||||||
}
|
|
||||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=158372
|
|
||||||
String version = 'unknown';
|
|
||||||
if (globals.platform.isWindows) {
|
|
||||||
final ProcessResult result = await globals.processManager.run(<String>[
|
|
||||||
r'reg', 'query', r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon', '/v', 'version',
|
|
||||||
]);
|
|
||||||
if (result.exitCode == 0) {
|
|
||||||
final List<String> parts = (result.stdout as String).split(RegExp(r'\s+'));
|
|
||||||
if (parts.length > 2) {
|
|
||||||
version = 'Google Chrome ' + parts[parts.length - 2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String chrome = findChromeExecutable(globals.platform, globals.fs);
|
|
||||||
final ProcessResult result = await globals.processManager.run(<String>[
|
|
||||||
chrome,
|
|
||||||
'--version',
|
|
||||||
]);
|
|
||||||
if (result.exitCode == 0) {
|
|
||||||
version = result.stdout as String;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return version.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LaunchResult> startApp(
|
Future<LaunchResult> startApp(
|
||||||
covariant WebApplicationPackage package, {
|
covariant WebApplicationPackage package, {
|
||||||
@ -139,9 +119,9 @@ class ChromeDevice extends Device {
|
|||||||
final String url = platformArgs['uri'] as String;
|
final String url = platformArgs['uri'] as String;
|
||||||
final bool launchChrome = platformArgs['no-launch-chrome'] != true;
|
final bool launchChrome = platformArgs['no-launch-chrome'] != true;
|
||||||
if (launchChrome) {
|
if (launchChrome) {
|
||||||
_chrome = await globals.chromeLauncher.launch(
|
_chrome = await chromeLauncher.launch(
|
||||||
url,
|
url,
|
||||||
cacheDir: globals.fs.currentDirectory
|
cacheDir: _fileSystem.currentDirectory
|
||||||
.childDirectory('.dart_tool')
|
.childDirectory('.dart_tool')
|
||||||
.childDirectory('chrome-device'),
|
.childDirectory('chrome-device'),
|
||||||
headless: debuggingOptions.webRunHeadless,
|
headless: debuggingOptions.webRunHeadless,
|
||||||
@ -149,7 +129,7 @@ class ChromeDevice extends Device {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
globals.logger.sendEvent('app.webLaunchUrl', <String, dynamic>{'url': url, 'launched': launchChrome});
|
_logger.sendEvent('app.webLaunchUrl', <String, dynamic>{'url': url, 'launched': launchChrome});
|
||||||
return LaunchResult.succeeded(observatoryUri: url != null ? Uri.parse(url): null);
|
return LaunchResult.succeeded(observatoryUri: url != null ? Uri.parse(url): null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,27 +157,140 @@ class ChromeDevice extends Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebDevices extends PollingDeviceDiscovery {
|
/// The Google Chrome browser based on Chromium.
|
||||||
WebDevices() : super('chrome');
|
class GoogleChromeDevice extends ChromiumDevice {
|
||||||
|
GoogleChromeDevice({
|
||||||
|
@required Platform platform,
|
||||||
|
@required ProcessManager processManager,
|
||||||
|
@required ChromiumLauncher chromiumLauncher,
|
||||||
|
@required Logger logger,
|
||||||
|
@required FileSystem fileSystem,
|
||||||
|
}) : _platform = platform,
|
||||||
|
_processManager = processManager,
|
||||||
|
super(
|
||||||
|
name: 'chrome',
|
||||||
|
chromeLauncher: chromiumLauncher,
|
||||||
|
logger: logger,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
);
|
||||||
|
|
||||||
final bool _chromeIsAvailable = globals.chromeLauncher.canFindChrome();
|
final Platform _platform;
|
||||||
final ChromeDevice _webDevice = ChromeDevice();
|
final ProcessManager _processManager;
|
||||||
final WebServerDevice _webServerDevice = WebServerDevice();
|
|
||||||
|
@override
|
||||||
|
String get name => 'Chrome';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> get sdkNameAndVersion async => _sdkNameAndVersion ??= await _computeSdkNameAndVersion();
|
||||||
|
|
||||||
|
String _sdkNameAndVersion;
|
||||||
|
Future<String> _computeSdkNameAndVersion() async {
|
||||||
|
if (!isSupported()) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=158372
|
||||||
|
String version = 'unknown';
|
||||||
|
if (_platform.isWindows) {
|
||||||
|
final ProcessResult result = await _processManager.run(<String>[
|
||||||
|
r'reg', 'query', r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon', '/v', 'version',
|
||||||
|
]);
|
||||||
|
if (result.exitCode == 0) {
|
||||||
|
final List<String> parts = (result.stdout as String).split(RegExp(r'\s+'));
|
||||||
|
if (parts.length > 2) {
|
||||||
|
version = 'Google Chrome ' + parts[parts.length - 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String chrome = chromeLauncher.findExecutable();
|
||||||
|
final ProcessResult result = await _processManager.run(<String>[
|
||||||
|
chrome,
|
||||||
|
'--version',
|
||||||
|
]);
|
||||||
|
if (result.exitCode == 0) {
|
||||||
|
version = result.stdout as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return version.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Microsoft Edge browser based on Chromium.
|
||||||
|
// This is not currently used, see https://github.com/flutter/flutter/issues/55322
|
||||||
|
class MicrosoftEdgeDevice extends ChromiumDevice {
|
||||||
|
MicrosoftEdgeDevice({
|
||||||
|
@required ChromiumLauncher chromiumLauncher,
|
||||||
|
@required Logger logger,
|
||||||
|
@required FileSystem fileSystem,
|
||||||
|
}) : super(
|
||||||
|
name: 'edge',
|
||||||
|
chromeLauncher: chromiumLauncher,
|
||||||
|
logger: logger,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => 'Edge';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> get sdkNameAndVersion async => '<?>';
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebDevices extends PollingDeviceDiscovery {
|
||||||
|
WebDevices({
|
||||||
|
@required FileSystem fileSystem,
|
||||||
|
@required Logger logger,
|
||||||
|
@required Platform platform,
|
||||||
|
@required ProcessManager processManager,
|
||||||
|
@required FeatureFlags featureFlags,
|
||||||
|
}) : _featureFlags = featureFlags,
|
||||||
|
super('Chrome') {
|
||||||
|
final OperatingSystemUtils operatingSystemUtils = OperatingSystemUtils(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
platform: platform,
|
||||||
|
logger: logger,
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
_chromeDevice = GoogleChromeDevice(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: logger,
|
||||||
|
platform: platform,
|
||||||
|
processManager: processManager,
|
||||||
|
chromiumLauncher: ChromiumLauncher(
|
||||||
|
browserFinder: findChromeExecutable,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: logger,
|
||||||
|
platform: platform,
|
||||||
|
processManager: processManager,
|
||||||
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
_webServerDevice = WebServerDevice(
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GoogleChromeDevice _chromeDevice;
|
||||||
|
WebServerDevice _webServerDevice;
|
||||||
|
final FeatureFlags _featureFlags;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get canListAnything => featureFlags.isWebEnabled;
|
bool get canListAnything => featureFlags.isWebEnabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
|
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
|
||||||
|
if (!_featureFlags.isWebEnabled) {
|
||||||
|
return <Device>[];
|
||||||
|
}
|
||||||
return <Device>[
|
return <Device>[
|
||||||
if (_chromeIsAvailable)
|
|
||||||
_webDevice,
|
|
||||||
_webServerDevice,
|
_webServerDevice,
|
||||||
|
if (_chromeDevice.isSupported())
|
||||||
|
_chromeDevice,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get supportsPlatform => featureFlags.isWebEnabled;
|
bool get supportsPlatform => _featureFlags.isWebEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
@ -208,13 +301,18 @@ String parseVersionForWindows(String input) {
|
|||||||
|
|
||||||
/// A special device type to allow serving for arbitrary browsers.
|
/// A special device type to allow serving for arbitrary browsers.
|
||||||
class WebServerDevice extends Device {
|
class WebServerDevice extends Device {
|
||||||
WebServerDevice() : super(
|
WebServerDevice({
|
||||||
|
@required Logger logger,
|
||||||
|
}) : _logger = logger,
|
||||||
|
super(
|
||||||
'web-server',
|
'web-server',
|
||||||
platformType: PlatformType.web,
|
platformType: PlatformType.web,
|
||||||
category: Category.web,
|
category: Category.web,
|
||||||
ephemeral: false,
|
ephemeral: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final Logger _logger;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void clearLogs() { }
|
void clearLogs() { }
|
||||||
|
|
||||||
@ -244,7 +342,7 @@ class WebServerDevice extends Device {
|
|||||||
Future<bool> get isLocalEmulator async => false;
|
Future<bool> get isLocalEmulator async => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isSupported() => featureFlags.isWebEnabled;
|
bool isSupported() => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isSupportedForProject(FlutterProject flutterProject) {
|
bool isSupportedForProject(FlutterProject flutterProject) {
|
||||||
@ -271,11 +369,11 @@ class WebServerDevice extends Device {
|
|||||||
}) async {
|
}) async {
|
||||||
final String url = platformArgs['uri'] as String;
|
final String url = platformArgs['uri'] as String;
|
||||||
if (debuggingOptions.startPaused) {
|
if (debuggingOptions.startPaused) {
|
||||||
globals.printStatus('Waiting for connection from Dart debug extension at $url', emphasis: true);
|
_logger.printStatus('Waiting for connection from Dart debug extension at $url', emphasis: true);
|
||||||
} else {
|
} else {
|
||||||
globals.printStatus('$mainPath is being served at $url', emphasis: true);
|
_logger.printStatus('$mainPath is being served at $url', emphasis: true);
|
||||||
}
|
}
|
||||||
globals.logger.sendEvent('app.webLaunchUrl', <String, dynamic>{'url': url, 'launched': false});
|
_logger.sendEvent('app.webLaunchUrl', <String, dynamic>{'url': url, 'launched': false});
|
||||||
return LaunchResult.succeeded(observatoryUri: url != null ? Uri.parse(url): null);
|
return LaunchResult.succeeded(observatoryUri: url != null ? Uri.parse(url): null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,47 +5,39 @@
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
import '../base/file_system.dart';
|
|
||||||
import '../doctor.dart';
|
import '../doctor.dart';
|
||||||
import 'chrome.dart';
|
import 'chrome.dart';
|
||||||
|
|
||||||
/// A validator that checks whether chrome is installed and can run.
|
/// A validator for Chromium-based brosers.
|
||||||
class WebValidator extends DoctorValidator {
|
abstract class ChromiumValidator extends DoctorValidator {
|
||||||
const WebValidator({
|
const ChromiumValidator(String title) : super(title);
|
||||||
@required Platform platform,
|
|
||||||
@required ChromeLauncher chromeLauncher,
|
|
||||||
@required FileSystem fileSystem,
|
|
||||||
}) : _platform = platform,
|
|
||||||
_chromeLauncher = chromeLauncher,
|
|
||||||
_fileSystem = fileSystem,
|
|
||||||
super('Chrome - develop for the web');
|
|
||||||
|
|
||||||
final Platform _platform;
|
Platform get _platform;
|
||||||
final ChromeLauncher _chromeLauncher;
|
ChromiumLauncher get _chromiumLauncher;
|
||||||
final FileSystem _fileSystem;
|
String get _name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ValidationResult> validate() async {
|
Future<ValidationResult> validate() async {
|
||||||
final String chrome = findChromeExecutable(_platform, _fileSystem);
|
final bool canRunChromium = _chromiumLauncher.canFindExecutable();
|
||||||
final bool canRunChrome = _chromeLauncher.canFindChrome();
|
final String chromimSearchLocation = _chromiumLauncher.findExecutable();
|
||||||
final List<ValidationMessage> messages = <ValidationMessage>[
|
final List<ValidationMessage> messages = <ValidationMessage>[
|
||||||
if (_platform.environment.containsKey(kChromeEnvironment))
|
if (_platform.environment.containsKey(kChromeEnvironment))
|
||||||
if (!canRunChrome)
|
if (!canRunChromium)
|
||||||
ValidationMessage.hint('$chrome is not executable.')
|
ValidationMessage.hint('$chromimSearchLocation is not executable.')
|
||||||
else
|
else
|
||||||
ValidationMessage('$kChromeEnvironment = $chrome')
|
ValidationMessage('$kChromeEnvironment = $chromimSearchLocation')
|
||||||
else
|
else
|
||||||
if (!canRunChrome)
|
if (!canRunChromium)
|
||||||
const ValidationMessage.hint('Cannot find Chrome. Try setting '
|
ValidationMessage.hint('Cannot find $_name. Try setting '
|
||||||
'$kChromeEnvironment to a Chrome executable.')
|
'$kChromeEnvironment to a $_name executable.')
|
||||||
else
|
else
|
||||||
ValidationMessage('Chrome at $chrome'),
|
ValidationMessage('$_name at $chromimSearchLocation'),
|
||||||
];
|
];
|
||||||
if (!canRunChrome) {
|
if (!canRunChromium) {
|
||||||
return ValidationResult(
|
return ValidationResult(
|
||||||
ValidationType.missing,
|
ValidationType.missing,
|
||||||
messages,
|
messages,
|
||||||
statusInfo: 'Cannot find chrome executable at $chrome',
|
statusInfo: 'Cannot find $_name executable at $chromimSearchLocation',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ValidationResult(
|
return ValidationResult(
|
||||||
@ -54,3 +46,42 @@ class WebValidator extends DoctorValidator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A validator that checks whether Chrome is installed and can run.
|
||||||
|
class ChromeValidator extends ChromiumValidator {
|
||||||
|
const ChromeValidator({
|
||||||
|
@required Platform platform,
|
||||||
|
@required ChromiumLauncher chromiumLauncher,
|
||||||
|
}) : _platform = platform,
|
||||||
|
_chromiumLauncher = chromiumLauncher,
|
||||||
|
super('Chrome - develop for the web');
|
||||||
|
|
||||||
|
@override
|
||||||
|
final Platform _platform;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final ChromiumLauncher _chromiumLauncher;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get _name => 'Chrome';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A validator that checks whethere Edge is installed and can run.
|
||||||
|
// This is not currently used, see https://github.com/flutter/flutter/issues/55322
|
||||||
|
class EdgeValidator extends ChromiumValidator {
|
||||||
|
const EdgeValidator({
|
||||||
|
@required Platform platform,
|
||||||
|
@required ChromiumLauncher chromiumLauncher,
|
||||||
|
}) : _platform = platform,
|
||||||
|
_chromiumLauncher = chromiumLauncher,
|
||||||
|
super('Edge - develop for the web');
|
||||||
|
|
||||||
|
@override
|
||||||
|
final Platform _platform;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final ChromiumLauncher _chromiumLauncher;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get _name => 'Edge';
|
||||||
|
}
|
||||||
|
@ -4,54 +4,55 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:file/file.dart';
|
|
||||||
import 'package:args/command_runner.dart';
|
import 'package:args/command_runner.dart';
|
||||||
|
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/device.dart';
|
|
||||||
import 'package:flutter_tools/src/web/chrome.dart';
|
|
||||||
import 'package:flutter_tools/src/commands/devices.dart';
|
import 'package:flutter_tools/src/commands/devices.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/config.dart';
|
import 'package:flutter_tools/src/device.dart';
|
||||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
import 'package:flutter_tools/src/features.dart';
|
||||||
import 'package:flutter_tools/src/base/context.dart';
|
import 'package:flutter_tools/src/base/context.dart';
|
||||||
|
import 'package:flutter_tools/src/web/web_device.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
import '../../src/testbed.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('devices', () {
|
|
||||||
Directory configDir;
|
|
||||||
Config config;
|
|
||||||
|
|
||||||
tearDown(() {
|
|
||||||
if (configDir != null) {
|
|
||||||
tryToDelete(configDir);
|
|
||||||
configDir = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
Cache.disableLocking();
|
Cache.disableLocking();
|
||||||
configDir ??= globals.fs.systemTempDirectory.createTempSync(
|
|
||||||
'flutter_config_dir_test.',
|
|
||||||
);
|
|
||||||
config = Config.test(
|
|
||||||
Config.kFlutterSettings,
|
|
||||||
directory: configDir,
|
|
||||||
logger: globals.logger,
|
|
||||||
)..setValue('enable-web', true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test assumes no devices connected.
|
testUsingContext('devices can display no connected devices with the --machine flag', () async {
|
||||||
// Should return only `web-server` device
|
|
||||||
testUsingContext('Test the --machine flag', () async {
|
|
||||||
final BufferLogger logger = context.get<Logger>() as BufferLogger;
|
final BufferLogger logger = context.get<Logger>() as BufferLogger;
|
||||||
final DevicesCommand command = DevicesCommand();
|
final DevicesCommand command = DevicesCommand();
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
await runner.run(<String>['devices', '--machine']);
|
await runner.run(<String>['devices', '--machine']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
json.decode(logger.statusText),
|
json.decode(logger.statusText),
|
||||||
<Map<String,Object>>[
|
isEmpty,
|
||||||
|
);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('devices can display via the --machine flag', () async {
|
||||||
|
when(deviceManager.refreshAllConnectedDevices()).thenAnswer((Invocation invocation) async {
|
||||||
|
return <Device>[
|
||||||
|
WebServerDevice(logger: BufferLogger.test()),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
final BufferLogger logger = context.get<Logger>() as BufferLogger;
|
||||||
|
final DevicesCommand command = DevicesCommand();
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
await runner.run(<String>['devices', '--machine']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
json.decode(logger.statusText),
|
||||||
|
contains(equals(
|
||||||
<String, Object>{
|
<String, Object>{
|
||||||
'name': 'Web Server',
|
'name': 'Web Server',
|
||||||
'id': 'web-server',
|
'id': 'web-server',
|
||||||
@ -69,27 +70,14 @@ void main() {
|
|||||||
'startPaused': true
|
'startPaused': true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
)),
|
||||||
);
|
);
|
||||||
},
|
}, overrides: <Type, Generator>{
|
||||||
overrides: <Type, Generator>{
|
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
|
||||||
DeviceManager: () => DeviceManager(),
|
DeviceManager: () => MockDeviceManager(),
|
||||||
Config: () => config,
|
|
||||||
ChromeLauncher: () => _DisabledChromeLauncher(),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Without ChromeLauncher DeviceManager constructor fails with noSuchMethodError
|
class MockDeviceManager extends Mock implements DeviceManager {
|
||||||
// trying to call canFindChrome on null
|
|
||||||
// Also, Chrome may have different versions on different machines and
|
|
||||||
// JSON will not match, because the `sdk` field of the Device contains version number
|
|
||||||
// Mock the launcher to make it appear that we don't have Chrome.
|
|
||||||
class _DisabledChromeLauncher implements ChromeLauncher {
|
|
||||||
@override
|
|
||||||
bool canFindChrome() => false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Chrome> launch(String url, {bool headless = false, int debugPort, bool skipCheck = false, Directory cacheDir})
|
|
||||||
=> Future<Chrome>.error('Chrome disabled');
|
|
||||||
}
|
}
|
@ -44,7 +44,7 @@ void main() {
|
|||||||
|
|
||||||
test('doctor validators includes web when feature is enabled', () => testbed.run(() {
|
test('doctor validators includes web when feature is enabled', () => testbed.run(() {
|
||||||
expect(DoctorValidatorsProvider.defaultInstance.validators,
|
expect(DoctorValidatorsProvider.defaultInstance.validators,
|
||||||
contains(isA<WebValidator>()));
|
contains(isA<ChromiumValidator>()));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(
|
FeatureFlags: () => TestFeatureFlags(
|
||||||
isWebEnabled: true,
|
isWebEnabled: true,
|
||||||
@ -53,7 +53,7 @@ void main() {
|
|||||||
|
|
||||||
test('doctor validators does not include web when feature is disabled', () => testbed.run(() {
|
test('doctor validators does not include web when feature is disabled', () => testbed.run(() {
|
||||||
expect(DoctorValidatorsProvider.defaultInstance.validators,
|
expect(DoctorValidatorsProvider.defaultInstance.validators,
|
||||||
isNot(contains(isA<WebValidator>())));
|
isNot(contains(isA<ChromiumValidator>())));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FeatureFlags: () => TestFeatureFlags(
|
FeatureFlags: () => TestFeatureFlags(
|
||||||
isWebEnabled: false,
|
isWebEnabled: false,
|
||||||
|
@ -131,14 +131,18 @@ void main() {
|
|||||||
final MockChromeConnection mockChromeConnection = MockChromeConnection();
|
final MockChromeConnection mockChromeConnection = MockChromeConnection();
|
||||||
final MockChromeTab mockChromeTab = MockChromeTab();
|
final MockChromeTab mockChromeTab = MockChromeTab();
|
||||||
final MockWipConnection mockWipConnection = MockWipConnection();
|
final MockWipConnection mockWipConnection = MockWipConnection();
|
||||||
|
final MockChromiumLauncher chromiumLauncher = MockChromiumLauncher();
|
||||||
when(mockChromeConnection.getTab(any)).thenAnswer((Invocation invocation) async {
|
when(mockChromeConnection.getTab(any)).thenAnswer((Invocation invocation) async {
|
||||||
return mockChromeTab;
|
return mockChromeTab;
|
||||||
});
|
});
|
||||||
when(mockChromeTab.connect()).thenAnswer((Invocation invocation) async {
|
when(mockChromeTab.connect()).thenAnswer((Invocation invocation) async {
|
||||||
return mockWipConnection;
|
return mockWipConnection;
|
||||||
});
|
});
|
||||||
|
when(chromiumLauncher.connectedInstance).thenAnswer((Invocation invocation) async {
|
||||||
|
return chrome;
|
||||||
|
});
|
||||||
when(chrome.chromeConnection).thenReturn(mockChromeConnection);
|
when(chrome.chromeConnection).thenReturn(mockChromeConnection);
|
||||||
launchChromeInstance(chrome);
|
when(chromeDevice.chromeLauncher).thenReturn(chromiumLauncher);
|
||||||
when(mockFlutterDevice.device).thenReturn(chromeDevice);
|
when(mockFlutterDevice.device).thenReturn(chromeDevice);
|
||||||
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
||||||
unawaited(residentWebRunner.run(
|
unawaited(residentWebRunner.run(
|
||||||
@ -163,10 +167,11 @@ class MockDebugConnection extends Mock implements DebugConnection {}
|
|||||||
class MockVmService extends Mock implements VmService {}
|
class MockVmService extends Mock implements VmService {}
|
||||||
class MockStatus extends Mock implements Status {}
|
class MockStatus extends Mock implements Status {}
|
||||||
class MockFlutterDevice extends Mock implements FlutterDevice {}
|
class MockFlutterDevice extends Mock implements FlutterDevice {}
|
||||||
class MockChromeDevice extends Mock implements ChromeDevice {}
|
class MockChromeDevice extends Mock implements ChromiumDevice {}
|
||||||
class MockChrome extends Mock implements Chrome {}
|
class MockChrome extends Mock implements Chromium {}
|
||||||
class MockChromeConnection extends Mock implements ChromeConnection {}
|
class MockChromeConnection extends Mock implements ChromeConnection {}
|
||||||
class MockChromeTab extends Mock implements ChromeTab {}
|
class MockChromeTab extends Mock implements ChromeTab {}
|
||||||
class MockWipConnection extends Mock implements WipConnection {}
|
class MockWipConnection extends Mock implements WipConnection {}
|
||||||
class MockBuildSystem extends Mock implements BuildSystem {}
|
class MockBuildSystem extends Mock implements BuildSystem {}
|
||||||
class MockPub extends Mock implements Pub {}
|
class MockPub extends Mock implements Pub {}
|
||||||
|
class MockChromiumLauncher extends Mock implements ChromiumLauncher {}
|
||||||
|
@ -93,7 +93,6 @@ void main() {
|
|||||||
FakeVmServiceHost fakeVmServiceHost;
|
FakeVmServiceHost fakeVmServiceHost;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
resetChromeForTesting();
|
|
||||||
mockDebugConnection = MockDebugConnection();
|
mockDebugConnection = MockDebugConnection();
|
||||||
mockDevice = MockDevice();
|
mockDevice = MockDevice();
|
||||||
mockAppConnection = MockAppConnection();
|
mockAppConnection = MockAppConnection();
|
||||||
@ -173,8 +172,10 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('runner with web server device does not support debugging without --start-paused', () => testbed.run(() {
|
test('runner with web server device does not support debugging without --start-paused', () => testbed.run(() {
|
||||||
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice(
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
));
|
||||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
||||||
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
||||||
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
||||||
mockFlutterDevice,
|
mockFlutterDevice,
|
||||||
flutterProject: FlutterProject.current(),
|
flutterProject: FlutterProject.current(),
|
||||||
@ -194,7 +195,9 @@ void main() {
|
|||||||
test('runner with web server device supports debugging with --start-paused', () => testbed.run(() {
|
test('runner with web server device supports debugging with --start-paused', () => testbed.run(() {
|
||||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
||||||
_setupMocks();
|
_setupMocks();
|
||||||
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice(
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
));
|
||||||
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
||||||
mockFlutterDevice,
|
mockFlutterDevice,
|
||||||
flutterProject: FlutterProject.current(),
|
flutterProject: FlutterProject.current(),
|
||||||
@ -355,7 +358,23 @@ void main() {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
_setupMocks();
|
_setupMocks();
|
||||||
launchChromeInstance(mockChrome);
|
final ChromiumLauncher chromiumLauncher = MockChromeLauncher();
|
||||||
|
when(chromiumLauncher.launch(any, cacheDir: anyNamed('cacheDir')))
|
||||||
|
.thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(chromiumLauncher.connectedInstance).thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(mockFlutterDevice.device).thenReturn(GoogleChromeDevice(
|
||||||
|
fileSystem: globals.fs,
|
||||||
|
chromiumLauncher: chromiumLauncher,
|
||||||
|
logger: globals.logger,
|
||||||
|
platform: FakePlatform(operatingSystem: 'linux'),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
));
|
||||||
|
when(chromiumLauncher.canFindExecutable()).thenReturn(true);
|
||||||
|
chromiumLauncher.testLaunchChromium(mockChrome);
|
||||||
when(mockWebDevFS.update(
|
when(mockWebDevFS.update(
|
||||||
mainUri: anyNamed('mainUri'),
|
mainUri: anyNamed('mainUri'),
|
||||||
target: anyNamed('target'),
|
target: anyNamed('target'),
|
||||||
@ -395,7 +414,7 @@ void main() {
|
|||||||
|
|
||||||
expect(config, allOf(<Matcher>[
|
expect(config, allOf(<Matcher>[
|
||||||
containsPair('cd27', 'web-javascript'),
|
containsPair('cd27', 'web-javascript'),
|
||||||
containsPair('cd28', null),
|
containsPair('cd28', ''),
|
||||||
containsPair('cd29', 'false'),
|
containsPair('cd29', 'false'),
|
||||||
containsPair('cd30', 'true'),
|
containsPair('cd30', 'true'),
|
||||||
]));
|
]));
|
||||||
@ -417,7 +436,23 @@ void main() {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
_setupMocks();
|
_setupMocks();
|
||||||
launchChromeInstance(mockChrome);
|
final ChromiumLauncher chromiumLauncher = MockChromeLauncher();
|
||||||
|
when(chromiumLauncher.launch(any, cacheDir: anyNamed('cacheDir')))
|
||||||
|
.thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(chromiumLauncher.connectedInstance).thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(chromiumLauncher.canFindExecutable()).thenReturn(true);
|
||||||
|
when(mockFlutterDevice.device).thenReturn(GoogleChromeDevice(
|
||||||
|
fileSystem: globals.fs,
|
||||||
|
chromiumLauncher: chromiumLauncher,
|
||||||
|
logger: globals.logger,
|
||||||
|
platform: FakePlatform(operatingSystem: 'linux'),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
));
|
||||||
|
chromiumLauncher.testLaunchChromium(mockChrome);
|
||||||
Uri entrypointFileUri;
|
Uri entrypointFileUri;
|
||||||
when(mockWebDevFS.update(
|
when(mockWebDevFS.update(
|
||||||
mainUri: anyNamed('mainUri'),
|
mainUri: anyNamed('mainUri'),
|
||||||
@ -461,7 +496,7 @@ void main() {
|
|||||||
|
|
||||||
expect(config, allOf(<Matcher>[
|
expect(config, allOf(<Matcher>[
|
||||||
containsPair('cd27', 'web-javascript'),
|
containsPair('cd27', 'web-javascript'),
|
||||||
containsPair('cd28', null),
|
containsPair('cd28', ''),
|
||||||
containsPair('cd29', 'false'),
|
containsPair('cd29', 'false'),
|
||||||
containsPair('cd30', 'true'),
|
containsPair('cd30', 'true'),
|
||||||
]));
|
]));
|
||||||
@ -1062,7 +1097,22 @@ void main() {
|
|||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
_setupMocks();
|
_setupMocks();
|
||||||
when(mockFlutterDevice.device).thenReturn(ChromeDevice());
|
final ChromiumLauncher chromiumLauncher = MockChromeLauncher();
|
||||||
|
when(chromiumLauncher.launch(any, cacheDir: anyNamed('cacheDir')))
|
||||||
|
.thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(chromiumLauncher.connectedInstance).thenAnswer((Invocation invocation) async {
|
||||||
|
return mockChrome;
|
||||||
|
});
|
||||||
|
when(mockFlutterDevice.device).thenReturn(GoogleChromeDevice(
|
||||||
|
fileSystem: globals.fs,
|
||||||
|
chromiumLauncher: chromiumLauncher,
|
||||||
|
logger: globals.logger,
|
||||||
|
platform: FakePlatform(operatingSystem: 'linux'),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
));
|
||||||
|
when(chromiumLauncher.canFindExecutable()).thenReturn(true);
|
||||||
when(mockWebDevFS.create()).thenAnswer((Invocation invocation) async {
|
when(mockWebDevFS.create()).thenAnswer((Invocation invocation) async {
|
||||||
return Uri.parse('http://localhost:8765/app/');
|
return Uri.parse('http://localhost:8765/app/');
|
||||||
});
|
});
|
||||||
@ -1077,7 +1127,7 @@ void main() {
|
|||||||
return mockWipConnection;
|
return mockWipConnection;
|
||||||
});
|
});
|
||||||
when(chrome.chromeConnection).thenReturn(mockChromeConnection);
|
when(chrome.chromeConnection).thenReturn(mockChromeConnection);
|
||||||
launchChromeInstance(chrome);
|
chromiumLauncher.testLaunchChromium(chrome);
|
||||||
|
|
||||||
final DelegateLogger delegateLogger = globals.logger as DelegateLogger;
|
final DelegateLogger delegateLogger = globals.logger as DelegateLogger;
|
||||||
final MockStatus mockStatus = MockStatus();
|
final MockStatus mockStatus = MockStatus();
|
||||||
@ -1110,13 +1160,14 @@ void main() {
|
|||||||
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
Logger: () => DelegateLogger(BufferLogger.test()),
|
Logger: () => DelegateLogger(BufferLogger.test()),
|
||||||
ChromeLauncher: () => MockChromeLauncher(),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test('Sends unlaunched app.webLaunchUrl event for Web Server device', () => testbed.run(() async {
|
test('Sends unlaunched app.webLaunchUrl event for Web Server device', () => testbed.run(() async {
|
||||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
|
||||||
_setupMocks();
|
_setupMocks();
|
||||||
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice(
|
||||||
|
logger: globals.logger,
|
||||||
|
));
|
||||||
when(mockWebDevFS.create()).thenAnswer((Invocation invocation) async {
|
when(mockWebDevFS.create()).thenAnswer((Invocation invocation) async {
|
||||||
return Uri.parse('http://localhost:8765/app/');
|
return Uri.parse('http://localhost:8765/app/');
|
||||||
});
|
});
|
||||||
@ -1219,9 +1270,9 @@ void main() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockChromeLauncher extends Mock implements ChromeLauncher {}
|
class MockChromeLauncher extends Mock implements ChromiumLauncher {}
|
||||||
class MockFlutterUsage extends Mock implements Usage {}
|
class MockFlutterUsage extends Mock implements Usage {}
|
||||||
class MockChromeDevice extends Mock implements ChromeDevice {}
|
class MockChromeDevice extends Mock implements ChromiumDevice {}
|
||||||
class MockDebugConnection extends Mock implements DebugConnection {}
|
class MockDebugConnection extends Mock implements DebugConnection {}
|
||||||
class MockAppConnection extends Mock implements AppConnection {}
|
class MockAppConnection extends Mock implements AppConnection {}
|
||||||
class MockVmService extends Mock implements VmService {}
|
class MockVmService extends Mock implements VmService {}
|
||||||
@ -1229,7 +1280,7 @@ class MockStatus extends Mock implements Status {}
|
|||||||
class MockFlutterDevice extends Mock implements FlutterDevice {}
|
class MockFlutterDevice extends Mock implements FlutterDevice {}
|
||||||
class MockWebDevFS extends Mock implements WebDevFS {}
|
class MockWebDevFS extends Mock implements WebDevFS {}
|
||||||
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
||||||
class MockChrome extends Mock implements Chrome {}
|
class MockChrome extends Mock implements Chromium {}
|
||||||
class MockChromeConnection extends Mock implements ChromeConnection {}
|
class MockChromeConnection extends Mock implements ChromeConnection {}
|
||||||
class MockChromeTab extends Mock implements ChromeTab {}
|
class MockChromeTab extends Mock implements ChromeTab {}
|
||||||
class MockWipConnection extends Mock implements WipConnection {}
|
class MockWipConnection extends Mock implements WipConnection {}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/common.dart';
|
import 'package:file_testing/file_testing.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/os.dart';
|
import 'package:flutter_tools/src/base/os.dart';
|
||||||
@ -16,7 +16,7 @@ import 'package:platform/platform.dart';
|
|||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
|
||||||
const List<String> _kChromeArgs = <String>[
|
const List<String> kChromeArgs = <String>[
|
||||||
'--disable-background-timer-throttling',
|
'--disable-background-timer-throttling',
|
||||||
'--disable-extensions',
|
'--disable-extensions',
|
||||||
'--disable-popup-blocking',
|
'--disable-popup-blocking',
|
||||||
@ -30,7 +30,7 @@ const List<String> _kChromeArgs = <String>[
|
|||||||
const String kDevtoolsStderr = '\n\nDevTools listening\n\n';
|
const String kDevtoolsStderr = '\n\nDevTools listening\n\n';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ChromeLauncher chromeLauncher;
|
ChromiumLauncher chromeLauncher;
|
||||||
FileSystem fileSystem;
|
FileSystem fileSystem;
|
||||||
Platform platform;
|
Platform platform;
|
||||||
FakeProcessManager processManager;
|
FakeProcessManager processManager;
|
||||||
@ -49,66 +49,91 @@ void main() {
|
|||||||
});
|
});
|
||||||
fileSystem = MemoryFileSystem.test();
|
fileSystem = MemoryFileSystem.test();
|
||||||
processManager = FakeProcessManager.list(<FakeCommand>[]);
|
processManager = FakeProcessManager.list(<FakeCommand>[]);
|
||||||
chromeLauncher = ChromeLauncher(
|
chromeLauncher = ChromiumLauncher(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
platform: platform,
|
platform: platform,
|
||||||
processManager: processManager,
|
processManager: processManager,
|
||||||
operatingSystemUtils: operatingSystemUtils,
|
operatingSystemUtils: operatingSystemUtils,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
browserFinder: findChromeExecutable,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() {
|
testWithoutContext('can launch chrome and connect to the devtools', () async {
|
||||||
resetChromeForTesting();
|
expect(
|
||||||
|
() async => await testLaunchChrome(
|
||||||
|
'/.tmp_rand0/flutter_tools_chrome_device.rand0',
|
||||||
|
processManager,
|
||||||
|
chromeLauncher,
|
||||||
|
),
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can launch chrome and connect to the devtools', () async {
|
testWithoutContext('cannot have two concurrent instances of chrome', () async {
|
||||||
await testLaunchChrome('/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher);
|
await testLaunchChrome(
|
||||||
|
'/.tmp_rand0/flutter_tools_chrome_device.rand0',
|
||||||
|
processManager,
|
||||||
|
chromeLauncher,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() async => await testLaunchChrome(
|
||||||
|
'/.tmp_rand0/flutter_tools_chrome_device.rand1',
|
||||||
|
processManager,
|
||||||
|
chromeLauncher,
|
||||||
|
),
|
||||||
|
throwsToolExit(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cannot have two concurrent instances of chrome', () async {
|
testWithoutContext('can launch new chrome after stopping a previous chrome', () async {
|
||||||
await testLaunchChrome('/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher);
|
final Chromium chrome = await testLaunchChrome(
|
||||||
bool pass = false;
|
'/.tmp_rand0/flutter_tools_chrome_device.rand0',
|
||||||
try {
|
processManager,
|
||||||
await testLaunchChrome('/.tmp_rand0/flutter_tools_chrome_device.rand1', processManager, chromeLauncher);
|
chromeLauncher,
|
||||||
} on ToolExit catch (_) {
|
);
|
||||||
pass = true;
|
|
||||||
}
|
|
||||||
expect(pass, isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('can launch new chrome after stopping a previous chrome', () async {
|
|
||||||
final Chrome chrome = await testLaunchChrome('/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher);
|
|
||||||
await chrome.close();
|
await chrome.close();
|
||||||
await testLaunchChrome('/.tmp_rand0/flutter_tools_chrome_device.rand1', processManager, chromeLauncher);
|
|
||||||
|
expect(
|
||||||
|
() async => await testLaunchChrome(
|
||||||
|
'/.tmp_rand0/flutter_tools_chrome_device.rand1',
|
||||||
|
processManager,
|
||||||
|
chromeLauncher,
|
||||||
|
),
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can launch chrome with a custom debug port', () async {
|
testWithoutContext('can launch chrome with a custom debug port', () async {
|
||||||
processManager.addCommand(const FakeCommand(
|
processManager.addCommand(const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'example_chrome',
|
'example_chrome',
|
||||||
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
||||||
'--remote-debugging-port=10000',
|
'--remote-debugging-port=10000',
|
||||||
..._kChromeArgs,
|
...kChromeArgs,
|
||||||
'example_url',
|
'example_url',
|
||||||
],
|
],
|
||||||
stderr: kDevtoolsStderr,
|
stderr: kDevtoolsStderr,
|
||||||
));
|
));
|
||||||
|
|
||||||
await chromeLauncher.launch(
|
expect(
|
||||||
|
() async => await chromeLauncher.launch(
|
||||||
'example_url',
|
'example_url',
|
||||||
skipCheck: true,
|
skipCheck: true,
|
||||||
debugPort: 10000,
|
debugPort: 10000,
|
||||||
|
),
|
||||||
|
returnsNormally,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can launch chrome headless', () async {
|
testWithoutContext('can launch chrome headless', () async {
|
||||||
processManager.addCommand(const FakeCommand(
|
processManager.addCommand(const FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'example_chrome',
|
'example_chrome',
|
||||||
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
||||||
'--remote-debugging-port=1234',
|
'--remote-debugging-port=1234',
|
||||||
..._kChromeArgs,
|
...kChromeArgs,
|
||||||
'--headless',
|
'--headless',
|
||||||
'--disable-gpu',
|
'--disable-gpu',
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
@ -118,14 +143,17 @@ void main() {
|
|||||||
stderr: kDevtoolsStderr,
|
stderr: kDevtoolsStderr,
|
||||||
));
|
));
|
||||||
|
|
||||||
await chromeLauncher.launch(
|
expect(
|
||||||
|
() async => await chromeLauncher.launch(
|
||||||
'example_url',
|
'example_url',
|
||||||
skipCheck: true,
|
skipCheck: true,
|
||||||
headless: true,
|
headless: true,
|
||||||
|
),
|
||||||
|
returnsNormally,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can seed chrome temp directory with existing session data', () async {
|
testWithoutContext('can seed chrome temp directory with existing session data', () async {
|
||||||
final Completer<void> exitCompleter = Completer<void>.sync();
|
final Completer<void> exitCompleter = Completer<void>.sync();
|
||||||
final Directory dataDir = fileSystem.directory('chrome-stuff');
|
final Directory dataDir = fileSystem.directory('chrome-stuff');
|
||||||
|
|
||||||
@ -148,7 +176,7 @@ void main() {
|
|||||||
'example_chrome',
|
'example_chrome',
|
||||||
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
'--user-data-dir=/.tmp_rand1/flutter_tools_chrome_device.rand1',
|
||||||
'--remote-debugging-port=1234',
|
'--remote-debugging-port=1234',
|
||||||
..._kChromeArgs,
|
...kChromeArgs,
|
||||||
'example_url',
|
'example_url',
|
||||||
], completer: exitCompleter));
|
], completer: exitCompleter));
|
||||||
|
|
||||||
@ -183,23 +211,23 @@ void main() {
|
|||||||
|
|
||||||
expect(storageDir.existsSync(), true);
|
expect(storageDir.existsSync(), true);
|
||||||
|
|
||||||
expect(storageDir.childFile('LOCK').existsSync(), true);
|
expect(storageDir.childFile('LOCK'), exists);
|
||||||
expect(storageDir.childFile('LOCK').readAsBytesSync(), hasLength(0));
|
expect(storageDir.childFile('LOCK').readAsBytesSync(), hasLength(0));
|
||||||
|
|
||||||
expect(storageDir.childFile('LOG').existsSync(), true);
|
expect(storageDir.childFile('LOG'), exists);
|
||||||
expect(storageDir.childFile('LOG').readAsStringSync(), 'contents');
|
expect(storageDir.childFile('LOG').readAsStringSync(), 'contents');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
|
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
|
||||||
|
|
||||||
Future<Chrome> testLaunchChrome(String userDataDir, FakeProcessManager processManager, ChromeLauncher chromeLauncher) {
|
Future<Chromium> testLaunchChrome(String userDataDir, FakeProcessManager processManager, ChromiumLauncher chromeLauncher) {
|
||||||
processManager.addCommand(FakeCommand(
|
processManager.addCommand(FakeCommand(
|
||||||
command: <String>[
|
command: <String>[
|
||||||
'example_chrome',
|
'example_chrome',
|
||||||
'--user-data-dir=$userDataDir',
|
'--user-data-dir=$userDataDir',
|
||||||
'--remote-debugging-port=1234',
|
'--remote-debugging-port=1234',
|
||||||
..._kChromeArgs,
|
...kChromeArgs,
|
||||||
'example_url',
|
'example_url',
|
||||||
],
|
],
|
||||||
stderr: kDevtoolsStderr,
|
stderr: kDevtoolsStderr,
|
||||||
|
@ -376,6 +376,7 @@ void main() {
|
|||||||
entrypoint: Uri.base,
|
entrypoint: Uri.base,
|
||||||
testMode: true,
|
testMode: true,
|
||||||
expressionCompiler: null,
|
expressionCompiler: null,
|
||||||
|
chromiumLauncher: null,
|
||||||
);
|
);
|
||||||
webDevFS.requireJS.createSync(recursive: true);
|
webDevFS.requireJS.createSync(recursive: true);
|
||||||
webDevFS.stackTraceMapper.createSync(recursive: true);
|
webDevFS.stackTraceMapper.createSync(recursive: true);
|
||||||
@ -469,6 +470,7 @@ void main() {
|
|||||||
entrypoint: Uri.base,
|
entrypoint: Uri.base,
|
||||||
testMode: true,
|
testMode: true,
|
||||||
expressionCompiler: null,
|
expressionCompiler: null,
|
||||||
|
chromiumLauncher: null,
|
||||||
);
|
);
|
||||||
webDevFS.requireJS.createSync(recursive: true);
|
webDevFS.requireJS.createSync(recursive: true);
|
||||||
webDevFS.stackTraceMapper.createSync(recursive: true);
|
webDevFS.stackTraceMapper.createSync(recursive: true);
|
||||||
@ -482,6 +484,7 @@ void main() {
|
|||||||
test('Launches DWDS with the correct arguments', () => testbed.run(() async {
|
test('Launches DWDS with the correct arguments', () => testbed.run(() async {
|
||||||
globals.fs.file('.packages').writeAsStringSync('\n');
|
globals.fs.file('.packages').writeAsStringSync('\n');
|
||||||
final WebAssetServer server = await WebAssetServer.start(
|
final WebAssetServer server = await WebAssetServer.start(
|
||||||
|
null,
|
||||||
'any',
|
'any',
|
||||||
8123,
|
8123,
|
||||||
(String url) => null,
|
(String url) => null,
|
||||||
|
@ -2,36 +2,42 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:file/memory.dart';
|
||||||
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/device.dart';
|
import 'package:flutter_tools/src/device.dart';
|
||||||
import 'package:flutter_tools/src/web/chrome.dart';
|
import 'package:flutter_tools/src/web/chrome.dart';
|
||||||
import 'package:flutter_tools/src/web/web_device.dart';
|
import 'package:flutter_tools/src/web/web_device.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
import 'package:process/process.dart';
|
|
||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
import '../../src/testbed.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
MockChromeLauncher mockChromeLauncher;
|
testWithoutContext('No web devices listed if feature is disabled', () async {
|
||||||
MockPlatform mockPlatform;
|
final WebDevices webDevices = WebDevices(
|
||||||
MockProcessManager mockProcessManager;
|
featureFlags: TestFeatureFlags(isWebEnabled: false),
|
||||||
MockWebApplicationPackage mockWebApplicationPackage;
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'linux',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
);
|
||||||
|
|
||||||
setUp(() async {
|
expect(await webDevices.pollingGetDevices(), isEmpty);
|
||||||
mockWebApplicationPackage = MockWebApplicationPackage();
|
|
||||||
mockProcessManager = MockProcessManager();
|
|
||||||
mockChromeLauncher = MockChromeLauncher();
|
|
||||||
mockPlatform = MockPlatform();
|
|
||||||
when(mockChromeLauncher.launch(any)).thenAnswer((Invocation invocation) async {
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
when(mockWebApplicationPackage.name).thenReturn('test');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Chrome defaults', () async {
|
testWithoutContext('GoogleChromeDevice defaults', () async {
|
||||||
final ChromeDevice chromeDevice = ChromeDevice();
|
final GoogleChromeDevice chromeDevice = GoogleChromeDevice(
|
||||||
|
chromiumLauncher: null,
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(operatingSystem: 'linux'),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
);
|
||||||
|
|
||||||
expect(chromeDevice.name, 'Chrome');
|
expect(chromeDevice.name, 'Chrome');
|
||||||
expect(chromeDevice.id, 'chrome');
|
expect(chromeDevice.id, 'chrome');
|
||||||
@ -41,13 +47,35 @@ void main() {
|
|||||||
expect(chromeDevice.supportsFlutterExit, true);
|
expect(chromeDevice.supportsFlutterExit, true);
|
||||||
expect(chromeDevice.supportsScreenshot, false);
|
expect(chromeDevice.supportsScreenshot, false);
|
||||||
expect(await chromeDevice.isLocalEmulator, false);
|
expect(await chromeDevice.isLocalEmulator, false);
|
||||||
expect(chromeDevice.getLogReader(app: mockWebApplicationPackage), isA<NoOpDeviceLogReader>());
|
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
|
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
expect(await chromeDevice.portForwarder.forward(1), 1);
|
expect(await chromeDevice.portForwarder.forward(1), 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Server defaults', () async {
|
testWithoutContext('MicrosoftEdge defaults', () async {
|
||||||
final WebServerDevice device = WebServerDevice();
|
final MicrosoftEdgeDevice chromeDevice = MicrosoftEdgeDevice(
|
||||||
|
chromiumLauncher: null,
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(chromeDevice.name, 'Edge');
|
||||||
|
expect(chromeDevice.id, 'edge');
|
||||||
|
expect(chromeDevice.supportsHotReload, true);
|
||||||
|
expect(chromeDevice.supportsHotRestart, true);
|
||||||
|
expect(chromeDevice.supportsStartPaused, true);
|
||||||
|
expect(chromeDevice.supportsFlutterExit, true);
|
||||||
|
expect(chromeDevice.supportsScreenshot, false);
|
||||||
|
expect(await chromeDevice.isLocalEmulator, false);
|
||||||
|
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
|
expect(chromeDevice.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
|
expect(await chromeDevice.portForwarder.forward(1), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Server defaults', () async {
|
||||||
|
final WebServerDevice device = WebServerDevice(
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
);
|
||||||
|
|
||||||
expect(device.name, 'Web Server');
|
expect(device.name, 'Web Server');
|
||||||
expect(device.id, 'web-server');
|
expect(device.id, 'web-server');
|
||||||
@ -57,95 +85,130 @@ void main() {
|
|||||||
expect(device.supportsFlutterExit, true);
|
expect(device.supportsFlutterExit, true);
|
||||||
expect(device.supportsScreenshot, false);
|
expect(device.supportsScreenshot, false);
|
||||||
expect(await device.isLocalEmulator, false);
|
expect(await device.isLocalEmulator, false);
|
||||||
expect(device.getLogReader(app: mockWebApplicationPackage), isA<NoOpDeviceLogReader>());
|
expect(device.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
expect(device.getLogReader(), isA<NoOpDeviceLogReader>());
|
expect(device.getLogReader(), isA<NoOpDeviceLogReader>());
|
||||||
expect(await device.portForwarder.forward(1), 1);
|
expect(await device.portForwarder.forward(1), 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Chrome device is listed when Chrome is available', () async {
|
testWithoutContext('Chrome device is listed when Chrome can be run', () async {
|
||||||
when(mockChromeLauncher.canFindChrome()).thenReturn(true);
|
final WebDevices webDevices = WebDevices(
|
||||||
|
featureFlags: TestFeatureFlags(isWebEnabled: true),
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'linux',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
);
|
||||||
|
|
||||||
final WebDevices deviceDiscoverer = WebDevices();
|
expect(await webDevices.pollingGetDevices(),
|
||||||
final List<Device> devices = await deviceDiscoverer.pollingGetDevices();
|
contains(isA<GoogleChromeDevice>()));
|
||||||
expect(devices, contains(isA<ChromeDevice>()));
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
ChromeLauncher: () => mockChromeLauncher,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Chrome device is not listed when Chrome is not available', () async {
|
testWithoutContext('Chrome device is not listed when Chrome cannot be run', () async {
|
||||||
when(mockChromeLauncher.canFindChrome()).thenReturn(false);
|
final MockProcessManager processManager = MockProcessManager();
|
||||||
|
when(processManager.canRun(any)).thenReturn(false);
|
||||||
|
final WebDevices webDevices = WebDevices(
|
||||||
|
featureFlags: TestFeatureFlags(isWebEnabled: true),
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'linux',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
final WebDevices deviceDiscoverer = WebDevices();
|
expect(await webDevices.pollingGetDevices(),
|
||||||
final List<Device> devices = await deviceDiscoverer.pollingGetDevices();
|
isNot(contains(isA<GoogleChromeDevice>())));
|
||||||
expect(devices, isNot(contains(isA<ChromeDevice>())));
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
ChromeLauncher: () => mockChromeLauncher,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Web Server device is listed even when Chrome is not available', () async {
|
testWithoutContext('Web Server device is listed by default', () async {
|
||||||
when(mockChromeLauncher.canFindChrome()).thenReturn(false);
|
final WebDevices webDevices = WebDevices(
|
||||||
|
featureFlags: TestFeatureFlags(isWebEnabled: true),
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'linux',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
);
|
||||||
|
|
||||||
final WebDevices deviceDiscoverer = WebDevices();
|
expect(await webDevices.pollingGetDevices(),
|
||||||
final List<Device> devices = await deviceDiscoverer.pollingGetDevices();
|
contains(isA<WebServerDevice>()));
|
||||||
expect(devices, contains(isA<WebServerDevice>()));
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
ChromeLauncher: () => mockChromeLauncher,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Chrome invokes version command on non-Windows platforms', () async{
|
testWithoutContext('Chrome invokes version command on non-Windows platforms', () async {
|
||||||
when(mockPlatform.isWindows).thenReturn(false);
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
when(mockProcessManager.canRun('chrome.foo')).thenReturn(true);
|
const FakeCommand(
|
||||||
when(mockProcessManager.run(<String>['chrome.foo', '--version'])).thenAnswer((Invocation invocation) async {
|
command: <String>[
|
||||||
return MockProcessResult(0, 'ABC');
|
kLinuxExecutable,
|
||||||
});
|
'--version',
|
||||||
final ChromeDevice chromeDevice = ChromeDevice();
|
],
|
||||||
|
stdout: 'ABC'
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
final WebDevices webDevices = WebDevices(
|
||||||
|
featureFlags: TestFeatureFlags(isWebEnabled: true),
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'linux',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
final GoogleChromeDevice chromeDevice = (await webDevices.pollingGetDevices())
|
||||||
|
.whereType<GoogleChromeDevice>().first;
|
||||||
|
|
||||||
expect(chromeDevice.isSupported(), true);
|
expect(chromeDevice.isSupported(), true);
|
||||||
expect(await chromeDevice.sdkNameAndVersion, 'ABC');
|
expect(await chromeDevice.sdkNameAndVersion, 'ABC');
|
||||||
|
|
||||||
// Verify caching works correctly.
|
// Verify caching works correctly.
|
||||||
expect(await chromeDevice.sdkNameAndVersion, 'ABC');
|
expect(await chromeDevice.sdkNameAndVersion, 'ABC');
|
||||||
verify(mockProcessManager.run(<String>['chrome.foo', '--version'])).called(1);
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
Platform: () => mockPlatform,
|
|
||||||
ProcessManager: () => mockProcessManager,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('Chrome invokes different version command on windows.', () async {
|
testWithoutContext('Chrome version check invokes registry query on windows.', () async {
|
||||||
when(mockPlatform.isWindows).thenReturn(true);
|
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
|
||||||
when(mockProcessManager.canRun('chrome.foo')).thenReturn(true);
|
const FakeCommand(
|
||||||
when(mockProcessManager.run(<String>[
|
command: <String>[
|
||||||
'reg',
|
'reg',
|
||||||
'query',
|
'query',
|
||||||
r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon',
|
r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon',
|
||||||
'/v',
|
'/v',
|
||||||
'version',
|
'version',
|
||||||
])).thenAnswer((Invocation invocation) async {
|
],
|
||||||
return MockProcessResult(0, r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon\ version REG_SZ 74.0.0 A');
|
stdout: r'HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon\ version REG_SZ 74.0.0 A',
|
||||||
});
|
)
|
||||||
final ChromeDevice chromeDevice = ChromeDevice();
|
]);
|
||||||
|
final WebDevices webDevices = WebDevices(
|
||||||
|
featureFlags: TestFeatureFlags(isWebEnabled: true),
|
||||||
|
fileSystem: MemoryFileSystem.test(),
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
platform: FakePlatform(
|
||||||
|
operatingSystem: 'windows',
|
||||||
|
environment: <String, String>{}
|
||||||
|
),
|
||||||
|
processManager: processManager,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
final GoogleChromeDevice chromeDevice = (await webDevices.pollingGetDevices())
|
||||||
|
.whereType<GoogleChromeDevice>().first;
|
||||||
|
|
||||||
expect(chromeDevice.isSupported(), true);
|
expect(chromeDevice.isSupported(), true);
|
||||||
expect(await chromeDevice.sdkNameAndVersion, 'Google Chrome 74.0.0');
|
expect(await chromeDevice.sdkNameAndVersion, 'Google Chrome 74.0.0');
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
Platform: () => mockPlatform,
|
// Verify caching works correctly.
|
||||||
ProcessManager: () => mockProcessManager,
|
expect(await chromeDevice.sdkNameAndVersion, 'Google Chrome 74.0.0');
|
||||||
|
expect(processManager.hasRemainingExpectations, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockChromeLauncher extends Mock implements ChromeLauncher {}
|
// This is used to set `canRun` to false in a test.
|
||||||
class MockPlatform extends Mock implements Platform {
|
|
||||||
@override
|
|
||||||
Map<String, String> environment = <String, String>{'FLUTTER_WEB': 'true', kChromeEnvironment: 'chrome.foo'};
|
|
||||||
}
|
|
||||||
class MockProcessManager extends Mock implements ProcessManager {}
|
class MockProcessManager extends Mock implements ProcessManager {}
|
||||||
class MockProcessResult extends Mock implements ProcessResult {
|
|
||||||
MockProcessResult(this.exitCode, this.stdout);
|
|
||||||
|
|
||||||
@override
|
|
||||||
final int exitCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
final String stdout;
|
|
||||||
}
|
|
||||||
class MockWebApplicationPackage extends Mock implements WebApplicationPackage {}
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/doctor.dart';
|
import 'package:flutter_tools/src/doctor.dart';
|
||||||
import 'package:flutter_tools/src/web/chrome.dart';
|
import 'package:flutter_tools/src/web/chrome.dart';
|
||||||
import 'package:flutter_tools/src/web/web_validator.dart';
|
import 'package:flutter_tools/src/web/web_validator.dart';
|
||||||
@ -17,9 +18,9 @@ import '../../src/fake_process_manager.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
Platform platform;
|
Platform platform;
|
||||||
ProcessManager processManager;
|
ProcessManager processManager;
|
||||||
ChromeLauncher chromeLauncher;
|
ChromiumLauncher chromeLauncher;
|
||||||
FileSystem fileSystem;
|
FileSystem fileSystem;
|
||||||
WebValidator webValidator;
|
ChromiumValidator webValidator;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fileSystem = MemoryFileSystem.test();
|
fileSystem = MemoryFileSystem.test();
|
||||||
@ -28,17 +29,17 @@ void main() {
|
|||||||
operatingSystem: 'macos',
|
operatingSystem: 'macos',
|
||||||
environment: <String, String>{},
|
environment: <String, String>{},
|
||||||
);
|
);
|
||||||
chromeLauncher = ChromeLauncher(
|
chromeLauncher = ChromiumLauncher(
|
||||||
fileSystem: fileSystem,
|
fileSystem: fileSystem,
|
||||||
platform: platform,
|
platform: platform,
|
||||||
processManager: processManager,
|
processManager: processManager,
|
||||||
operatingSystemUtils: null,
|
operatingSystemUtils: null,
|
||||||
logger: null,
|
logger: BufferLogger.test(),
|
||||||
|
browserFinder: findChromeExecutable,
|
||||||
);
|
);
|
||||||
webValidator = webValidator = WebValidator(
|
webValidator = webValidator = ChromeValidator(
|
||||||
platform: platform,
|
platform: platform,
|
||||||
chromeLauncher: chromeLauncher,
|
chromiumLauncher: chromeLauncher,
|
||||||
fileSystem: fileSystem,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user