-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite logOutAccount actions test to use realistic routes #1257
base: main
Are you sure you want to change the base?
Conversation
0da58df
to
cf815ce
Compare
It would be possible to use two A partially done implementation might look like this: diffdiff --git a/test/widgets/actions_test.dart b/test/widgets/actions_test.dart
index e75bc84df..dd30b062c 100644
--- a/test/widgets/actions_test.dart
+++ b/test/widgets/actions_test.dart
@@ -19,6 +19,7 @@ import 'package:zulip/notifications/receive.dart';
import 'package:zulip/widgets/actions.dart';
import 'package:zulip/widgets/app.dart';
import 'package:zulip/widgets/inbox.dart';
+import 'package:zulip/widgets/message_list.dart';
import 'package:zulip/widgets/page.dart';
import 'package:zulip/widgets/store.dart';
@@ -157,14 +158,15 @@ void main() {
});
testWidgets("logged-out account's routes removed from nav; other accounts' remain", (tester) async {
- Future<void> makeUnreadTopicInInbox(int accountId, String topic) async {
+ Future<StreamMessage> prepareMessage(int accountId, String topic, String content) async {
final stream = eg.stream();
- final message = eg.streamMessage(stream: stream, topic: topic);
+ final message = eg.streamMessage(stream: stream, topic: topic, content: content);
final store = await testBinding.globalStore.perAccount(accountId);
await store.addStream(stream);
await store.addSubscription(eg.subscription(stream));
await store.addMessage(message);
await tester.pump();
+ return message;
}
addTearDown(testBinding.reset);
@@ -181,25 +183,29 @@ void main() {
navigator.popUntil((_) => false); // clear starting routes
await tester.pumpAndSettle();
+ final account1Message = await prepareMessage(account1.id, 'topic in account1', 'content in account1');
+ final findAccount1PageContent = find.text('content in account1', skipOffstage: false);
+
+ final account2Message = await prepareMessage(account2.id, 'topic in account2', 'content in account2');
+ final findAccount2PageContent = find.text('content in account2', skipOffstage: false);
+
final pushedRoutes = <Route<dynamic>>[];
testNavObserver.onPushed = (route, prevRoute) => pushedRoutes.add(route);
// TODO: switch to a realistic setup:
// https://github.com/zulip/zulip-flutter/pull/1076#discussion_r1874124363
- final account1Route = MaterialAccountWidgetRoute(
- accountId: account1.id, page: const InboxPageBody());
- final account2Route = MaterialAccountWidgetRoute(
- accountId: account2.id, page: const InboxPageBody());
+ final account1Route = MessageListPage.buildRoute(accountId: account1.id, narrow: const CombinedFeedNarrow());
+ final account2Route = MessageListPage.buildRoute(accountId: account2.id, narrow: const CombinedFeedNarrow());
+ (testBinding.globalStore.perAccountSync(account1.id)!.connection as FakeApiConnection)
+ .prepare(json: eg.newestGetMessagesResult(
+ foundOldest: true, messages: [account1Message]).toJson());
unawaited(navigator.push(account1Route));
+ (testBinding.globalStore.perAccountSync(account2.id)!.connection as FakeApiConnection)
+ .prepare(json: eg.newestGetMessagesResult(
+ foundOldest: true, messages: [account2Message]).toJson());
unawaited(navigator.push(account2Route));
await tester.pumpAndSettle();
check(pushedRoutes).deepEquals([account1Route, account2Route]);
- await makeUnreadTopicInInbox(account1.id, 'topic in account1');
- final findAccount1PageContent = find.text('topic in account1', skipOffstage: false);
-
- await makeUnreadTopicInInbox(account2.id, 'topic in account2');
- final findAccount2PageContent = find.text('topic in account2', skipOffstage: false);
-
final findLoadingPage = find.byType(LoadingPlaceholderPage, skipOffstage: false);
check(findAccount1PageContent).findsOne(); But there are some remaining issues, most notably, it's failing an assertion by the navigator: '_history.isNotEmpty': is not true.
This motivated me to avoid clearing the navigator stack in the first place, and write the test to set up a HomePage for account1 and a MessageListPage for account2. |
LGTM, thanks! Marking for Greg's review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Some initial comments below.
This feels surprisingly complex. Let's hold off investing further engineering into it until we've completed #1183, which seems to have overlapping work and is a priority.
lib/widgets/actions.dart
Outdated
Future<void> logOutAccount(BuildContext context, int accountId) async { | ||
final globalStore = GlobalStoreWidget.of(context); | ||
|
||
Future<void> logOutAccount(GlobalStore globalStore, int accountId) async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
login [nfc]: Pass GlobalStore to logOutAccount
This allows us to call it from model code when GlobalStore is available.
Hmm. If we were going to call this from model code (i.e. lib/model/
), it should move out of lib/widgets/ — in general widgets should be importing models but not the other way around.
It doesn't look like later commits actually do that, though — the only call site that stops using a BuildContext for the call is in this function's own tests. So this change can just be dropped.
test/widgets/actions_test.dart
Outdated
testNavObserver.onRemoved = (route, prevRoute) => removedRoutes.add(route); | ||
|
||
final context = tester.element(find.byType(MaterialApp)); | ||
final future = logOutAccount(context, account1.id); | ||
final future = logOutAccount(testBinding.globalStore, account1.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get a context if there isn't a more direct way at hand:
final future = logOutAccount(ZulipApp.navigatorKey.currentContext!, account1.id);
Oh hey or in this case:
final future = logOutAccount(testBinding.globalStore, account1.id); | |
final future = logOutAccount(navigator.context, account1.id); |
since this code has already accessed ZulipApp.navigator
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ended up leaving this unchanged and access the context the old way, because we no longer need to use the navigator.
test/widgets/actions_test.dart
Outdated
final account2Route = MessageListPage.buildRoute( | ||
accountId: account2.id, narrow: const CombinedFeedNarrow()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still doesn't seem realistic — how would you get to a CombinedFeedNarrow for account 2 atop a HomePage for account 1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using openNotification
to get a MessageListPage
route with a TopicMessage
narrow?
We could pass realmUrl when initializing the `_LoadingPlaceholderPage`, but that will still require a check for the existence of the account. The loading page will contain a CircularLoadingIndicator when the account does not exist. The user can't easily reach this page because they can only logout from `ChooseAccountPage`, until we start invalidating API keys. Even then, they will only see the page briefly before getting navigated, so we should not show any text at all. Fixes: zulip#1219 Signed-off-by: Zixuan James Li <[email protected]>
Coming up with a realistic test case doesn't actually require invalidating API key. Signed-off-by: Zixuan James Li <[email protected]>
Signed-off-by: Zixuan James Li <[email protected]>
This rewrite ended being a bit more substantial than just switching both accounts initial routes to the result of MessageListPage.buildRoute(). We do not use popUtil because the navigator stack normally should not become empty, so the HomePage route for account1 stays. Additionally, because we are pushing a different page route, we no longer need to set up different messages as the discriminator, further simplifying the test. See also: zulip#1183 (comment) Signed-off-by: Zixuan James Li <[email protected]>
cf815ce
to
4feb3e8
Compare
Updated the PR to make |
This rewrite ended being a bit more substantial than just switching both
accounts initial routes to the result of MessageListPage.buildRoute().
We do not use popUtil because the navigator stack normally should not
become empty, so the HomePage route for account1 stays. Additionally,
because we are pushing a different page route, we no longer need to set
up different messages as the discriminator, further simplifying the
test.
This is rebased on top of #1235, and taken from #1183.
See also: #1183 (comment)