Skip to content

Commit

Permalink
Add Widget Tests to Bloc Library
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel committed Mar 7, 2019
1 parent a9339cc commit a7b0d50
Show file tree
Hide file tree
Showing 33 changed files with 2,056 additions and 77 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -21,6 +21,7 @@ Examples have been updated to Dart 2.
* [InheritedWidget Example](inherited_widget) - Uses an InheritedWidget to pass app state down the widget hierarchy.
* [BLoC Example](bloc_flutter) - An implementation of the BLoC pattern, which uses Sinks for Inputs and Streams for Ouputs
* ["Simple" BLoC Example](simple_bloc_flutter) - Similar to the BLoC pattern, but uses Functions for Inputs and Streams for Outputs. Results in far less code compared to standard BLoC.
* [Bloc Library Example](bloc_library) - Uses the [bloc](https://pub.dartlang.org/packages/bloc) and [flutter_bloc](https://pub.dartlang.org/packages/flutter_bloc) libraries to manage app state and update Widgets.
* [Redux Example](redux) - Uses the [Redux](https://pub.dartlang.org/packages/redux) library to manage app state and update Widgets
* [built_redux Example](built_redux) - Uses the [built_redux](https://pub.dartlang.org/packages/built_redux) library to enforce immutability and manage app state
* [scoped_model Example](scoped_model) - Uses the [scoped_model](https://pub.dartlang.org/packages/scoped_model) library to hold app state and notify Widgets of Updates
Expand Down Expand Up @@ -73,5 +74,6 @@ All of these ideas and even some of the language are directly influenced by two
* [Pavel Shilyagov](https://github.com/p69)
* [Leo Cavalcante](https://github.com/leocavalcante)
* [Greg Perry](https://github.com/AndriousSolutions)
* [Felix Angelov](https://github.com/felangel)

I'd like to thank all of the folks who have helped write new samples, improve the current implementations, and added documentation! You're amazing! :)
18 changes: 18 additions & 0 deletions bloc_library/lib/bloc_library_keys.dart
@@ -0,0 +1,18 @@
// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved.
// Use of this source code is governed by the MIT license that can be found
// in the LICENSE file.

import 'package:flutter/widgets.dart';

class BlocLibraryKeys {
static final extraActionsPopupMenuButton =
const Key('__extraActionsPopupMenuButton__');
static final extraActionsEmptyContainer =
const Key('__extraActionsEmptyContainer__');
static final filteredTodosEmptyContainer =
const Key('__filteredTodosEmptyContainer__');
static final statsLoadingIndicator = const Key('__statsLoadingIndicator__');
static final emptyStatsContainer = const Key('__emptyStatsContainer__');
static final emptyDetailsContainer = const Key('__emptyDetailsContainer__');
static final detailsScreenCheckBox = const Key('__detailsScreenCheckBox__');
}
2 changes: 1 addition & 1 deletion bloc_library/lib/localization.dart
Expand Up @@ -14,7 +14,7 @@ class FlutterBlocLocalizations {
);
}

String get appTitle => "Flutter Bloc Example";
String get appTitle => "Bloc Library Example";
}

class FlutterBlocLocalizationsDelegate
Expand Down
4 changes: 3 additions & 1 deletion bloc_library/lib/screens/details_screen.dart
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todos_app_core/todos_app_core.dart';
import 'package:bloc_library/blocs/todos/todos.dart';
import 'package:bloc_library/screens/screens.dart';
import 'package:bloc_library/bloc_library_keys.dart';

class DetailsScreen extends StatelessWidget {
final String id;
Expand Down Expand Up @@ -41,7 +42,7 @@ class DetailsScreen extends StatelessWidget {
],
),
body: todo == null
? Container()
? Container(key: BlocLibraryKeys.emptyDetailsContainer)
: Padding(
padding: EdgeInsets.all(16.0),
child: ListView(
Expand All @@ -52,6 +53,7 @@ class DetailsScreen extends StatelessWidget {
Padding(
padding: EdgeInsets.only(right: 8.0),
child: Checkbox(
key: BlocLibraryKeys.detailsScreenCheckBox,
value: todo.complete,
onChanged: (_) {
todosBloc.dispatch(
Expand Down
50 changes: 25 additions & 25 deletions bloc_library/lib/screens/home_screen.dart
Expand Up @@ -40,31 +40,31 @@ class HomeScreenState extends State<HomeScreen> {
return BlocBuilder(
bloc: _tabBloc,
builder: (BuildContext context, AppTab activeTab) {
return BlocProvider(
bloc: _tabBloc,
child: BlocProvider(
bloc: _filteredTodosBloc,
child: Scaffold(
appBar: AppBar(
title: Text(FlutterBlocLocalizations.of(context).appTitle),
actions: [
FilterButton(visible: activeTab == AppTab.todos),
ExtraActions(),
],
),
body: activeTab == AppTab.todos ? FilteredTodos() : Stats(),
floatingActionButton: FloatingActionButton(
key: ArchSampleKeys.addTodoFab,
onPressed: () {
Navigator.pushNamed(context, ArchSampleRoutes.addTodo);
},
child: Icon(Icons.add),
tooltip: ArchSampleLocalizations.of(context).addTodo,
),
bottomNavigationBar: TabSelector(
activeTab: activeTab,
onTabSelected: (tab) => _tabBloc.dispatch(UpdateTab(tab)),
),
return BlocProviderTree(
blocProviders: [
BlocProvider<TabBloc>(bloc: _tabBloc),
BlocProvider<FilteredTodosBloc>(bloc: _filteredTodosBloc),
],
child: Scaffold(
appBar: AppBar(
title: Text(FlutterBlocLocalizations.of(context).appTitle),
actions: [
FilterButton(visible: activeTab == AppTab.todos),
ExtraActions(),
],
),
body: activeTab == AppTab.todos ? FilteredTodos() : Stats(),
floatingActionButton: FloatingActionButton(
key: ArchSampleKeys.addTodoFab,
onPressed: () {
Navigator.pushNamed(context, ArchSampleRoutes.addTodo);
},
child: Icon(Icons.add),
tooltip: ArchSampleLocalizations.of(context).addTodo,
),
bottomNavigationBar: TabSelector(
activeTab: activeTab,
onTabSelected: (tab) => _tabBloc.dispatch(UpdateTab(tab)),
),
),
);
Expand Down
7 changes: 5 additions & 2 deletions bloc_library/lib/widgets/extra_actions.dart
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todos_app_core/todos_app_core.dart';
import 'package:bloc_library/blocs/todos/todos.dart';
import 'package:bloc_library/models/models.dart';
import 'package:bloc_library/bloc_library_keys.dart';

class ExtraActions extends StatelessWidget {
ExtraActions({Key key}) : super(key: ArchSampleKeys.extraActionsButton);
Expand All @@ -24,6 +25,7 @@ class ExtraActions extends StatelessWidget {
.todos
.every((todo) => todo.complete);
return PopupMenuButton<ExtraAction>(
key: BlocLibraryKeys.extraActionsPopupMenuButton,
onSelected: (action) {
switch (action) {
case ExtraAction.clearCompleted:
Expand All @@ -49,12 +51,13 @@ class ExtraActions extends StatelessWidget {
key: ArchSampleKeys.clearCompleted,
value: ExtraAction.clearCompleted,
child: Text(
ArchSampleLocalizations.of(context).clearCompleted),
ArchSampleLocalizations.of(context).clearCompleted,
),
),
],
);
}
return Container();
return Container(key: BlocLibraryKeys.extraActionsEmptyContainer);
},
);
}
Expand Down
3 changes: 2 additions & 1 deletion bloc_library/lib/widgets/filtered_todos.dart
Expand Up @@ -10,6 +10,7 @@ import 'package:todos_app_core/todos_app_core.dart';
import 'package:bloc_library/blocs/blocs.dart';
import 'package:bloc_library/widgets/widgets.dart';
import 'package:bloc_library/screens/screens.dart';
import 'package:bloc_library/bloc_library_keys.dart';

class FilteredTodos extends StatelessWidget {
FilteredTodos({Key key}) : super(key: key);
Expand Down Expand Up @@ -71,7 +72,7 @@ class FilteredTodos extends StatelessWidget {
},
);
} else {
return Container();
return Container(key: BlocLibraryKeys.filteredTodosEmptyContainer);
}
},
);
Expand Down
5 changes: 3 additions & 2 deletions bloc_library/lib/widgets/stats.dart
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todos_app_core/todos_app_core.dart';
import 'package:bloc_library/blocs/todos/todos.dart';
import 'package:bloc_library/widgets/widgets.dart';
import 'package:bloc_library/bloc_library_keys.dart';

class Stats extends StatelessWidget {
Stats({Key key}) : super(key: key);
Expand All @@ -20,7 +21,7 @@ class Stats extends StatelessWidget {
bloc: todosBloc,
builder: (BuildContext context, TodosState state) {
if (state is TodosLoading) {
return LoadingIndicator(key: Key('__statsLoading__'));
return LoadingIndicator(key: BlocLibraryKeys.statsLoadingIndicator);
} else if (state is TodosLoaded) {
int numActive =
state.todos.where((todo) => !todo.complete).toList().length;
Expand Down Expand Up @@ -64,7 +65,7 @@ class Stats extends StatelessWidget {
),
);
} else {
return Container();
return Container(key: BlocLibraryKeys.emptyStatsContainer);
}
},
);
Expand Down
3 changes: 2 additions & 1 deletion bloc_library/lib/widgets/todo_item.dart
Expand Up @@ -14,11 +14,12 @@ class TodoItem extends StatelessWidget {
final Todo todo;

TodoItem({
Key key,
@required this.onDismissed,
@required this.onTap,
@required this.onCheckboxChanged,
@required this.todo,
});
}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand Down
4 changes: 2 additions & 2 deletions bloc_library/pubspec.yaml
Expand Up @@ -6,8 +6,8 @@ environment:

dependencies:
meta: ">=1.1.0 <2.0.0"
equatable: ^0.1.0
flutter_bloc: ^0.6.0
equatable: ^0.2.0
flutter_bloc: ^0.7.0
flutter:
sdk: flutter
todos_app_core:
Expand Down
55 changes: 52 additions & 3 deletions bloc_library/test/all_tests.dart
Expand Up @@ -2,12 +2,61 @@
// Use of this source code is governed by the MIT license that can be found
// in the LICENSE file.

import 'filtered_todos_bloc_test.dart' as filteredTodosBloc;
import 'tab_bloc_test.dart' as tabBloc;
import 'todos_bloc_test.dart' as todosBloc;
import './blocs/filtered_todos_bloc_test.dart' as filteredTodosBloc;
import './blocs/filtered_todos_event_test.dart' as filteredTodosEvent;
import './blocs/simple_bloc_delegate_test.dart' as simpleBlocDelegate;
import './blocs/tab_bloc_test.dart' as tabBloc;
import './blocs/tab_event_test.dart' as tabEvent;
import './blocs/todos_bloc_test.dart' as todosBloc;
import './blocs/todos_event_test.dart' as todosEvent;
import './blocs/todos_state_test.dart' as todosState;

import './models/todo_test.dart' as todo;

import './screens//add_edit_screen_test.dart' as addEditScreen;
import './screens/details_screen_test.dart' as detailsScreen;
import './screens/home_screen_test.dart' as homeScreen;

import './widgets/delete_todo_snack_bar_test.dart' as deleteTodoSnackbar;
import './widgets/extra_actions_test.dart' as extraActions;
import './widgets/filter_button_test.dart' as filterButton;
import './widgets/filtered_todos_test.dart' as filteredTodos;
import './widgets/loading_indicator_test.dart' as loadingIndicator;
import './widgets/stats_tab_test.dart' as statsTab;
import './widgets/tab_selector_test.dart' as tabSelector;
import './widgets/todo_item_test.dart' as todoItem;

import './localization_test.dart' as localization;

main() {
// Blocs
filteredTodosBloc.main();
filteredTodosEvent.main();
simpleBlocDelegate.main();
tabBloc.main();
tabEvent.main();
todosBloc.main();
todosEvent.main();
todosState.main();

// Models
todo.main();

// Screens
addEditScreen.main();
detailsScreen.main();
homeScreen.main();

// Widgets
deleteTodoSnackbar.main();
extraActions.main();
filterButton.main();
filteredTodos.main();
loadingIndicator.main();
statsTab.main();
tabSelector.main();
todoItem.main();

// Localization
localization.main();
}

0 comments on commit a7b0d50

Please sign in to comment.