Тест виджета flutter: снимок streambuilder имеет connectionstate = ожидание с непустым потоком

Я пытаюсь написать тест виджета для виджета, который использует StreamBuilder. В компоновщике я возвращаю CircularProgressIndicator, если snapshot.hasData - это false, в противном случае я возвращаю ListView виджетов.

В своем тесте я создаю StreamController и добавляю к нему элемент. Когда я запускаю тест, я ожидаю увидеть snapshot.hasData = true, но вместо этого это false, и я вижу, что connectionState - это waiting. Итак, мой тест не удался.

Как-то кажется, что первый элемент из потока не выдергивается, а соединение остается в состоянии 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() не имеют значения.

Любые идеи?

5
0
4 668
1

Ответы 1

Решение

Используйте 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();
});

Другие вопросы по теме