felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.8k stars 3.39k forks source link

'Bad state: Cannot add new events after calling close' when using transformEvents #1438

Closed Albert221 closed 4 years ago

Albert221 commented 4 years ago

Description

I get Bad state: Cannot add new events after calling close (...) on tests that use transformEvents.

To reproduce

Run the code below. See how the second test fails. Now comment whole transformEvents overriden method and run tests again. They pass.

dependencies:
  flutter_bloc: ^4.0.1
  rxdart: ^0.23.1
  bloc_test: ^5.1.0
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:rxdart/rxdart.dart';

class TestBloc extends Bloc<bool, bool> {
  @override
  bool get initialState => false;

  @override
  Stream<Transition<bool, bool>> transformEvents(
    Stream<bool> events,
    TransitionFunction<bool, bool> transitionFn,
  ) {
    return events
        .debounceTime(const Duration(milliseconds: 300))
        .switchMap(transitionFn);
  }

  @override
  Stream<bool> mapEventToState(bool event) async* {
    yield event;
  }
}

void main() {
  group('TestBloc', () {
    TestBloc bloc;
    setUp(() => bloc = TestBloc());
    tearDown(() => bloc.close());

    blocTest<TestBloc, bool, bool>(
      'has correct initial state',
      build: () async => bloc,
      skip: 0,
      expect: <bool>[false],
    );

    blocTest<TestBloc, bool, bool>(
      'emits true on event true',
      build: () async => bloc,
      act: (bloc) async => bloc.add(true),
      wait: const Duration(milliseconds: 300),
      expect: <bool>[true],
    );
  });
}

Expected behavior

Both tests pass.

Logs

[✓] Flutter (Channel stable, v1.17.4, on Mac OS X 10.15.5 19F101, locale pl)
    • Flutter version 1.17.4 at /Users/albert/Flutter
    • Framework revision 1ad9baa8b9 (3 weeks ago), 2020-06-17 14:41:16 -0700
    • Engine revision ee76268252
    • Dart version 2.8.4
YeungKC commented 4 years ago

Hi, @Albert221

If I change wait: const Duration(milliseconds: 300) to wait: const Duration(milliseconds: 305) I can pass the test. I think the time is not so precise because of the dart event loop.

Albert221 commented 4 years ago

Yes, that's right, but I think that's not the wanted behavior. Maybe we can somehow make it pass with microtasks or some other stuff under the hood.

YeungKC commented 4 years ago

I checked the source code. I don’t think it is necessary. There are a lot of Futures in the execution process, and Futures are event loops. Event loops are first come first served. To be honest, even if such a specific problem is solved, It may not satisfy other examples.

felangel commented 4 years ago

Hi @Albert221 👋 Thanks for opening an issue!

This will be resolved in v6.0.0 and is likely related to https://github.com/felangel/bloc/issues/1415.