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
5667b782
Unverified
Commit
5667b782
authored
Aug 27, 2019
by
adazh
Committed by
GitHub
Aug 27, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added a Driver wait condition for no pending platform messages (#39196)
parent
6f71ce26
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
348 additions
and
5 deletions
+348
-5
wait.dart
packages/flutter_driver/lib/src/common/wait.dart
+22
-0
extension.dart
packages/flutter_driver/lib/src/extension/extension.dart
+5
-0
wait_conditions.dart
...ges/flutter_driver/lib/src/extension/wait_conditions.dart
+41
-5
flutter_driver_test.dart
packages/flutter_driver/test/flutter_driver_test.dart
+12
-0
extension_test.dart
packages/flutter_driver/test/src/extension_test.dart
+202
-0
binding.dart
packages/flutter_test/lib/src/binding.dart
+66
-0
No files found.
packages/flutter_driver/lib/src/common/wait.dart
View file @
5667b782
...
...
@@ -201,6 +201,26 @@ class FirstFrameRasterized extends SerializableWaitCondition {
String
get
conditionName
=>
'FirstFrameRasterizedCondition'
;
}
/// A condition that waits until there are no pending platform messages.
class
NoPendingPlatformMessages
extends
SerializableWaitCondition
{
/// Creates a [NoPendingPlatformMessages] condition.
const
NoPendingPlatformMessages
();
/// Factory constructor to parse a [NoPendingPlatformMessages] instance from the
/// given JSON map.
///
/// The [json] argument must not be null.
factory
NoPendingPlatformMessages
.
deserialize
(
Map
<
String
,
dynamic
>
json
)
{
assert
(
json
!=
null
);
if
(
json
[
'conditionName'
]
!=
'NoPendingPlatformMessagesCondition'
)
throw
SerializationException
(
'Error occurred during deserializing the NoPendingPlatformMessagesCondition JSON string:
$json
'
);
return
const
NoPendingPlatformMessages
();
}
@override
String
get
conditionName
=>
'NoPendingPlatformMessagesCondition'
;
}
/// A combined condition that waits until all the given [conditions] are met.
class
CombinedCondition
extends
SerializableWaitCondition
{
/// Creates a [CombinedCondition] condition.
...
...
@@ -260,6 +280,8 @@ SerializableWaitCondition _deserialize(Map<String, dynamic> json) {
return
NoPendingFrame
.
deserialize
(
json
);
case
'FirstFrameRasterizedCondition'
:
return
FirstFrameRasterized
.
deserialize
(
json
);
case
'NoPendingPlatformMessagesCondition'
:
return
NoPendingPlatformMessages
.
deserialize
(
json
);
case
'CombinedCondition'
:
return
CombinedCondition
.
deserialize
(
json
);
}
...
...
packages/flutter_driver/lib/src/extension/extension.dart
View file @
5667b782
...
...
@@ -56,6 +56,11 @@ class _DriverBinding extends BindingBase with ServicesBinding, SchedulerBinding,
callback:
extension
.
call
,
);
}
@override
BinaryMessenger
createBinaryMessenger
()
{
return
TestDefaultBinaryMessenger
(
super
.
createBinaryMessenger
());
}
}
/// Enables Flutter Driver VM service extension.
...
...
packages/flutter_driver/lib/src/extension/wait_conditions.dart
View file @
5667b782
...
...
@@ -3,7 +3,9 @@
// found in the LICENSE file.
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../common/wait.dart'
;
...
...
@@ -32,7 +34,7 @@ abstract class WaitCondition {
/// A condition that waits until no transient callbacks are scheduled.
class
_InternalNoTransientCallbacksCondition
implements
WaitCondition
{
/// Creates an [InternalNoTransientCallbacksCondition] instance.
/// Creates an [
_
InternalNoTransientCallbacksCondition] instance.
const
_InternalNoTransientCallbacksCondition
();
/// Factory constructor to parse an [InternalNoTransientCallbacksCondition]
...
...
@@ -60,7 +62,7 @@ class _InternalNoTransientCallbacksCondition implements WaitCondition {
/// A condition that waits until no pending frame is scheduled.
class
_InternalNoPendingFrameCondition
implements
WaitCondition
{
/// Creates an [InternalNoPendingFrameCondition] instance.
/// Creates an [
_
InternalNoPendingFrameCondition] instance.
const
_InternalNoPendingFrameCondition
();
/// Factory constructor to parse an [InternalNoPendingFrameCondition] instance
...
...
@@ -88,7 +90,7 @@ class _InternalNoPendingFrameCondition implements WaitCondition {
/// A condition that waits until the Flutter engine has rasterized the first frame.
class
_InternalFirstFrameRasterizedCondition
implements
WaitCondition
{
/// Creates an [InternalFirstFrameRasterizedCondition] instance.
/// Creates an [
_
InternalFirstFrameRasterizedCondition] instance.
const
_InternalFirstFrameRasterizedCondition
();
/// Factory constructor to parse an [InternalNoPendingFrameCondition] instance
...
...
@@ -112,16 +114,48 @@ class _InternalFirstFrameRasterizedCondition implements WaitCondition {
}
}
/// A condition that waits until no pending platform messages.
class
_InternalNoPendingPlatformMessagesCondition
implements
WaitCondition
{
/// Creates an [_InternalNoPendingPlatformMessagesCondition] instance.
const
_InternalNoPendingPlatformMessagesCondition
();
/// Factory constructor to parse an [_InternalNoPendingPlatformMessagesCondition] instance
/// from the given [SerializableWaitCondition] instance.
///
/// The [condition] argument must not be null.
factory
_InternalNoPendingPlatformMessagesCondition
.
deserialize
(
SerializableWaitCondition
condition
)
{
assert
(
condition
!=
null
);
if
(
condition
.
conditionName
!=
'NoPendingPlatformMessagesCondition'
)
throw
SerializationException
(
'Error occurred during deserializing from the given condition:
${condition.serialize()}
'
);
return
const
_InternalNoPendingPlatformMessagesCondition
();
}
@override
bool
get
condition
{
final
TestDefaultBinaryMessenger
binaryMessenger
=
ServicesBinding
.
instance
.
defaultBinaryMessenger
;
return
binaryMessenger
.
pendingMessageCount
==
0
;
}
@override
Future
<
void
>
wait
()
async
{
final
TestDefaultBinaryMessenger
binaryMessenger
=
ServicesBinding
.
instance
.
defaultBinaryMessenger
;
while
(!
condition
)
{
await
binaryMessenger
.
platformMessagesFinished
;
}
assert
(
condition
);
}
}
/// A combined condition that waits until all the given [conditions] are met.
class
_InternalCombinedCondition
implements
WaitCondition
{
/// Creates an [InternalCombinedCondition] instance with the given list of
/// Creates an [
_
InternalCombinedCondition] instance with the given list of
/// [conditions].
///
/// The [conditions] argument must not be null.
const
_InternalCombinedCondition
(
this
.
conditions
)
:
assert
(
conditions
!=
null
);
/// Factory constructor to parse an [InternalCombinedCondition] instance from
/// Factory constructor to parse an [
_
InternalCombinedCondition] instance from
/// the given [SerializableWaitCondition] instance.
///
/// The [condition] argument must not be null.
...
...
@@ -173,6 +207,8 @@ WaitCondition deserializeCondition(SerializableWaitCondition waitCondition) {
return
_InternalNoPendingFrameCondition
.
deserialize
(
waitCondition
);
case
'FirstFrameRasterizedCondition'
:
return
_InternalFirstFrameRasterizedCondition
.
deserialize
(
waitCondition
);
case
'NoPendingPlatformMessagesCondition'
:
return
_InternalNoPendingPlatformMessagesCondition
.
deserialize
(
waitCondition
);
case
'CombinedCondition'
:
return
_InternalCombinedCondition
.
deserialize
(
waitCondition
);
}
...
...
packages/flutter_driver/test/flutter_driver_test.dart
View file @
5667b782
...
...
@@ -262,6 +262,18 @@ void main() {
await
driver
.
waitForCondition
(
const
NoPendingFrame
(),
timeout:
_kTestTimeout
);
});
test
(
'sends the wait for NoPendingPlatformMessages command'
,
()
async
{
when
(
mockIsolate
.
invokeExtension
(
any
,
any
)).
thenAnswer
((
Invocation
i
)
{
expect
(
i
.
positionalArguments
[
1
],
<
String
,
dynamic
>{
'command'
:
'waitForCondition'
,
'timeout'
:
_kSerializedTestTimeout
,
'conditionName'
:
'NoPendingPlatformMessagesCondition'
,
});
return
makeMockResponse
(<
String
,
dynamic
>{});
});
await
driver
.
waitForCondition
(
const
NoPendingPlatformMessages
(),
timeout:
_kTestTimeout
);
});
test
(
'sends the waitForCondition of combined conditions command'
,
()
async
{
when
(
mockIsolate
.
invokeExtension
(
any
,
any
)).
thenAnswer
((
Invocation
i
)
{
expect
(
i
.
positionalArguments
[
1
],
<
String
,
dynamic
>{
...
...
packages/flutter_driver/test/src/extension_test.dart
View file @
5667b782
...
...
@@ -5,6 +5,7 @@
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_driver/flutter_driver.dart'
;
import
'package:flutter_driver/src/common/diagnostics_tree.dart'
;
...
...
@@ -245,6 +246,207 @@ void main() {
},
);
});
testWidgets
(
'waiting for NoPendingPlatformMessages returns immediately when there
\'
re no platform messages'
,
(
WidgetTester
tester
)
async
{
extension
.
call
(
const
WaitForCondition
(
NoPendingPlatformMessages
()).
serialize
())
.
then
<
void
>(
expectAsync1
((
Map
<
String
,
dynamic
>
r
)
{
result
=
r
;
}));
await
tester
.
idle
();
expect
(
result
,
<
String
,
dynamic
>{
'isError'
:
false
,
'response'
:
null
,
},
);
});
testWidgets
(
'waiting for NoPendingPlatformMessages returns until a single method channel call returns'
,
(
WidgetTester
tester
)
async
{
const
MethodChannel
channel
=
MethodChannel
(
'helloChannel'
,
JSONMethodCodec
());
const
MessageCodec
<
dynamic
>
jsonMessage
=
JSONMessageCodec
();
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
10
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
channel
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
extension
.
call
(
const
WaitForCondition
(
NoPendingPlatformMessages
()).
serialize
())
.
then
<
void
>(
expectAsync1
((
Map
<
String
,
dynamic
>
r
)
{
result
=
r
;
}));
// The channel message are delayed for 10 milliseconds, so nothing happens yet.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
isNull
);
// Now we receive the result.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
<
String
,
dynamic
>{
'isError'
:
false
,
'response'
:
null
,
},
);
});
testWidgets
(
'waiting for NoPendingPlatformMessages returns until both method channel calls return'
,
(
WidgetTester
tester
)
async
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
JSONMessageCodec
();
// Configures channel 1
const
MethodChannel
channel1
=
MethodChannel
(
'helloChannel1'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel1'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
10
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
// Configures channel 2
const
MethodChannel
channel2
=
MethodChannel
(
'helloChannel2'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel2'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
20
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
channel1
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
channel2
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
extension
.
call
(
const
WaitForCondition
(
NoPendingPlatformMessages
()).
serialize
())
.
then
<
void
>(
expectAsync1
((
Map
<
String
,
dynamic
>
r
)
{
result
=
r
;
}));
// Neither of the channel responses is received, so nothing happens yet.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
isNull
);
// Result of channel 1 is received, but channel 2 is still pending, so still waiting.
await
tester
.
pump
(
const
Duration
(
milliseconds:
10
));
expect
(
result
,
isNull
);
// Both of the results are received. Now we receive the result.
await
tester
.
pump
(
const
Duration
(
milliseconds:
30
));
expect
(
result
,
<
String
,
dynamic
>{
'isError'
:
false
,
'response'
:
null
,
},
);
});
testWidgets
(
'waiting for NoPendingPlatformMessages returns until new method channel call returns'
,
(
WidgetTester
tester
)
async
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
JSONMessageCodec
();
// Configures channel 1
const
MethodChannel
channel1
=
MethodChannel
(
'helloChannel1'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel1'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
10
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
// Configures channel 2
const
MethodChannel
channel2
=
MethodChannel
(
'helloChannel2'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel2'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
20
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
channel1
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
// Calls the waiting API before the second channel message is sent.
extension
.
call
(
const
WaitForCondition
(
NoPendingPlatformMessages
()).
serialize
())
.
then
<
void
>(
expectAsync1
((
Map
<
String
,
dynamic
>
r
)
{
result
=
r
;
}));
// The first channel message is not received, so nothing happens yet.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
isNull
);
channel2
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
// Result of channel 1 is received, but channel 2 is still pending, so still waiting.
await
tester
.
pump
(
const
Duration
(
milliseconds:
15
));
expect
(
result
,
isNull
);
// Both of the results are received. Now we receive the result.
await
tester
.
pump
(
const
Duration
(
milliseconds:
10
));
expect
(
result
,
<
String
,
dynamic
>{
'isError'
:
false
,
'response'
:
null
,
},
);
});
testWidgets
(
'waiting for NoPendingPlatformMessages returns until both old and new method channel calls return'
,
(
WidgetTester
tester
)
async
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
JSONMessageCodec
();
// Configures channel 1
const
MethodChannel
channel1
=
MethodChannel
(
'helloChannel1'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel1'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
20
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
// Configures channel 2
const
MethodChannel
channel2
=
MethodChannel
(
'helloChannel2'
,
JSONMethodCodec
());
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'helloChannel2'
,
(
ByteData
message
)
{
return
Future
<
ByteData
>.
delayed
(
const
Duration
(
milliseconds:
10
),
()
=>
jsonMessage
.
encodeMessage
(<
dynamic
>[
'hello world'
]));
});
channel1
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
extension
.
call
(
const
WaitForCondition
(
NoPendingPlatformMessages
()).
serialize
())
.
then
<
void
>(
expectAsync1
((
Map
<
String
,
dynamic
>
r
)
{
result
=
r
;
}));
// The first channel message is not received, so nothing happens yet.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
isNull
);
channel2
.
invokeMethod
<
String
>(
'sayHello'
,
'hello'
);
// Result of channel 2 is received, but channel 1 is still pending, so still waiting.
await
tester
.
pump
(
const
Duration
(
milliseconds:
10
));
expect
(
result
,
isNull
);
// Now we receive the result.
await
tester
.
pump
(
const
Duration
(
milliseconds:
5
));
expect
(
result
,
<
String
,
dynamic
>{
'isError'
:
false
,
'response'
:
null
,
},
);
});
});
group
(
'getSemanticsId'
,
()
{
...
...
packages/flutter_test/lib/src/binding.dart
View file @
5667b782
...
...
@@ -80,6 +80,67 @@ enum TestBindingEventSource {
const
Size
_kDefaultTestViewportSize
=
Size
(
800.0
,
600.0
);
/// A [BinaryMessenger] subclass that is used as the default binary messenger
/// under testing environment.
///
/// It tracks status of data sent across the Flutter platform barrier, which is
/// useful for testing frameworks to monitor and synchronize against the
/// platform messages.
class
TestDefaultBinaryMessenger
extends
BinaryMessenger
{
/// Creates a [TestDefaultBinaryMessenger] instance.
///
/// The [delegate] instance must not be null.
TestDefaultBinaryMessenger
(
this
.
delegate
):
assert
(
delegate
!=
null
);
/// The delegate [BinaryMessenger].
final
BinaryMessenger
delegate
;
final
List
<
Future
<
ByteData
>>
_pendingMessages
=
<
Future
<
ByteData
>>[];
/// The number of incomplete/pending calls sent to the platform channels.
int
get
pendingMessageCount
=>
_pendingMessages
.
length
;
@override
Future
<
ByteData
>
send
(
String
channel
,
ByteData
message
)
{
final
Future
<
ByteData
>
resultFuture
=
delegate
.
send
(
channel
,
message
);
// Removes the future itself from the [_pendingMessages] list when it
// completes.
if
(
resultFuture
!=
null
)
{
_pendingMessages
.
add
(
resultFuture
);
resultFuture
.
whenComplete
(()
=>
_pendingMessages
.
remove
(
resultFuture
));
}
return
resultFuture
;
}
/// Returns a Future that completes after all the platform calls are finished.
///
/// If a new platform message is sent after this method is called, this new
/// message is not tracked. Use with [pendingMessageCount] to guarantee no
/// pending message calls.
Future
<
void
>
get
platformMessagesFinished
{
return
Future
.
wait
<
void
>(
_pendingMessages
);
}
@override
Future
<
void
>
handlePlatformMessage
(
String
channel
,
ByteData
data
,
ui
.
PlatformMessageResponseCallback
callback
,
)
{
return
delegate
.
handlePlatformMessage
(
channel
,
data
,
callback
);
}
@override
void
setMessageHandler
(
String
channel
,
MessageHandler
handler
)
{
delegate
.
setMessageHandler
(
channel
,
handler
);
}
@override
void
setMockMessageHandler
(
String
channel
,
MessageHandler
handler
)
{
delegate
.
setMockMessageHandler
(
channel
,
handler
);
}
}
/// Base class for bindings used by widgets library tests.
///
/// The [ensureInitialized] method creates (if necessary) and returns
...
...
@@ -220,6 +281,11 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// doesn't get generated for tests.
}
@override
BinaryMessenger
createBinaryMessenger
()
{
return
TestDefaultBinaryMessenger
(
super
.
createBinaryMessenger
());
}
/// Whether there is currently a test executing.
bool
get
inTest
;
...
...
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