content: import 'dart:developer';
  
  import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
  import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.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('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();
    }
  }
  