only-bible-app v3.7.2+24

#kotlin#android#ios

git clone https://git.pyrossh.dev/only-bible-app

The only bible app you will ever need. No ads. No in-app purchases. No distractions.


test/navigation_integration_test.dart
64b2ff0 1
// Integration-style tests: these mount the real App widget and drive it
64b2ff0 2
// through actual taps (find + tap real keys/text), rather than dispatching
64b2ff0 3
// actions programmatically against a bare store/router. That distinction
64b2ff0 4
// matters: an earlier bug (App._syncCurrentChapter clobbering
64b2ff0 5
// savedBook/savedChapter right after a push()) went unnoticed by unit tests
64b2ff0 6
// that dispatched actions directly, because they never mounted the widget
64b2ff0 7
// tree that wires the router's listener up in the first place. Driving the
64b2ff0 8
// same flows through the UI is what actually would have caught it.
64b2ff0 9
import "package:flutter/material.dart";
64b2ff0 10
import "package:flutter_test/flutter_test.dart";
64b2ff0 11
import "package:async_redux/async_redux.dart";
64b2ff0 12
import "package:only_bible_app/app.dart";
64b2ff0 13
import "package:only_bible_app/store/app_state.dart";
64b2ff0 14
import "package:only_bible_app/widgets/book_select_sheet.dart";
64b2ff0 15
import "package:only_bible_app/widgets/book_tile.dart";
64b2ff0 16
import "app_logic_test.dart" show buildTestBible;
64b2ff0 17
64b2ff0 18
/// Taps the [label] tile inside whichever [BookSelectSheet] is currently on
64b2ff0 19
/// screen - scoped there (rather than a bare find.text(label)) because plain
64b2ff0 20
/// text like a chapter number ("1", "2") can otherwise collide with the
64b2ff0 21
/// current-chapter number shown in the app bar behind the sheet.
64b2ff0 22
Future<void> tapSheetTile(WidgetTester tester, String label) async {
64b2ff0 23
  final sheet = find.byType(BookSelectSheet);
64b2ff0 24
  await tester.tap(find.descendant(of: sheet, matching: find.text(label)));
64b2ff0 25
  await tester.pumpAndSettle();
64b2ff0 26
}
64b2ff0 27
64b2ff0 28
bool _isSelectedTile(Widget w, String label) =>
64b2ff0 29
    w is BookTile && w.label == label && w.isSelected;
64b2ff0 30
64b2ff0 31
void main() {
64b2ff0 32
  TestWidgetsFlutterBinding.ensureInitialized();
64b2ff0 33
64b2ff0 34
  testWidgets(
64b2ff0 35
    "navigating via the book+chapter selector updates the displayed chapter, and "
64b2ff0 36
    "reopening the selector highlights that new book/chapter - not the one "
64b2ff0 37
    "navigated away from (regression: App._syncCurrentChapter used to clobber "
64b2ff0 38
    "savedBook/savedChapter right after the push, so the selector kept "
64b2ff0 39
    "highlighting the pre-navigation position)",
64b2ff0 40
    (tester) async {
64b2ff0 41
      final bible = buildTestBible();
64b2ff0 42
      final store = Store<AppState>(
64b2ff0 43
        initialState: AppState(bible: bible, savedBook: 0, savedChapter: 0),
64b2ff0 44
      );
64b2ff0 45
      await tester.pumpWidget(
64b2ff0 46
        App(globalNavigatorKey: GlobalKey<NavigatorState>(), store: store),
64b2ff0 47
      );
64b2ff0 48
      await tester.pumpAndSettle();
64b2ff0 49
64b2ff0 50
      // Sanity check: Genesis 1 is on screen to start with. Verse text
64b2ff0 51
      // renders as rich text with a "1 " verse-number span prefixed, so this
64b2ff0 52
      // is a substring match rather than find.text's exact match.
64b2ff0 53
      expect(find.textContaining("In the beginning..."), findsOneWidget);
64b2ff0 54
64b2ff0 55
      // Open the book selector via the app bar's book title.
64b2ff0 56
      await tester.tap(find.byKey(const Key("bookTitle")));
64b2ff0 57
      await tester.pumpAndSettle();
64b2ff0 58
64b2ff0 59
      // Pick Revelation (a multi-chapter book, so this animates to the
64b2ff0 60
      // chapter grid rather than closing immediately).
64b2ff0 61
      await tapSheetTile(tester, "Rev");
64b2ff0 62
64b2ff0 63
      // Pick chapter 2.
64b2ff0 64
      await tapSheetTile(tester, "2");
64b2ff0 65
64b2ff0 66
      // The displayed chapter should now be Revelation 2.
64b2ff0 67
      expect(find.textContaining("Rev 2:1"), findsOneWidget);
64b2ff0 68
      expect(store.state.savedBook, 2);
64b2ff0 69
      expect(store.state.savedChapter, 1);
64b2ff0 70
64b2ff0 71
      // Reopen the book selector - this is the exact regression.
64b2ff0 72
      await tester.tap(find.byKey(const Key("bookTitle")));
64b2ff0 73
      await tester.pumpAndSettle();
64b2ff0 74
64b2ff0 75
      final sheet = find.byType(BookSelectSheet);
64b2ff0 76
      expect(
64b2ff0 77
        find.descendant(
64b2ff0 78
          of: sheet,
64b2ff0 79
          matching: find.byWidgetPredicate((w) => _isSelectedTile(w, "Rev")),
64b2ff0 80
        ),
64b2ff0 81
        findsOneWidget,
64b2ff0 82
      );
64b2ff0 83
      expect(
64b2ff0 84
        find.descendant(
64b2ff0 85
          of: sheet,
64b2ff0 86
          matching: find.byWidgetPredicate((w) => _isSelectedTile(w, "Gen")),
64b2ff0 87
        ),
64b2ff0 88
        findsNothing,
64b2ff0 89
      );
64b2ff0 90
    },
64b2ff0 91
  );
64b2ff0 92
64b2ff0 93
  testWidgets(
64b2ff0 94
    "swiping to the next chapter after using the picker keeps the app bar's chapter number in sync",
64b2ff0 95
    (tester) async {
64b2ff0 96
      final bible = buildTestBible();
64b2ff0 97
      final store = Store<AppState>(
64b2ff0 98
        initialState: AppState(bible: bible, savedBook: 0, savedChapter: 0),
64b2ff0 99
      );
64b2ff0 100
      await tester.pumpWidget(
64b2ff0 101
        App(globalNavigatorKey: GlobalKey<NavigatorState>(), store: store),
64b2ff0 102
      );
64b2ff0 103
      await tester.pumpAndSettle();
64b2ff0 104
64b2ff0 105
      // Jump to Revelation 1 via the picker (push).
64b2ff0 106
      await tester.tap(find.byKey(const Key("bookTitle")));
64b2ff0 107
      await tester.pumpAndSettle();
64b2ff0 108
      await tapSheetTile(tester, "Rev");
64b2ff0 109
      await tapSheetTile(tester, "1");
64b2ff0 110
      expect(find.textContaining("Rev 1:1"), findsOneWidget);
64b2ff0 111
64b2ff0 112
      // Swipe left to advance to chapter 2 (pushReplacement on top of the
64b2ff0 113
      // still-2-entry stack the picker's push left behind).
64b2ff0 114
      await tester.fling(
64b2ff0 115
        find.byType(SingleChildScrollView),
64b2ff0 116
        const Offset(-400, 0),
64b2ff0 117
        800,
64b2ff0 118
      );
64b2ff0 119
      await tester.pumpAndSettle();
64b2ff0 120
64b2ff0 121
      expect(find.textContaining("Rev 2:1"), findsOneWidget);
64b2ff0 122
      expect(store.state.savedBook, 2);
64b2ff0 123
      expect(store.state.savedChapter, 1);
64b2ff0 124
      // The app bar's chapter number (built from the same live state) must
64b2ff0 125
      // agree with what's actually on screen.
64b2ff0 126
      expect(
64b2ff0 127
        find.descendant(
64b2ff0 128
          of: find.byKey(const Key("chapterTitle")),
64b2ff0 129
          matching: find.text("2"),
64b2ff0 130
        ),
64b2ff0 131
        findsOneWidget,
64b2ff0 132
      );
64b2ff0 133
    },
64b2ff0 134
  );
64b2ff0 135
}