chore: add integration tests
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
parent
803205b7b7
commit
1992d18a64
18 changed files with 491 additions and 103 deletions
182
integration_test/extensions/default_flows.dart
Normal file
182
integration_test/extensions/default_flows.dart
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
|
||||
import 'package:fluffychat/pages/settings_account/settings_account_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../users.dart';
|
||||
import 'wait_for.dart';
|
||||
|
||||
extension DefaultFlowExtensions on WidgetTester {
|
||||
Future<void> login() async {
|
||||
final tester = this;
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.waitFor(find.text('Let\'s start'));
|
||||
|
||||
expect(find.text('Let\'s start'), findsOneWidget);
|
||||
|
||||
final input = find.byType(TextField);
|
||||
|
||||
expect(input, findsOneWidget);
|
||||
|
||||
// getting the placeholder in place
|
||||
await tester.tap(find.byIcon(Icons.search));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.enterText(input, homeserver);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// in case registration is allowed
|
||||
// try {
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Login'),
|
||||
500,
|
||||
scrollable: find.descendant(
|
||||
of: find.byKey(const Key('ConnectPageListView')),
|
||||
matching: find.byType(Scrollable).first,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.text('Login'));
|
||||
await tester.pumpAndSettle();
|
||||
/*} catch (e) {
|
||||
log('Registration is not allowed. Proceeding with login...');
|
||||
}*/
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
|
||||
final inputs = find.byType(TextField);
|
||||
|
||||
await tester.enterText(inputs.first, Users.user1.name);
|
||||
await tester.enterText(inputs.last, Users.user1.password);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
|
||||
try {
|
||||
// pumpAndSettle does not work in here as setState is called
|
||||
// asynchronously
|
||||
await tester.waitFor(
|
||||
find.byType(LinearProgressIndicator),
|
||||
timeout: const Duration(milliseconds: 1500),
|
||||
skipPumpAndSettle: true,
|
||||
);
|
||||
} catch (_) {
|
||||
// in case the input action does not work on the desired platform
|
||||
if (find.text('Login').evaluate().isNotEmpty) {
|
||||
await tester.tap(find.text('Login'));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await tester.pumpAndSettle();
|
||||
} catch (_) {
|
||||
// may fail because of ongoing animation below dialog
|
||||
}
|
||||
|
||||
await tester.waitFor(
|
||||
find.byType(ChatListViewBody),
|
||||
skipPumpAndSettle: true,
|
||||
);
|
||||
}
|
||||
|
||||
/// ensure PushProvider check passes
|
||||
Future<void> acceptPushWarning() async {
|
||||
final tester = this;
|
||||
|
||||
final matcher = find.maybeUppercaseText('Do not show again');
|
||||
|
||||
try {
|
||||
await tester.waitFor(matcher, timeout: const Duration(seconds: 5));
|
||||
|
||||
// the FCM push error dialog to be handled...
|
||||
await tester.tap(matcher);
|
||||
await tester.pumpAndSettle();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> ensureLoggedOut() async {
|
||||
final tester = this;
|
||||
await tester.pumpAndSettle();
|
||||
if (find.byType(ChatListViewBody).evaluate().isNotEmpty) {
|
||||
await tester.tap(find.byTooltip('Show menu'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Settings'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Account'),
|
||||
500,
|
||||
scrollable: find.descendant(
|
||||
of: find.byKey(const Key('SettingsListViewContent')),
|
||||
matching: find.byType(Scrollable),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Account'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Logout'),
|
||||
500,
|
||||
scrollable: find.descendant(
|
||||
of: find.byType(SettingsAccountView),
|
||||
matching: find.byType(Scrollable),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Logout'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.maybeUppercaseText('Yes'));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> ensureAppStartedHomescreen({
|
||||
Duration timeout = const Duration(seconds: 20),
|
||||
}) async {
|
||||
final tester = this;
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final homeserverPickerFinder = find.byType(HomeserverPicker);
|
||||
final chatListFinder = find.byType(ChatListViewBody);
|
||||
|
||||
final end = DateTime.now().add(timeout);
|
||||
|
||||
log(
|
||||
'Waiting for HomeserverPicker or ChatListViewBody...',
|
||||
name: 'Test Runner',
|
||||
);
|
||||
do {
|
||||
if (DateTime.now().isAfter(end)) {
|
||||
throw Exception(
|
||||
'Timed out waiting for HomeserverPicker or ChatListViewBody');
|
||||
}
|
||||
|
||||
await pumpAndSettle();
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
} while (homeserverPickerFinder.evaluate().isEmpty &&
|
||||
chatListFinder.evaluate().isEmpty);
|
||||
|
||||
if (homeserverPickerFinder.evaluate().isNotEmpty) {
|
||||
log(
|
||||
'Found HomeserverPicker, performing login.',
|
||||
name: 'Test Runner',
|
||||
);
|
||||
await tester.login();
|
||||
} else {
|
||||
log(
|
||||
'Found ChatListViewBody, skipping login.',
|
||||
name: 'Test Runner',
|
||||
);
|
||||
}
|
||||
|
||||
await tester.acceptPushWarning();
|
||||
}
|
||||
}
|
||||
49
integration_test/extensions/wait_for.dart
Normal file
49
integration_test/extensions/wait_for.dart
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Workaround for https://github.com/flutter/flutter/issues/88765
|
||||
extension WaitForExtension on WidgetTester {
|
||||
Future<void> waitFor(
|
||||
Finder finder, {
|
||||
Duration timeout = const Duration(seconds: 20),
|
||||
bool skipPumpAndSettle = false,
|
||||
}) async {
|
||||
final end = DateTime.now().add(timeout);
|
||||
|
||||
do {
|
||||
if (DateTime.now().isAfter(end)) {
|
||||
throw Exception('Timed out waiting for $finder');
|
||||
}
|
||||
|
||||
if (!skipPumpAndSettle) {
|
||||
await pumpAndSettle();
|
||||
}
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
} while (finder.evaluate().isEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
extension MaybeUppercaseFinder on CommonFinders {
|
||||
/// On Android some button labels are in uppercase while on iOS they
|
||||
/// are not. This method tries both.
|
||||
Finder maybeUppercaseText(
|
||||
String text, {
|
||||
bool findRichText = false,
|
||||
bool skipOffstage = true,
|
||||
}) {
|
||||
try {
|
||||
final finder = find.text(
|
||||
text.toUpperCase(),
|
||||
findRichText: findRichText,
|
||||
skipOffstage: skipOffstage,
|
||||
);
|
||||
expect(finder, findsOneWidget);
|
||||
return finder;
|
||||
} catch (_) {
|
||||
return find.text(
|
||||
text,
|
||||
findRichText: findRichText,
|
||||
skipOffstage: skipOffstage,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue