Skip to content

Commit d9aafc8

Browse files
chrisbobbegnprice
authored andcommitted
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 01655d6 commit d9aafc8

File tree

2 files changed

+164
-3
lines changed

2 files changed

+164
-3
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: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,62 @@ import 'package:flutter/material.dart';
44
import 'package:flutter_checks/flutter_checks.dart';
55
import 'package:flutter_test/flutter_test.dart';
66
import 'package:zulip/model/settings.dart';
7+
import 'package:zulip/widgets/page.dart';
78
import 'package:zulip/widgets/settings.dart';
9+
import 'package:zulip/widgets/store.dart';
810

911
import '../flutter_checks.dart';
1012
import '../model/binding.dart';
1113
import '../model/store_checks.dart';
1214
import '../example_data.dart' as eg;
15+
import '../test_navigation.dart';
16+
import 'checks.dart';
1317
import 'test_app.dart';
1418

1519
void main() {
1620
TestZulipBinding.ensureInitialized();
1721

22+
late TestNavigatorObserver testNavObserver;
23+
late Route<dynamic>? lastPushedRoute;
24+
late Route<dynamic>? lastPoppedRoute;
25+
1826
Future<void> prepare(WidgetTester tester) async {
1927
addTearDown(testBinding.reset);
2028

29+
testNavObserver = TestNavigatorObserver()
30+
..onPushed = ((route, _) => lastPushedRoute = route)
31+
..onPopped = ((route, _) => lastPoppedRoute = route);
32+
lastPushedRoute = null;
33+
lastPoppedRoute = null;
34+
2135
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
2236
await tester.pumpWidget(TestZulipApp(
2337
accountId: eg.selfAccount.id,
38+
navigatorObservers: [testNavObserver],
2439
child: SettingsPage()));
2540
await tester.pump();
2641
await tester.pump();
2742
}
2843

44+
void checkTileOnSettingsPage(WidgetTester tester, {
45+
required String expectedTitle,
46+
required String expectedSubtitle,
47+
}) {
48+
check(find.descendant(of: find.widgetWithText(ListTile, expectedTitle),
49+
matching: find.text(expectedSubtitle))).findsOne();
50+
}
51+
2952
Finder findRadioListTileWithTitle<T>(String title) => find.ancestor(
3053
of: find.text(title),
3154
matching: find.byType(RadioListTile<T>));
3255

33-
void checkRadioButtonAppearsChecked<T>(WidgetTester tester, String title, bool expectedIsChecked) {
56+
void checkRadioButtonAppearsChecked<T>(WidgetTester tester,
57+
String title, bool expectedIsChecked, {String? subtitle}) {
3458
check(tester.semantics.find(findRadioListTileWithTitle<T>(title)))
3559
.containsSemantics(
36-
label: title,
60+
label: subtitle == null
61+
? title
62+
: '$title\n$subtitle',
3763
isInMutuallyExclusiveGroup: true,
3864
hasCheckedState: true, isChecked: expectedIsChecked);
3965
}
@@ -134,7 +160,140 @@ void main() {
134160
}, variant: TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
135161
});
136162

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

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

0 commit comments

Comments
 (0)