ReactiveX / rxdart

The Reactive Extensions for Dart

Home Page:http://reactivex.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BehaviorSubject doesn't provide value via 'first' in test environment

agavrilko opened this issue · comments

The dartpad example:
https://dartpad.dev/?id=02878d4135fdf329059f95fb9f7a72c4

Description

The issue only appears in widget test environment ('testWidgets').
If widget utilize the 'stream.first' within itself or bloc, not really matters,
and stream is BehaviorSubject, the Future provided by 'first' never finishes.

Example

The widget in the example below just shows text 'Value = $number'
with the number from assigned stream.

In the real environment the last added value to the stream is shown on the screen.
But in the test we see 'Value = -1' because timeout fires.
Without timeout widget never receives any value.

void main() {
  testWidgets('Proof', (tester) async {
    final BehaviorSubject<int> subject = BehaviorSubject.seeded(99);
    final valueFinder = find.text('Value = 99');
    final noneFinder = find.text('None');
    await tester.pumpWidget(
      MaterialApp(
        home: SomeWidget(stream: subject),
      ),
    );
    print('Looking for None');
    expect(valueFinder, findsNothing);
    expect(noneFinder, findsOneWidget);
    await tester.pumpAndSettle();
    print('Looking for Value = 99');
    expect(valueFinder, findsOneWidget);
    expect(noneFinder, findsNothing);
  });
}

class SomeWidget extends StatelessWidget {
  const SomeWidget({Key? key, required this.stream}) : super(key: key);

  final Stream<int> stream;

  @override
  Widget build(BuildContext context) => FutureBuilder<int>(
        future: stream.first
            .timeout(const Duration(milliseconds: 10))
            .onError<TimeoutException>((e, st) => -1),
        builder: (context, snapshot) => Center(
          child: Text(
            snapshot.hasData ? 'Value = ${snapshot.data}' : 'None',
          ),
        ),
      );
}

Note

According to this issue, if we wrap pumpWidget within runAsync, it actually works.
However, it doesn't feel right. It is more like a workaround.

The question is, can this issue be resolved?
If not, or if you believe this is not an issue, could you clarify why such behavior is legit.

Thanks in advance.

We are running into this issue as well