diff --git a/packages/flutter_driver/lib/src/common/diagnostics_tree.dart b/packages/flutter_driver/lib/src/common/diagnostics_tree.dart index 595cb8cee0c..496bce5e7fe 100644 --- a/packages/flutter_driver/lib/src/common/diagnostics_tree.dart +++ b/packages/flutter_driver/lib/src/common/diagnostics_tree.dart @@ -33,11 +33,11 @@ class GetDiagnosticsTree extends CommandWithTarget { super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - GetDiagnosticsTree.deserialize(Map json) + GetDiagnosticsTree.deserialize(Map json, DeserializeFinderFactory finderFactory) : subtreeDepth = int.parse(json['subtreeDepth']), includeProperties = json['includeProperties'] == 'true', diagnosticsType = _diagnosticsTypeIndex.lookupBySimpleName(json['diagnosticsType']), - super.deserialize(json); + super.deserialize(json, finderFactory); /// How many levels of children to include in the JSON result. /// diff --git a/packages/flutter_driver/lib/src/common/find.dart b/packages/flutter_driver/lib/src/common/find.dart index 93e88f9b5d4..cdeeadef6d4 100644 --- a/packages/flutter_driver/lib/src/common/find.dart +++ b/packages/flutter_driver/lib/src/common/find.dart @@ -9,6 +9,25 @@ import 'package:meta/meta.dart'; import 'error.dart'; import 'message.dart'; +/// A factory for deserializing [Finder]s. +mixin DeserializeFinderFactory { + /// Deserializes the finder from JSON generated by [SerializableFinder.serialize]. + SerializableFinder deserializeFinder(Map json) { + final String finderType = json['finderType']; + switch (finderType) { + case 'ByType': return ByType.deserialize(json); + case 'ByValueKey': return ByValueKey.deserialize(json); + case 'ByTooltipMessage': return ByTooltipMessage.deserialize(json); + case 'BySemanticsLabel': return BySemanticsLabel.deserialize(json); + case 'ByText': return ByText.deserialize(json); + case 'PageBack': return const PageBack(); + case 'Descendant': return Descendant.deserialize(json, this); + case 'Ancestor': return Ancestor.deserialize(json, this); + } + throw DriverError('Unsupported search specification type $finderType'); + } +} + const List _supportedKeyValueTypes = [String, int]; DriverError _createInvalidKeyValueTypeError(String invalidType) { @@ -28,8 +47,8 @@ abstract class CommandWithTarget extends Command { } /// Deserializes this command from the value generated by [serialize]. - CommandWithTarget.deserialize(Map json) - : finder = SerializableFinder.deserialize(json), + CommandWithTarget.deserialize(Map json, DeserializeFinderFactory finderFactory) + : finder = finderFactory.deserializeFinder(json), super.deserialize(json); /// Locates the object or objects targeted by this command. @@ -58,7 +77,7 @@ class WaitFor extends CommandWithTarget { : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - WaitFor.deserialize(Map json) : super.deserialize(json); + WaitFor.deserialize(Map json, DeserializeFinderFactory finderFactory) : super.deserialize(json, finderFactory); @override String get kind => 'waitFor'; @@ -88,7 +107,7 @@ class WaitForAbsent extends CommandWithTarget { : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - WaitForAbsent.deserialize(Map json) : super.deserialize(json); + WaitForAbsent.deserialize(Map json, DeserializeFinderFactory finderFactory) : super.deserialize(json, finderFactory); @override String get kind => 'waitForAbsent'; @@ -126,22 +145,6 @@ abstract class SerializableFinder { Map serialize() => { 'finderType': finderType, }; - - /// Deserializes a finder from JSON generated by [serialize]. - static SerializableFinder deserialize(Map json) { - final String finderType = json['finderType']; - switch (finderType) { - case 'ByType': return ByType.deserialize(json); - case 'ByValueKey': return ByValueKey.deserialize(json); - case 'ByTooltipMessage': return ByTooltipMessage.deserialize(json); - case 'BySemanticsLabel': return BySemanticsLabel.deserialize(json); - case 'ByText': return ByText.deserialize(json); - case 'PageBack': return const PageBack(); - case 'Descendant': return Descendant.deserialize(json); - case 'Ancestor': return Ancestor.deserialize(json); - } - throw DriverError('Unsupported search specification type $finderType'); - } } /// A Flutter Driver finder that finds widgets by tooltip text. @@ -349,14 +352,14 @@ class Descendant extends SerializableFinder { } /// Deserializes the finder from JSON generated by [serialize]. - static Descendant deserialize(Map json) { + static Descendant deserialize(Map json, DeserializeFinderFactory finderFactory) { final Map jsonOfMatcher = Map.from(jsonDecode(json['of']) as Map); final Map jsonMatchingMatcher = Map.from(jsonDecode(json['matching']) as Map); return Descendant( - of: SerializableFinder.deserialize(jsonOfMatcher), - matching: SerializableFinder.deserialize(jsonMatchingMatcher), + of: finderFactory.deserializeFinder(jsonOfMatcher), + matching: finderFactory.deserializeFinder(jsonMatchingMatcher), matchRoot: json['matchRoot'] == 'true', firstMatchOnly: json['firstMatchOnly'] == 'true', ); @@ -404,14 +407,14 @@ class Ancestor extends SerializableFinder { } /// Deserializes the finder from JSON generated by [serialize]. - static Ancestor deserialize(Map json) { + static Ancestor deserialize(Map json, DeserializeFinderFactory finderFactory) { final Map jsonOfMatcher = Map.from(jsonDecode(json['of']) as Map); final Map jsonMatchingMatcher = Map.from(jsonDecode(json['matching']) as Map); return Ancestor( - of: SerializableFinder.deserialize(jsonOfMatcher), - matching: SerializableFinder.deserialize(jsonMatchingMatcher), + of: finderFactory.deserializeFinder(jsonOfMatcher), + matching: finderFactory.deserializeFinder(jsonMatchingMatcher), matchRoot: json['matchRoot'] == 'true', firstMatchOnly: json['firstMatchOnly'] == 'true', ); @@ -436,8 +439,8 @@ class GetSemanticsId extends CommandWithTarget { GetSemanticsId(SerializableFinder finder, {Duration timeout}) : super(finder, timeout: timeout); /// Creates a command from a JSON map. - GetSemanticsId.deserialize(Map json) - : super.deserialize(json); + GetSemanticsId.deserialize(Map json, DeserializeFinderFactory finderFactory) + : super.deserialize(json, finderFactory); @override String get kind => 'get_semantics_id'; diff --git a/packages/flutter_driver/lib/src/common/geometry.dart b/packages/flutter_driver/lib/src/common/geometry.dart index 1ecc50b4f4b..3aea6f1b119 100644 --- a/packages/flutter_driver/lib/src/common/geometry.dart +++ b/packages/flutter_driver/lib/src/common/geometry.dart @@ -36,9 +36,9 @@ class GetOffset extends CommandWithTarget { GetOffset(SerializableFinder finder, this.offsetType, { Duration timeout }) : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - GetOffset.deserialize(Map json) + GetOffset.deserialize(Map json, DeserializeFinderFactory finderFactory) : offsetType = _offsetTypeIndex.lookupBySimpleName(json['offsetType']), - super.deserialize(json); + super.deserialize(json, finderFactory); @override Map serialize() => super.serialize()..addAll({ diff --git a/packages/flutter_driver/lib/src/common/gesture.dart b/packages/flutter_driver/lib/src/common/gesture.dart index a5e722e1ce7..8d652c3fc25 100644 --- a/packages/flutter_driver/lib/src/common/gesture.dart +++ b/packages/flutter_driver/lib/src/common/gesture.dart @@ -11,7 +11,7 @@ class Tap extends CommandWithTarget { Tap(SerializableFinder finder, { Duration timeout }) : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - Tap.deserialize(Map json) : super.deserialize(json); + Tap.deserialize(Map json, DeserializeFinderFactory finderFactory) : super.deserialize(json, finderFactory); @override String get kind => 'tap'; @@ -46,12 +46,12 @@ class Scroll extends CommandWithTarget { }) : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - Scroll.deserialize(Map json) + Scroll.deserialize(Map json, DeserializeFinderFactory finderFactory) : dx = double.parse(json['dx']), dy = double.parse(json['dy']), duration = Duration(microseconds: int.parse(json['duration'])), frequency = int.parse(json['frequency']), - super.deserialize(json); + super.deserialize(json, finderFactory); /// Delta X offset per move event. final double dx; @@ -99,9 +99,9 @@ class ScrollIntoView extends CommandWithTarget { ScrollIntoView(SerializableFinder finder, { this.alignment = 0.0, Duration timeout }) : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - ScrollIntoView.deserialize(Map json) + ScrollIntoView.deserialize(Map json, DeserializeFinderFactory finderFactory) : alignment = double.parse(json['alignment']), - super.deserialize(json); + super.deserialize(json, finderFactory); /// How the widget should be aligned. /// diff --git a/packages/flutter_driver/lib/src/common/text.dart b/packages/flutter_driver/lib/src/common/text.dart index edec6a244b7..7d60139d8cf 100644 --- a/packages/flutter_driver/lib/src/common/text.dart +++ b/packages/flutter_driver/lib/src/common/text.dart @@ -11,7 +11,7 @@ class GetText extends CommandWithTarget { GetText(SerializableFinder finder, { Duration timeout }) : super(finder, timeout: timeout); /// Deserializes this command from the value generated by [serialize]. - GetText.deserialize(Map json) : super.deserialize(json); + GetText.deserialize(Map json, DeserializeFinderFactory finderFactory) : super.deserialize(json, finderFactory); @override String get kind => 'get_text'; diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 135c888694a..530599a2c64 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart @@ -43,15 +43,16 @@ const String _extensionMethod = 'ext.flutter.$_extensionMethodName'; typedef DataHandler = Future Function(String message); class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { - _DriverBinding(this._handler, this._silenceErrors); + _DriverBinding(this._handler, this._silenceErrors, this.finders); final DataHandler _handler; final bool _silenceErrors; + final List finders; @override void initServiceExtensions() { super.initServiceExtensions(); - final FlutterDriverExtension extension = FlutterDriverExtension(_handler, _silenceErrors); + final FlutterDriverExtension extension = FlutterDriverExtension(_handler, _silenceErrors, finders); registerServiceExtension( name: _extensionMethodName, callback: extension.call, @@ -86,9 +87,59 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, /// for tests where exceptions are expected. Defaults to false. Any errors /// will still be returned in the `response` field of the result JSON along /// with an `isError` boolean. -void enableFlutterDriverExtension({ DataHandler handler, bool silenceErrors = false }) { +/// +/// The `finders` parameter are used to add custom finders, as in the following example. +/// +/// ```dart main +/// void main() { +/// enableFlutterDriverExtension(finders: [ SomeFinderExtension() ]); +/// +/// app.main(); +/// } +/// ``` +/// +/// ```dart +/// class Some extends SerializableFinder { +/// const Some(this.title); +/// +/// final String title; +/// +/// @override +/// String get finderType => 'Some'; +/// +/// @override +/// Map serialize() => super.serialize()..addAll({ +/// 'title': title, +/// }); +/// } +/// ``` +/// +/// ```dart +/// class SomeFinderExtension extends FinderExtension { +/// +/// String get finderType => 'Some'; +/// +/// SerializableFinder deserialize(Map params, DeserializeFinderFactory finderFactory) { +/// return Some(json['title']); +/// } +/// +/// Finder createFinder(SerializableFinder finder) { +/// Some someFinder = finder as Some; +/// +/// return find.byElementPredicate((Element element) { +/// final Widget widget = element.widget; +/// if (element.widget is SomeWidget) { +/// return element.widget.title == someFinder.title; +/// } +/// return false; +/// }); +/// } +/// } +/// ``` +/// +void enableFlutterDriverExtension({ DataHandler handler, bool silenceErrors = false, List finders}) { assert(WidgetsBinding.instance == null); - _DriverBinding(handler, silenceErrors); + _DriverBinding(handler, silenceErrors, finders ?? []); assert(WidgetsBinding.instance is _DriverBinding); } @@ -98,9 +149,19 @@ typedef CommandHandlerCallback = Future Function(Command c); /// Signature for functions that deserialize a JSON map to a command object. typedef CommandDeserializerCallback = Command Function(Map params); -/// Signature for functions that run the given finder and return the [Element] -/// found, if any, or null otherwise. -typedef FinderConstructor = Finder Function(SerializableFinder finder); +/// Used to expand the new Finder +abstract class FinderExtension { + + /// Identifies the type of finder to be used by the driver extension. + String get finderType; + + /// Deserializes the finder from JSON generated by [SerializableFinder.serialize]. + SerializableFinder deserialize(Map params, DeserializeFinderFactory finderFactory); + + /// Signature for functions that run the given finder and return the [Element] + /// found, if any, or null otherwise. + Finder createFinder(SerializableFinder finder); +} /// The class that manages communication between a Flutter Driver test and the /// application being remote-controlled, on the application side. @@ -108,9 +169,9 @@ typedef FinderConstructor = Finder Function(SerializableFinder finder); /// This is not normally used directly. It is instantiated automatically when /// calling [enableFlutterDriverExtension]. @visibleForTesting -class FlutterDriverExtension { +class FlutterDriverExtension with DeserializeFinderFactory { /// Creates an object to manage a Flutter Driver connection. - FlutterDriverExtension(this._requestDataHandler, this._silenceErrors) { + FlutterDriverExtension(this._requestDataHandler, this._silenceErrors, List finders) { _testTextInput.register(); _commandHandlers.addAll({ @@ -142,35 +203,28 @@ class FlutterDriverExtension { 'get_layer_tree': (Map params) => GetLayerTree.deserialize(params), 'get_render_tree': (Map params) => GetRenderTree.deserialize(params), 'enter_text': (Map params) => EnterText.deserialize(params), - 'get_text': (Map params) => GetText.deserialize(params), + 'get_text': (Map params) => GetText.deserialize(params, this), 'request_data': (Map params) => RequestData.deserialize(params), - 'scroll': (Map params) => Scroll.deserialize(params), - 'scrollIntoView': (Map params) => ScrollIntoView.deserialize(params), + 'scroll': (Map params) => Scroll.deserialize(params, this), + 'scrollIntoView': (Map params) => ScrollIntoView.deserialize(params, this), 'set_frame_sync': (Map params) => SetFrameSync.deserialize(params), 'set_semantics': (Map params) => SetSemantics.deserialize(params), 'set_text_entry_emulation': (Map params) => SetTextEntryEmulation.deserialize(params), - 'tap': (Map params) => Tap.deserialize(params), - 'waitFor': (Map params) => WaitFor.deserialize(params), - 'waitForAbsent': (Map params) => WaitForAbsent.deserialize(params), + 'tap': (Map params) => Tap.deserialize(params, this), + 'waitFor': (Map params) => WaitFor.deserialize(params, this), + 'waitForAbsent': (Map params) => WaitForAbsent.deserialize(params, this), 'waitForCondition': (Map params) => WaitForCondition.deserialize(params), 'waitUntilNoTransientCallbacks': (Map params) => WaitUntilNoTransientCallbacks.deserialize(params), 'waitUntilNoPendingFrame': (Map params) => WaitUntilNoPendingFrame.deserialize(params), 'waitUntilFirstFrameRasterized': (Map params) => WaitUntilFirstFrameRasterized.deserialize(params), - 'get_semantics_id': (Map params) => GetSemanticsId.deserialize(params), - 'get_offset': (Map params) => GetOffset.deserialize(params), - 'get_diagnostics_tree': (Map params) => GetDiagnosticsTree.deserialize(params), + 'get_semantics_id': (Map params) => GetSemanticsId.deserialize(params, this), + 'get_offset': (Map params) => GetOffset.deserialize(params, this), + 'get_diagnostics_tree': (Map params) => GetDiagnosticsTree.deserialize(params, this), }); - _finders.addAll({ - 'ByText': (SerializableFinder finder) => _createByTextFinder(finder as ByText), - 'ByTooltipMessage': (SerializableFinder finder) => _createByTooltipMessageFinder(finder as ByTooltipMessage), - 'BySemanticsLabel': (SerializableFinder finder) => _createBySemanticsLabelFinder(finder as BySemanticsLabel), - 'ByValueKey': (SerializableFinder finder) => _createByValueKeyFinder(finder as ByValueKey), - 'ByType': (SerializableFinder finder) => _createByTypeFinder(finder as ByType), - 'PageBack': (SerializableFinder finder) => _createPageBackFinder(), - 'Ancestor': (SerializableFinder finder) => _createAncestorFinder(finder as Ancestor), - 'Descendant': (SerializableFinder finder) => _createDescendantFinder(finder as Descendant), - }); + for(final FinderExtension finder in finders) { + _finderExtensions[finder.finderType] = finder; + } } final TestTextInput _testTextInput = TestTextInput(); @@ -185,7 +239,7 @@ class FlutterDriverExtension { final WidgetController _prober = LiveWidgetController(WidgetsBinding.instance); final Map _commandHandlers = {}; final Map _commandDeserializers = {}; - final Map _finders = {}; + final Map _finderExtensions = {}; /// With [_frameSync] enabled, Flutter Driver will wait to perform an action /// until there are no pending frames in the app under test. @@ -372,12 +426,30 @@ class FlutterDriverExtension { } Finder _createFinder(SerializableFinder finder) { - final FinderConstructor constructor = _finders[finder.finderType]; - - if (constructor == null) - throw 'Unsupported finder type: ${finder.finderType}'; - - return constructor(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 _tap(Command command) async { diff --git a/packages/flutter_driver/test/src/real_tests/extension_test.dart b/packages/flutter_driver/test/src/real_tests/extension_test.dart index b00abea68bd..f251f71ee36 100644 --- a/packages/flutter_driver/test/src/real_tests/extension_test.dart +++ b/packages/flutter_driver/test/src/real_tests/extension_test.dart @@ -37,7 +37,7 @@ void main() { setUp(() { result = null; - extension = 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 { @@ -98,7 +98,7 @@ void main() { setUp(() { result = null; - extension = 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 { @@ -464,7 +464,7 @@ void main() { group('getSemanticsId', () { FlutterDriverExtension extension; setUp(() { - extension = FlutterDriverExtension((String arg) async => '', true); + extension = FlutterDriverExtension((String arg) async => '', true, []); }); testWidgets('works when semantics are enabled', (WidgetTester tester) async { @@ -513,7 +513,7 @@ void main() { }); testWidgets('getOffset', (WidgetTester tester) async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getOffset(OffsetType offset) async { final Map arguments = GetOffset(ByValueKey(1), offset).serialize(); @@ -545,7 +545,7 @@ void main() { testWidgets('getText', (WidgetTester tester) async { await silenceDriverLogger(() async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getTextInternal(SerializableFinder search) async { final Map arguments = GetText(search, timeout: const Duration(seconds: 1)).serialize(); @@ -615,7 +615,7 @@ void main() { testWidgets('descendant finder', (WidgetTester tester) async { await silenceDriverLogger(() async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getDescendantText({ String of, bool matchRoot = false}) async { final Map arguments = GetText(Descendant( @@ -660,7 +660,7 @@ void main() { testWidgets('descendant finder firstMatchOnly', (WidgetTester tester) async { await silenceDriverLogger(() async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getDescendantText() async { final Map arguments = GetText(Descendant( @@ -694,7 +694,7 @@ void main() { testWidgets('ancestor finder', (WidgetTester tester) async { await silenceDriverLogger(() async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getAncestorTopLeft({ String of, String matching, bool matchRoot = false}) async { final Map arguments = GetOffset(Ancestor( @@ -764,7 +764,7 @@ void main() { testWidgets('ancestor finder firstMatchOnly', (WidgetTester tester) async { await silenceDriverLogger(() async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future getAncestorTopLeft() async { final Map arguments = GetOffset(Ancestor( @@ -812,7 +812,7 @@ void main() { }); testWidgets('GetDiagnosticsTree', (WidgetTester tester) async { - final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true); + final FlutterDriverExtension extension = FlutterDriverExtension((String arg) async => '', true, []); Future> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async { final Map arguments = GetDiagnosticsTree(finder, type, subtreeDepth: depth, includeProperties: properties).serialize(); @@ -882,7 +882,7 @@ void main() { Map result; setUp(() { - extension = FlutterDriverExtension((String arg) async => '', true); + extension = FlutterDriverExtension((String arg) async => '', true, []); result = null; }); diff --git a/packages/flutter_driver/test/src/real_tests/find_test.dart b/packages/flutter_driver/test/src/real_tests/find_test.dart index b2407e376d1..f50a32b2a3f 100644 --- a/packages/flutter_driver/test/src/real_tests/find_test.dart +++ b/packages/flutter_driver/test/src/real_tests/find_test.dart @@ -2,11 +2,15 @@ // 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'; import 'package:flutter_driver/src/common/find.dart'; +import 'package:mockito/mockito.dart'; import '../../common.dart'; void main() { + final MockDeserialize mockDeserialize = MockDeserialize(); + test('Ancestor finder serialize', () { const SerializableFinder of = ByType('Text'); final SerializableFinder matching = ByValueKey('hello'); @@ -35,7 +39,7 @@ void main() { 'firstMatchOnly': 'true', }; - final Ancestor a = Ancestor.deserialize(serialized); + final Ancestor a = Ancestor.deserialize(serialized, mockDeserialize); expect(a.of, isA()); expect(a.matching, isA()); expect(a.matchRoot, isTrue); @@ -70,10 +74,12 @@ void main() { 'firstMatchOnly': 'true', }; - final Descendant a = Descendant.deserialize(serialized); + final Descendant a = Descendant.deserialize(serialized, mockDeserialize); expect(a.of, isA()); expect(a.matching, isA()); expect(a.matchRoot, isTrue); expect(a.firstMatchOnly, isTrue); }); } + +class MockDeserialize with Mock, DeserializeFinderFactory { }