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
f28eb28f
Unverified
Commit
f28eb28f
authored
Apr 07, 2023
by
Rexios
Committed by
GitHub
Apr 07, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_test] Adds method to mock EventChannels (#123726)
[flutter_test] Adds method to mock EventChannels
parent
4e5e9f46
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
216 additions
and
45 deletions
+216
-45
platform_channel_test.dart
packages/flutter/test/services/platform_channel_test.dart
+26
-45
flutter_test.dart
packages/flutter_test/lib/flutter_test.dart
+1
-0
mock_event_channel.dart
packages/flutter_test/lib/src/mock_event_channel.dart
+79
-0
test_default_binary_messenger.dart
...s/flutter_test/lib/src/test_default_binary_messenger.dart
+84
-0
test_default_binary_messenger_test.dart
...flutter_test/test/test_default_binary_messenger_test.dart
+26
-0
No files found.
packages/flutter/test/services/platform_channel_test.dart
View file @
f28eb28f
...
...
@@ -265,69 +265,50 @@ void main() {
});
group
(
'EventChannel'
,
()
{
const
MessageCodec
<
dynamic
>
jsonMessage
=
JSONMessageCodec
();
const
MethodCodec
jsonMethod
=
JSONMethodCodec
();
const
EventChannel
channel
=
EventChannel
(
'ch'
,
jsonMethod
);
void
emitEvent
(
ByteData
?
event
)
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'ch'
,
event
,
(
ByteData
?
reply
)
{},
);
}
test
(
'can receive event stream'
,
()
async
{
bool
canceled
=
false
;
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'ch'
,
(
ByteData
?
message
)
async
{
final
Map
<
dynamic
,
dynamic
>
methodCall
=
jsonMessage
.
decodeMessage
(
message
)
as
Map
<
dynamic
,
dynamic
>;
if
(
methodCall
[
'method'
]
==
'listen'
)
{
final
String
argument
=
methodCall
[
'args'
]
as
String
;
emitEvent
(
jsonMethod
.
encodeSuccessEnvelope
(
'
${argument}
1'
));
emitEvent
(
jsonMethod
.
encodeSuccessEnvelope
(
'
${argument}
2'
));
emitEvent
(
null
);
return
jsonMethod
.
encodeSuccessEnvelope
(
null
);
}
else
if
(
methodCall
[
'method'
]
==
'cancel'
)
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockStreamHandler
(
channel
,
MockStreamHandler
.
inline
(
onListen:
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
)
{
events
.
success
(
'
${arguments}
1'
);
events
.
success
(
'
${arguments}
2'
);
events
.
endOfStream
();
},
onCancel:
(
Object
?
arguments
)
{
canceled
=
true
;
return
jsonMethod
.
encodeSuccessEnvelope
(
null
);
}
else
{
fail
(
'Expected listen or cancel'
);
}
},
},
),
);
final
List
<
dynamic
>
events
=
await
channel
.
receiveBroadcastStream
(
'hello'
).
toList
();
final
List
<
Object
?
>
events
=
await
channel
.
receiveBroadcastStream
(
'hello'
).
toList
();
expect
(
events
,
orderedEquals
(<
String
>[
'hello1'
,
'hello2'
]));
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
canceled
,
isTrue
);
});
test
(
'can receive error event'
,
()
async
{
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockMessageHandler
(
'ch'
,
(
ByteData
?
message
)
async
{
final
Map
<
dynamic
,
dynamic
>
methodCall
=
jsonMessage
.
decodeMessage
(
message
)
as
Map
<
dynamic
,
dynamic
>;
if
(
methodCall
[
'method'
]
==
'listen'
)
{
final
String
argument
=
methodCall
[
'args'
]
as
String
;
emitEvent
(
jsonMethod
.
encodeErrorEnvelope
(
code:
'404'
,
message:
'Not Found.'
,
details:
argument
));
return
jsonMethod
.
encodeSuccessEnvelope
(
null
);
}
else
if
(
methodCall
[
'method'
]
==
'cancel'
)
{
return
jsonMethod
.
encodeSuccessEnvelope
(
null
);
}
else
{
fail
(
'Expected listen or cancel'
);
}
},
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockStreamHandler
(
channel
,
MockStreamHandler
.
inline
(
onListen:
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
)
{
events
.
error
(
code:
'404'
,
message:
'Not Found.'
,
details:
arguments
);
},
),
);
final
List
<
dynamic
>
events
=
<
dynamic
>[];
final
List
<
dynamic
>
errors
=
<
dynamic
>[];
final
List
<
Object
?>
events
=
<
Object
?
>[];
final
List
<
Object
?>
errors
=
<
Object
?
>[];
channel
.
receiveBroadcastStream
(
'hello'
).
listen
(
events
.
add
,
onError:
errors
.
add
);
await
Future
<
void
>.
delayed
(
Duration
.
zero
);
expect
(
events
,
isEmpty
);
expect
(
errors
,
hasLength
(
1
));
expect
(
errors
[
0
],
isA
<
PlatformException
>());
final
PlatformException
error
=
errors
[
0
]
as
PlatformException
;
expect
(
error
.
code
,
'404'
);
expect
(
error
.
message
,
'Not Found.'
);
expect
(
error
.
details
,
'hello'
);
final
PlatformException
?
error
=
errors
[
0
]
as
PlatformException
?
;
expect
(
error
?
.
code
,
'404'
);
expect
(
error
?
.
message
,
'Not Found.'
);
expect
(
error
?
.
details
,
'hello'
);
});
});
}
packages/flutter_test/lib/flutter_test.dart
View file @
f28eb28f
...
...
@@ -69,6 +69,7 @@ export 'src/frame_timing_summarizer.dart';
export
'src/goldens.dart'
;
export
'src/image.dart'
;
export
'src/matchers.dart'
;
export
'src/mock_event_channel.dart'
;
export
'src/nonconst.dart'
;
export
'src/platform.dart'
;
export
'src/restoration.dart'
;
...
...
packages/flutter_test/lib/src/mock_event_channel.dart
0 → 100644
View file @
f28eb28f
// 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
'dart:async'
;
import
'package:flutter/services.dart'
;
/// A mock stream handler for an [EventChannel] that mimics the native
/// StreamHandler API.
///
/// The [onListen] callback is provided a [MockStreamHandlerEventSink] with
/// the following API:
/// - [MockStreamHandlerEventSink.success] sends a success event.
/// - [MockStreamHandlerEventSink.error] sends an error event.
/// - [MockStreamHandlerEventSink.endOfStream] sends an end of stream event.
abstract
class
MockStreamHandler
{
/// Create a new [MockStreamHandler].
MockStreamHandler
();
/// Create a new inline [MockStreamHandler] with the given [onListen] and
/// [onCancel] handlers.
factory
MockStreamHandler
.
inline
({
required
MockStreamHandlerOnListenCallback
onListen
,
MockStreamHandlerOnCancelCallback
?
onCancel
,
})
=>
_InlineMockStreamHandler
(
onListen:
onListen
,
onCancel:
onCancel
);
/// Handler for the listen event.
void
onListen
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
);
/// Handler for the cancel event.
void
onCancel
(
Object
?
arguments
);
}
/// Typedef for the inline onListen callback.
typedef
MockStreamHandlerOnListenCallback
=
void
Function
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
);
/// Typedef for the inline onCancel callback.
typedef
MockStreamHandlerOnCancelCallback
=
void
Function
(
Object
?
arguments
);
class
_InlineMockStreamHandler
extends
MockStreamHandler
{
_InlineMockStreamHandler
({
required
MockStreamHandlerOnListenCallback
onListen
,
MockStreamHandlerOnCancelCallback
?
onCancel
,
})
:
_onListenInline
=
onListen
,
_onCancelInline
=
onCancel
;
final
MockStreamHandlerOnListenCallback
_onListenInline
;
final
MockStreamHandlerOnCancelCallback
?
_onCancelInline
;
@override
void
onListen
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
)
=>
_onListenInline
(
arguments
,
events
);
@override
void
onCancel
(
Object
?
arguments
)
=>
_onCancelInline
?.
call
(
arguments
);
}
/// A mock event sink for a [MockStreamHandler] that mimics the native
/// [EventSink](https://api.flutter.dev/javadoc/io/flutter/plugin/common/EventChannel.EventSink.html)
/// API.
class
MockStreamHandlerEventSink
{
/// Create a new [MockStreamHandlerEventSink] with the given [sink].
MockStreamHandlerEventSink
(
EventSink
<
Object
?>
sink
)
:
_sink
=
sink
;
final
EventSink
<
Object
?>
_sink
;
/// Send a success event.
void
success
(
Object
?
event
)
=>
_sink
.
add
(
event
);
/// Send an error event.
void
error
({
required
String
code
,
String
?
message
,
Object
?
details
,
})
=>
_sink
.
addError
(
PlatformException
(
code:
code
,
message:
message
,
details:
details
));
/// Send an end of stream event.
void
endOfStream
()
=>
_sink
.
close
();
}
packages/flutter_test/lib/src/test_default_binary_messenger.dart
View file @
f28eb28f
...
...
@@ -8,6 +8,9 @@ import 'dart:ui' as ui;
import
'package:fake_async/fake_async.dart'
;
import
'package:flutter/services.dart'
;
import
'mock_event_channel.dart'
;
import
'widget_tester.dart'
;
/// A function which takes the name of the method channel, it's handler,
/// platform message and asynchronously returns an encoded response.
typedef
AllMessagesHandler
=
Future
<
ByteData
?>?
Function
(
...
...
@@ -197,6 +200,9 @@ class TestDefaultBinaryMessenger extends BinaryMessenger {
///
/// * [setMockMethodCallHandler], which wraps this method but decodes
/// the messages using a [MethodCodec].
///
/// * [setMockStreamHandler], which wraps [setMockMethodCallHandler] to
/// handle [EventChannel] messages.
void
setMockMessageHandler
(
String
channel
,
MessageHandler
?
handler
,
[
Object
?
identity
])
{
if
(
handler
==
null
)
{
_outboundHandlers
.
remove
(
channel
);
...
...
@@ -237,6 +243,9 @@ class TestDefaultBinaryMessenger extends BinaryMessenger {
///
/// * [setMockMethodCallHandler], which is similar but decodes
/// the messages using a [MethodCodec].
///
/// * [setMockStreamHandler], which wraps [setMockMethodCallHandler] to
/// handle [EventChannel] messages.
void
setMockDecodedMessageHandler
<
T
>(
BasicMessageChannel
<
T
>
channel
,
Future
<
T
>
Function
(
T
?
message
)?
handler
)
{
if
(
handler
==
null
)
{
setMockMessageHandler
(
channel
.
name
,
null
);
...
...
@@ -302,6 +311,81 @@ class TestDefaultBinaryMessenger extends BinaryMessenger {
},
handler
);
}
/// Set a handler for intercepting stream events sent to the
/// platform on the given channel.
///
/// Intercepted method calls are not forwarded to the platform.
///
/// The given handler will replace the currently registered
/// handler for that channel, if any. To stop intercepting messages
/// at all, pass null as the handler.
///
/// Events are decoded using the codec of the channel.
///
/// The handler's stream messages are used as a response, after encoding
/// them using the channel's codec.
///
/// To send an error, pass the error information to the handler's event sink.
///
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
///
/// Registered handlers are cleared after each test.
///
/// See also:
///
/// * [setMockMethodCallHandler], which is the similar method for
/// [MethodChannel].
///
/// * [setMockMessageHandler], which is similar but provides raw
/// access to the underlying bytes.
///
/// * [setMockDecodedMessageHandler], which is similar but decodes
/// the messages using a [MessageCodec].
void
setMockStreamHandler
(
EventChannel
channel
,
MockStreamHandler
?
handler
)
{
if
(
handler
==
null
)
{
setMockMessageHandler
(
channel
.
name
,
null
);
return
;
}
final
StreamController
<
Object
?>
controller
=
StreamController
<
Object
?>();
addTearDown
(
controller
.
close
);
setMockMethodCallHandler
(
MethodChannel
(
channel
.
name
,
channel
.
codec
),
(
MethodCall
call
)
async
{
switch
(
call
.
method
)
{
case
'listen'
:
return
handler
.
onListen
(
call
.
arguments
,
MockStreamHandlerEventSink
(
controller
.
sink
));
case
'cancel'
:
return
handler
.
onCancel
(
call
.
arguments
);
default
:
throw
UnimplementedError
(
'Method
${call.method}
not implemented'
);
}
});
final
StreamSubscription
<
Object
?>
sub
=
controller
.
stream
.
listen
(
(
Object
?
e
)
=>
channel
.
binaryMessenger
.
handlePlatformMessage
(
channel
.
name
,
channel
.
codec
.
encodeSuccessEnvelope
(
e
),
null
,
),
);
addTearDown
(
sub
.
cancel
);
sub
.
onError
((
Object
?
e
)
{
if
(
e
is
!
PlatformException
)
{
throw
ArgumentError
(
'Stream error must be a PlatformException'
);
}
channel
.
binaryMessenger
.
handlePlatformMessage
(
channel
.
name
,
channel
.
codec
.
encodeErrorEnvelope
(
code:
e
.
code
,
message:
e
.
message
,
details:
e
.
details
,
),
null
,
);
});
sub
.
onDone
(()
=>
channel
.
binaryMessenger
.
handlePlatformMessage
(
channel
.
name
,
null
,
null
));
}
/// Returns true if the `handler` argument matches the `handler`
/// previously passed to [setMockMessageHandler],
/// [setMockDecodedMessageHandler], or [setMockMethodCallHandler].
...
...
packages/flutter_test/test/test_default_binary_messenger_test.dart
View file @
f28eb28f
...
...
@@ -69,6 +69,32 @@ void main() {
expect
(
result
?.
buffer
.
asUint8List
(),
Uint8List
.
fromList
(<
int
>[
2
,
3
,
4
]));
});
test
(
'Mock StreamHandler is set correctly'
,
()
async
{
const
EventChannel
channel
=
EventChannel
(
''
);
TestDefaultBinaryMessengerBinding
.
instance
.
defaultBinaryMessenger
.
setMockStreamHandler
(
channel
,
MockStreamHandler
.
inline
(
onListen:
(
Object
?
arguments
,
MockStreamHandlerEventSink
events
)
{
events
.
success
(
arguments
);
events
.
error
(
code:
'code'
,
message:
'message'
,
details:
'details'
);
events
.
endOfStream
();
})
);
expect
(
channel
.
receiveBroadcastStream
(
'argument'
),
emitsInOrder
(<
Object
?>[
'argument'
,
emitsError
(
isA
<
PlatformException
>()
.
having
((
PlatformException
e
)
=>
e
.
code
,
'code'
,
'code'
)
.
having
((
PlatformException
e
)
=>
e
.
message
,
'message'
,
'message'
)
.
having
((
PlatformException
e
)
=>
e
.
details
,
'details'
,
'details'
),
),
emitsDone
,
]),
);
});
testWidgets
(
'Mock AllMessagesHandler is set correctly'
,
(
WidgetTester
tester
)
async
{
final
TestDefaultBinaryMessenger
binaryMessenger
=
...
...
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