Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 164 additions & 5 deletions integration_test/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,170 @@ import 'users.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('Integration Test', () {
setUpAll(() {
// this random dialog popping up is super hard to cover in tests
SharedPreferences.setMockInitialValues({
'chat.fluffy.show_no_google': false,
group(
'Integration Test',
() {
setUpAll(
() async {
// this random dialog popping up is super hard to cover in tests
SharedPreferences.setMockInitialValues({
'chat.fluffy.show_no_google': false,
});
},
);

testWidgets(
'Start app, login and logout',
(WidgetTester tester) async {
app.main([]);
await tester.ensureAppStartedHomescreen();
await tester.ensureLoggedOut();
},
);

testWidgets(
'Login again',
(WidgetTester tester) async {
app.main([]);
await tester.ensureAppStartedHomescreen();
},
);

testWidgets(
'Start chat and send message',
(WidgetTester tester) async {
app.main([]);
await tester.ensureAppStartedHomescreen();
await tester.waitFor(find.byType(TextField));
await tester.enterText(find.byType(TextField), Users.user2.name);
await tester.pumpAndSettle();

await tester.scrollUntilVisible(
find.text('Chats').first,
500,
scrollable: find
.descendant(
of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable),
)
.first,
);
await tester.pumpAndSettle();
await tester.tap(find.text('Chats'));
await tester.pumpAndSettle();
await tester.waitFor(find.byType(SearchTitle));
await tester.pumpAndSettle();

await tester.scrollUntilVisible(
find.text(Users.user2.name).first,
500,
scrollable: find
.descendant(
of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable),
)
.first,
);
await tester.pumpAndSettle();
await tester.tap(find.text(Users.user2.name).first);

try {
await tester.waitFor(
find.byType(ChatView),
timeout: const Duration(seconds: 5),
);
} catch (_) {
// in case the homeserver sends the username as search result
if (find.byIcon(Icons.send_outlined).evaluate().isNotEmpty) {
await tester.tap(find.byIcon(Icons.send_outlined));
await tester.pumpAndSettle();
}
}

await tester.waitFor(find.byType(ChatView));
await tester.enterText(find.byType(TextField).last, 'Test');
await tester.pumpAndSettle();
try {
await tester.waitFor(find.byIcon(Icons.send_outlined));
await tester.tap(find.byIcon(Icons.send_outlined));
} catch (_) {
await tester.testTextInput.receiveAction(TextInputAction.done);
}
await tester.pumpAndSettle();
await tester.waitFor(find.text('Test'));
await tester.pumpAndSettle();
},
);

testWidgets('Spaces', (tester) async {
app.main([]);
await tester.ensureAppStartedHomescreen();

await tester.waitFor(find.byTooltip('Show menu'));
await tester.tap(find.byTooltip('Show menu'));
await tester.pumpAndSettle();

await tester.waitFor(find.byIcon(Icons.workspaces_outlined));
await tester.tap(find.byIcon(Icons.workspaces_outlined));
await tester.pumpAndSettle();

await tester.waitFor(find.byType(TextField));
await tester.enterText(find.byType(TextField).last, 'Test Space');
await tester.pumpAndSettle();

await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();

await tester.waitFor(find.text('Invite contact'));

await tester.tap(find.text('Invite contact'));
await tester.pumpAndSettle();

await tester.waitFor(
find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(TextField),
),
);
await tester.enterText(
find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(TextField),
),
Users.user2.name,
);

await Future.delayed(const Duration(milliseconds: 250));
await tester.testTextInput.receiveAction(TextInputAction.done);

await Future.delayed(const Duration(milliseconds: 1000));
await tester.pumpAndSettle();

await tester.tap(
find
.descendant(
of: find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(ListTile),
),
matching: find.text(Users.user2.name),
)
.last,
);
await tester.pumpAndSettle();

await tester.waitFor(find.maybeUppercaseText('Yes'));
await tester.tap(find.maybeUppercaseText('Yes'));
await tester.pumpAndSettle();

await tester.tap(find.byTooltip('Back'));
await tester.pumpAndSettle();

await tester.waitFor(find.text('Load 2 more participants'));
await tester.tap(find.text('Load 2 more participants'));
await tester.pumpAndSettle();

expect(find.text(Users.user2.name), findsOneWidget);
});
});

Expand Down
3 changes: 2 additions & 1 deletion lib/config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ abstract class AppConfig {
static const String deepLinkPrefix = 'im.fluffychat://chat/';
static const String schemePrefix = 'matrix:';
static const String pushNotificationsChannelId = 'fluffychat_push';
static const String pushNotificationsAppId = 'chat.fluffy.fluffychat';
static const String pushNotificationsAppId = 'chat.fluffy.fluffychat'; // except for Linux!
static const double borderRadius = 18.0;
static const double spaceBorderRadius = 11.0;
static const double columnWidth = 360.0;
Expand All @@ -32,6 +32,7 @@ abstract class AppConfig {
'https://fluffy.chat/faq/#how_do_i_get_stickers';
static const String appId = 'im.fluffychat.FluffyChat';
static const String appOpenUrlScheme = 'chat.fluffy';
static const String appIdFlatpak = 'im.fluffychat.Fluffychat';

static const String sourceCodeUrl =
'https://github.com/krille-chan/fluffychat';
Expand Down
23 changes: 17 additions & 6 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import 'widgets/fluffy_chat_app.dart';

ReceivePort? mainIsolateReceivePort;

void main() async {
void main(List<String> args) async {
if (PlatformInfos.isAndroid) {
final port = mainIsolateReceivePort = ReceivePort();
IsolateNameServer.removePortNameMapping(AppConfig.mainIsolatePortName);
Expand Down Expand Up @@ -55,18 +55,29 @@ void main() async {

// If the app starts in detached mode, we assume that it is in
// background fetch mode for processing push notifications. This is
// currently only supported on Android.
if (PlatformInfos.isAndroid &&
AppLifecycleState.detached == WidgetsBinding.instance.lifecycleState) {
// currently only supported on Android and Linux.
final backgroundMode = (() {
if (PlatformInfos.isAndroid) {
return WidgetsBinding.instance.lifecycleState ==
AppLifecycleState.detached;
}
if (PlatformInfos.isLinux) {
return args.contains('--unifiedpush-bg');
}

return false;
})();

if (backgroundMode) {
// Do not send online presences when app is in background fetch mode.
for (final client in clients) {
client.backgroundSync = false;
client.syncPresence = PresenceType.offline;
}

// In the background fetch mode we do not want to waste ressources with
// In the background fetch mode we do not want to waste resources with
// starting the Flutter engine but process incoming push notifications.
BackgroundPush.clientOnly(clients.first);
BackgroundPush.clientOnly(clients.first, backgroundMode);
// To start the flutter engine afterwards we add an custom observer.
WidgetsBinding.instance.addObserver(AppStarter(clients, store));
Logs().i(
Expand Down
Loading
Loading