title: Flutter Widget Test: StreamBuilder snapshot has connectionState = waiting with a non-empty Stream
body: <p>I'm trying to write a widget test for a widget that uses <code>StreamBuilder</code>. In the builder, I return a <code>CircularProgressIndicator</code> if <code>snapshot.hasData</code> is <code>false</code>, otherwise I return a <code>ListView</code> of widgets.</p>
  
  <p>In my test I create a <code>StreamController</code> and add an element to it. When I run the test, I would expect to see <code>snapshot.hasData</code> = <code>true</code>, but instead it's <code>false</code> and I can see that the <code>connectionState</code> is <code>waiting</code>. So my test fails.</p>
  
  <p>Somehow it seems that the first element is not pulled out of the stream, and the connection remains in <code>waiting</code> state. I'm not sure what I'm doing wrong.</p>
  
  <p>Here's my widget test:</p>
  
  <pre><code>testWidgets('Job item pressed - shows edit job page',
    (WidgetTester tester) async {
  StreamController&lt;List&lt;Job&gt;&gt; controller =
      StreamController&lt;List&lt;Job&gt;&gt;.broadcast(sync: true);
  
  Job job = Job(id: '0', createdAt: 0, jobName: 'Dart');
  controller.add([job]);
  
  final page = JobsPage(
    jobsStream: controller.stream,
  );
  MockRouter mockRouter = MockRouter();
  await tester.pumpWidget(makeTestableWidget(
    child: page,
    auth: MockAuth(),
    database: MockDatabase(),
    router: mockRouter,
  ));
  
  Finder waiting = find.byType(CircularProgressIndicator);
  expect(waiting, findsNothing);
  
  Finder placeholder = find.byType(PlaceholderContent);
  expect(placeholder, findsNothing);
  
  Finder item = find.byKey(Key('jobListItem-${job.id}'));
  expect(item, findsOneWidget);
  
  await controller.close();
  });
  </code></pre>
  
  <p>And here is my widget code:</p>
  
  <pre><code>Widget _buildContent(BuildContext context) {
  return StreamBuilder&lt;List&lt;Job&gt;&gt;(
    stream: jobsStream,
    builder: (context, snapshot) {
      return ListItemsBuilder(
        snapshot: snapshot,
        itemBuilder: (BuildContext context, Job job) {
          return JobListItem(
            key: Key('jobListItem-${job.id}'),
            title: job.jobName, // TODO: This be null?
            onTap: () =&gt; _select(context, job),
          );
        },
      );
    },
  );
  }
  </code></pre>
  
  <p>And the <code>ListItemsBuilder</code>:</p>
  
  <pre><code>typedef Widget ItemWidgetBuilder&lt;T&gt;(BuildContext context, T item);
  
  class ListItemsBuilder&lt;T&gt; extends StatelessWidget {
    ListItemsBuilder({this.snapshot, this.itemBuilder});
    final AsyncSnapshot&lt;List&lt;T&gt;&gt; snapshot;
    final ItemWidgetBuilder&lt;T&gt; itemBuilder;
  
    @override
    Widget build(BuildContext context) {
      // prints "waiting"
      print('${snapshot.connectionState.toString()}');
      if (snapshot.hasData) {
        final items = snapshot.data;
        if (items.length &gt; 0) {
          return _buildList(items);
        } else {
          return PlaceholderContent();
        }
      } else if (snapshot.error != null) {
        print('${snapshot.error}');
        return PlaceholderContent(
          title: 'Something went wrong',
          message: 'Can\'t load entries right now',
        );
      } else {
        return Center(child: CircularProgressIndicator());
      }
    }
  
    Widget _buildList(List&lt;T&gt; items) {
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return itemBuilder(context, items[index]);
        },
      );
    }
  }
  </code></pre>
  
  <p>I tried using a <code>StreamController.broadcast(sync: true)</code> instead of a simple <code>StreamController</code>, but it didn't make a difference.</p>
  
  <p>Also any additional <code>pump()</code> and <code>pumpAndSettle()</code> calls don't make a difference.</p>
  
  <p>Any ideas?</p>