Unverified Commit 4042eb97 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Revert "Flutter Driver - Create widget finders from serialized finders...

Revert "Flutter Driver - Create widget finders from serialized finders extensions (#67456)" (#67687)

This reverts commit 74f6fa45.
parent 74f6fa45
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'find.dart';
/// A factory which creates [Finder]s from [SerializableFinder]s.
mixin CreateFinderFactory {
/// Creates the flutter widget finder from [SerializableFinder].
Finder createFinder(SerializableFinder finder) {
switch (finder.finderType) {
case 'ByText':
return _createByTextFinder(finder as ByText);
case 'ByTooltipMessage':
return _createByTooltipMessageFinder(finder as ByTooltipMessage);
case 'BySemanticsLabel':
return _createBySemanticsLabelFinder(finder as BySemanticsLabel);
case 'ByValueKey':
return _createByValueKeyFinder(finder as ByValueKey);
case 'ByType':
return _createByTypeFinder(finder as ByType);
case 'PageBack':
return _createPageBackFinder();
case 'Ancestor':
return _createAncestorFinder(finder as Ancestor);
case 'Descendant':
return _createDescendantFinder(finder as Descendant);
default:
return null;
}
}
Finder _createByTextFinder(ByText arguments) {
return find.text(arguments.text);
}
Finder _createByTooltipMessageFinder(ByTooltipMessage arguments) {
return find.byElementPredicate((Element element) {
final Widget widget = element.widget;
if (widget is Tooltip) {
return widget.message == arguments.text;
}
return false;
}, description: 'widget with text tooltip "${arguments.text}"');
}
Finder _createBySemanticsLabelFinder(BySemanticsLabel arguments) {
return find.byElementPredicate((Element element) {
if (element is! RenderObjectElement) {
return false;
}
final String semanticsLabel = element.renderObject?.debugSemantics?.label;
if (semanticsLabel == null) {
return false;
}
final Pattern label = arguments.label;
return label is RegExp
? label.hasMatch(semanticsLabel)
: label == semanticsLabel;
}, description: 'widget with semantic label "${arguments.label}"');
}
Finder _createByValueKeyFinder(ByValueKey arguments) {
switch (arguments.keyValueType) {
case 'int':
return find.byKey(ValueKey<int>(arguments.keyValue as int));
case 'String':
return find.byKey(ValueKey<String>(arguments.keyValue as String));
default:
throw 'Unsupported ByValueKey type: ${arguments.keyValueType}';
}
}
Finder _createByTypeFinder(ByType arguments) {
return find.byElementPredicate((Element element) {
return element.widget.runtimeType.toString() == arguments.type;
}, description: 'widget with runtimeType "${arguments.type}"');
}
Finder _createPageBackFinder() {
return find.byElementPredicate((Element element) {
final Widget widget = element.widget;
if (widget is Tooltip) {
return widget.message == 'Back';
}
if (widget is CupertinoNavigationBarBackButton) {
return true;
}
return false;
}, description: 'Material or Cupertino back button');
}
Finder _createAncestorFinder(Ancestor arguments) {
final Finder finder = find.ancestor(
of: createFinder(arguments.of),
matching: createFinder(arguments.matching),
matchRoot: arguments.matchRoot,
);
return arguments.firstMatchOnly ? finder.first : finder;
}
Finder _createDescendantFinder(Descendant arguments) {
final Finder finder = find.descendant(
of: createFinder(arguments.of),
matching: createFinder(arguments.matching),
matchRoot: arguments.matchRoot,
);
return arguments.firstMatchOnly ? finder.first : finder;
}
}
......@@ -24,7 +24,7 @@ mixin DeserializeFinderFactory {
case 'Descendant': return Descendant.deserialize(json, this);
case 'Ancestor': return Ancestor.deserialize(json, this);
}
return null;
throw DriverError('Unsupported search specification type $finderType');
}
}
......
......@@ -4,7 +4,6 @@
import 'dart:async';
import 'package:flutter_driver/src/common/create_finder_factory.dart';
import 'package:meta/meta.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
......@@ -124,7 +123,7 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// return Some(json['title']);
/// }
///
/// Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory) {
/// Finder createFinder(SerializableFinder finder) {
/// Some someFinder = finder as Some;
///
/// return find.byElementPredicate((Element element) {
......@@ -157,13 +156,11 @@ abstract class FinderExtension {
String get finderType;
/// Deserializes the finder from JSON generated by [SerializableFinder.serialize].
/// [finderFactory] could be used to deserialize nested finders.
SerializableFinder deserialize(Map<String, String> params, DeserializeFinderFactory finderFactory);
/// Signature for functions that run the given finder and return the [Element]
/// found, if any, or null otherwise.
/// [finderFactory] could be used to create nested finders.
Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory);
Finder createFinder(SerializableFinder finder);
}
/// The class that manages communication between a Flutter Driver test and the
......@@ -172,7 +169,7 @@ abstract class FinderExtension {
/// This is not normally used directly. It is instantiated automatically when
/// calling [enableFlutterDriverExtension].
@visibleForTesting
class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory {
class FlutterDriverExtension with DeserializeFinderFactory {
/// Creates an object to manage a Flutter Driver connection.
FlutterDriverExtension(
this._requestDataHandler,
......@@ -357,39 +354,112 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
return finder;
}
@override
SerializableFinder deserializeFinder(Map<String, String> json) {
final SerializableFinder standard = super.deserializeFinder(json);
if (standard != null) {
return standard;
Finder _createByTextFinder(ByText arguments) {
return find.text(arguments.text);
}
final String finderType = json['finderType'];
if (_finderExtensions.containsKey(finderType)) {
return _finderExtensions[finderType].deserialize(json, this);
Finder _createByTooltipMessageFinder(ByTooltipMessage arguments) {
return find.byElementPredicate((Element element) {
final Widget widget = element.widget;
if (widget is Tooltip)
return widget.message == arguments.text;
return false;
}, description: 'widget with text tooltip "${arguments.text}"');
}
throw DriverError('Unsupported search specification type $finderType');
Finder _createBySemanticsLabelFinder(BySemanticsLabel arguments) {
return find.byElementPredicate((Element element) {
if (element is! RenderObjectElement) {
return false;
}
final String semanticsLabel = element.renderObject?.debugSemantics?.label;
if (semanticsLabel == null) {
return false;
}
final Pattern label = arguments.label;
return label is RegExp
? label.hasMatch(semanticsLabel)
: label == semanticsLabel;
}, description: 'widget with semantic label "${arguments.label}"');
}
@override
Finder createFinder(SerializableFinder finder) {
final Finder standard = super.createFinder(finder);
if(standard != null) {
return standard;
Finder _createByValueKeyFinder(ByValueKey arguments) {
switch (arguments.keyValueType) {
case 'int':
return find.byKey(ValueKey<int>(arguments.keyValue as int));
case 'String':
return find.byKey(ValueKey<String>(arguments.keyValue as String));
default:
throw 'Unsupported ByValueKey type: ${arguments.keyValueType}';
}
}
if (_finderExtensions.containsKey(finder.finderType)) {
return _finderExtensions[finder.finderType].createFinder(finder, this);
Finder _createByTypeFinder(ByType arguments) {
return find.byElementPredicate((Element element) {
return element.widget.runtimeType.toString() == arguments.type;
}, description: 'widget with runtimeType "${arguments.type}"');
}
Finder _createPageBackFinder() {
return find.byElementPredicate((Element element) {
final Widget widget = element.widget;
if (widget is Tooltip)
return widget.message == 'Back';
if (widget is CupertinoNavigationBarBackButton)
return true;
return false;
}, description: 'Material or Cupertino back button');
}
throw DriverError('Unsupported search specification type ${finder.finderType}');
Finder _createAncestorFinder(Ancestor arguments) {
final Finder finder = find.ancestor(
of: _createFinder(arguments.of),
matching: _createFinder(arguments.matching),
matchRoot: arguments.matchRoot,
);
return arguments.firstMatchOnly ? finder.first : finder;
}
Finder _createDescendantFinder(Descendant arguments) {
final Finder finder = find.descendant(
of: _createFinder(arguments.of),
matching: _createFinder(arguments.matching),
matchRoot: arguments.matchRoot,
);
return arguments.firstMatchOnly ? finder.first : finder;
}
Finder _createFinder(SerializableFinder finder) {
switch (finder.finderType) {
case 'ByText':
return _createByTextFinder(finder as ByText);
case 'ByTooltipMessage':
return _createByTooltipMessageFinder(finder as ByTooltipMessage);
case 'BySemanticsLabel':
return _createBySemanticsLabelFinder(finder as BySemanticsLabel);
case 'ByValueKey':
return _createByValueKeyFinder(finder as ByValueKey);
case 'ByType':
return _createByTypeFinder(finder as ByType);
case 'PageBack':
return _createPageBackFinder();
case 'Ancestor':
return _createAncestorFinder(finder as Ancestor);
case 'Descendant':
return _createDescendantFinder(finder as Descendant);
default:
if (_finderExtensions.containsKey(finder.finderType)) {
return _finderExtensions[finder.finderType].createFinder(finder);
} else {
throw 'Unsupported finder type: ${finder.finderType}';
}
}
}
Future<TapResult> _tap(Command command) async {
final Tap tapCommand = command as Tap;
final Finder computedFinder = await _waitForElement(
createFinder(tapCommand.finder).hitTestable()
_createFinder(tapCommand.finder).hitTestable()
);
await _prober.tap(computedFinder);
return const TapResult();
......@@ -397,13 +467,13 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<WaitForResult> _waitFor(Command command) async {
final WaitFor waitForCommand = command as WaitFor;
await _waitForElement(createFinder(waitForCommand.finder));
await _waitForElement(_createFinder(waitForCommand.finder));
return const WaitForResult();
}
Future<WaitForAbsentResult> _waitForAbsent(Command command) async {
final WaitForAbsent waitForAbsentCommand = command as WaitForAbsent;
await _waitForAbsentElement(createFinder(waitForAbsentCommand.finder));
await _waitForAbsentElement(_createFinder(waitForAbsentCommand.finder));
return const WaitForAbsentResult();
}
......@@ -458,7 +528,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<GetSemanticsIdResult> _getSemanticsId(Command command) async {
final GetSemanticsId semanticsCommand = command as GetSemanticsId;
final Finder target = await _waitForElement(createFinder(semanticsCommand.finder));
final Finder target = await _waitForElement(_createFinder(semanticsCommand.finder));
final Iterable<Element> elements = target.evaluate();
if (elements.length > 1) {
throw StateError('Found more than one element with the same ID: $elements');
......@@ -477,7 +547,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<GetOffsetResult> _getOffset(Command command) async {
final GetOffset getOffsetCommand = command as GetOffset;
final Finder finder = await _waitForElement(createFinder(getOffsetCommand.finder));
final Finder finder = await _waitForElement(_createFinder(getOffsetCommand.finder));
final Element element = finder.evaluate().single;
final RenderBox box = element.renderObject as RenderBox;
Offset localPoint;
......@@ -504,7 +574,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<DiagnosticsTreeResult> _getDiagnosticsTree(Command command) async {
final GetDiagnosticsTree diagnosticsCommand = command as GetDiagnosticsTree;
final Finder finder = await _waitForElement(createFinder(diagnosticsCommand.finder));
final Finder finder = await _waitForElement(_createFinder(diagnosticsCommand.finder));
final Element element = finder.evaluate().single;
DiagnosticsNode diagnosticsNode;
switch (diagnosticsCommand.diagnosticsType) {
......@@ -523,7 +593,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<ScrollResult> _scroll(Command command) async {
final Scroll scrollCommand = command as Scroll;
final Finder target = await _waitForElement(createFinder(scrollCommand.finder));
final Finder target = await _waitForElement(_createFinder(scrollCommand.finder));
final int totalMoves = scrollCommand.duration.inMicroseconds * scrollCommand.frequency ~/ Duration.microsecondsPerSecond;
final Offset delta = Offset(scrollCommand.dx, scrollCommand.dy) / totalMoves.toDouble();
final Duration pause = scrollCommand.duration ~/ totalMoves;
......@@ -544,14 +614,14 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory
Future<ScrollResult> _scrollIntoView(Command command) async {
final ScrollIntoView scrollIntoViewCommand = command as ScrollIntoView;
final Finder target = await _waitForElement(createFinder(scrollIntoViewCommand.finder));
final Finder target = await _waitForElement(_createFinder(scrollIntoViewCommand.finder));
await Scrollable.ensureVisible(target.evaluate().single, duration: const Duration(milliseconds: 100), alignment: scrollIntoViewCommand.alignment ?? 0.0);
return const ScrollResult();
}
Future<GetTextResult> _getText(Command command) async {
final GetText getTextCommand = command as GetText;
final Finder target = await _waitForElement(createFinder(getTextCommand.finder));
final Finder target = await _waitForElement(_createFinder(getTextCommand.finder));
final Widget widget = target.evaluate().single.widget;
String text;
......
......@@ -18,9 +18,6 @@ import 'package:flutter_driver/src/common/wait.dart';
import 'package:flutter_driver/src/extension/extension.dart';
import 'package:flutter_test/flutter_test.dart';
import 'stubs/stub_finder.dart';
import 'stubs/stub_finder_extension.dart';
Future<void> silenceDriverLogger(AsyncCallback callback) async {
final DriverLogCallback oldLogger = driverLog;
driverLog = (String source, String message) { };
......@@ -33,18 +30,18 @@ Future<void> silenceDriverLogger(AsyncCallback callback) async {
void main() {
group('waitUntilNoTransientCallbacks', () {
FlutterDriverExtension driverExtension;
FlutterDriverExtension extension;
Map<String, dynamic> result;
int messageId = 0;
final List<String> log = <String>[];
setUp(() {
result = null;
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false);
extension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false);
});
testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async {
driverExtension.call(const WaitUntilNoTransientCallbacks().serialize())
extension.call(const WaitUntilNoTransientCallbacks().serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -64,7 +61,7 @@ void main() {
// Intentionally blank. We only care about existence of a callback.
});
driverExtension.call(const WaitUntilNoTransientCallbacks().serialize())
extension.call(const WaitUntilNoTransientCallbacks().serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -86,7 +83,7 @@ void main() {
testWidgets('handler', (WidgetTester tester) async {
expect(log, isEmpty);
final Map<String, dynamic> response = await driverExtension.call(const RequestData('hello').serialize());
final Map<String, dynamic> response = await extension.call(const RequestData('hello').serialize());
final RequestDataResult result = RequestDataResult.fromJson(response['response'] as Map<String, dynamic>);
expect(log, <String>['hello']);
expect(result.message, '1');
......@@ -94,18 +91,18 @@ void main() {
});
group('waitForCondition', () {
FlutterDriverExtension driverExtension;
FlutterDriverExtension extension;
Map<String, dynamic> result;
int messageId = 0;
final List<String> log = <String>[];
setUp(() {
result = null;
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false);
extension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false);
});
testWidgets('waiting for NoTransientCallbacks returns immediately when transient callback queue is empty', (WidgetTester tester) async {
driverExtension.call(const WaitForCondition(NoTransientCallbacks()).serialize())
extension.call(const WaitForCondition(NoTransientCallbacks()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -125,7 +122,7 @@ void main() {
// Intentionally blank. We only care about existence of a callback.
});
driverExtension.call(const WaitForCondition(NoTransientCallbacks()).serialize())
extension.call(const WaitForCondition(NoTransientCallbacks()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -147,7 +144,7 @@ void main() {
testWidgets('waiting for NoPendingFrame returns immediately when frame is synced', (
WidgetTester tester) async {
driverExtension.call(const WaitForCondition(NoPendingFrame()).serialize())
extension.call(const WaitForCondition(NoPendingFrame()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -165,7 +162,7 @@ void main() {
testWidgets('waiting for NoPendingFrame returns until no pending scheduled frame', (WidgetTester tester) async {
SchedulerBinding.instance.scheduleFrame();
driverExtension.call(const WaitForCondition(NoPendingFrame()).serialize())
extension.call(const WaitForCondition(NoPendingFrame()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -189,7 +186,7 @@ void main() {
'waiting for combined conditions returns immediately', (WidgetTester tester) async {
const SerializableWaitCondition combinedCondition =
CombinedCondition(<SerializableWaitCondition>[NoTransientCallbacks(), NoPendingFrame()]);
driverExtension.call(const WaitForCondition(combinedCondition).serialize())
extension.call(const WaitForCondition(combinedCondition).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -213,7 +210,7 @@ void main() {
const SerializableWaitCondition combinedCondition =
CombinedCondition(<SerializableWaitCondition>[NoTransientCallbacks(), NoPendingFrame()]);
driverExtension.call(const WaitForCondition(combinedCondition).serialize())
extension.call(const WaitForCondition(combinedCondition).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -242,7 +239,7 @@ void main() {
const SerializableWaitCondition combinedCondition =
CombinedCondition(<SerializableWaitCondition>[NoPendingFrame(), NoTransientCallbacks()]);
driverExtension.call(const WaitForCondition(combinedCondition).serialize())
extension.call(const WaitForCondition(combinedCondition).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -264,7 +261,7 @@ void main() {
testWidgets(
"waiting for NoPendingPlatformMessages returns immediately when there're no platform messages", (WidgetTester tester) async {
driverExtension
extension
.call(const WaitForCondition(NoPendingPlatformMessages()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
......@@ -292,7 +289,7 @@ void main() {
});
channel.invokeMethod<String>('sayHello', 'hello');
driverExtension
extension
.call(const WaitForCondition(NoPendingPlatformMessages()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
......@@ -337,7 +334,7 @@ void main() {
channel1.invokeMethod<String>('sayHello', 'hello');
channel2.invokeMethod<String>('sayHello', 'hello');
driverExtension
extension
.call(const WaitForCondition(NoPendingPlatformMessages()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
......@@ -386,7 +383,7 @@ void main() {
channel1.invokeMethod<String>('sayHello', 'hello');
// Calls the waiting API before the second channel message is sent.
driverExtension
extension
.call(const WaitForCondition(NoPendingPlatformMessages()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
......@@ -436,7 +433,7 @@ void main() {
channel1.invokeMethod<String>('sayHello', 'hello');
driverExtension
extension
.call(const WaitForCondition(NoPendingPlatformMessages()).serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
......@@ -465,9 +462,9 @@ void main() {
});
group('getSemanticsId', () {
FlutterDriverExtension driverExtension;
FlutterDriverExtension extension;
setUp(() {
driverExtension = FlutterDriverExtension((String arg) async => '', true);
extension = FlutterDriverExtension((String arg) async => '', true);
});
testWidgets('works when semantics are enabled', (WidgetTester tester) async {
......@@ -476,7 +473,7 @@ void main() {
const Text('hello', textDirection: TextDirection.ltr));
final Map<String, String> arguments = GetSemanticsId(const ByText('hello')).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
final GetSemanticsIdResult result = GetSemanticsIdResult.fromJson(response['response'] as Map<String, dynamic>);
expect(result.id, 1);
......@@ -488,7 +485,7 @@ void main() {
const Text('hello', textDirection: TextDirection.ltr));
final Map<String, String> arguments = GetSemanticsId(const ByText('hello')).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
expect(response['isError'], true);
expect(response['response'], contains('Bad state: No semantics data found'));
......@@ -507,7 +504,7 @@ void main() {
);
final Map<String, String> arguments = GetSemanticsId(const ByText('hello')).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
expect(response['isError'], true);
expect(response['response'], contains('Bad state: Found more than one element with the same ID'));
......@@ -516,11 +513,11 @@ void main() {
});
testWidgets('getOffset', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<Offset> getOffset(OffsetType offset) async {
final Map<String, String> arguments = GetOffset(ByValueKey(1), offset).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
final GetOffsetResult result = GetOffsetResult.fromJson(response['response'] as Map<String, dynamic>);
return Offset(result.dx, result.dy);
}
......@@ -548,11 +545,11 @@ void main() {
testWidgets('getText', (WidgetTester tester) async {
await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<String> getTextInternal(SerializableFinder search) async {
final Map<String, String> arguments = GetText(search, timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> result = await driverExtension.call(arguments);
final Map<String, dynamic> result = await extension.call(arguments);
if (result['isError'] as bool) {
return null;
}
......@@ -610,7 +607,7 @@ void main() {
// Check if error thrown for other types
final Map<String, String> arguments = GetText(ByValueKey('column'), timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
expect(response['isError'], true);
expect(response['response'], contains('is currently not supported by getText'));
});
......@@ -618,7 +615,7 @@ void main() {
testWidgets('descendant finder', (WidgetTester tester) async {
await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<String> getDescendantText({ String of, bool matchRoot = false}) async {
final Map<String, String> arguments = GetText(Descendant(
......@@ -626,7 +623,7 @@ void main() {
matching: ByValueKey('text2'),
matchRoot: matchRoot,
), timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> result = await driverExtension.call(arguments);
final Map<String, dynamic> result = await extension.call(arguments);
if (result['isError'] as bool) {
return null;
}
......@@ -663,7 +660,7 @@ void main() {
testWidgets('descendant finder firstMatchOnly', (WidgetTester tester) async {
await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<String> getDescendantText() async {
final Map<String, String> arguments = GetText(Descendant(
......@@ -671,7 +668,7 @@ void main() {
matching: const ByType('Text'),
firstMatchOnly: true,
), timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> result = await driverExtension.call(arguments);
final Map<String, dynamic> result = await extension.call(arguments);
if (result['isError'] as bool) {
return null;
}
......@@ -697,7 +694,7 @@ void main() {
testWidgets('ancestor finder', (WidgetTester tester) async {
await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<Offset> getAncestorTopLeft({ String of, String matching, bool matchRoot = false}) async {
final Map<String, String> arguments = GetOffset(Ancestor(
......@@ -705,7 +702,7 @@ void main() {
matching: ByValueKey(matching),
matchRoot: matchRoot,
), OffsetType.topLeft, timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
if (response['isError'] as bool) {
return null;
}
......@@ -767,7 +764,7 @@ void main() {
testWidgets('ancestor finder firstMatchOnly', (WidgetTester tester) async {
await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<Offset> getAncestorTopLeft() async {
final Map<String, String> arguments = GetOffset(Ancestor(
......@@ -775,7 +772,7 @@ void main() {
matching: const ByType('Container'),
firstMatchOnly: true,
), OffsetType.topLeft, timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
if (response['isError'] as bool) {
return null;
}
......@@ -815,11 +812,11 @@ void main() {
});
testWidgets('GetDiagnosticsTree', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true);
final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true);
Future<Map<String, Object>> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async {
final Map<String, String> arguments = GetDiagnosticsTree(finder, type, subtreeDepth: depth, includeProperties: properties).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
final Map<String, dynamic> response = await extension.call(arguments);
final DiagnosticsTreeResult result = DiagnosticsTreeResult(response['response'] as Map<String, dynamic>);
return result.json;
}
......@@ -880,120 +877,18 @@ void main() {
expect(children.single['children'], isEmpty);
});
group('extension finders', () {
final Widget debugTree = Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Column(
key: const ValueKey<String>('Column'),
children: <Widget>[
const Text('Foo', key: ValueKey<String>('Text1')),
const Text('Bar', key: ValueKey<String>('Text2')),
FlatButton(
child: const Text('Whatever'),
key: const ValueKey<String>('Button'),
onPressed: () {},
),
],
),
),
);
testWidgets('unknown extension finder', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '',
true,
finders: <FinderExtension>[],
);
Future<Map<String, dynamic>> getText(SerializableFinder finder) async {
final Map<String, String> arguments = GetText(finder, timeout: const Duration(seconds: 1)).serialize();
return await driverExtension.call(arguments);
}
await tester.pumpWidget(debugTree);
final Map<String, dynamic> result = await getText(StubFinder('Text1'));
expect(result['isError'], true);
expect(result['response'] is String, true);
expect(result['response'] as String, contains('Unsupported search specification type Stub'));
});
testWidgets('simple extension finder', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '',
true,
finders: <FinderExtension>[
StubFinderExtension(),
],
);
Future<GetTextResult> getText(SerializableFinder finder) async {
final Map<String, String> arguments = GetText(finder, timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
return GetTextResult.fromJson(response['response'] as Map<String, dynamic>);
}
await tester.pumpWidget(debugTree);
final GetTextResult result = await getText(StubFinder('Text1'));
expect(result.text, 'Foo');
});
testWidgets('complex extension finder', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '',
true,
finders: <FinderExtension>[
StubFinderExtension(),
],
);
Future<GetTextResult> getText(SerializableFinder finder) async {
final Map<String, String> arguments = GetText(finder, timeout: const Duration(seconds: 1)).serialize();
final Map<String, dynamic> response = await driverExtension.call(arguments);
return GetTextResult.fromJson(response['response'] as Map<String, dynamic>);
}
await tester.pumpWidget(debugTree);
final GetTextResult result = await getText(Descendant(of: StubFinder('Column'), matching: StubFinder('Text1')));
expect(result.text, 'Foo');
});
testWidgets('extension finder with command', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '',
true,
finders: <FinderExtension>[
StubFinderExtension(),
],
);
Future<Map<String, dynamic>> tap(SerializableFinder finder) async {
final Map<String, String> arguments = Tap(finder, timeout: const Duration(seconds: 1)).serialize();
return await driverExtension.call(arguments);
}
await tester.pumpWidget(debugTree);
final Map<String, dynamic> result = await tap(StubFinder('Button'));
expect(result['isError'], false);
});
});
group('waitUntilFrameSync', () {
FlutterDriverExtension driverExtension;
FlutterDriverExtension extension;
Map<String, dynamic> result;
setUp(() {
driverExtension = FlutterDriverExtension((String arg) async => '', true);
extension = FlutterDriverExtension((String arg) async => '', true);
result = null;
});
testWidgets('returns immediately when frame is synced', (
WidgetTester tester) async {
driverExtension.call(const WaitUntilNoPendingFrame().serialize())
extension.call(const WaitUntilNoPendingFrame().serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -1014,7 +909,7 @@ void main() {
// Intentionally blank. We only care about existence of a callback.
});
driverExtension.call(const WaitUntilNoPendingFrame().serialize())
extension.call(const WaitUntilNoPendingFrame().serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......@@ -1038,7 +933,7 @@ void main() {
'waits until no pending scheduled frame', (WidgetTester tester) async {
SchedulerBinding.instance.scheduleFrame();
driverExtension.call(const WaitUntilNoPendingFrame().serialize())
extension.call(const WaitUntilNoPendingFrame().serialize())
.then<void>(expectAsync1((Map<String, dynamic> r) {
result = r;
}));
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_driver/flutter_driver.dart';
class StubFinder extends SerializableFinder {
StubFinder(this.keyString);
final String keyString;
@override
String get finderType => 'Stub';
@override
Map<String, String> serialize() {
return super.serialize()..addAll(<String, String>{'keyString': keyString});
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter_driver/src/common/create_finder_factory.dart';
import 'package:flutter_test/src/finders.dart';
import 'package:flutter_driver/src/common/find.dart';
import 'stub_finder.dart';
class StubFinderExtension extends FinderExtension {
@override
Finder createFinder(
SerializableFinder finder,
CreateFinderFactory finderFactory,
) {
return find.byWidgetPredicate((Widget widget) {
final Key key = widget.key;
if (key is! ValueKey<String>) {
return false;
}
return (key as ValueKey<String>).value == (finder as StubFinder).keyString;
});
}
@override
SerializableFinder deserialize(
Map<String, String> params,
DeserializeFinderFactory finderFactory,
) {
return StubFinder(params['keyString']);
}
@override
String get finderType => 'Stub';
}
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