Flutter Widget测试:StreamBuilder快照具有connectionState =等待非空Stream

时间:2018-08-10 12:44:17

标签: dart flutter

我正在尝试为使用StreamBuilder的小部件编写小部件测试。在构建器中,如果CircularProgressIndicatorsnapshot.hasData,则返回false,否则返回ListView的小部件。

在测试中,我创建一个StreamController并向其中添加一个元素。运行测试时,我希望看到snapshot.hasData = true,但是它是false,我可以看到connectionStatewaiting。所以我的测试失败了。

以某种方式似乎没有将第一个元素从流中拉出,并且连接保持在waiting状态。我不确定自己在做什么错。

这是我的小部件测试:

testWidgets('Job item pressed - shows edit job page',
  (WidgetTester tester) async {
StreamController<List<Job>> controller =
    StreamController<List<Job>>.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();
});

这是我的小部件代码:

Widget _buildContent(BuildContext context) {
return StreamBuilder<List<Job>>(
  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: () => _select(context, job),
        );
      },
    );
  },
);
}

还有ListItemsBuilder

typedef Widget ItemWidgetBuilder<T>(BuildContext context, T item);

class ListItemsBuilder<T> extends StatelessWidget {
  ListItemsBuilder({this.snapshot, this.itemBuilder});
  final AsyncSnapshot<List<T>> snapshot;
  final ItemWidgetBuilder<T> itemBuilder;

  @override
  Widget build(BuildContext context) {
    // prints "waiting"
    print('${snapshot.connectionState.toString()}');
    if (snapshot.hasData) {
      final items = snapshot.data;
      if (items.length > 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<T> items) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return itemBuilder(context, items[index]);
      },
    );
  }
}

我尝试使用StreamController.broadcast(sync: true)而不是简单的StreamController,但这没什么区别。

此外,任何其他pump()pumpAndSettle()调用都没有影响。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

解决方案

使用await tester.pump(Duration.zero);

完整测试代码:

testWidgets('Job item pressed - shows edit job page',
    (WidgetTester tester) async {
  StreamController<List<Job>> controller = StreamController<List<Job>>();

  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,
  ));

  // this will cause the stream to emit the first event
  await tester.pump(Duration.zero);

  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();
});