Skip to content

Commit 456d176

Browse files
authored
Add tests for stream_builder.0.dart API example. (#147832)
This PR contributes to flutter/flutter#130459 ### Description - Updates `examples/api/lib/widgets/async/stream_builder.0.dart` - Adds test for `examples/api/lib/widgets/async/stream_builder.0.dart`
1 parent 1128eab commit 456d176

File tree

3 files changed

+236
-85
lines changed

3 files changed

+236
-85
lines changed

dev/bots/check_code_samples.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ final Set<String> _knownMissingTests = <String>{
405405
'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.0_test.dart',
406406
'examples/api/test/widgets/scroll_position/scroll_metrics_notification.0_test.dart',
407407
'examples/api/test/widgets/media_query/media_query_data.system_gesture_insets.0_test.dart',
408-
'examples/api/test/widgets/async/stream_builder.0_test.dart',
409408
'examples/api/test/widgets/async/future_builder.0_test.dart',
410409
'examples/api/test/widgets/restoration_properties/restorable_value.0_test.dart',
411410
'examples/api/test/widgets/animated_size/animated_size.0_test.dart',

examples/api/lib/widgets/async/stream_builder.0.dart

Lines changed: 126 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,54 @@ void main() => runApp(const StreamBuilderExampleApp());
1313
class StreamBuilderExampleApp extends StatelessWidget {
1414
const StreamBuilderExampleApp({super.key});
1515

16+
static const Duration delay = Duration(seconds: 1);
17+
1618
@override
1719
Widget build(BuildContext context) {
1820
return const MaterialApp(
19-
home: StreamBuilderExample(),
21+
home: StreamBuilderExample(delay: delay),
2022
);
2123
}
2224
}
2325

2426
class StreamBuilderExample extends StatefulWidget {
25-
const StreamBuilderExample({super.key});
27+
const StreamBuilderExample({
28+
required this.delay,
29+
super.key,
30+
});
31+
32+
final Duration delay;
2633

2734
@override
2835
State<StreamBuilderExample> createState() => _StreamBuilderExampleState();
2936
}
3037

3138
class _StreamBuilderExampleState extends State<StreamBuilderExample> {
32-
final Stream<int> _bids = (() {
33-
late final StreamController<int> controller;
34-
controller = StreamController<int>(
35-
onListen: () async {
36-
await Future<void>.delayed(const Duration(seconds: 1));
37-
controller.add(1);
38-
await Future<void>.delayed(const Duration(seconds: 1));
39-
await controller.close();
40-
},
41-
);
42-
return controller.stream;
43-
})();
39+
late final StreamController<int> _controller = StreamController<int>(
40+
onListen: () async {
41+
await Future<void>.delayed(widget.delay);
42+
43+
if (!_controller.isClosed) {
44+
_controller.add(1);
45+
}
46+
47+
await Future<void>.delayed(widget.delay);
48+
49+
if (!_controller.isClosed) {
50+
_controller.close();
51+
}
52+
},
53+
);
54+
55+
Stream<int> get _bids => _controller.stream;
56+
57+
@override
58+
void dispose() {
59+
if (!_controller.isClosed) {
60+
_controller.close();
61+
}
62+
super.dispose();
63+
}
4464

4565
@override
4666
Widget build(BuildContext context) {
@@ -50,86 +70,108 @@ class _StreamBuilderExampleState extends State<StreamBuilderExample> {
5070
child: Container(
5171
alignment: FractionalOffset.center,
5272
color: Colors.white,
53-
child: StreamBuilder<int>(
54-
stream: _bids,
55-
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
56-
List<Widget> children;
57-
if (snapshot.hasError) {
73+
child: BidsStatus(bids: _bids),
74+
),
75+
);
76+
}
77+
}
78+
79+
class BidsStatus extends StatelessWidget {
80+
const BidsStatus({
81+
required this.bids,
82+
super.key,
83+
});
84+
85+
final Stream<int>? bids;
86+
87+
@override
88+
Widget build(BuildContext context) {
89+
return StreamBuilder<int>(
90+
stream: bids,
91+
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
92+
List<Widget> children;
93+
if (snapshot.hasError) {
94+
children = <Widget>[
95+
const Icon(
96+
Icons.error_outline,
97+
color: Colors.red,
98+
size: 60,
99+
),
100+
Padding(
101+
padding: const EdgeInsets.only(top: 16),
102+
child: Text('Error: ${snapshot.error}'),
103+
),
104+
Padding(
105+
padding: const EdgeInsets.only(top: 8),
106+
child: Text(
107+
'Stack trace: ${snapshot.stackTrace}',
108+
maxLines: 1,
109+
overflow: TextOverflow.ellipsis,
110+
),
111+
),
112+
];
113+
} else {
114+
switch (snapshot.connectionState) {
115+
case ConnectionState.none:
116+
children = const <Widget>[
117+
Icon(
118+
Icons.info,
119+
color: Colors.blue,
120+
size: 60,
121+
),
122+
Padding(
123+
padding: EdgeInsets.only(top: 16),
124+
child: Text('Select a lot'),
125+
),
126+
];
127+
case ConnectionState.waiting:
128+
children = const <Widget>[
129+
SizedBox(
130+
width: 60,
131+
height: 60,
132+
child: CircularProgressIndicator(),
133+
),
134+
Padding(
135+
padding: EdgeInsets.only(top: 16),
136+
child: Text('Awaiting bids...'),
137+
),
138+
];
139+
case ConnectionState.active:
58140
children = <Widget>[
59141
const Icon(
60-
Icons.error_outline,
61-
color: Colors.red,
142+
Icons.check_circle_outline,
143+
color: Colors.green,
62144
size: 60,
63145
),
64146
Padding(
65147
padding: const EdgeInsets.only(top: 16),
66-
child: Text('Error: ${snapshot.error}'),
148+
child: Text('\$${snapshot.data}'),
149+
),
150+
];
151+
case ConnectionState.done:
152+
children = <Widget>[
153+
const Icon(
154+
Icons.info,
155+
color: Colors.blue,
156+
size: 60,
67157
),
68158
Padding(
69-
padding: const EdgeInsets.only(top: 8),
70-
child: Text('Stack trace: ${snapshot.stackTrace}'),
159+
padding: const EdgeInsets.only(top: 16),
160+
child: Text(
161+
snapshot.hasData
162+
? '\$${snapshot.data} (closed)'
163+
: '(closed)',
164+
),
71165
),
72166
];
73-
} else {
74-
switch (snapshot.connectionState) {
75-
case ConnectionState.none:
76-
children = const <Widget>[
77-
Icon(
78-
Icons.info,
79-
color: Colors.blue,
80-
size: 60,
81-
),
82-
Padding(
83-
padding: EdgeInsets.only(top: 16),
84-
child: Text('Select a lot'),
85-
),
86-
];
87-
case ConnectionState.waiting:
88-
children = const <Widget>[
89-
SizedBox(
90-
width: 60,
91-
height: 60,
92-
child: CircularProgressIndicator(),
93-
),
94-
Padding(
95-
padding: EdgeInsets.only(top: 16),
96-
child: Text('Awaiting bids...'),
97-
),
98-
];
99-
case ConnectionState.active:
100-
children = <Widget>[
101-
const Icon(
102-
Icons.check_circle_outline,
103-
color: Colors.green,
104-
size: 60,
105-
),
106-
Padding(
107-
padding: const EdgeInsets.only(top: 16),
108-
child: Text('\$${snapshot.data}'),
109-
),
110-
];
111-
case ConnectionState.done:
112-
children = <Widget>[
113-
const Icon(
114-
Icons.info,
115-
color: Colors.blue,
116-
size: 60,
117-
),
118-
Padding(
119-
padding: const EdgeInsets.only(top: 16),
120-
child: Text('\$${snapshot.data} (closed)'),
121-
),
122-
];
123-
}
124-
}
125-
126-
return Column(
127-
mainAxisAlignment: MainAxisAlignment.center,
128-
children: children,
129-
);
130-
},
131-
),
132-
),
167+
}
168+
}
169+
170+
return Column(
171+
mainAxisAlignment: MainAxisAlignment.center,
172+
children: children,
173+
);
174+
},
133175
);
134176
}
135177
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter_api_samples/widgets/async/stream_builder.0.dart'
9+
as example;
10+
import 'package:flutter_test/flutter_test.dart';
11+
12+
void main() {
13+
testWidgets('StreamBuilder listens to internal stream', (WidgetTester tester) async {
14+
await tester.pumpWidget(
15+
const example.StreamBuilderExampleApp(),
16+
);
17+
18+
expect(find.byType(CircularProgressIndicator), findsOneWidget);
19+
expect(find.text('Awaiting bids...'), findsOneWidget);
20+
21+
await tester.pump(example.StreamBuilderExampleApp.delay);
22+
23+
expect(find.byIcon(Icons.check_circle_outline), findsOneWidget);
24+
expect(find.text(r'$1'), findsOneWidget);
25+
26+
await tester.pump(example.StreamBuilderExampleApp.delay);
27+
28+
expect(find.byIcon(Icons.info), findsOneWidget);
29+
expect(find.text(r'$1 (closed)'), findsOneWidget);
30+
});
31+
32+
testWidgets('BidsStatus correctly displays error state', (WidgetTester tester) async {
33+
final StreamController<int> controller = StreamController<int>();
34+
addTearDown(controller.close);
35+
36+
controller.onListen = () {
37+
controller.addError('Unexpected error!', StackTrace.empty);
38+
};
39+
40+
await tester.pumpWidget(
41+
MaterialApp(
42+
home: example.BidsStatus(bids: controller.stream),
43+
),
44+
);
45+
await tester.pump();
46+
47+
expect(find.byIcon(Icons.error_outline), findsOneWidget);
48+
expect(find.text('Error: Unexpected error!'), findsOneWidget);
49+
expect(find.text('Stack trace: ${StackTrace.empty}'), findsOneWidget);
50+
});
51+
52+
testWidgets('BidsStatus correctly displays none state', (WidgetTester tester) async {
53+
await tester.pumpWidget(
54+
const MaterialApp(
55+
home: example.BidsStatus(bids: null),
56+
),
57+
);
58+
59+
expect(find.byIcon(Icons.info), findsOneWidget);
60+
expect(find.text('Select a lot'), findsOneWidget);
61+
});
62+
63+
testWidgets('BidsStatus correctly displays waiting state', (WidgetTester tester) async {
64+
final StreamController<int> controller = StreamController<int>();
65+
addTearDown(controller.close);
66+
67+
await tester.pumpWidget(
68+
MaterialApp(
69+
home: example.BidsStatus(bids: controller.stream),
70+
),
71+
);
72+
73+
expect(find.byType(CircularProgressIndicator), findsOneWidget);
74+
expect(find.text('Awaiting bids...'), findsOneWidget);
75+
});
76+
77+
testWidgets('BidsStatus correctly displays active state', (WidgetTester tester) async {
78+
final StreamController<int> controller = StreamController<int>();
79+
addTearDown(controller.close);
80+
81+
controller.onListen = () {
82+
controller.add(1);
83+
};
84+
85+
await tester.pumpWidget(
86+
MaterialApp(
87+
home: example.BidsStatus(bids: controller.stream),
88+
),
89+
);
90+
await tester.pump();
91+
92+
expect(find.byIcon(Icons.check_circle_outline), findsOneWidget);
93+
expect(find.text(r'$1'), findsOneWidget);
94+
});
95+
96+
testWidgets('BidsStatus correctly displays done state', (WidgetTester tester) async {
97+
final StreamController<int> controller = StreamController<int>();
98+
controller.close();
99+
100+
await tester.pumpWidget(
101+
MaterialApp(
102+
home: example.BidsStatus(bids: controller.stream),
103+
),
104+
);
105+
await tester.pump();
106+
107+
expect(find.byIcon(Icons.info), findsOneWidget);
108+
expect(find.text('(closed)'), findsOneWidget);
109+
});
110+
}

0 commit comments

Comments
 (0)