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
85f0aea8
Unverified
Commit
85f0aea8
authored
Nov 14, 2020
by
creativecreatorormaybenot
Committed by
GitHub
Nov 14, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add stackTrace to AsyncSnapshot (#69507)
parent
0d7270ba
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
125 additions
and
79 deletions
+125
-79
async.dart
packages/flutter/lib/src/widgets/async.dart
+60
-36
async_test.dart
packages/flutter/test/widgets/async_test.dart
+65
-43
No files found.
packages/flutter/lib/src/widgets/async.dart
View file @
85f0aea8
...
...
@@ -75,10 +75,11 @@ abstract class StreamBuilderBase<T, S> extends StatefulWidget {
/// is combined with the new data item in the fold computation.
S
afterData
(
S
current
,
T
data
);
/// Returns an updated version of the [current] summary following an error.
/// Returns an updated version of the [current] summary following an error
/// with a stack trace.
///
/// The default implementation returns [current] as is.
S
afterError
(
S
current
,
Object
error
)
=>
current
;
S
afterError
(
S
current
,
Object
error
,
StackTrace
stackTrace
)
=>
current
;
/// Returns an updated version of the [current] summary following stream
/// termination.
...
...
@@ -138,9 +139,9 @@ class _StreamBuilderBaseState<T, S> extends State<StreamBuilderBase<T, S>> {
setState
(()
{
_summary
=
widget
.
afterData
(
_summary
,
data
);
});
},
onError:
(
Object
error
)
{
},
onError:
(
Object
error
,
StackTrace
stackTrace
)
{
setState
(()
{
_summary
=
widget
.
afterError
(
_summary
,
error
);
_summary
=
widget
.
afterError
(
_summary
,
error
,
stackTrace
);
});
},
onDone:
()
{
setState
(()
{
...
...
@@ -204,22 +205,31 @@ enum ConnectionState {
@immutable
class
AsyncSnapshot
<
T
>
{
/// Creates an [AsyncSnapshot] with the specified [connectionState],
/// and optionally either [data] or [error] (but not both).
const
AsyncSnapshot
.
_
(
this
.
connectionState
,
this
.
data
,
this
.
error
)
/// and optionally either [data] or [error] with an optional [stackTrace]
/// (but not both data and error).
const
AsyncSnapshot
.
_
(
this
.
connectionState
,
this
.
data
,
this
.
error
,
this
.
stackTrace
)
:
assert
(
connectionState
!=
null
),
assert
(!(
data
!=
null
&&
error
!=
null
));
assert
(!(
data
!=
null
&&
error
!=
null
)),
assert
(
stackTrace
==
null
||
error
!=
null
);
/// Creates an [AsyncSnapshot] in [ConnectionState.none] with null data and error.
const
AsyncSnapshot
.
nothing
()
:
this
.
_
(
ConnectionState
.
none
,
null
,
null
);
const
AsyncSnapshot
.
nothing
()
:
this
.
_
(
ConnectionState
.
none
,
null
,
null
,
null
);
/// Creates an [AsyncSnapshot] in [ConnectionState.waiting] with null data and error.
const
AsyncSnapshot
.
waiting
()
:
this
.
_
(
ConnectionState
.
waiting
,
null
,
null
);
const
AsyncSnapshot
.
waiting
()
:
this
.
_
(
ConnectionState
.
waiting
,
null
,
null
,
null
);
/// Creates an [AsyncSnapshot] in the specified [state] and with the specified [data].
const
AsyncSnapshot
.
withData
(
ConnectionState
state
,
T
data
):
this
.
_
(
state
,
data
,
null
);
const
AsyncSnapshot
.
withData
(
ConnectionState
state
,
T
data
):
this
.
_
(
state
,
data
,
null
,
null
);
/// Creates an [AsyncSnapshot] in the specified [state] and with the specified [error].
const
AsyncSnapshot
.
withError
(
ConnectionState
state
,
Object
error
)
:
this
.
_
(
state
,
null
,
error
);
/// Creates an [AsyncSnapshot] in the specified [state] with the specified [error]
/// and a [stackTrace].
///
/// If no [stackTrace] is explicitly specified, [StackTrace.empty] will be used instead.
const
AsyncSnapshot
.
withError
(
ConnectionState
state
,
Object
error
,
[
StackTrace
stackTrace
=
StackTrace
.
empty
,
])
:
this
.
_
(
state
,
null
,
error
,
stackTrace
);
/// Current state of connection to the asynchronous computation.
final
ConnectionState
connectionState
;
...
...
@@ -254,11 +264,20 @@ class AsyncSnapshot<T> {
/// If [data] is not null, this will be null.
final
Object
?
error
;
/// The latest stack trace object received by the asynchronous computation.
///
/// This will not be null iff [error] is not null. Consequently, [stackTrace]
/// will be non-null when [hasError] is true.
///
/// However, even when not null, [stackTrace] might be empty. The stack trace
/// is empty when there is an error but no stack trace has been provided.
final
StackTrace
?
stackTrace
;
/// Returns a snapshot like this one, but in the specified [state].
///
/// The [data]
and [error] fields persist unmodified, even if the new state is
/// [ConnectionState.none].
AsyncSnapshot
<
T
>
inState
(
ConnectionState
state
)
=>
AsyncSnapshot
<
T
>.
_
(
state
,
data
,
error
);
/// The [data]
, [error], and [stackTrace] fields persist unmodified, even if
///
the new state is
[ConnectionState.none].
AsyncSnapshot
<
T
>
inState
(
ConnectionState
state
)
=>
AsyncSnapshot
<
T
>.
_
(
state
,
data
,
error
,
stackTrace
);
/// Returns whether this snapshot contains a non-null [data] value.
///
...
...
@@ -275,7 +294,7 @@ class AsyncSnapshot<T> {
bool
get
hasError
=>
error
!=
null
;
@override
String
toString
()
=>
'
${objectRuntimeType(this, 'AsyncSnapshot')}
(
$connectionState
,
$data
,
$error
)'
;
String
toString
()
=>
'
${objectRuntimeType(this, 'AsyncSnapshot')}
(
$connectionState
,
$data
,
$error
,
$stackTrace
)'
;
@override
bool
operator
==(
Object
other
)
{
...
...
@@ -284,7 +303,8 @@ class AsyncSnapshot<T> {
return
other
is
AsyncSnapshot
<
T
>
&&
other
.
connectionState
==
connectionState
&&
other
.
data
==
data
&&
other
.
error
==
error
;
&&
other
.
error
==
error
&&
other
.
stackTrace
==
stackTrace
;
}
@override
...
...
@@ -318,12 +338,12 @@ typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnaps
/// of the following snapshots that includes the last one (the one with
/// ConnectionState.done):
///
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.waiting, null)`
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.active, 0)`
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.active, 1)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.waiting, null)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.active, 0)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.active, 1)`
/// * ...
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.active, 9)`
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.done, 9)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.active, 9)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.done, 9)`
///
/// The actual sequence of invocations of the [builder] depends on the relative
/// timing of events produced by the stream and the build rate of the Flutter
...
...
@@ -332,15 +352,15 @@ typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnaps
/// Changing the [StreamBuilder] configuration to another stream during event
/// generation introduces snapshot pairs of the form:
///
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.none, 5)`
/// * `
new
AsyncSnapshot<int>.withData(ConnectionState.waiting, 5)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.none, 5)`
/// * `AsyncSnapshot<int>.withData(ConnectionState.waiting, 5)`
///
/// The latter will be produced only when the new stream is non-null, and the
/// former only when the old stream is non-null.
///
/// The stream may produce errors, resulting in snapshots of the form:
///
/// * `
new AsyncSnapshot<int>.withError(ConnectionState.active, 'some error'
)`
/// * `
AsyncSnapshot<int>.withError(ConnectionState.active, 'some error', someStackTrace
)`
///
/// The data and error fields of snapshots produced are only changed when the
/// state is `ConnectionState.active`.
...
...
@@ -386,7 +406,11 @@ typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnaps
/// Padding(
/// padding: const EdgeInsets.only(top: 16),
/// child: Text('Error: ${snapshot.error}'),
/// )
/// ),
/// Padding(
/// padding: const EdgeInsets.only(top: 8),
/// child: Text('Stack trace: ${snapshot.stackTrace}'),
/// ),
/// ];
/// } else {
/// switch (snapshot.connectionState) {
...
...
@@ -511,8 +535,8 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> {
}
@override
AsyncSnapshot
<
T
>
afterError
(
AsyncSnapshot
<
T
>
current
,
Object
error
)
{
return
AsyncSnapshot
<
T
>.
withError
(
ConnectionState
.
active
,
error
);
AsyncSnapshot
<
T
>
afterError
(
AsyncSnapshot
<
T
>
current
,
Object
error
,
StackTrace
stackTrace
)
{
return
AsyncSnapshot
<
T
>.
withError
(
ConnectionState
.
active
,
error
,
stackTrace
);
}
@override
...
...
@@ -559,14 +583,14 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> {
/// is null, the [builder] will be called with either both or only the latter of
/// the following snapshots:
///
/// * `
new
AsyncSnapshot<String>.withData(ConnectionState.waiting, null)`
/// * `
new
AsyncSnapshot<String>.withData(ConnectionState.done, 'some data')`
/// * `AsyncSnapshot<String>.withData(ConnectionState.waiting, null)`
/// * `AsyncSnapshot<String>.withData(ConnectionState.done, 'some data')`
///
/// If that same future instead completed with an error, the [builder] would be
/// called with either both or only the latter of:
///
/// * `
new
AsyncSnapshot<String>.withData(ConnectionState.waiting, null)`
/// * `
new AsyncSnapshot<String>.withError(ConnectionState.done, 'some error'
)`
/// * `AsyncSnapshot<String>.withData(ConnectionState.waiting, null)`
/// * `
AsyncSnapshot<String>.withError(ConnectionState.done, 'some error', someStackTrace
)`
///
/// The initial snapshot data can be controlled by specifying [initialData]. You
/// would use this facility to ensure that if the [builder] is invoked before
...
...
@@ -579,8 +603,8 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> {
/// old future has already completed successfully with data as above, changing
/// configuration to a new future results in snapshot pairs of the form:
///
/// * `
new
AsyncSnapshot<String>.withData(ConnectionState.none, 'data of first future')`
/// * `
new
AsyncSnapshot<String>.withData(ConnectionState.waiting, 'data of second future')`
/// * `AsyncSnapshot<String>.withData(ConnectionState.none, 'data of first future')`
/// * `AsyncSnapshot<String>.withData(ConnectionState.waiting, 'data of second future')`
///
/// In general, the latter will be produced only when the new future is
/// non-null, and the former only when the old future is non-null.
...
...
@@ -768,10 +792,10 @@ class _FutureBuilderState<T> extends State<FutureBuilder<T>> {
_snapshot
=
AsyncSnapshot
<
T
>.
withData
(
ConnectionState
.
done
,
data
);
});
}
},
onError:
(
Object
error
)
{
},
onError:
(
Object
error
,
StackTrace
stackTrace
)
{
if
(
_activeCallbackIdentity
==
callbackIdentity
)
{
setState
(()
{
_snapshot
=
AsyncSnapshot
<
T
>.
withError
(
ConnectionState
.
done
,
error
);
_snapshot
=
AsyncSnapshot
<
T
>.
withError
(
ConnectionState
.
done
,
error
,
stackTrace
);
});
}
});
...
...
packages/flutter/test/widgets/async_test.dart
View file @
85f0aea8
...
...
@@ -34,9 +34,20 @@ void main() {
expect
(
const
AsyncSnapshot
<
int
>.
nothing
().
connectionState
,
ConnectionState
.
none
);
expect
(
const
AsyncSnapshot
<
int
>.
nothing
().
data
,
isNull
);
expect
(
const
AsyncSnapshot
<
int
>.
nothing
().
error
,
isNull
);
expect
(
const
AsyncSnapshot
<
int
>.
nothing
().
stackTrace
,
isNull
);
expect
(
const
AsyncSnapshot
<
int
>.
waiting
().
connectionState
,
ConnectionState
.
waiting
);
expect
(
const
AsyncSnapshot
<
int
>.
waiting
().
data
,
isNull
);
expect
(
const
AsyncSnapshot
<
int
>.
waiting
().
error
,
isNull
);
expect
(
const
AsyncSnapshot
<
int
>.
waiting
().
stackTrace
,
isNull
);
});
test
(
'withError uses empty stack trace if no stack trace is specified'
,
()
{
// We need to store the error as a local variable in order for the
// equality check on the error to be true.
final
Error
error
=
Error
();
expect
(
AsyncSnapshot
<
int
>.
withError
(
ConnectionState
.
done
,
error
),
AsyncSnapshot
<
int
>.
withError
(
ConnectionState
.
done
,
error
,
StackTrace
.
empty
));
});
});
group
(
'Async smoke tests'
,
()
{
...
...
@@ -67,12 +78,12 @@ void main() {
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
null
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsOneWidget
);
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
completer
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'gracefully handles transition to null future'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -80,14 +91,14 @@ void main() {
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
completer
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
null
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsOneWidget
);
completer
.
complete
(
'hello'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'gracefully handles transition to other future'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -96,35 +107,35 @@ void main() {
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
completerA
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
future:
completerB
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
completerB
.
complete
(
'B'
);
completerA
.
complete
(
'A'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, B, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, B, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'tracks life-cycle of Future to success'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
completer
.
complete
(
'hello'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'tracks life-cycle of Future to error'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
completer
.
completeError
(
'bad'
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
completer
.
completeError
(
'bad'
,
StackTrace
.
fromString
(
'trace'
)
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, null, bad)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, null, bad
, trace
)'
),
findsOneWidget
);
});
testWidgets
(
'runs the builder using given initial data'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -134,7 +145,7 @@ void main() {
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'ignores initialData when reconfiguring'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -144,7 +155,7 @@ void main() {
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null
, null
)'
),
findsOneWidget
);
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
FutureBuilder
<
String
>(
key:
key
,
...
...
@@ -152,7 +163,7 @@ void main() {
builder:
snapshotText
,
initialData:
'Ignored'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null
, null
)'
),
findsOneWidget
);
});
});
group
(
'StreamBuilder'
,
()
{
...
...
@@ -161,12 +172,12 @@ void main() {
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
null
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsOneWidget
);
final
StreamController
<
String
>
controller
=
StreamController
<
String
>();
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
controller
.
stream
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'gracefully handles transition to null stream'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -174,11 +185,11 @@ void main() {
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
controller
.
stream
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
null
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'gracefully handles transition to other stream'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -187,14 +198,14 @@ void main() {
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
controllerA
.
stream
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
controllerB
.
stream
,
builder:
snapshotText
,
));
controllerB
.
add
(
'B'
);
controllerA
.
add
(
'A'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, B, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, B, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'tracks events and errors of stream until completion'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -202,19 +213,19 @@ void main() {
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
stream:
controller
.
stream
,
builder:
snapshotText
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsOneWidget
);
controller
.
add
(
'1'
);
controller
.
add
(
'2'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, 2, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, 2, null
, null
)'
),
findsOneWidget
);
controller
.
add
(
'3'
);
controller
.
addError
(
'bad'
);
controller
.
addError
(
'bad'
,
StackTrace
.
fromString
(
'trace'
)
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, null, bad)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.active, null, bad
, trace
)'
),
findsOneWidget
);
controller
.
add
(
'4'
);
controller
.
close
();
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, 4, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, 4, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'runs the builder using given initial data'
,
(
WidgetTester
tester
)
async
{
final
StreamController
<
String
>
controller
=
StreamController
<
String
>();
...
...
@@ -223,7 +234,7 @@ void main() {
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null
, null
)'
),
findsOneWidget
);
});
testWidgets
(
'ignores initialData when reconfiguring'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
GlobalKey
();
...
...
@@ -233,7 +244,7 @@ void main() {
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null
, null
)'
),
findsOneWidget
);
final
StreamController
<
String
>
controller
=
StreamController
<
String
>();
await
tester
.
pumpWidget
(
StreamBuilder
<
String
>(
key:
key
,
...
...
@@ -241,7 +252,7 @@ void main() {
builder:
snapshotText
,
initialData:
'Ignored'
,
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null
, null
)'
),
findsOneWidget
);
});
});
group
(
'FutureBuilder and StreamBuilder behave identically on Stream from Future'
,
()
{
...
...
@@ -251,35 +262,46 @@ void main() {
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
),
StreamBuilder
<
String
>(
stream:
completer
.
future
.
asStream
(),
builder:
snapshotText
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsNWidgets
(
2
));
completer
.
complete
(
'hello'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null, null)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when completing with error and with empty stack trace'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
Column
(
children:
<
Widget
>[
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
),
StreamBuilder
<
String
>(
stream:
completer
.
future
.
asStream
(),
builder:
snapshotText
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null, null)'
),
findsNWidgets
(
2
));
completer
.
completeError
(
'bad'
,
StackTrace
.
empty
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, null, bad, )'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when completing with error'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'when completing with error
and with stack trace
'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
await
tester
.
pumpWidget
(
Column
(
children:
<
Widget
>[
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
),
StreamBuilder
<
String
>(
stream:
completer
.
future
.
asStream
(),
builder:
snapshotText
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null)'
),
findsNWidgets
(
2
));
completer
.
completeError
(
'bad'
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, null, null
, null
)'
),
findsNWidgets
(
2
));
completer
.
completeError
(
'bad'
,
StackTrace
.
fromString
(
'trace'
)
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, null, bad)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, null, bad
, trace
)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when Future is null'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Column
(
children:
<
Widget
>[
FutureBuilder
<
String
>(
future:
null
,
builder:
snapshotText
),
StreamBuilder
<
String
>(
stream:
null
,
builder:
snapshotText
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, null, null
, null
)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when initialData is used with null Future and Stream'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Column
(
children:
<
Widget
>[
FutureBuilder
<
String
>(
future:
null
,
builder:
snapshotText
,
initialData:
'I'
),
StreamBuilder
<
String
>(
stream:
null
,
builder:
snapshotText
,
initialData:
'I'
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.none, I, null
, null
)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when using initialData and completing with data'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
Completer
<
String
>();
...
...
@@ -287,10 +309,10 @@ void main() {
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
,
initialData:
'I'
),
StreamBuilder
<
String
>(
stream:
completer
.
future
.
asStream
(),
builder:
snapshotText
,
initialData:
'I'
),
]));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.waiting, I, null
, null
)'
),
findsNWidgets
(
2
));
completer
.
complete
(
'hello'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null)'
),
findsNWidgets
(
2
));
expect
(
find
.
text
(
'AsyncSnapshot<String>(ConnectionState.done, hello, null
, null
)'
),
findsNWidgets
(
2
));
});
});
group
(
'StreamBuilderBase'
,
()
{
...
...
@@ -326,11 +348,11 @@ void main() {
final
StreamController
<
String
>
controller
=
StreamController
<
String
>();
await
tester
.
pumpWidget
(
StringCollector
(
key:
key
,
stream:
controller
.
stream
));
controller
.
add
(
'1'
);
controller
.
addError
(
'bad'
);
controller
.
addError
(
'bad'
,
StackTrace
.
fromString
(
'trace'
)
);
controller
.
add
(
'2'
);
controller
.
close
();
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'conn, data:1, error:bad, data:2, done'
),
findsOneWidget
);
expect
(
find
.
text
(
'conn, data:1, error:bad
stackTrace:trace
, data:2, done'
),
findsOneWidget
);
});
});
}
...
...
@@ -352,7 +374,7 @@ class StringCollector extends StreamBuilderBase<String, List<String>> {
List
<
String
>
afterData
(
List
<
String
>
current
,
String
data
)
=>
current
..
add
(
'data:
$data
'
);
@override
List
<
String
>
afterError
(
List
<
String
>
current
,
dynamic
error
)
=>
current
..
add
(
'error:
$error
'
);
List
<
String
>
afterError
(
List
<
String
>
current
,
dynamic
error
,
StackTrace
stackTrace
)
=>
current
..
add
(
'error:
$error
stackTrace:
$stackTrace
'
);
@override
List
<
String
>
afterDone
(
List
<
String
>
current
)
=>
current
..
add
(
'done'
);
...
...
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