Allow Developers to enable Accessibility testing on WebFlutterDriver and get the underlying webDriver (#65051)
This commit is contained in:
parent
46eacc5462
commit
d2fa384c31
@ -2,10 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
||||
import 'package:webdriver/async_io.dart';
|
||||
|
||||
/// The following test is used as a simple smoke test for verfying Flutter
|
||||
/// The following test is used as a simple smoke test for verifying Flutter
|
||||
/// Framework and Flutter Web Engine integration.
|
||||
void main() {
|
||||
group('Hello World App', () {
|
||||
@ -28,5 +31,20 @@ void main() {
|
||||
test('title is correct', () async {
|
||||
expect(await driver.getText(titleFinder), 'Hello, world!');
|
||||
});
|
||||
|
||||
test('enable accessibility', () async {
|
||||
await driver.enableAccessibility();
|
||||
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
|
||||
// Elements with tag "flt-semantics" would show up after enabling
|
||||
// accessibility.
|
||||
//
|
||||
// The tag used here is based on
|
||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/semantics/semantics.dart#L534
|
||||
final WebElement element = await driver.webDriver.findElement(const By.tagName('flt-semantics'));
|
||||
|
||||
expect(element, isNotNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import 'dart:io';
|
||||
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:vm_service_client/vm_service_client.dart';
|
||||
import 'package:webdriver/async_io.dart' as async_io;
|
||||
|
||||
import '../common/diagnostics_tree.dart';
|
||||
import '../common/error.dart';
|
||||
@ -169,6 +170,14 @@ abstract class FlutterDriver {
|
||||
/// Getter of serviceClient.
|
||||
VMServiceClient get serviceClient => throw UnimplementedError();
|
||||
|
||||
/// Getter of webDriver.
|
||||
async_io.WebDriver get webDriver => throw UnimplementedError();
|
||||
|
||||
/// Enables accessibility feature.
|
||||
Future<void> enableAccessibility() async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Sends [command] to the Flutter Driver extensions.
|
||||
/// This must be implemented by subclass.
|
||||
///
|
||||
|
@ -12,6 +12,7 @@ import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:vm_service_client/vm_service_client.dart';
|
||||
import 'package:webdriver/async_io.dart' as async_io;
|
||||
import 'package:web_socket_channel/io.dart';
|
||||
|
||||
import '../../flutter_driver.dart';
|
||||
@ -303,6 +304,9 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
@override
|
||||
VMServiceClient get serviceClient => _serviceClient;
|
||||
|
||||
@override
|
||||
async_io.WebDriver get webDriver => throw UnsupportedError('VMServiceFlutterDriver does not support webDriver');
|
||||
|
||||
/// The main isolate hosting the Flutter application.
|
||||
///
|
||||
/// If you used the [registerExtension] API to instrument your application,
|
||||
@ -316,6 +320,11 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
/// Whether to log communication between host and app to `flutter_driver_commands.log`.
|
||||
final bool _logCommunicationToFile;
|
||||
|
||||
@override
|
||||
Future<void> enableAccessibility() async {
|
||||
throw UnsupportedError('VMServiceFlutterDriver does not support enableAccessibility');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> sendCommand(Command command) async {
|
||||
Map<String, dynamic> response;
|
||||
|
@ -30,6 +30,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
|
||||
final FlutterWebConnection _connection;
|
||||
DateTime _startTime;
|
||||
bool _accessibilityEnabled = false;
|
||||
|
||||
/// Start time for tracing.
|
||||
@visibleForTesting
|
||||
@ -41,11 +42,15 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
@override
|
||||
VMServiceClient get serviceClient => throw UnsupportedError('WebFlutterDriver does not support serviceClient');
|
||||
|
||||
@override
|
||||
async_io.WebDriver get webDriver => _connection._driver;
|
||||
|
||||
/// Creates a driver that uses a connection provided by the given
|
||||
/// [hostUrl] which would fallback to environment variable VM_SERVICE_URL.
|
||||
/// Driver also depends on environment variables DRIVER_SESSION_ID,
|
||||
/// BROWSER_SUPPORTS_TIMELINE, DRIVER_SESSION_URI, DRIVER_SESSION_SPEC
|
||||
/// and ANDROID_CHROME_ON_EMULATOR for configurations.
|
||||
/// BROWSER_SUPPORTS_TIMELINE, DRIVER_SESSION_URI, DRIVER_SESSION_SPEC,
|
||||
/// DRIVER_SESSION_CAPABILITIES and ANDROID_CHROME_ON_EMULATOR for
|
||||
/// configurations.
|
||||
static Future<FlutterDriver> connectWeb(
|
||||
{String hostUrl, Duration timeout}) async {
|
||||
hostUrl ??= Platform.environment['VM_SERVICE_URL'];
|
||||
@ -55,12 +60,29 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
'session-uri': Platform.environment['DRIVER_SESSION_URI'],
|
||||
'session-spec': Platform.environment['DRIVER_SESSION_SPEC'],
|
||||
'android-chrome-on-emulator': Platform.environment['ANDROID_CHROME_ON_EMULATOR'] == 'true',
|
||||
'session-capabilities': Platform.environment['DRIVER_SESSION_CAPABILITIES'],
|
||||
};
|
||||
final FlutterWebConnection connection = await FlutterWebConnection.connect
|
||||
(hostUrl, settings, timeout: timeout);
|
||||
return WebFlutterDriver.connectedTo(connection);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> enableAccessibility() async {
|
||||
if (!_accessibilityEnabled) {
|
||||
// Clicks the button to enable accessibility via Javascript for Desktop Web.
|
||||
//
|
||||
// The tag used in the script is based on
|
||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart#L193
|
||||
//
|
||||
// TODO(angjieli): Support Mobile Web. (https://github.com/flutter/flutter/issues/65192)
|
||||
await webDriver.execute(
|
||||
'document.querySelector(\'flt-semantics-placeholder\').click();',
|
||||
<String>[]);
|
||||
_accessibilityEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> sendCommand(Command command) async {
|
||||
Map<String, dynamic> response;
|
||||
@ -177,12 +199,14 @@ class FlutterWebConnection {
|
||||
String url,
|
||||
Map<String, dynamic> settings,
|
||||
{Duration timeout}) async {
|
||||
// Use sync WebDriver because async version will create a 15 seconds
|
||||
// overhead when quitting.
|
||||
final async_io.WebDriver driver = await async_io.fromExistingSession(
|
||||
settings['session-id'].toString(),
|
||||
uri: Uri.parse(settings['session-uri'].toString()),
|
||||
spec: _convertToSpec(settings['session-spec'].toString().toLowerCase()));
|
||||
final String sessionId = settings['session-id'].toString();
|
||||
final Uri sessionUri = Uri.parse(settings['session-uri'].toString());
|
||||
final async_io.WebDriver driver = async_io.WebDriver(
|
||||
sessionUri,
|
||||
sessionId,
|
||||
json.decode(settings['session-capabilities'] as String) as Map<String, dynamic>,
|
||||
async_io.AsyncIoRequestClient(sessionUri.resolve('session/$sessionId/')),
|
||||
_convertToSpec(settings['session-spec'].toString().toLowerCase()));
|
||||
if (settings['android-chrome-on-emulator'] == true) {
|
||||
final Uri localUri = Uri.parse(url);
|
||||
// Converts to Android Emulator Uri.
|
||||
|
@ -768,6 +768,16 @@ void main() {
|
||||
expect(driver.waitFor(find.byTooltip('foo')), throwsDriverError);
|
||||
});
|
||||
});
|
||||
|
||||
group('VMServiceFlutterDriver Unsupported error', () {
|
||||
test('enableAccessibility', () async {
|
||||
expect(driver.enableAccessibility(), throwsA(isA<UnsupportedError>()));
|
||||
});
|
||||
|
||||
test('webDriver', () async {
|
||||
expect(() => driver.webDriver, throwsA(isA<UnsupportedError>()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('VMServiceFlutterDriver with custom timeout', () {
|
||||
@ -1117,7 +1127,7 @@ void main() {
|
||||
await driver.checkHealth();
|
||||
});
|
||||
|
||||
group('WebFlutterDriver Unimplemented error', () {
|
||||
group('WebFlutterDriver Unimplemented/Unsupported error', () {
|
||||
test('forceGC', () async {
|
||||
expect(driver.forceGC(),
|
||||
throwsA(isA<UnimplementedError>()));
|
||||
|
@ -18,6 +18,7 @@ import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/process.dart';
|
||||
import '../build_info.dart';
|
||||
import '../convert.dart';
|
||||
import '../dart/package_map.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
@ -306,6 +307,7 @@ $ex
|
||||
'DRIVER_SESSION_ID': driver.id,
|
||||
'DRIVER_SESSION_URI': driver.uri.toString(),
|
||||
'DRIVER_SESSION_SPEC': driver.spec.toString(),
|
||||
'DRIVER_SESSION_CAPABILITIES': json.encode(driver.capabilities),
|
||||
'SUPPORT_TIMELINE_ACTION': (browser == Browser.chrome).toString(),
|
||||
'FLUTTER_WEB_TEST': 'true',
|
||||
'ANDROID_CHROME_ON_EMULATOR': (isAndroidChrome && useEmulator).toString(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user