Skip to content

Commit 9880eeb

Browse files
authored
Merge pull request #41 from ashtanko/feature/rocket_details
Add rocket details
2 parents bdae65a + 1ac0eeb commit 9880eeb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2092
-14
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,5 @@ jobs:
134134
flutter test integration_test/launches_test.dart --flavor dev
135135
flutter test integration_test/settings_test.dart --flavor dev
136136
flutter test integration_test/rockets_screen_integration_test.dart --flavor dev
137+
flutter test integration_test/rocket_screen_test.dart --flavor dev
138+
flutter test integration_test/rockets_integration_live_test.dart --flavor dev

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,8 @@ force_upgrade:
6363
integration_test:
6464
flutter test integration_test --flavor dev
6565

66+
screenshot_test:
67+
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/settings_screenshot_test.dart --flavor dev
68+
6669
# upgrade_deps:
6770
# flutter pub upgrade --major-versions
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc_app_template/features/rocket/bloc/rocket_bloc.dart';
3+
import 'package:flutter_bloc_app_template/features/rocket/rocket_screen.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:integration_test/integration_test.dart';
6+
import 'package:mocktail/mocktail.dart';
7+
8+
import '../test/bloc/utils.dart';
9+
import '../test/features/rocket/rocket_screen_test.dart';
10+
import '../test/repository/rocket_repository_test.dart';
11+
import '../test/utils/screenshot.dart';
12+
13+
void main() {
14+
final binding = IntegrationTestWidgetsFlutterBinding();
15+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
16+
17+
late RocketBloc rocketBloc;
18+
19+
setUp(() {
20+
rocketBloc = MockRocketBloc();
21+
});
22+
23+
group('Rockets Screen Tests', () {
24+
testWidgets(
25+
'renders UI '
26+
'when rocket screen state is success', (tester) async {
27+
when(() => rocketBloc.state).thenReturn(RocketSuccessState(
28+
rocket: mockRocket,
29+
));
30+
31+
await tester.pumpLocalizedWidgetWithBloc<RocketBloc>(
32+
bloc: rocketBloc,
33+
child: const RocketScreenBlocContent(
34+
rocketId: 'falcon9',
35+
),
36+
locale: const Locale('en'),
37+
);
38+
39+
await tester.pump();
40+
41+
expect(find.text('Falcon 9'), findsOneWidget);
42+
expect(find.text('Overview'), findsOneWidget);
43+
44+
await takePlatformScreenshot('rocket-screenshot', tester, binding);
45+
});
46+
});
47+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc_app_template/app/localization.dart';
3+
import 'package:flutter_bloc_app_template/features/rocket/bloc/rocket_bloc.dart';
4+
import 'package:flutter_bloc_app_template/features/rocket/rocket_screen.dart';
5+
import 'package:flutter_bloc_app_template/generated/l10n.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:integration_test/integration_test.dart';
8+
import 'package:mocktail/mocktail.dart';
9+
10+
import '../test/bloc/utils.dart';
11+
import '../test/features/rocket/rocket_screen_test.dart';
12+
import '../test/repository/rocket_repository_test.dart';
13+
14+
void main() {
15+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
16+
17+
late RocketBloc rocketBloc;
18+
19+
setUp(() {
20+
rocketBloc = MockRocketBloc();
21+
});
22+
23+
Future<void> pumpRocketScreen(
24+
WidgetTester tester, {
25+
required Locale locale,
26+
void Function(BuildContext context)? contextCallback,
27+
}) async {
28+
when(() => rocketBloc.state).thenReturn(
29+
RocketSuccessState(
30+
rocket: mockRocket,
31+
),
32+
);
33+
34+
await tester.pumpLocalizedWidgetWithBloc<RocketBloc>(
35+
bloc: rocketBloc,
36+
child: const RocketScreenBlocContent(rocketId: 'falcon9'),
37+
locale: locale,
38+
);
39+
await tester.pumpAndSettle();
40+
}
41+
42+
void expectRocketScreenTexts(
43+
String specificationLabel, {
44+
List<String> additionalTexts = const [],
45+
}) {
46+
expect(find.text('Falcon 9'), findsOneWidget);
47+
expect(find.text(specificationLabel), findsOneWidget);
48+
for (final text in additionalTexts) {
49+
expect(find.text(text), findsAtLeast(1));
50+
}
51+
}
52+
53+
group('Rocket Screen Tests', () {
54+
for (final locale in appSupportedLocales) {
55+
testWidgets('rocket screen $locale test', (tester) async {
56+
await pumpRocketScreen(tester, locale: locale, contextCallback: (ctx) {
57+
expectRocketScreenTexts(
58+
S.of(ctx).specifications,
59+
additionalTexts: [S.of(ctx).payloadCapacity],
60+
);
61+
});
62+
});
63+
}
64+
});
65+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'package:flutter_bloc_app_template/features/rockets/widget/rocket_item/rocket_item.dart';
3+
import 'package:flutter_bloc_app_template/main.dart' as app;
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:integration_test/integration_test.dart';
6+
7+
void main() {
8+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
9+
10+
setUp(() {});
11+
12+
testWidgets('rockets navigation test', (
13+
WidgetTester tester,
14+
) async {
15+
app.main([]);
16+
await tester.pumpAndSettle();
17+
18+
expect(find.byKey(const Key('rockets_screen')), findsOneWidget);
19+
20+
final rocketsTab = find.byKey(const Key('rockets_screen'));
21+
await tester.ensureVisible(rocketsTab);
22+
await tester.tap(rocketsTab);
23+
await tester.pumpAndSettle();
24+
25+
final firstItem = find.byKey(const Key('Falcon 1rocket'));
26+
27+
expect(firstItem, findsOneWidget);
28+
await tester.ensureVisible(firstItem);
29+
await tester.tap(find.byType(RocketItemWidget).first);
30+
await tester.pumpAndSettle();
31+
expect(find.text('Falcon 1'), findsOneWidget);
32+
expect(find.text('Overview'), findsOneWidget);
33+
});
34+
}

lib/features/main/navigation/destinations.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ List<NavDestination> getDestinations(BuildContext context) {
1717
icon: const Icon(Icons.rocket_outlined),
1818
selectedIcon: const Icon(Icons.rocket),
1919
screen: const RocketsScreen(),
20-
key: const Key('rockets'),
20+
key: const Key('rockets_screen'),
2121
),
2222
NavDestination(
2323
label: context.settingsTitle,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:flutter_bloc_app_template/index.dart';
3+
import 'package:flutter_bloc_app_template/repository/rocket_repository.dart';
4+
import 'package:freezed_annotation/freezed_annotation.dart';
5+
6+
part 'rocket_bloc.freezed.dart';
7+
part 'rocket_event.dart';
8+
part 'rocket_state.dart';
9+
10+
class RocketBloc extends Bloc<RocketEvent, RocketState> {
11+
RocketBloc(this._repository) : super(const RocketState.loading()) {
12+
on<RocketLoadEvent>((event, emit) async {
13+
emit(const RocketState.loading());
14+
try {
15+
final rocket = await _repository.getRocket(event.rocketId);
16+
emit(RocketState.success(rocket: rocket));
17+
} catch (e) {
18+
emit(const RocketState.error());
19+
}
20+
});
21+
}
22+
23+
final RocketRepository _repository;
24+
}

0 commit comments

Comments
 (0)