Skip to content

Commit

Permalink
feat: implement train journey search (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
Grodien authored Nov 12, 2024
1 parent d1c2724 commit adf7fb9
Show file tree
Hide file tree
Showing 28 changed files with 3,598 additions and 135 deletions.
10 changes: 8 additions & 2 deletions das_client/integration_test/app_test.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import 'package:das_client/flavor.dart';
import 'package:das_client/app/i18n/i18n.dart';
import 'package:das_client/flavor.dart';
import 'package:das_client/main.dart';
import 'package:fimber/fimber.dart';
import 'package:flutter_gen/gen_l10n/app_localizations_de.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'di.dart';
import 'test/train_journey_test.dart' as train_journey_tests;
import 'test/navigation_test.dart' as navigation_tests;
import 'test/train_journey_test.dart' as train_journey_tests;
import 'test/train_search_test.dart' as train_search_tests;

AppLocalizations l10n = AppLocalizationsDe();

Expand All @@ -18,9 +19,14 @@ void main() {

train_journey_tests.main();
navigation_tests.main();
train_search_tests.main();
}

Future<void> prepareAndStartApp(WidgetTester tester) async {
// iOS workaround for enterText not working on some devices, if its the first element
// (https://github.com/leancodepl/patrol/issues/1868#issuecomment-1814241939)
tester.testTextInput.register();

await IntegrationTestDI.init(Flavor.dev);
runDasApp();
await tester.pumpAndSettle(const Duration(milliseconds: 500));
Expand Down
33 changes: 14 additions & 19 deletions das_client/integration_test/di.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@ import 'auth/mqtt_client_user_connector.dart';
class IntegrationTestDI {
const IntegrationTestDI._();

static bool _initialized = false;

static Future<void> init(Flavor flavor) {
if (_initialized) {
return GetIt.I.allReady();
} else {
Fimber.i('Initialize integration test dependency injection');
GetIt.I.registerFlavor(flavor);
GetIt.I.registerTokenSpecProvider();
GetIt.I.registerOidcClient();
_registerIntegrationTestAuthenticator();
GetIt.I.registerSferaComponents();
GetIt.I.registerMqttComponent();

GetIt.I.unregister<MqttClientConnector>();
_registerMqttClientConnector();

_initialized = true;
}
static Future<void> init(Flavor flavor) async {
Fimber.i('Initialize integration test dependency injection');
await GetIt.I.reset();

GetIt.I.registerFlavor(flavor);
GetIt.I.registerTokenSpecProvider();
GetIt.I.registerOidcClient();
_registerIntegrationTestAuthenticator();
GetIt.I.registerSferaComponents();
GetIt.I.registerMqttComponent();

GetIt.I.unregister<MqttClientConnector>();
_registerMqttClientConnector();

return GetIt.I.allReady();
}

Expand Down
12 changes: 6 additions & 6 deletions das_client/integration_test/test/train_journey_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ void main() {
// Load app widget.
await prepareAndStartApp(tester);

await tester.pump(const Duration(seconds: 1));

// Verify we have trainnumber with 9232.
// Verify we have trainnumber with 7839.
expect(find.text('7839'), findsOneWidget);

// Verify we have company with 1088.
expect(find.text('1085'), findsOneWidget);
// Verify we have ru SBB.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

// check that the primary button is enabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
Expand All @@ -25,10 +23,12 @@ void main() {
await tester.tap(primaryButton);

// wait for train journey to load
await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.pumpAndSettle();

// check if station is present
expect(find.text('SO_W'), findsOneWidget);

await tester.pumpAndSettle();
});
});
}
154 changes: 154 additions & 0 deletions das_client/integration_test/test/train_search_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import 'package:das_client/util/error_code.dart';
import 'package:das_client/util/format.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import '../app_test.dart';
import '../util/test_utils.dart';

void main() {
group('train search screen tests', () {

testWidgets('test default values', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

// Verify we have ru SBB.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

// Verify that today is preselected
expect(find.text(Format.date(DateTime.now())), findsOneWidget);
});

testWidgets('test selecting ru values', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

// Verify we have ru SBB.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

await tapElement(tester, find.text(l10n.c_ru_sbb_p));

expect(find.text(l10n.c_ru_sbb_c), findsOneWidget);
expect(find.text(l10n.c_ru_bls_p), findsOneWidget);
expect(find.text(l10n.c_ru_bls_c), findsOneWidget);
expect(find.text(l10n.c_ru_sob), findsOneWidget);

await tapElement(tester, find.text(l10n.c_ru_sob));

expect(find.text(l10n.c_ru_sob), findsOneWidget);
expect(find.text(l10n.c_ru_sbb_p), findsNothing);
});

testWidgets('test load button disabled when validation fails', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

// Verify we have ru SBB.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

// Verify that today is preselected
expect(find.text(Format.date(DateTime.now())), findsOneWidget);

var trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
expect(trainNumberText, findsOneWidget);

await enterText(tester, trainNumberText, '');

// check that the primary button is disabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
expect(tester.widget<SBBPrimaryButton>(primaryButton).onPressed, isNull);

});

testWidgets('test can select yesterday', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

final today = DateTime.now();
final yesterday = today.add(Duration(days: -1));

var todayDateTextFinder = find.text(Format.date(today));
var yesterdayDateTextFinder = find.text(Format.date(yesterday));

// Verify that today is preselected
expect(todayDateTextFinder, findsOneWidget);
expect(yesterdayDateTextFinder, findsNothing);

await tapElement(tester, todayDateTextFinder);

final sbbDatePickerFinder = find.byWidgetPredicate((widget) => widget is SBBDatePicker);
final yesterdayFinder = find.descendant(
of: sbbDatePickerFinder,
matching: find.byWidgetPredicate((widget) => widget is Text && widget.data == '${(yesterday.day)}.'));
await tapElement(tester, yesterdayFinder);

// tap outside dialog
await tester.tapAt(Offset(200, 200));
await tester.pumpAndSettle();

expect(todayDateTextFinder, findsNothing);
expect(yesterdayDateTextFinder, findsOneWidget);

});

testWidgets('test can not select day before yesterday', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

final today = DateTime.now();
final yesterday = today.add(Duration(days: -1));
final dayBeforeYesterday = today.add(Duration(days: -2));

var todayDateTextFinder = find.text(Format.date(today));
var yesterdayDateTextFinder = find.text(Format.date(yesterday));
var dayBeforeYesterdayDateTextFinder = find.text(Format.date(dayBeforeYesterday));

// Verify that today is preselected
expect(todayDateTextFinder, findsOneWidget);
expect(yesterdayDateTextFinder, findsNothing);

await tapElement(tester, todayDateTextFinder);

final sbbDatePickerFinder = find.byWidgetPredicate((widget) => widget is SBBDatePicker);
final yesterdayFinder = find.descendant(
of: sbbDatePickerFinder,
matching: find.byWidgetPredicate((widget) => widget is Text && widget.data == '${(dayBeforeYesterday.day)}.'));
await tapElement(tester, yesterdayFinder);

// tap outside dialog
await tester.tapAt(Offset(200, 200));
await tester.pumpAndSettle();

expect(todayDateTextFinder, findsNothing);
expect(yesterdayDateTextFinder, findsOneWidget);
expect(dayBeforeYesterdayDateTextFinder, findsNothing);
});

testWidgets('test error if JP unavailable', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);

// Verify we have ru SBB.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

// Verify that today is preselected
expect(find.text(Format.date(DateTime.now())), findsOneWidget);

var trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
expect(trainNumberText, findsOneWidget);

await enterText(tester, trainNumberText, '1234');

// check that the primary button is disabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
expect(tester.widget<SBBPrimaryButton>(primaryButton).onPressed, isNotNull);

await tapElement(tester, primaryButton);

expect(find.text('${ErrorCode.sferaJpUnavailable.code}: ${l10n.c_error_sfera_jp_unavailable}'), findsOneWidget);
});

});
}
15 changes: 11 additions & 4 deletions das_client/integration_test/util/test_utils.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

Expand All @@ -10,10 +11,16 @@ Future<void> openDrawer(WidgetTester tester) async {
}

Future<void> tapElement(WidgetTester tester, FinderBase<Element> element) async {
var gestureDetector = find.ancestor(of: element, matching: find.byType(GestureDetector)).first;
await tester.tap(gestureDetector);

await tester.pumpAndSettle(const Duration(milliseconds: 250));
await tester.tap(element);
await tester.pumpAndSettle();
}

Future<void> enterText(WidgetTester tester, FinderBase<Element> element, String text) async {
await tester.enterText(element, text);
await tester.pumpAndSettle();
}

Finder findTextFieldByLabel(String label) {
var sbbTextField = find.byWidgetPredicate((widget) => widget is SBBTextField && widget.labelText == label);
return find.descendant(of: sbbTextField, matching: find.byType(TextField));
}
21 changes: 16 additions & 5 deletions das_client/l10n/strings_de.arb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"c_app_name": "DAS Client",
"p_train_selection_load": "Fahrbild laden",
"p_train_selection_load": "Übernehmen",
"p_train_selection_trainnumber_description": "Zugnummer",
"p_train_selection_trainnumber_placeholder": "z.B. 711",
"p_train_selection_company_description": "Company code",
"p_train_selection_company_placeholder": "z.B. 0085",
"p_train_selection_ru_description": "EVU",
"p_train_selection_date_description": "Datum",
"p_train_selection_choose_date": "Datum wählen",
"p_train_journey_header_button_dark_theme": "Nachtmodus",
"p_train_journey_header_button_pause": "Pause",
"w_navigation_drawer_fahrtinfo_title": "Fahrtinfo",
Expand All @@ -15,5 +15,16 @@
"p_login_login_button_text": "Login",
"p_login_login_button_description": "Mit Ihrem Account einloggen",
"p_login_login_failed": "Login fehlgeschlagen",
"w_adl_notification_title": "ADL Meldung"
"w_adl_notification_title": "ADL Meldung",
"c_ru_sbb_p": "SBB",
"c_ru_sbb_c": "SBB Cargo",
"c_ru_bls_p": "BLS",
"c_ru_bls_c": "BLS Cargo",
"c_ru_sob": "SOB",
"c_error_connection_failed": "Verbindung fehlgeschlagen",
"c_error_sfera_validation_failed": "Validierung der Daten fehlgeschlagen",
"c_error_sfera_handshake_rejected": "Server hat die Verbindung abgelehnt",
"c_error_sfera_request_timeout": "Timeout bei der Anfrage",
"c_error_sfera_jp_unavailable": "Fahrordnung nicht vorhanden",
"c_error_sfera_sp_invalid": "Unvollständige Daten erhalten"
}
Loading

0 comments on commit adf7fb9

Please sign in to comment.