Skip to content

Commit 985c29d

Browse files
committed
settings test: Add widget tests for latest settings
"Open message feeds at" and "Mark messages as read on scroll". Related: #1571 Related: #1583
1 parent 9fa743f commit 985c29d

File tree

2 files changed

+153
-1
lines changed

2 files changed

+153
-1
lines changed

test/model/store_checks.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ extension GlobalSettingsStoreChecks on Subject<GlobalSettingsStore> {
3232
Subject<BrowserPreference?> get browserPreference => has((x) => x.browserPreference, 'browserPreference');
3333
Subject<BrowserPreference> get effectiveBrowserPreference => has((x) => x.effectiveBrowserPreference, 'effectiveBrowserPreference');
3434
Subject<UrlLaunchMode> getUrlLaunchMode(Uri url) => has((x) => x.getUrlLaunchMode(url), 'getUrlLaunchMode');
35+
Subject<VisitFirstUnreadSetting> get visitFirstUnread => has((x) => x.visitFirstUnread, 'visitFirstUnread');
36+
Subject<MarkReadOnScrollSetting> get markReadOnScroll => has((x) => x.markReadOnScroll, 'markReadOnScroll');
3537
Subject<bool> getBool(BoolGlobalSetting setting) => has((x) => x.getBool(setting), 'getBool(${setting.name}');
3638
}
3739

test/widgets/settings_test.dart

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,55 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/foundation.dart';
33
import 'package:flutter/material.dart';
4+
import 'package:flutter_checks/flutter_checks.dart';
45
import 'package:flutter_test/flutter_test.dart';
56
import 'package:legacy_checks/legacy_checks.dart';
67
import 'package:zulip/model/settings.dart';
8+
import 'package:zulip/widgets/page.dart';
79
import 'package:zulip/widgets/settings.dart';
10+
import 'package:zulip/widgets/store.dart';
811

912
import '../flutter_checks.dart';
1013
import '../model/binding.dart';
1114
import '../model/store_checks.dart';
1215
import '../example_data.dart' as eg;
16+
import '../test_navigation.dart';
17+
import 'page_checks.dart';
1318
import 'test_app.dart';
1419

1520
void main() {
1621
TestZulipBinding.ensureInitialized();
1722

23+
late TestNavigatorObserver testNavObserver;
24+
late Route<dynamic>? lastPushedRoute;
25+
late Route<dynamic>? lastPoppedRoute;
26+
1827
Future<void> prepare(WidgetTester tester) async {
1928
addTearDown(testBinding.reset);
2029

30+
testNavObserver = TestNavigatorObserver()
31+
..onPushed = ((route, _) => lastPushedRoute = route)
32+
..onPopped = ((route, _) => lastPoppedRoute = route);
33+
lastPushedRoute = null;
34+
lastPoppedRoute = null;
35+
2136
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
2237
await tester.pumpWidget(TestZulipApp(
2338
accountId: eg.selfAccount.id,
39+
navigatorObservers: [testNavObserver],
2440
child: SettingsPage()));
2541
await tester.pump();
2642
await tester.pump();
2743
}
2844

45+
void checkTileOnSettingsPage(WidgetTester tester, {
46+
required String expectedTitle,
47+
required String expectedSubtitle,
48+
}) {
49+
check(find.descendant(of: find.widgetWithText(ListTile, expectedTitle),
50+
matching: find.text(expectedSubtitle))).findsOne();
51+
}
52+
2953
Finder findRadioListTileWithTitle<T>(String title) => find.ancestor(
3054
of: find.text(title),
3155
matching: find.byType(RadioListTile<T>));
@@ -140,7 +164,133 @@ void main() {
140164
}, variant: TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
141165
});
142166

143-
// TODO(#1571): test visitFirstUnread setting UI
167+
group('VisitFirstUnreadSetting', () {
168+
String settingTitle(VisitFirstUnreadSetting setting) => switch (setting) {
169+
VisitFirstUnreadSetting.always => 'First unread message',
170+
VisitFirstUnreadSetting.conversations => 'First unread message in conversation views, newest message elsewhere',
171+
VisitFirstUnreadSetting.never => 'Newest message',
172+
};
173+
174+
void checkPage(WidgetTester tester, {
175+
required VisitFirstUnreadSetting expectedSetting,
176+
}) {
177+
for (final setting in VisitFirstUnreadSetting.values) {
178+
final thisSettingTitle = settingTitle(setting);
179+
checkRadioButtonAppearsChecked<VisitFirstUnreadSetting>(tester,
180+
thisSettingTitle, thisSettingTitle == settingTitle(expectedSetting));
181+
}
182+
}
183+
184+
testWidgets('smoke', (tester) async {
185+
await prepare(tester);
186+
await tester.pumpAndSettle();
187+
188+
// "conversations" is the default, and it appears in the SettingsPage
189+
// (as the setting tile's subtitle)
190+
check(GlobalStoreWidget.settingsOf(tester.element(find.byType(SettingsPage))))
191+
.visitFirstUnread.equals(VisitFirstUnreadSetting.conversations);
192+
checkTileOnSettingsPage(tester,
193+
expectedTitle: 'Open message feeds at',
194+
expectedSubtitle: settingTitle(VisitFirstUnreadSetting.conversations));
195+
196+
await tester.tap(find.text('Open message feeds at'));
197+
await tester.pump();
198+
check(lastPushedRoute).isA<MaterialWidgetRoute>()
199+
.page.isA<VisitFirstUnreadSettingPage>();
200+
await tester.pump((lastPushedRoute as TransitionRoute).transitionDuration);
201+
checkPage(tester, expectedSetting: VisitFirstUnreadSetting.conversations);
202+
203+
await tester.tap(findRadioListTileWithTitle<VisitFirstUnreadSetting>(
204+
settingTitle(VisitFirstUnreadSetting.always)));
205+
await tester.pumpAndSettle(); // TODO why doesn't just `pump` work?
206+
checkPage(tester, expectedSetting: VisitFirstUnreadSetting.always);
207+
208+
await tester.tap(findRadioListTileWithTitle<VisitFirstUnreadSetting>(
209+
settingTitle(VisitFirstUnreadSetting.conversations)));
210+
await tester.pumpAndSettle();
211+
checkPage(tester, expectedSetting: VisitFirstUnreadSetting.conversations);
212+
213+
await tester.tap(findRadioListTileWithTitle<VisitFirstUnreadSetting>(
214+
settingTitle(VisitFirstUnreadSetting.never)));
215+
await tester.pumpAndSettle();
216+
checkPage(tester, expectedSetting: VisitFirstUnreadSetting.never);
217+
218+
await tester.tap(find.byType(BackButton));
219+
check(lastPoppedRoute).isA<MaterialWidgetRoute>()
220+
.page.isA<VisitFirstUnreadSettingPage>();
221+
await tester.pump((lastPoppedRoute as TransitionRoute).reverseTransitionDuration);
222+
check(GlobalStoreWidget.settingsOf(tester.element(find.byType(SettingsPage))))
223+
.visitFirstUnread.equals(VisitFirstUnreadSetting.never);
224+
225+
checkTileOnSettingsPage(tester,
226+
expectedTitle: 'Open message feeds at',
227+
expectedSubtitle: settingTitle(VisitFirstUnreadSetting.never));
228+
});
229+
});
230+
231+
group('MarkReadOnScrollSetting', () {
232+
String settingTitle(MarkReadOnScrollSetting setting) => switch (setting) {
233+
MarkReadOnScrollSetting.always => 'Always',
234+
MarkReadOnScrollSetting.conversations => 'Only in conversation views',
235+
MarkReadOnScrollSetting.never => 'Never',
236+
};
237+
238+
void checkPage(WidgetTester tester, {
239+
required MarkReadOnScrollSetting expectedSetting,
240+
}) {
241+
for (final setting in MarkReadOnScrollSetting.values) {
242+
final thisSettingTitle = settingTitle(setting);
243+
checkRadioButtonAppearsChecked<MarkReadOnScrollSetting>(tester,
244+
thisSettingTitle, thisSettingTitle == settingTitle(expectedSetting));
245+
}
246+
}
247+
248+
testWidgets('smoke', (tester) async {
249+
await prepare(tester);
250+
await tester.pumpAndSettle();
251+
252+
// "conversations" is the default, and it appears in the SettingsPage
253+
// (as the setting tile's subtitle)
254+
check(GlobalStoreWidget.settingsOf(tester.element(find.byType(SettingsPage))))
255+
.markReadOnScroll.equals(MarkReadOnScrollSetting.conversations);
256+
checkTileOnSettingsPage(tester,
257+
expectedTitle: 'Mark messages as read on scroll',
258+
expectedSubtitle: settingTitle(MarkReadOnScrollSetting.conversations));
259+
260+
await tester.tap(find.text('Mark messages as read on scroll'));
261+
await tester.pump();
262+
check(lastPushedRoute).isA<MaterialWidgetRoute>()
263+
.page.isA<MarkReadOnScrollSettingPage>();
264+
await tester.pump((lastPushedRoute as TransitionRoute).transitionDuration);
265+
checkPage(tester, expectedSetting: MarkReadOnScrollSetting.conversations);
266+
267+
await tester.tap(findRadioListTileWithTitle<MarkReadOnScrollSetting>(
268+
settingTitle(MarkReadOnScrollSetting.always)));
269+
await tester.pumpAndSettle(); // TODO why doesn't just `pump` work?
270+
checkPage(tester, expectedSetting: MarkReadOnScrollSetting.always);
271+
272+
await tester.tap(findRadioListTileWithTitle<MarkReadOnScrollSetting>(
273+
settingTitle(MarkReadOnScrollSetting.conversations)));
274+
await tester.pumpAndSettle();
275+
checkPage(tester, expectedSetting: MarkReadOnScrollSetting.conversations);
276+
277+
await tester.tap(findRadioListTileWithTitle<MarkReadOnScrollSetting>(
278+
settingTitle(MarkReadOnScrollSetting.never)));
279+
await tester.pumpAndSettle();
280+
checkPage(tester, expectedSetting: MarkReadOnScrollSetting.never);
281+
282+
await tester.tap(find.byType(BackButton));
283+
check(lastPoppedRoute).isA<MaterialWidgetRoute>()
284+
.page.isA<MarkReadOnScrollSettingPage>();
285+
await tester.pump((lastPoppedRoute as TransitionRoute).reverseTransitionDuration);
286+
check(GlobalStoreWidget.settingsOf(tester.element(find.byType(SettingsPage))))
287+
.markReadOnScroll.equals(MarkReadOnScrollSetting.never);
288+
289+
checkTileOnSettingsPage(tester,
290+
expectedTitle: 'Mark messages as read on scroll',
291+
expectedSubtitle: settingTitle(MarkReadOnScrollSetting.never));
292+
});
293+
});
144294

145295
// TODO maybe test GlobalSettingType.experimentalFeatureFlag settings
146296
// Or maybe not; after all, it's a developer-facing feature, so

0 commit comments

Comments
 (0)