-
Notifications
You must be signed in to change notification settings - Fork 177
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
msglist: Use [User.avatarUrl] instead of [Message.avatarUrl] #246
Conversation
test/test_images.dart
Outdated
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
|
||
class FakeHttpClient extends Fake implements HttpClient { |
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.
test [nfc]: Move fake-image-request code to its own file
N.B.: This now has the same name as FakeHttpClient
in test/api/fake_api.dart, which causes awkwardness when a file wants import lines for both files. Later in this branch, this awkwardness shows up like this:
-import '../api/fake_api.dart';
+import '../api/fake_api.dart' as fake_api;
Maybe there's a better name for this class, like FakeImageHttpClient
? (Then maybe also its friends, like FakeHttpClientResponse
, get renamed correspondingly?)
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.
Yeah, I think if this is going to be a public name that's imported in various tests (rather than a private name in one test file), it needs a more specific name.
The FakeImageFoo
names sound good. It's likely that if we wanted to use these for faking something other than fetching a network image, we'd need to add other features to them.
a75fcb1
to
278acdc
Compare
This came up when thinking about avatar URLs for #119. |
278acdc
to
5f18921
Compare
(Just rebased onto current |
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! Small comments, all in the tests.
test/test_images.dart
Outdated
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
|
||
class FakeHttpClient extends Fake implements HttpClient { |
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.
Yeah, I think if this is going to be a public name that's imported in various tests (rather than a private name in one test file), it needs a more specific name.
The FakeImageFoo
names sound good. It's likely that if we wanted to use these for faking something other than fetching a network image, we'd need to add other features to them.
test/widgets/message_list_test.dart
Outdated
import 'package:zulip/widgets/message_list.dart'; | ||
import 'package:zulip/widgets/sticky_header.dart'; | ||
import 'package:zulip/widgets/store.dart'; | ||
|
||
import '../api/fake_api.dart'; | ||
import '../api/fake_api.dart' as fake_api; |
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.
If we were keeping the generic FakeHttpClient
name so did have to deal with a collision here, I think I'd prefer in this case to use show
to just expose the one name we want from this library:
import '../api/fake_api.dart' as fake_api; | |
import '../api/fake_api.dart' show FakeApiConnection; |
That way we don't have to say fake_api.FakeApiConnection
, which looks awfully redundant.
test/widgets/message_list_test.dart
Outdated
@@ -51,6 +59,58 @@ Future<void> setupMessageListPage(WidgetTester tester, { | |||
void main() { | |||
TestZulipBinding.ensureInitialized(); | |||
|
|||
group('MessageWithSender', () { |
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.
nit: let's put this after the ScrollToBottomButton
group, so the tests are in roughly the order of the code they respectively focus on
test/widgets/message_list_test.dart
Outdated
addTearDown(TestZulipBinding.instance.reset); | ||
|
||
RealmContentNetworkImage? findAvatarImageWidget(WidgetTester tester) { | ||
final firstMessageWithSender = tester.widgetList(find.byType(MessageWithSender)).first; |
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.
There's a tester.firstWidget
; can this use that?
test/widgets/message_list_test.dart
Outdated
final firstMessageWithSender = tester.widgetList(find.byType(MessageWithSender)).first; | ||
return tester.widgetList<RealmContentNetworkImage>( | ||
find.descendant( | ||
of: find.byWidget(firstMessageWithSender), |
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.
Also this could just be the find.byType(MessageWithSender)
directly, and then firstWidget
around the whole thing.
I think the difference in behavior would just be: if the first MessageWithSender has several RealmContentNetworkImage descendants, then this version would throw and that version wouldn't. Which… hmm, in fact it's bad to throw in that case, right? The message content could legitimately have an image, though it doesn't actually in this test.
In any event it doesn't seem helpful to throw in that case. If we have a bug where MessageWithSender shows the avatar twice or whatever, this isn't the test to detect that.
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.
Whichever way it's organized, I don't love that we have to look for RealmContentNetworkImage here to find the avatar. That feels like a bit of an implementation detail of the message list, and also a bit fragile because that widget type could appear in the content. I'd rather have something we can look for that more specifically marks the avatar.
I guess with an Avatar
widget that'd provide an answer. Though that also feels like a bit of an implementation detail.
Another version would be to look for a semantic label. That'd be appealing because it's not an implementation detail — it's something user-facing. Not sure what the right semantic label would be in this case, though. In fact I kind of think for the semantics tree we likely want to hide the avatar — there's nothing it communicates that isn't already covered by the sender name, other than the visual of the image itself.
Anyway, using RealmContentNetworkImage is fine for now. We can switch to the Avatar widget upon adding that, and possibly to semantics later.
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.
Makes sense. Yeah, I felt kind of uneasy having it look for RealmContentNetworkImage
too.
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.
Also this could just be the
find.byType(MessageWithSender)
directly, and thenfirstWidget
around the whole thing.
Ah: I tried this just now, but then a test failure reminded me that we'd need it to be firstWidgetOrNull, and that isn't offered.
test/widgets/message_list_test.dart
Outdated
case String(): { | ||
check(findAvatarImageWidget(tester)).isNotNull().src.equals(resolveUrl(avatarUrl, eg.selfAccount)); | ||
} |
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.
No need for the braces:
case String(): { | |
check(findAvatarImageWidget(tester)).isNotNull().src.equals(resolveUrl(avatarUrl, eg.selfAccount)); | |
} | |
case String(): | |
check(findAvatarImageWidget(tester)).isNotNull().src.equals(resolveUrl(avatarUrl, eg.selfAccount)); |
In fact in Dart (unlike JS) one can even declare variables in a switch
case, with no need for extra braces.
test/widgets/message_list_test.dart
Outdated
switch (avatarUrl) { | ||
case String(): { |
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.
Also when the switch is just "null or not" it's probably simplest to just use an if/else 🙂
test/widgets/message_list_test.dart
Outdated
final avatarUrl = sender.avatarUrl; | ||
switch (avatarUrl) { | ||
case String(): { | ||
check(findAvatarImageWidget(tester)).isNotNull().src.equals(resolveUrl(avatarUrl, eg.selfAccount)); |
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.
nit:
check(findAvatarImageWidget(tester)).isNotNull().src.equals(resolveUrl(avatarUrl, eg.selfAccount)); | |
check(findAvatarImageWidget(tester)).isNotNull() | |
.src.equals(resolveUrl(avatarUrl, eg.selfAccount)); |
test/widgets/message_list_test.dart
Outdated
// TODO only vary [avatarUrl], not other fields | ||
checkResultForSender(eg.user(userId: eg.selfUser.userId, avatarUrl: '/foo.png')); |
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 checkResultForSender
is a private helper for this test, right? And it only consults the avatarUrl
.
So it seems like you could resolve this TODO by just passing the avatarUrl
value itself.
5f18921
to
6141ee3
Compare
Thanks for the review! Revision pushed. |
Now, as demonstrated in the new test, if the author of a message changes their avatar, we'll see the update in the message list as soon as we get the event. While we're at it, comment out the property on [Message] to guide future consumers to [User]. Related: zulip#135
Thanks! LGTM; merging. |
6141ee3
to
aade783
Compare
Now, as demonstrated in the new test, if the author of a message
changes their avatar, we'll see the update in the message list as
soon as we get the event.
While we're at it, comment out the property on [Message] to guide
future consumers to [User].
Related: #135