Skip to content

Commit 6767bbc

Browse files
committed
Add launches instrumental tests
1 parent 4d61eb5 commit 6767bbc

File tree

12 files changed

+378
-44
lines changed

12 files changed

+378
-44
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,9 @@ jobs:
122122
profile: Nexus 6
123123
script: |
124124
flutter pub get
125-
flutter test integration_test --flavor dev --timeout 1h
125+
flutter test integration_test/app_test.dart --flavor dev
126+
flutter test integration_test/appearance_test.dart --flavor dev
127+
flutter test integration_test/launch_test.dart --flavor dev
128+
flutter test integration_test/launches_mock_test.dart --flavor dev
129+
flutter test integration_test/launches_test.dart --flavor dev
130+
flutter test integration_test/settings_test.dart --flavor dev
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc_app_template/features/launches/bloc/launches_bloc.dart';
3+
import 'package:flutter_bloc_app_template/features/launches/launches_screen.dart';
4+
import 'package:flutter_bloc_app_template/index.dart';
5+
import 'package:flutter_test/flutter_test.dart';
6+
import 'package:integration_test/integration_test.dart';
7+
import 'package:mocktail/mocktail.dart';
8+
9+
import '../test/bloc/utils.dart';
10+
import '../test/features/launches/launches_screen_test.dart';
11+
12+
void main() {
13+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
14+
15+
late LaunchesBloc launchesBloc;
16+
17+
setUp(() {
18+
launchesBloc = MockLaunchesBloc();
19+
});
20+
21+
group('Launches Screen Tests', () {
22+
testWidgets(
23+
'renders CircularProgressIndicator '
24+
'when launches list state is initial', (tester) async {
25+
when(() => launchesBloc.state).thenReturn(const LaunchesLoadingState());
26+
27+
await tester.pumpLocalizedWidgetWithBloc<LaunchesBloc>(
28+
bloc: launchesBloc,
29+
child: const LaunchesList(),
30+
locale: const Locale('en'),
31+
);
32+
33+
await tester.pump();
34+
35+
expect(find.byType(CircularProgressIndicator), findsOneWidget);
36+
});
37+
38+
testWidgets(
39+
'renders Empty list text '
40+
'when launches list state is success but with 0 items', (tester) async {
41+
when(() => launchesBloc.state).thenReturn(const LaunchesEmptyState());
42+
await tester.pumpLocalizedWidgetWithBloc<LaunchesBloc>(
43+
bloc: launchesBloc,
44+
child: const LaunchesList(),
45+
locale: const Locale('en'),
46+
);
47+
await tester.pumpAndSettle();
48+
49+
expect(find.text('Empty list'), findsOneWidget);
50+
});
51+
52+
testWidgets('launches test', (
53+
WidgetTester tester,
54+
) async {
55+
// app.main([]);
56+
// await tester.pumpAndSettle();
57+
58+
when(() => launchesBloc.state).thenReturn(
59+
const LaunchesSuccessState(
60+
launches: [
61+
LaunchResource(
62+
id: '1',
63+
flightNumber: 1,
64+
missionName: 'FalconSat',
65+
launchDays: Since(
66+
'2021-10-01T00:00:00Z',
67+
),
68+
launchTime: '00:00',
69+
rocket: RocketResource(
70+
rocketName: 'Rocket 1',
71+
rocketType: 'Type 1',
72+
),
73+
launchSuccess: true,
74+
)
75+
],
76+
),
77+
);
78+
await tester.pumpLocalizedWidgetWithBloc<LaunchesBloc>(
79+
bloc: launchesBloc,
80+
child: const LaunchesList(),
81+
locale: const Locale('en'),
82+
);
83+
await tester.pumpAndSettle();
84+
85+
final firstItem = find.byKey(const Key('FalconSat1'));
86+
87+
expect(firstItem, findsOneWidget);
88+
await tester.ensureVisible(firstItem);
89+
});
90+
});
91+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc_app_template/main.dart' as app;
3+
import 'package:flutter_test/flutter_test.dart';
4+
import 'package:integration_test/integration_test.dart';
5+
6+
import '../test/utils/screenshot.dart';
7+
8+
void main() async {
9+
final binding = IntegrationTestWidgetsFlutterBinding();
10+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
11+
setUp(() {});
12+
13+
testWidgets('settings test', (
14+
WidgetTester tester,
15+
) async {
16+
app.main([]);
17+
await tester.pumpAndSettle();
18+
19+
expect(find.byKey(const Key('settings')), findsOneWidget);
20+
21+
await tester.tap(find.byTooltip('Settings'));
22+
23+
await tester.pumpAndSettle();
24+
25+
expect(find.textContaining('Appearance'), findsAtLeast(1));
26+
expect(find.textContaining('About'), findsAtLeast(1));
27+
28+
await takePlatformScreenshot('settings-screenshot', tester, binding);
29+
});
30+
}

lib/app/app.dart

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,21 @@ import 'package:flutter/material.dart';
33
import 'package:flutter_bloc/flutter_bloc.dart';
44
import 'package:flutter_bloc_app_template/app/localization.dart';
55
import 'package:flutter_bloc_app_template/bloc/init/init_bloc.dart';
6-
import 'package:flutter_bloc_app_template/di/di_container.dart';
7-
import 'package:flutter_bloc_app_template/features/launches/bloc/launches_bloc.dart';
6+
import 'package:flutter_bloc_app_template/di/app_bloc_providers.dart';
7+
import 'package:flutter_bloc_app_template/di/app_repository_providers.dart';
88
import 'package:flutter_bloc_app_template/index.dart';
99
import 'package:flutter_bloc_app_template/theme/util.dart';
1010

11-
class MyApp extends StatelessWidget {
12-
const MyApp({
11+
class App extends StatelessWidget {
12+
const App({
1313
super.key,
1414
});
1515

1616
@override
1717
Widget build(BuildContext context) => MultiRepositoryProvider(
18-
providers: [
19-
RepositoryProvider<EmailListRepository>(
20-
create: (context) => EmailListRepository(),
21-
),
22-
RepositoryProvider<NavigationService>(
23-
create: (context) => NavigationService(),
24-
),
25-
RepositoryProvider<LaunchesRepository>(
26-
create: (context) => diContainer.get<LaunchesRepository>(),
27-
),
28-
],
18+
providers: [...AppRepositoryProviders.providers()],
2919
child: MultiBlocProvider(
30-
providers: [
31-
BlocProvider(
32-
create: (context) =>
33-
ThemeCubit(diContainer.get<ThemeRepository>())..loadTheme(),
34-
),
35-
BlocProvider(
36-
create: (context) => EmailListBloc(
37-
messagesRepository:
38-
RepositoryProvider.of<EmailListRepository>(context),
39-
)..add(
40-
EmailListFetched(),
41-
),
42-
),
43-
BlocProvider(
44-
create: (context) => LaunchesBloc(
45-
RepositoryProvider.of<LaunchesRepository>(context),
46-
)..add(
47-
const LaunchesEvent.load(),
48-
),
49-
),
50-
BlocProvider<InitBloc>(
51-
create: (_) => InitBloc()
52-
..add(
53-
StartAppEvent(),
54-
),
55-
),
56-
],
20+
providers: [...AppBlocProviders.providers()],
5721
child: Builder(
5822
builder: (context) {
5923
final navigator = NavigationService.of(context);

lib/app_runner.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ Future<void> run([
2121
}
2222

2323
void _runApp() {
24-
runApp(const MyApp());
24+
runApp(const App());
2525
}

lib/di/app_bloc_providers.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:flutter_bloc/flutter_bloc.dart';
2+
import 'package:flutter_bloc_app_template/bloc/email_list/email_list_bloc.dart';
3+
import 'package:flutter_bloc_app_template/bloc/init/init_bloc.dart';
4+
import 'package:flutter_bloc_app_template/bloc/theme/theme_cubit.dart';
5+
import 'package:flutter_bloc_app_template/features/launches/bloc/launches_bloc.dart';
6+
import 'package:flutter_bloc_app_template/repository/email_list_repository.dart';
7+
import 'package:flutter_bloc_app_template/repository/launches_repository.dart';
8+
import 'package:flutter_bloc_app_template/repository/theme_repository.dart';
9+
import 'package:provider/single_child_widget.dart' show SingleChildWidget;
10+
11+
import 'di_container.dart';
12+
13+
abstract class AppBlocProviders {
14+
static List<SingleChildWidget> providers() {
15+
return [
16+
BlocProvider(
17+
create: (context) =>
18+
ThemeCubit(diContainer.get<ThemeRepository>())..loadTheme(),
19+
),
20+
BlocProvider(
21+
create: (context) => EmailListBloc(
22+
messagesRepository:
23+
RepositoryProvider.of<EmailListRepository>(context),
24+
)..add(
25+
EmailListFetched(),
26+
),
27+
),
28+
BlocProvider(
29+
create: (context) => LaunchesBloc(
30+
RepositoryProvider.of<LaunchesRepository>(context),
31+
)..add(
32+
const LaunchesEvent.load(),
33+
),
34+
),
35+
BlocProvider<InitBloc>(
36+
create: (_) => InitBloc()
37+
..add(
38+
StartAppEvent(),
39+
),
40+
),
41+
];
42+
}
43+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:flutter_bloc/flutter_bloc.dart';
2+
import 'package:flutter_bloc_app_template/repository/email_list_repository.dart';
3+
import 'package:flutter_bloc_app_template/repository/launches_repository.dart';
4+
import 'package:flutter_bloc_app_template/routes/router.dart';
5+
import 'package:provider/single_child_widget.dart' show SingleChildWidget;
6+
7+
import 'di_container.dart';
8+
9+
abstract class AppRepositoryProviders {
10+
static List<SingleChildWidget> providers() {
11+
return [
12+
RepositoryProvider<EmailListRepository>(
13+
create: (context) => EmailListRepository(),
14+
),
15+
RepositoryProvider<NavigationService>(
16+
create: (context) => NavigationService(),
17+
),
18+
RepositoryProvider<LaunchesRepository>(
19+
create: (context) => diContainer.get<LaunchesRepository>(),
20+
),
21+
];
22+
}
23+
}

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ dependencies:
4545
yaml: ^3.1.2
4646
collection: ^1.18.0
4747
package_info_plus: ^8.3.0
48+
provider: ^6.1.5
4849

4950
flutter_localizations:
5051
sdk: flutter
104 KB
Loading

0 commit comments

Comments
 (0)