Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
32aa3128
Unverified
Commit
32aa3128
authored
Aug 15, 2023
by
Michael Goderbauer
Committed by
GitHub
Aug 15, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Analyze code snippets in flutter_driver docs (#132337)
parent
33b66f64
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
144 additions
and
102 deletions
+144
-102
analyze_snippet_code.dart
dev/bots/analyze_snippet_code.dart
+35
-14
custom_imports_broken.dart
...nalyze-snippet-code-test-input/custom_imports_broken.dart
+21
-0
analyze_snippet_code_test.dart
dev/bots/test/analyze_snippet_code_test.dart
+3
-2
driver.dart
packages/flutter_driver/lib/src/driver/driver.dart
+7
-2
gc_summarizer.dart
packages/flutter_driver/lib/src/driver/gc_summarizer.dart
+1
-1
profiling_summarizer.dart
...s/flutter_driver/lib/src/driver/profiling_summarizer.dart
+1
-1
raster_cache_summarizer.dart
...lutter_driver/lib/src/driver/raster_cache_summarizer.dart
+1
-1
scene_display_lag_summarizer.dart
...r_driver/lib/src/driver/scene_display_lag_summarizer.dart
+1
-1
extension.dart
packages/flutter_driver/lib/src/extension/extension.dart
+74
-80
No files found.
dev/bots/analyze_snippet_code.dart
View file @
32aa3128
...
...
@@ -55,10 +55,12 @@
//
// At the top of a file you can say `// Examples can assume:` and then list some
// commented-out declarations that will be included in the analysis for snippets
// in that file.
// in that file.
This section may also contain explicit import statements.
//
// Snippets generally import all the main Flutter packages (including material
// and flutter_test), as well as most core Dart packages with the usual prefixes.
// For files without an `// Examples can assume:` section or if that section
// contains no explicit imports, the snippets will implicitly import all the
// main Flutter packages (including material and flutter_test), as well as most
// core Dart packages with the usual prefixes.
import
'dart:async'
;
import
'dart:convert'
;
...
...
@@ -72,6 +74,7 @@ import 'package:watcher/watcher.dart';
final
String
_flutterRoot
=
path
.
dirname
(
path
.
dirname
(
path
.
dirname
(
path
.
fromUri
(
Platform
.
script
))));
final
String
_packageFlutter
=
path
.
join
(
_flutterRoot
,
'packages'
,
'flutter'
,
'lib'
);
final
String
_packageFlutterTest
=
path
.
join
(
_flutterRoot
,
'packages'
,
'flutter_test'
,
'lib'
);
final
String
_packageFlutterDriver
=
path
.
join
(
_flutterRoot
,
'packages'
,
'flutter_driver'
,
'lib'
);
final
String
_packageIntegrationTest
=
path
.
join
(
_flutterRoot
,
'packages'
,
'integration_test'
,
'lib'
);
final
String
_defaultDartUiLocation
=
path
.
join
(
_flutterRoot
,
'bin'
,
'cache'
,
'pkg'
,
'sky_engine'
,
'lib'
,
'ui'
);
final
String
_flutter
=
path
.
join
(
_flutterRoot
,
'bin'
,
Platform
.
isWindows
?
'flutter.bat'
:
'flutter'
);
...
...
@@ -153,7 +156,8 @@ Future<void> main(List<String> arguments) async {
Directory
(
_packageFlutter
),
Directory
(
_packageFlutterTest
),
Directory
(
_packageIntegrationTest
),
// TODO(goderbauer): Add all other packages.
Directory
(
_packageFlutterDriver
),
// TODO(goderbauer): Add all other packages for which we publish docs.
];
}
...
...
@@ -574,6 +578,7 @@ class _SnippetChecker {
final
List
<
String
>
fileLines
=
file
.
readAsLinesSync
();
final
List
<
_Line
>
ignorePreambleLinesOnly
=
<
_Line
>[];
final
List
<
_Line
>
preambleLines
=
<
_Line
>[];
final
List
<
_Line
>
customImports
=
<
_Line
>[];
bool
inExamplesCanAssumePreamble
=
false
;
// Whether or not we're in the file-wide preamble section ("Examples can assume").
bool
inToolSection
=
false
;
// Whether or not we're in a code snippet
bool
inDartSection
=
false
;
// Whether or not we're in a '```dart' segment.
...
...
@@ -592,7 +597,11 @@ class _SnippetChecker {
throw
_SnippetCheckerException
(
'Unexpected content in snippet code preamble.'
,
file:
relativeFilePath
,
line:
lineNumber
);
}
else
{
final
_Line
newLine
=
_Line
(
line:
lineNumber
,
indent:
3
,
code:
line
.
substring
(
3
));
if
(
newLine
.
code
.
startsWith
(
'import '
))
{
customImports
.
add
(
newLine
);
}
else
{
preambleLines
.
add
(
newLine
);
}
if
(
line
.
startsWith
(
'// // ignore_for_file: '
))
{
ignorePreambleLinesOnly
.
add
(
newLine
);
}
...
...
@@ -612,7 +621,7 @@ class _SnippetChecker {
}
if
(
trimmedLine
.
startsWith
(
_codeBlockEndRegex
))
{
inDartSection
=
false
;
final
_SnippetFile
snippet
=
_processBlock
(
startLine
,
block
,
preambleLines
,
ignorePreambleLinesOnly
,
relativeFilePath
,
lastExample
);
final
_SnippetFile
snippet
=
_processBlock
(
startLine
,
block
,
preambleLines
,
ignorePreambleLinesOnly
,
relativeFilePath
,
lastExample
,
customImports
);
final
String
path
=
_writeSnippetFile
(
snippet
).
path
;
assert
(!
snippetMap
.
containsKey
(
path
));
snippetMap
[
path
]
=
snippet
;
...
...
@@ -655,6 +664,7 @@ class _SnippetChecker {
line
.
contains
(
'```kotlin'
)
||
line
.
contains
(
'```swift'
)
||
line
.
contains
(
'```glsl'
)
||
line
.
contains
(
'```json'
)
||
line
.
contains
(
'```csv'
))
{
inOtherBlock
=
true
;
}
else
if
(
line
.
startsWith
(
_uncheckedCodeBlockStartRegex
))
{
...
...
@@ -694,7 +704,7 @@ class _SnippetChecker {
/// a primitive heuristic to make snippet blocks into valid Dart code.
///
/// `block` argument will get mutated, but is copied before this function returns.
_SnippetFile
_processBlock
(
_Line
startingLine
,
List
<
String
>
block
,
List
<
_Line
>
assumptions
,
List
<
_Line
>
ignoreAssumptionsOnly
,
String
filename
,
_SnippetFile
?
lastExample
)
{
_SnippetFile
_processBlock
(
_Line
startingLine
,
List
<
String
>
block
,
List
<
_Line
>
assumptions
,
List
<
_Line
>
ignoreAssumptionsOnly
,
String
filename
,
_SnippetFile
?
lastExample
,
List
<
_Line
>
customImports
)
{
if
(
block
.
isEmpty
)
{
throw
_SnippetCheckerException
(
'
${startingLine.asLocation(filename, 0)}
: Empty ```dart block in snippet code.'
);
}
...
...
@@ -755,7 +765,7 @@ class _SnippetChecker {
return
_SnippetFile
.
fromStrings
(
startingLine
,
block
.
toList
(),
importPreviousExample
?
<
_Line
>[]
:
headersWithoutImports
,
headersWithoutImports
,
<
_Line
>[
...
ignoreAssumptionsOnly
,
if
(
hasEllipsis
)
...
...
@@ -764,13 +774,24 @@ class _SnippetChecker {
'self-contained program'
,
filename
,
);
}
else
if
(
hasStatefulWidgetComment
)
{
}
final
List
<
_Line
>
headers
=
switch
((
importPreviousExample
,
customImports
.
length
))
{
(
true
,
_
)
=>
<
_Line
>[],
(
false
,
0
)
=>
headersWithImports
,
(
false
,
_
)
=>
<
_Line
>[
...
headersWithoutImports
,
const
_Line
.
generated
(
code:
'// ignore_for_file: unused_import'
),
...
customImports
,
]
};
if
(
hasStatefulWidgetComment
)
{
return
_SnippetFile
.
fromStrings
(
startingLine
,
prefix:
'class _State extends State<StatefulWidget> {'
,
block
.
toList
(),
postfix:
'}'
,
importPreviousExample
?
<
_Line
>[]
:
headersWithImport
s
,
header
s
,
preamble
,
'stateful widget'
,
filename
,
...
...
@@ -782,7 +803,7 @@ class _SnippetChecker {
return
_SnippetFile
.
fromStrings
(
startingLine
,
block
.
toList
(),
importPreviousExample
?
<
_Line
>[]
:
headersWithImport
s
,
header
s
,
preamble
,
'top-level declaration'
,
filename
,
...
...
@@ -795,7 +816,7 @@ class _SnippetChecker {
prefix:
'Future<void> function() async {'
,
block
.
toList
(),
postfix:
'}'
,
importPreviousExample
?
<
_Line
>[]
:
headersWithImport
s
,
header
s
,
preamble
,
'statement'
,
filename
,
...
...
@@ -807,7 +828,7 @@ class _SnippetChecker {
prefix:
'class Class {'
,
block
.
toList
(),
postfix:
'}'
,
importPreviousExample
?
<
_Line
>[]
:
headersWithImport
s
,
header
s
,
<
_Line
>[
...
preamble
,
const
_Line
.
generated
(
code:
'// ignore_for_file: avoid_classes_with_only_static_members'
),
...
...
@@ -849,7 +870,7 @@ class _SnippetChecker {
prefix:
'dynamic expression = '
,
block
.
toList
(),
postfix:
';'
,
importPreviousExample
?
<
_Line
>[]
:
headersWithImport
s
,
header
s
,
preamble
,
'expression'
,
filename
,
...
...
dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart
0 → 100644
View file @
32aa3128
// 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.
// This file is used by ../analyze_snippet_code_test.dart, which depends on the
// precise contents (including especially the comments) of this file.
// Examples can assume:
// import 'package:flutter/rendering.dart';
/// no error: rendering library was imported.
/// ```dart
/// print(RenderObject);
/// ```
String
?
bar
;
/// error: widgets library was not imported (not even implicitly).
/// ```dart
/// print(Widget);
/// ```
String
?
foo
;
dev/bots/test/analyze_snippet_code_test.dart
View file @
32aa3128
...
...
@@ -11,6 +11,7 @@ import 'dart:io';
import
'common.dart'
;
const
List
<
String
>
expectedMainErrors
=
<
String
>[
'dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart:19:11: (statement) (undefined_identifier)'
,
'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:30:5: (expression) (unnecessary_new)'
,
'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:103:5: (statement) (always_specify_types)'
,
'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:111:5: (top-level declaration) (prefer_const_declarations)'
,
...
...
@@ -68,7 +69,7 @@ void main() {
final
List
<
String
>
stderrNoDescriptions
=
stderrLines
.
map
(
removeLintDescriptions
).
toList
();
expect
(
stderrNoDescriptions
,
<
String
>[
...
expectedMainErrors
,
'Found 1
5
snippet code errors.'
,
'Found 1
6
snippet code errors.'
,
'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.'
,
''
,
// because we end with a newline, split gives us an extra blank line
]);
...
...
@@ -92,7 +93,7 @@ void main() {
expect
(
stderrNoDescriptions
,
<
String
>[
...
expectedUiErrors
,
...
expectedMainErrors
,
'Found
19
snippet code errors.'
,
'Found
20
snippet code errors.'
,
'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.'
,
''
,
// because we end with a newline, split gives us an extra blank line
]);
...
...
packages/flutter_driver/lib/src/driver/driver.dart
View file @
32aa3128
...
...
@@ -83,6 +83,11 @@ const CommonFinders find = CommonFinders._();
/// See also [FlutterDriver.waitFor].
typedef
EvaluatorFunction
=
dynamic
Function
();
// Examples can assume:
// import 'package:flutter_driver/flutter_driver.dart';
// import 'package:test/test.dart';
// late FlutterDriver driver;
/// Drives a Flutter Application running in another process.
abstract
class
FlutterDriver
{
/// Default constructor.
...
...
@@ -478,7 +483,7 @@ abstract class FlutterDriver {
///
/// ```dart
/// test('enters text in a text field', () async {
///
va
r textField = find.byValueKey('enter-text-field');
///
final SerializableFinde
r textField = find.byValueKey('enter-text-field');
/// await driver.tap(textField); // acquire focus
/// await driver.enterText('Hello!'); // enter text
/// await driver.waitFor(find.text('Hello!')); // verify text appears on UI
...
...
@@ -520,7 +525,7 @@ abstract class FlutterDriver {
///
/// ```dart
/// test('submit text in a text field', () async {
///
va
r textField = find.byValueKey('enter-text-field');
///
final SerializableFinde
r textField = find.byValueKey('enter-text-field');
/// await driver.tap(textField); // acquire focus
/// await driver.enterText('Hello!'); // enter text
/// await driver.waitFor(find.text('Hello!')); // verify text appears on UI
...
...
packages/flutter_driver/lib/src/driver/gc_summarizer.dart
View file @
32aa3128
...
...
@@ -17,7 +17,7 @@ const Set<String> kGCRootEvents = <String>{
/// Summarizes [TimelineEvents]s corresponding to [kGCRootEvents] category.
///
/// A sample event (some fields have been omitted for brevity):
/// ```
/// ```
json
/// {
/// "name": "StartConcurrentMarking",
/// "cat": "GC",
...
...
packages/flutter_driver/lib/src/driver/profiling_summarizer.dart
View file @
32aa3128
...
...
@@ -36,7 +36,7 @@ enum ProfileType {
/// Summarizes [TimelineEvents]s corresponding to [kProfilingEvents] category.
///
/// A sample event (some fields have been omitted for brevity):
/// ```
/// ```
json
/// {
/// "category": "embedder",
/// "name": "CpuUsage",
...
...
packages/flutter_driver/lib/src/driver/raster_cache_summarizer.dart
View file @
32aa3128
...
...
@@ -16,7 +16,7 @@ const String _kPictureMemory = 'PictureMBytes';
/// Summarizes [TimelineEvents]s corresponding to [kRasterCacheEvent] events.
///
/// A sample event (some fields have been omitted for brevity):
/// ```
/// ```
json
/// {
/// "name": "RasterCache",
/// "ts": 75598996256,
...
...
packages/flutter_driver/lib/src/driver/scene_display_lag_summarizer.dart
View file @
32aa3128
...
...
@@ -13,7 +13,7 @@ const String _kVsyncTransitionsMissed = 'vsync_transitions_missed';
/// Summarizes [TimelineEvents]s corresponding to [kSceneDisplayLagEvent] events.
///
/// A sample event (some fields have been omitted for brevity):
/// ```
/// ```
json
/// {
/// "name": "SceneDisplayLag",
/// "ts": 408920509340,
...
...
packages/flutter_driver/lib/src/extension/extension.dart
View file @
32aa3128
...
...
@@ -58,6 +58,19 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
}
}
// Examples can assume:
// import 'package:flutter_driver/flutter_driver.dart';
// import 'package:flutter/widgets.dart';
// import 'package:flutter_driver/driver_extension.dart';
// import 'package:flutter_test/flutter_test.dart' hide find;
// import 'package:flutter_test/flutter_test.dart' as flutter_test;
// typedef MyHomeWidget = Placeholder;
// abstract class SomeWidget extends StatelessWidget { const SomeWidget({super.key, required this.title}); final String title; }
// late FlutterDriver driver;
// abstract class StubNestedCommand { int get times; SerializableFinder get finder; }
// class StubCommandResult extends Result { const StubCommandResult(this.arg); final String arg; @override Map<String, dynamic> toJson() => <String, dynamic>{}; }
// abstract class StubProberCommand { int get times; SerializableFinder get finder; }
/// Enables Flutter Driver VM service extension.
///
/// This extension is required for tests that use `package:flutter_driver` to
...
...
@@ -87,105 +100,54 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// The `finders` and `commands` parameters are optional and used to add custom
/// finders or commands, as in the following example.
///
/// ```dart
main
/// ```dart
/// void main() {
/// enableFlutterDriverExtension(
/// finders: <FinderExtension>[ SomeFinderExtension() ],
/// commands: <CommandExtension>[ SomeCommandExtension() ],
/// );
///
///
app.main(
);
///
runApp(const MyHomeWidget()
);
/// }
/// ```
///
/// ```dart
/// driver.sendCommand(SomeCommand(ByValueKey('Button'), 7));
/// ```
///
/// `SomeFinder` and `SomeFinderExtension` must be placed in different files
/// to avoid `dart:ui` import issue. Imports relative to `dart:ui` can't be
/// accessed from host runner, where flutter runtime is not accessible.
///
/// ```dart
/// class SomeFinder extends SerializableFinder {
/// const SomeFinder(this.title);
///
/// final String title;
///
/// class SomeFinderExtension extends FinderExtension {
/// @override
/// String get finderType => 'SomeFinder';
///
/// @override
/// Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
/// 'title': title,
/// });
/// }
/// ```
///
/// ```dart
/// class SomeFinderExtension extends FinderExtension {
///
/// String get finderType => 'SomeFinder';
///
/// SerializableFinder deserialize(Map<String, String> params, DeserializeFinderFactory finderFactory) {
///
return SomeFinder(json['title']
);
///
return SomeFinder(params['title']!
);
/// }
///
/// @override
/// Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory) {
///
Some
someFinder = finder as SomeFinder;
///
final SomeFinder
someFinder = finder as SomeFinder;
///
///
return
find.byElementPredicate((Element element) {
///
return flutter_test.
find.byElementPredicate((Element element) {
/// final Widget widget = element.widget;
///
if (element.
widget is SomeWidget) {
///
return element.
widget.title == someFinder.title;
///
if (
widget is SomeWidget) {
///
return
widget.title == someFinder.title;
/// }
/// return false;
/// });
/// }
/// }
/// ```
///
/// `SomeCommand`, `SomeResult` and `SomeCommandExtension` must be placed in
/// different files to avoid `dart:ui` import issue. Imports relative to `dart:ui`
/// can't be accessed from host runner, where flutter runtime is not accessible.
///
/// ```dart
/// class SomeCommand extends CommandWithTarget {
/// SomeCommand(SerializableFinder finder, this.times, {Duration? timeout})
/// : super(finder, timeout: timeout);
///
/// SomeCommand.deserialize(Map<String, String> json, DeserializeFinderFactory finderFactory)
/// : times = int.parse(json['times']!),
/// super.deserialize(json, finderFactory);
/// // Use this class in a test anywhere where a SerializableFinder is expected.
/// class SomeFinder extends SerializableFinder {
/// const SomeFinder(this.title);
///
/// @override
/// Map<String, String> serialize() {
/// return super.serialize()..addAll(<String, String>{'times': '$times'});
/// }
/// final String title;
///
/// @override
/// String get kind => 'SomeCommand';
///
/// final int times;
/// }
/// ```
///
/// ```dart
/// class SomeCommandResult extends Result {
/// const SomeCommandResult(this.resultParam);
///
/// final String resultParam;
/// String get finderType => 'SomeFinder';
///
/// @override
/// Map<String, dynamic> toJson() {
/// return <String, dynamic>{
/// 'resultParam': resultParam,
/// };
/// }
/// Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
/// 'title': title,
/// });
/// }
/// ```
///
/// ```dart
/// class SomeCommandExtension extends CommandExtension {
/// @override
/// String get commandKind => 'SomeCommand';
...
...
@@ -195,7 +157,7 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// final SomeCommand someCommand = command as SomeCommand;
///
/// // Deserialize [Finder]:
/// final Finder finder = finderFactory.createFinder(s
tub
Command.finder);
/// final Finder finder = finderFactory.createFinder(s
ome
Command.finder);
///
/// // Wait for [Element]:
/// handlerFactory.waitForElement(finder);
...
...
@@ -204,12 +166,12 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// handlerFactory.waitForAbsentElement(finder);
///
/// // Submit known [Command]s:
/// for (int i
ndex = 0; i < someCommand.times; index
++) {
/// for (int i
= 0; i < someCommand.times; i
++) {
/// await handlerFactory.handleCommand(Tap(someCommand.finder), prober, finderFactory);
/// }
///
/// // Alternatively, use [WidgetController]:
/// for (int i
ndex = 0; i < stubCommand.times; index
++) {
/// for (int i
= 0; i < someCommand.times; i
++) {
/// await prober.tap(finder);
/// }
///
...
...
@@ -221,8 +183,40 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// return SomeCommand.deserialize(params, finderFactory);
/// }
/// }
/// ```
///
/// // Pass an instance of this class to `FlutterDriver.sendCommand` to invoke
/// // the custom command during a test.
/// class SomeCommand extends CommandWithTarget {
/// SomeCommand(super.finder, this.times, {super.timeout});
///
/// SomeCommand.deserialize(super.json, super.finderFactory)
/// : times = int.parse(json['times']!),
/// super.deserialize();
///
/// @override
/// Map<String, String> serialize() {
/// return super.serialize()..addAll(<String, String>{'times': '$times'});
/// }
///
/// @override
/// String get kind => 'SomeCommand';
///
/// final int times;
/// }
///
/// class SomeCommandResult extends Result {
/// const SomeCommandResult(this.resultParam);
///
/// final String resultParam;
///
/// @override
/// Map<String, dynamic> toJson() {
/// return <String, dynamic>{
/// 'resultParam': resultParam,
/// };
/// }
/// }
/// ```
void
enableFlutterDriverExtension
(
{
DataHandler
?
handler
,
bool
silenceErrors
=
false
,
bool
enableTextEntryEmulation
=
true
,
List
<
FinderExtension
>?
finders
,
List
<
CommandExtension
>?
commands
})
{
_DriverBinding
(
handler
,
silenceErrors
,
enableTextEntryEmulation
,
finders
??
<
FinderExtension
>[],
commands
??
<
CommandExtension
>[]);
assert
(
WidgetsBinding
.
instance
is
_DriverBinding
);
...
...
@@ -287,7 +281,7 @@ abstract class CommandExtension {
/// @override
/// Future<Result> call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async {
/// final StubNestedCommand stubCommand = command as StubNestedCommand;
/// for (int i
ndex = 0; i < stubCommand.times; index
++) {
/// for (int i
= 0; i < stubCommand.times; i
++) {
/// await handlerFactory.handleCommand(Tap(stubCommand.finder), prober, finderFactory);
/// }
/// return const StubCommandResult('stub response');
...
...
@@ -300,7 +294,7 @@ abstract class CommandExtension {
/// @override
/// Future<Result> call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async {
/// final StubProberCommand stubCommand = command as StubProberCommand;
/// for (int i
ndex = 0; i < stubCommand.times; index
++) {
/// for (int i
= 0; i < stubCommand.times; i
++) {
/// await prober.tap(finderFactory.createFinder(stubCommand.finder));
/// }
/// return const StubCommandResult('stub response');
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment