Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
431 views
in Technique[技术] by (71.8m points)

dart - Flutter-Test: Getting BlocProvider.of() called with a context that does not container Bloc

I am trying to test my submit button which fires a bloc event onPress.

SubmitButton.dart - Widget

class AuthenticationSubmitButton extends StatefulWidget {
  final String buttonLabel;
  final TextEditingController _userEmailController;
  final TextEditingController _passwordController;

  AuthenticationSubmitButton(
      this.buttonLabel, this._userEmailController, this._passwordController);

  @override
  _AuthenticationSubmitButtonState createState() =>
      _AuthenticationSubmitButtonState();
}

class _AuthenticationSubmitButtonState
    extends State<AuthenticationSubmitButton> {
  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    final _authBloc = BlocProvider.of<AuthenticationBloc>(context);
    return Container(
      child: FlatButton.icon(
        height: screenSize.height * 0.07,
        minWidth: screenSize.width * 0.5,
        padding: EdgeInsets.all(10),
        color: Colors.green,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
        onPressed: () {
          final email = widget._userEmailController.text.trim();
          final password = widget._passwordController.text.trim();
          _authBloc.add(UserLoginEvent(email, password));
        },
        icon: Icon(Icons.keyboard_return_rounded),
        label: Text(
          widget.buttonLabel,
          style: SubmitButtonStyle,
        ),
      ),
    );
  }
}

As you can see I am calling the event UserLoginEvent

authentication_events.dart

@immutable
abstract class AuthenticationEvent {}

/**
 * Login Event
 * Logout Event
 */

class UserLoginEvent extends AuthenticationEvent {
  final String userEmail;
  final String userPassword;
  UserLoginEvent(this.userEmail, this.userPassword);
}

class ClearLoginEvent extends AuthenticationEvent {
  
}

And here is my authentication states

authentication_states.dart

@immutable
abstract class AuthenticationState extends Equatable {

}

class AuthenticationInitial extends AuthenticationState {
  @override
  List<Object> get props => [];
}

/**
 * LoginSuccessful
 * LoginFailed
 * LogoutSuccessful
 */

class LoginSuccessful extends AuthenticationState {
  @override
  List<Object> get props => [];
}

class LoginError extends AuthenticationState {
  @override
  List<Object> get props => [];
}

authentication_bloc.dart

    class AuthenticationBloc
        extends Bloc<AuthenticationEvent, AuthenticationState> {
      AuthenticationBloc({this.userRepository}) : super(AuthenticationInitial());
      UserRepository userRepository;
      @override
      Stream<AuthenticationState> mapEventToState(
        AuthenticationEvent event,
      ) async* {
        if (event is UserLoginEvent) {
          UserRepository repository = userRepository ?? UserRepository();
          try {
            bool loggedIn = await repository.authenticateUserWithCredentials(
                event.userEmail, event.userPassword);
            if (loggedIn) {
              yield LoginSuccessful();
            } else {
              yield LoginError();
            }
          } catch (e) {
            yield EmptyLoginCredentials();
          }
        } else if (event is ClearLoginEvent) {
          yield AuthenticationInitial();
        }
      }
    }

And finally my test for submit button

> submit_button_test.dart

class MockAuthBloc extends MockBloc<AuthenticationState>
    implements AuthenticationBloc {}

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();
  MockAuthBloc authBloc = MockAuthBloc();
  TextEditingController _userEmailController;
  TextEditingController _passwordController;

  setUp(() {
    _userEmailController = TextEditingController();
    _passwordController = TextEditingController();
    authBloc = MockAuthBloc();
  });

  tearDown(() {
    _userEmailController.dispose();
    _passwordController.dispose();
    authBloc?.close();
  });

  ///Provide Material App for giving access to MediaQuery
  ///Wrap any widget that needs Material widget
  Widget buildTestableWidget(Widget widget) {
    return MediaQuery(
      data: MediaQueryData(),
      child: BlocProvider.value(
        value: authBloc,
        child: MaterialApp(
          home: Material(
            child: widget,
          ),
        ),
      ),
    );
  }

  group('Testing Submit button |', () {
    testWidgets('description', (WidgetTester tester) async {
      whenListen(
        authBloc,
        Stream.fromIterable(<AuthenticationState>[LoginSuccessful()]),
      );

      await tester.pumpWidget(buildTestableWidget(AuthenticationSubmitButton(
          'Submit', _userEmailController, _passwordController)));
      final buttonFinder = find.byType(FlatButton);
      final button = tester.firstWidget(buttonFinder);
    });
  });
}

Could you please tell me what am I doing wrong here? Below is my error

00:03 +19: /home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart: Testing Submit button | description                                                                
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building AuthenticationSubmitButton(dirty, dependencies:
[MediaQuery], state: _AuthenticationSubmitButtonState#da4f9):
        BlocProvider.of() called with a context that does not contain a Bloc/Cubit of type
AuthenticationBloc.
        No ancestor could be found starting from the context that was passed to
BlocProvider.of<AuthenticationBloc>().

        This can happen if the context you used comes from a widget above the BlocProvider.

        The context used was: AuthenticationSubmitButton(dirty, dependencies: [MediaQuery], state:
_AuthenticationSubmitButtonState#da4f9)


The relevant error-causing widget was:
  AuthenticationSubmitButton
  file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:57:51

When the exception was thrown, this was the stack:
#0      BlocProvider.of (package:flutter_bloc/src/bloc_provider.dart:121:7)
#1      _AuthenticationSubmitButtonState.build (package:kaadhal_host_client/screens/Authentication/widgets/submit_button.dart:26:36)
#2      StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
#3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
#4      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
#5      Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#6      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4606:5)
#7      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4791:11)
#8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
...     Normal element mounting (174 frames)
#182    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#183    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
...     Normal element mounting (267 frames)
#450    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#451    Element.updateChild (package:flutter/src/widgets/framework.dart:3327:18)
#452    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
#453    _InheritedProviderScopeElement.performRebuild (package:provider/src/inherited_provider.dart:426:11)
#454    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#455    ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4606:5)
#456    ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
...     Normal element mounting (7 frames)
#463    SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
...     Normal element mounting (7 frames)
#470    SingleChildWidgetElementMixin.mount (package:nested/nested.dart:223:11)
...     Normal element mounting (7 frames)
#477    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#478    Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
#479    RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1252:16)
#480    RenderObjectToWidgetElement.update (package:flutter/src/widgets/binding.dart:1230:5)
#481    RenderObjectToWidgetElement.performRebuild (package:flutter/src/widgets/binding.dart:1244:7)
#482    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
#483    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
#484    AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1088:18)
#485    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
#486    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#487    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
#488    AutomatedTestWidgetsFlutterBinding.pump.<anonymous closure> (package:flutter_test/src/binding.dart:961:9)
#491    TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#492    AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:948:27)
#493    WidgetTester.pumpWidget.<anonymous closure> (package:flutter_test/src/widget_tester.dart:524:22)
#496    TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#497    WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:521:27)
#498    main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:57:20)
#499    main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:46:32)
#500    testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:146:29)
#511    FakeAsync.flushMicrotasks (package:fake_async/fake_async.dart:193:32)
#512    AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1189:17)
#513    AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1177:35)
(elided 29 frames from dart:async and package:stack_trace)

════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following StateError was thrown running a test:
Bad state: No element

When the exception was thrown, this was the stack:
#0      Iterable.first (dart:core/iterable.dart:524:7)
#1      WidgetController.firstWidget (package:flutter_test/src/controller.dart:79:30)
#2      main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart:60:29)
<asynchronous suspension>
#3      main.<anonymous closure>.<anonymous closure> (file:///home/bhuvanesh/code/kaadhal_host_client/test/screens/Authentication/widgets/submit_button_test.dart)
#4      testWidgets.<anonymous closure&

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...