Unverified Commit 81c91924 authored by Yegor's avatar Yegor Committed by GitHub

[web] use resident resident runner in flutter drive (#86381)

* [web] use resident resident runner in flutter drive
parent e990f4b9
......@@ -46,6 +46,7 @@ class FlutterDriverFactory {
DriverService createDriverService(bool web) {
if (web) {
return WebDriverService(
logger: _logger,
processUtils: _processUtils,
dartSdkPath: _dartSdkPath,
);
......
......@@ -13,6 +13,7 @@ import 'package:package_config/package_config.dart';
import 'package:webdriver/async_io.dart' as async_io;
import '../base/common.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../convert.dart';
......@@ -28,15 +29,25 @@ class WebDriverService extends DriverService {
WebDriverService({
@required ProcessUtils processUtils,
@required String dartSdkPath,
@required Logger logger,
}) : _processUtils = processUtils,
_dartSdkPath = dartSdkPath;
_dartSdkPath = dartSdkPath,
_logger = logger;
final ProcessUtils _processUtils;
final String _dartSdkPath;
final Logger _logger;
ResidentRunner _residentRunner;
Uri _webUri;
/// The result of [ResidentRunner.run].
///
/// This is expected to stay `null` throughout the test, as the application
/// must be running until [stop] is called. If it becomes non-null, it likely
/// indicates a bug.
int _runResult;
@override
Future<void> start(
BuildInfo buildInfo,
......@@ -69,23 +80,48 @@ class WebDriverService extends DriverService {
port: debuggingOptions.port,
disablePortPublication: debuggingOptions.disablePortPublication,
),
stayResident: false,
stayResident: true,
urlTunneller: null,
flutterProject: FlutterProject.current(),
fileSystem: globals.fs,
usage: globals.flutterUsage,
logger: globals.logger,
logger: _logger,
systemClock: globals.systemClock,
);
final Completer<void> appStartedCompleter = Completer<void>.sync();
final int result = await _residentRunner.run(
final Future<int> runFuture = _residentRunner.run(
appStartedCompleter: appStartedCompleter,
enableDevTools: false,
route: route,
);
bool isAppStarted = false;
await Future.any<Object>(<Future<Object>>[
runFuture.then((int result) {
_runResult = result;
return null;
}),
appStartedCompleter.future.then((_) {
isAppStarted = true;
return null;
}),
]);
if (_runResult != null) {
throw ToolExit(
'Application exited before the test started. Check web driver logs '
'for possible application-side errors.'
);
}
if (!isAppStarted) {
throw ToolExit('Failed to start application');
}
_webUri = _residentRunner.uri;
if (result != 0) {
throwToolExit(null);
if (_webUri == null) {
throw ToolExit('Unable to connect to the app. URL not available.');
}
}
......@@ -150,7 +186,16 @@ class WebDriverService extends DriverService {
@override
Future<void> stop({File writeSkslOnExit, String userIdentifier}) async {
final bool appDidFinishPrematurely = _runResult != null;
await _residentRunner.exitApp();
await _residentRunner.cleanupAtFinish();
if (appDidFinishPrematurely) {
throw ToolExit(
'Application exited before the test finished. Check web driver logs '
'for possible application-side errors.'
);
}
}
Map<String, String> _additionalDriverEnvironment(async_io.WebDriver webDriver, String browserName, bool androidEmulator) {
......
......@@ -1376,7 +1376,7 @@ abstract class ResidentRunner extends ResidentHandlers {
Future<void> exitApp() async {
final List<Future<void>> futures = <Future<void>>[
for (final FlutterDevice device in flutterDevices) device.exitApps(),
for (final FlutterDevice device in flutterDevices) device.exitApps(),
];
await Future.wait(futures);
appFinished();
......
......@@ -460,6 +460,7 @@ void main() {
testWithoutContext('WebDriver error message includes link to documentation', () async {
const String link = 'https://flutter.dev/docs/testing/integration-tests#running-in-a-browser';
final DriverService driverService = WebDriverService(
logger: BufferLogger.test(),
dartSdkPath: 'dart',
processUtils: ProcessUtils(
processManager: FakeProcessManager.empty(),
......
......@@ -4,10 +4,26 @@
// @dart = 2.8
import 'dart:async';
import 'package:file/src/interface/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/net.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/drive/web_driver_service.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/web/web_runner.dart';
import 'package:test/fake.dart';
import 'package:webdriver/sync_io.dart' as sync_io;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fake_vm_services.dart';
void main() {
testWithoutContext('getDesiredCapabilities Chrome with headless on', () {
......@@ -165,4 +181,113 @@ void main() {
expect(getDesiredCapabilities(Browser.androidChrome, false), expected);
});
testUsingContext('WebDriverService starts and stops an app', () async {
final WebDriverService service = setUpDriverService();
final FakeDevice device = FakeDevice();
await service.start(BuildInfo.profile, device, DebuggingOptions.enabled(BuildInfo.profile), true);
await service.stop();
expect(FakeResidentRunner.instance.callLog, <String>[
'run',
'exitApp',
'cleanupAtFinish',
]);
}, overrides: <Type, Generator>{
WebRunnerFactory: () => FakeWebRunnerFactory(),
});
testUsingContext('WebDriverService forwards exception when run future fails before app starts', () async {
final WebDriverService service = setUpDriverService();
final Device device = FakeDevice();
await expectLater(
service.start(BuildInfo.profile, device, DebuggingOptions.enabled(BuildInfo.profile), true),
throwsA('This is a test error'),
);
}, overrides: <Type, Generator>{
WebRunnerFactory: () => FakeWebRunnerFactory(
doResolveToError: true,
),
});
}
class FakeWebRunnerFactory implements WebRunnerFactory {
FakeWebRunnerFactory({
this.doResolveToError = false,
});
final bool doResolveToError;
@override
ResidentRunner createWebRunner(FlutterDevice device, {String target, bool stayResident, FlutterProject flutterProject, bool ipv6, DebuggingOptions debuggingOptions, UrlTunneller urlTunneller, Logger logger, FileSystem fileSystem, SystemClock systemClock, Usage usage, bool machine = false}) {
expect(stayResident, isTrue);
return FakeResidentRunner(
doResolveToError: doResolveToError,
);
}
}
class FakeResidentRunner extends Fake implements ResidentRunner {
FakeResidentRunner({
this.doResolveToError,
}) {
instance = this;
}
static FakeResidentRunner instance;
final bool doResolveToError;
final Completer<int> _exitCompleter = Completer<int>();
final List<String> callLog = <String>[];
@override
Uri get uri => Uri();
@override
Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<void> appStartedCompleter,
bool enableDevTools = false,
String route,
}) async {
callLog.add('run');
if (doResolveToError) {
return Future<int>.error('This is a test error');
}
appStartedCompleter.complete();
// Emulate stayResident by completing after exitApp is called.
return _exitCompleter.future;
}
@override
Future<void> exitApp() async {
callLog.add('exitApp');
_exitCompleter.complete();
}
@override
Future<void> cleanupAtFinish() async {
callLog.add('cleanupAtFinish');
}
}
WebDriverService setUpDriverService() {
final BufferLogger logger = BufferLogger.test();
return WebDriverService(
logger: logger,
processUtils: ProcessUtils(
logger: logger,
processManager: FakeProcessManager.any(),
),
dartSdkPath: 'dart',
);
}
class FakeDevice extends Fake implements Device {
@override
final PlatformType platformType = PlatformType.web;
@override
Future<TargetPlatform> get targetPlatform async => TargetPlatform.android_arm;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment