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
d053a4d0
Unverified
Commit
d053a4d0
authored
Jul 29, 2020
by
Ming Lyu (CareF)
Committed by
GitHub
Jul 29, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move key event and semantics related method from WidgetTester to WidgetController (#62362)
parent
0a69e810
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
252 additions
and
246 deletions
+252
-246
controller.dart
packages/flutter_test/lib/src/controller.dart
+113
-0
widget_tester.dart
packages/flutter_test/lib/src/widget_tester.dart
+4
-112
controller_test.dart
packages/flutter_test/test/controller_test.dart
+135
-0
widget_tester_test.dart
packages/flutter_test/test/widget_tester_test.dart
+0
-134
No files found.
packages/flutter_test/lib/src/controller.dart
View file @
d053a4d0
...
...
@@ -7,9 +7,11 @@ import 'dart:async';
import
'package:clock/clock.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'all_elements.dart'
;
import
'event_simulation.dart'
;
import
'finders.dart'
;
import
'test_async_utils.dart'
;
import
'test_pointer.dart'
;
...
...
@@ -686,10 +688,121 @@ abstract class WidgetController {
return
box
.
size
;
}
/// Simulates sending physical key down and up events through the system channel.
///
/// This only simulates key events coming from a physical keyboard, not from a
/// soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". Must not be null. Some platforms (e.g.
/// Windows, iOS) are not yet supported.
///
/// Keys that are down when the test completes are cleared after each test.
///
/// This method sends both the key down and the key up events, to simulate a
/// key press. To simulate individual down and/or up events, see
/// [sendKeyDownEvent] and [sendKeyUpEvent].
///
/// See also:
///
/// - [sendKeyDownEvent] to simulate only a key down event.
/// - [sendKeyUpEvent] to simulate only a key up event.
Future
<
void
>
sendKeyEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
await
simulateKeyDownEvent
(
key
,
platform:
platform
);
// Internally wrapped in async guard.
return
simulateKeyUpEvent
(
key
,
platform:
platform
);
}
/// Simulates sending a physical key down event through the system channel.
///
/// This only simulates key down events coming from a physical keyboard, not
/// from a soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". Must not be null. Some platforms (e.g.
/// Windows, iOS) are not yet supported.
///
/// Keys that are down when the test completes are cleared after each test.
///
/// See also:
///
/// - [sendKeyUpEvent] to simulate the corresponding key up event.
/// - [sendKeyEvent] to simulate both the key up and key down in the same call.
Future
<
void
>
sendKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
// Internally wrapped in async guard.
return
simulateKeyDownEvent
(
key
,
platform:
platform
);
}
/// Simulates sending a physical key up event through the system channel.
///
/// This only simulates key up events coming from a physical keyboard,
/// not from a soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". May not be null.
///
/// See also:
///
/// - [sendKeyDownEvent] to simulate the corresponding key down event.
/// - [sendKeyEvent] to simulate both the key up and key down in the same call.
Future
<
void
>
sendKeyUpEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
// Internally wrapped in async guard.
return
simulateKeyUpEvent
(
key
,
platform:
platform
);
}
/// Returns the rect of the given widget. This is only valid once
/// the widget's render object has been laid out at least once.
Rect
getRect
(
Finder
finder
)
=>
getTopLeft
(
finder
)
&
getSize
(
finder
);
/// Attempts to find the [SemanticsNode] of first result from `finder`.
///
/// If the object identified by the finder doesn't own it's semantic node,
/// this will return the semantics data of the first ancestor with semantics.
/// The ancestor's semantic data will include the child's as well as
/// other nodes that have been merged together.
///
/// If the [SemanticsNode] of the object identified by the finder is
/// force-merged into an ancestor (e.g. via the [MergeSemantics] widget)
/// the node into which it is merged is returned. That node will include
/// all the semantics information of the nodes merged into it.
///
/// Will throw a [StateError] if the finder returns more than one element or
/// if no semantics are found or are not enabled.
SemanticsNode
getSemantics
(
Finder
finder
)
{
if
(
binding
.
pipelineOwner
.
semanticsOwner
==
null
)
throw
StateError
(
'Semantics are not enabled.'
);
final
Iterable
<
Element
>
candidates
=
finder
.
evaluate
();
if
(
candidates
.
isEmpty
)
{
throw
StateError
(
'Finder returned no matching elements.'
);
}
if
(
candidates
.
length
>
1
)
{
throw
StateError
(
'Finder returned more than one element.'
);
}
final
Element
element
=
candidates
.
single
;
RenderObject
renderObject
=
element
.
findRenderObject
();
SemanticsNode
result
=
renderObject
.
debugSemantics
;
while
(
renderObject
!=
null
&&
(
result
==
null
||
result
.
isMergedIntoParent
))
{
renderObject
=
renderObject
?.
parent
as
RenderObject
;
result
=
renderObject
?.
debugSemantics
;
}
if
(
result
==
null
)
throw
StateError
(
'No Semantics data found.'
);
return
result
;
}
/// Enable semantics in a test by creating a [SemanticsHandle].
///
/// The handle must be disposed at the end of the test.
SemanticsHandle
ensureSemantics
()
{
return
binding
.
pipelineOwner
.
ensureSemantics
();
}
/// Given a widget `W` specified by [finder] and a [Scrollable] widget `S` in
/// its ancestry tree, this scrolls `S` so as to make `W` visible.
///
...
...
packages/flutter_test/lib/src/widget_tester.dart
View file @
d053a4d0
...
...
@@ -20,7 +20,6 @@ import 'package:test_api/test_api.dart' as test_package;
import
'all_elements.dart'
;
import
'binding.dart'
;
import
'controller.dart'
;
import
'event_simulation.dart'
;
import
'finders.dart'
;
import
'matchers.dart'
;
import
'restoration.dart'
;
...
...
@@ -560,6 +559,10 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
/// frames) for `duration` amount of time, and then received a "Vsync" signal
/// to paint the application.
///
/// For a [FakeAsync] environment (typically in `flutter test`), this advances
/// time and timeout counting; for a live environment this delays `duration`
/// time.
///
/// This is a convenience function that just calls
/// [TestWidgetsFlutterBinding.pump].
///
...
...
@@ -1055,74 +1058,6 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
});
}
/// Simulates sending physical key down and up events through the system channel.
///
/// This only simulates key events coming from a physical keyboard, not from a
/// soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". Must not be null. Some platforms (e.g.
/// Windows, iOS) are not yet supported.
///
/// Keys that are down when the test completes are cleared after each test.
///
/// This method sends both the key down and the key up events, to simulate a
/// key press. To simulate individual down and/or up events, see
/// [sendKeyDownEvent] and [sendKeyUpEvent].
///
/// See also:
///
/// - [sendKeyDownEvent] to simulate only a key down event.
/// - [sendKeyUpEvent] to simulate only a key up event.
Future
<
void
>
sendKeyEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
await
simulateKeyDownEvent
(
key
,
platform:
platform
);
// Internally wrapped in async guard.
return
simulateKeyUpEvent
(
key
,
platform:
platform
);
}
/// Simulates sending a physical key down event through the system channel.
///
/// This only simulates key down events coming from a physical keyboard, not
/// from a soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". Must not be null. Some platforms (e.g.
/// Windows, iOS) are not yet supported.
///
/// Keys that are down when the test completes are cleared after each test.
///
/// See also:
///
/// - [sendKeyUpEvent] to simulate the corresponding key up event.
/// - [sendKeyEvent] to simulate both the key up and key down in the same call.
Future
<
void
>
sendKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
// Internally wrapped in async guard.
return
simulateKeyDownEvent
(
key
,
platform:
platform
);
}
/// Simulates sending a physical key up event through the system channel.
///
/// This only simulates key up events coming from a physical keyboard,
/// not from a soft keyboard.
///
/// Specify `platform` as one of the platforms allowed in
/// [Platform.operatingSystem] to make the event appear to be from that type
/// of system. Defaults to "android". May not be null.
///
/// See also:
///
/// - [sendKeyDownEvent] to simulate the corresponding key down event.
/// - [sendKeyEvent] to simulate both the key up and key down in the same call.
Future
<
void
>
sendKeyUpEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
'android'
})
async
{
assert
(
platform
!=
null
);
// Internally wrapped in async guard.
return
simulateKeyUpEvent
(
key
,
platform:
platform
);
}
/// Makes an effort to dismiss the current page with a Material [Scaffold] or
/// a [CupertinoPageScaffold].
///
...
...
@@ -1139,49 +1074,6 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
await
tap
(
backButton
);
});
}
/// Attempts to find the [SemanticsNode] of first result from `finder`.
///
/// If the object identified by the finder doesn't own it's semantic node,
/// this will return the semantics data of the first ancestor with semantics.
/// The ancestor's semantic data will include the child's as well as
/// other nodes that have been merged together.
///
/// If the [SemanticsNode] of the object identified by the finder is
/// force-merged into an ancestor (e.g. via the [MergeSemantics] widget)
/// the node into which it is merged is returned. That node will include
/// all the semantics information of the nodes merged into it.
///
/// Will throw a [StateError] if the finder returns more than one element or
/// if no semantics are found or are not enabled.
SemanticsNode
getSemantics
(
Finder
finder
)
{
if
(
binding
.
pipelineOwner
.
semanticsOwner
==
null
)
throw
StateError
(
'Semantics are not enabled.'
);
final
Iterable
<
Element
>
candidates
=
finder
.
evaluate
();
if
(
candidates
.
isEmpty
)
{
throw
StateError
(
'Finder returned no matching elements.'
);
}
if
(
candidates
.
length
>
1
)
{
throw
StateError
(
'Finder returned more than one element.'
);
}
final
Element
element
=
candidates
.
single
;
RenderObject
renderObject
=
element
.
findRenderObject
();
SemanticsNode
result
=
renderObject
.
debugSemantics
;
while
(
renderObject
!=
null
&&
(
result
==
null
||
result
.
isMergedIntoParent
))
{
renderObject
=
renderObject
?.
parent
as
RenderObject
;
result
=
renderObject
?.
debugSemantics
;
}
if
(
result
==
null
)
throw
StateError
(
'No Semantics data found.'
);
return
result
;
}
/// Enable semantics in a test by creating a [SemanticsHandle].
///
/// The handle must be disposed at the end of the test.
SemanticsHandle
ensureSemantics
()
{
return
binding
.
pipelineOwner
.
ensureSemantics
();
}
}
typedef
_TickerDisposeCallback
=
void
Function
(
_TestTicker
ticker
);
...
...
packages/flutter_test/test/controller_test.dart
View file @
d053a4d0
...
...
@@ -4,6 +4,7 @@
import
'dart:ui'
;
import
'package:flutter/semantics.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -22,6 +23,140 @@ class TestDragData {
}
void
main
(
)
{
group
(
'getSemanticsData'
,
()
{
testWidgets
(
'throws when there are no semantics'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Scaffold
(
body:
Text
(
'hello'
),
),
),
);
expect
(()
=>
tester
.
getSemantics
(
find
.
text
(
'hello'
)),
throwsStateError
);
},
semanticsEnabled:
false
);
testWidgets
(
'throws when there are multiple results from the finder'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Row
(
children:
const
<
Widget
>[
Text
(
'hello'
),
Text
(
'hello'
),
],
),
),
),
);
expect
(()
=>
tester
.
getSemantics
(
find
.
text
(
'hello'
)),
throwsStateError
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Returns the correct SemanticsData'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Container
(
child:
OutlineButton
(
onPressed:
()
{
},
child:
const
Text
(
'hello'
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
text
(
'hello'
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'hello'
);
expect
(
semantics
.
hasAction
(
SemanticsAction
.
tap
),
true
);
expect
(
semantics
.
hasFlag
(
SemanticsFlag
.
isButton
),
true
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Can enable semantics for tests via semanticsEnabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Container
(
child:
OutlineButton
(
onPressed:
()
{
},
child:
const
Text
(
'hello'
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
text
(
'hello'
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'hello'
);
expect
(
semantics
.
hasAction
(
SemanticsAction
.
tap
),
true
);
expect
(
semantics
.
hasFlag
(
SemanticsFlag
.
isButton
),
true
);
},
semanticsEnabled:
true
);
testWidgets
(
'Returns merged SemanticsData'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
const
Key
key
=
Key
(
'test'
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Semantics
(
label:
'A'
,
child:
Semantics
(
label:
'B'
,
child:
Semantics
(
key:
key
,
label:
'C'
,
child:
Container
(),
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
byKey
(
key
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'A
\n
B
\n
C'
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Does not return partial semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
final
Key
key
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
MergeSemantics
(
child:
Semantics
(
container:
true
,
label:
'A'
,
child:
Semantics
(
container:
true
,
key:
key
,
label:
'B'
,
child:
Container
(),
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
byKey
(
key
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'A
\n
B'
);
semanticsHandle
.
dispose
();
});
});
testWidgets
(
'WidgetTester.drag must break the offset into multiple parallel components if '
'the drag goes outside the touch slop values'
,
...
...
packages/flutter_test/test/widget_tester_test.dart
View file @
d053a4d0
...
...
@@ -24,140 +24,6 @@ const List<Widget> fooBarTexts = <Text>[
];
void
main
(
)
{
group
(
'getSemanticsData'
,
()
{
testWidgets
(
'throws when there are no semantics'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Scaffold
(
body:
Text
(
'hello'
),
),
),
);
expect
(()
=>
tester
.
getSemantics
(
find
.
text
(
'hello'
)),
throwsStateError
);
},
semanticsEnabled:
false
);
testWidgets
(
'throws when there are multiple results from the finder'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Row
(
children:
const
<
Widget
>[
Text
(
'hello'
),
Text
(
'hello'
),
],
),
),
),
);
expect
(()
=>
tester
.
getSemantics
(
find
.
text
(
'hello'
)),
throwsStateError
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Returns the correct SemanticsData'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Container
(
child:
OutlineButton
(
onPressed:
()
{
},
child:
const
Text
(
'hello'
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
text
(
'hello'
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'hello'
);
expect
(
semantics
.
hasAction
(
SemanticsAction
.
tap
),
true
);
expect
(
semantics
.
hasFlag
(
SemanticsFlag
.
isButton
),
true
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Can enable semantics for tests via semanticsEnabled'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Container
(
child:
OutlineButton
(
onPressed:
()
{
},
child:
const
Text
(
'hello'
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
text
(
'hello'
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'hello'
);
expect
(
semantics
.
hasAction
(
SemanticsAction
.
tap
),
true
);
expect
(
semantics
.
hasFlag
(
SemanticsFlag
.
isButton
),
true
);
},
semanticsEnabled:
true
);
testWidgets
(
'Returns merged SemanticsData'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
const
Key
key
=
Key
(
'test'
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
Semantics
(
label:
'A'
,
child:
Semantics
(
label:
'B'
,
child:
Semantics
(
key:
key
,
label:
'C'
,
child:
Container
(),
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
byKey
(
key
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'A
\n
B
\n
C'
);
semanticsHandle
.
dispose
();
});
testWidgets
(
'Does not return partial semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsHandle
semanticsHandle
=
tester
.
ensureSemantics
();
final
Key
key
=
UniqueKey
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
body:
MergeSemantics
(
child:
Semantics
(
container:
true
,
label:
'A'
,
child:
Semantics
(
container:
true
,
key:
key
,
label:
'B'
,
child:
Container
(),
),
),
),
),
),
);
final
SemanticsNode
node
=
tester
.
getSemantics
(
find
.
byKey
(
key
));
final
SemanticsData
semantics
=
node
.
getSemanticsData
();
expect
(
semantics
.
label
,
'A
\n
B'
);
semanticsHandle
.
dispose
();
});
});
group
(
'expectLater'
,
()
{
testWidgets
(
'completes when matcher completes'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
void
>
completer
=
Completer
<
void
>();
...
...
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