Skip to content

Commit 9a25819

Browse files
chrisbobbegnprice
authored andcommitted
content test [nfc]: Use prepareContentBare, not ad hoc tester.pumpWidget
It should now be easy to drop in natural dependencies of our content widgets, such as a ThemeExtension for custom light- and dark-theme colors, for all the tests of our Zulip content widgets. To do that, we can just add unconditional code to this function. After this change, some ad-hoc `tester.pumpWidget` calls do remain in this file; see tests of RealmContentNetworkImage and AvatarImage. But those aren't "Zulip content widgets" in the same sense as most of the widgets in lib/widgets/content.dart, which are used exclusively to render parsed Zulip Markdown. (There isn't even any Zulip Markdown that would produce an AvatarImage.) So, leave them be. Perhaps these widgets belong in some other file. Related: #95
1 parent 08f31a3 commit 9a25819

File tree

1 file changed

+62
-97
lines changed

1 file changed

+62
-97
lines changed

test/widgets/content_test.dart

Lines changed: 62 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ void main() {
9696
return BlockContentList(nodes: parseContent(html).nodes);
9797
}
9898

99+
Widget messageContent(String html) {
100+
return MessageContent(message: eg.streamMessage(content: html),
101+
content: parseContent(html));
102+
}
103+
104+
// TODO(#488) For content that we need to show outside a per-message context
105+
// or a context without a full PerAccountStore, make sure to include tests
106+
// that don't provide such context.
99107
Future<void> prepareContentBare(WidgetTester tester, Widget child, {
100108
List<NavigatorObserver> navObservers = const [],
101109
bool wrapWithPerAccountStoreWidget = false,
@@ -173,27 +181,16 @@ void main() {
173181

174182
group('interactions: spoiler with tappable content (an image) in the header', () {
175183
Future<List<Route<dynamic>>> prepareContent(WidgetTester tester, String html) async {
176-
addTearDown(testBinding.reset);
177-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
178-
prepareBoringImageHttpClient();
179-
180184
final pushedRoutes = <Route<dynamic>>[];
181185
final testNavObserver = TestNavigatorObserver()
182186
..onPushed = (route, prevRoute) => pushedRoutes.add(route);
183-
184-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
185-
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
186-
supportedLocales: ZulipLocalizations.supportedLocales,
187-
navigatorObservers: [testNavObserver],
188-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
189-
child: MessageContent(
190-
message: eg.streamMessage(content: html),
191-
content: parseContent(html))))));
192-
await tester.pump(); // global store
193-
await tester.pump(); // per-account store
194-
debugNetworkImageHttpClientProvider = null;
195-
196-
// `tester.pumpWidget` introduces an initial route;
187+
await prepareContentBare(tester,
188+
// Message is needed for the image's lightbox.
189+
messageContent(html),
190+
navObservers: [testNavObserver],
191+
// We try to resolve the image's URL on the self-account's realm.
192+
wrapWithPerAccountStoreWidget: true);
193+
// `tester.pumpWidget` in prepareContentBare introduces an initial route;
197194
// remove it so consumers only have newly pushed routes.
198195
assert(pushedRoutes.length == 1);
199196
pushedRoutes.removeLast();
@@ -261,18 +258,12 @@ void main() {
261258

262259
group('MessageImage, MessageImageList', () {
263260
Future<void> prepareContent(WidgetTester tester, String html) async {
264-
addTearDown(testBinding.reset);
265-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
266-
prepareBoringImageHttpClient();
267-
268-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
269-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
270-
child: MessageContent(
271-
message: eg.streamMessage(content: html),
272-
content: parseContent(html))))));
273-
await tester.pump(); // global store
274-
await tester.pump(); // per-account store
275-
debugNetworkImageHttpClientProvider = null;
261+
await prepareContentBare(tester,
262+
// Message is needed for an image's lightbox.
263+
messageContent(html),
264+
// We try to resolve image URLs on the self-account's realm.
265+
// For URLs on the self-account's realm, we include the auth credential.
266+
wrapWithPerAccountStoreWidget: true);
276267
}
277268

278269
testWidgets('single image', (tester) async {
@@ -353,22 +344,21 @@ void main() {
353344

354345
group("MessageInlineVideo", () {
355346
Future<List<Route<dynamic>>> prepareContent(WidgetTester tester, String html) async {
356-
addTearDown(testBinding.reset);
357-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
358-
359347
final pushedRoutes = <Route<dynamic>>[];
360348
final testNavObserver = TestNavigatorObserver()
361349
..onPushed = (route, prevRoute) => pushedRoutes.add(route);
362-
363-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
364-
navigatorObservers: [testNavObserver],
365-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
366-
child: MessageContent(
367-
message: eg.streamMessage(content: html),
368-
content: parseContent(html))))));
369-
await tester.pump(); // global store
370-
await tester.pump(); // per-account store
371-
350+
await prepareContentBare(tester,
351+
// Message is needed for a video's lightbox.
352+
messageContent(html),
353+
navObservers: [testNavObserver],
354+
// We try to resolve video URLs on the self-account's realm.
355+
// With #656, we'll show a preview image. We'll try to resolve this
356+
// image's URL on the self-account's realm. If it's on the
357+
// self-account's realm, we'll request it with the auth credential.
358+
// TODO(#656) in above comment, change "we will" to "we do"
359+
wrapWithPerAccountStoreWidget: true);
360+
// `tester.pumpWidget` in prepareContentBare introduces an initial route;
361+
// remove it so consumers only have newly pushed routes.
372362
assert(pushedRoutes.length == 1);
373363
pushedRoutes.removeLast();
374364
return pushedRoutes;
@@ -386,18 +376,11 @@ void main() {
386376

387377
group("MessageEmbedVideo", () {
388378
Future<void> prepareContent(WidgetTester tester, String html) async {
389-
addTearDown(testBinding.reset);
390-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
391-
prepareBoringImageHttpClient();
392-
393-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
394-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
395-
child: MessageContent(
396-
message: eg.streamMessage(content: html),
397-
content: parseContent(html))))));
398-
await tester.pump(); // global store
399-
await tester.pump(); // per-account store
400-
debugNetworkImageHttpClientProvider = null;
379+
await prepareContentBare(tester,
380+
// Message is needed for a video's lightbox.
381+
messageContent(html),
382+
// We try to resolve a video preview URL on the self-account's realm.
383+
wrapWithPerAccountStoreWidget: true);
401384
}
402385

403386
Future<void> checkEmbedVideo(WidgetTester tester, ContentExample example) async {
@@ -537,17 +520,9 @@ void main() {
537520
// We use this to simulate taps on specific glyphs.
538521

539522
Future<void> prepareContent(WidgetTester tester, String html) async {
540-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
541-
addTearDown(testBinding.reset);
542-
543-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
544-
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
545-
supportedLocales: ZulipLocalizations.supportedLocales,
546-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
547-
child: BlockContentList(
548-
nodes: parseContent(html).nodes)))));
549-
await tester.pump();
550-
await tester.pump();
523+
await prepareContentBare(tester, plainContent(html),
524+
// We try to resolve relative links on the self-account's realm.
525+
wrapWithPerAccountStoreWidget: true);
551526
}
552527

553528
testWidgets('can tap a link to open URL', (tester) async {
@@ -636,32 +611,29 @@ void main() {
636611
});
637612

638613
group('LinkNode on internal links', () {
639-
Future<List<Route<dynamic>>> prepareContent(WidgetTester tester, {
640-
required String html,
641-
}) async {
642-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot(
643-
streams: [eg.stream(streamId: 1, name: 'check')],
644-
));
645-
addTearDown(testBinding.reset);
614+
Future<List<Route<dynamic>>> prepareContent(WidgetTester tester, String html) async {
646615
final pushedRoutes = <Route<dynamic>>[];
647616
final testNavObserver = TestNavigatorObserver()
648617
..onPushed = (route, prevRoute) => pushedRoutes.add(route);
649-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
650-
navigatorObservers: [testNavObserver],
651-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
652-
child: BlockContentList(nodes: parseContent(html).nodes)))));
653-
await tester.pump(); // global store
654-
await tester.pump(); // per-account store
655-
// `tester.pumpWidget` introduces an initial route, remove so
656-
// consumers only have newly pushed routes.
618+
619+
await prepareContentBare(tester, plainContent(html),
620+
navObservers: [testNavObserver],
621+
// We try to resolve relative links on the self-account's realm.
622+
wrapWithPerAccountStoreWidget: true);
623+
624+
// `tester.pumpWidget` in prepareContentBare introduces an initial route;
625+
// remove it so consumers only have newly pushed routes.
657626
assert(pushedRoutes.length == 1);
658627
pushedRoutes.removeLast();
628+
629+
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
630+
store.addStream(eg.stream(name: 'stream'));
659631
return pushedRoutes;
660632
}
661633

662634
testWidgets('valid internal links are navigated to within app', (tester) async {
663635
final pushedRoutes = await prepareContent(tester,
664-
html: '<p><a href="/#narrow/stream/1-check">stream</a></p>');
636+
'<p><a href="/#narrow/stream/1-check">stream</a></p>');
665637

666638
await tapText(tester, find.text('stream'));
667639
check(testBinding.takeLaunchUrlCalls()).isEmpty();
@@ -672,7 +644,7 @@ void main() {
672644
testWidgets('invalid internal links are opened in browser', (tester) async {
673645
// Link is invalid due to `topic` operator missing an operand.
674646
final pushedRoutes = await prepareContent(tester,
675-
html: '<p><a href="/#narrow/stream/1-check/topic">invalid</a></p>');
647+
'<p><a href="/#narrow/stream/1-check/topic">invalid</a></p>');
676648

677649
await tapText(tester, find.text('invalid'));
678650
final expectedUrl = eg.realmUrl.resolve('/#narrow/stream/1-check/topic');
@@ -717,11 +689,9 @@ void main() {
717689
});
718690

719691
testWidgets('clock icon and text are the same color', (tester) async {
720-
await tester.pumpWidget(MaterialApp(home: DefaultTextStyle(
721-
style: const TextStyle(color: Colors.green),
722-
child: BlockContentList(nodes:
723-
parseContent('<p>$timeSpanHtml</p>').nodes),
724-
)));
692+
await prepareContentBare(tester,
693+
DefaultTextStyle(style: const TextStyle(color: Colors.green),
694+
child: plainContent('<p>$timeSpanHtml</p>')));
725695

726696
final icon = tester.widget<Icon>(
727697
find.descendant(of: find.byType(GlobalTime),
@@ -779,15 +749,10 @@ void main() {
779749

780750
group('MessageImageEmoji', () {
781751
Future<void> prepareContent(WidgetTester tester, String html) async {
782-
addTearDown(testBinding.reset);
783-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
784-
prepareBoringImageHttpClient();
785-
786-
await tester.pumpWidget(GlobalStoreWidget(child: MaterialApp(
787-
home: PerAccountStoreWidget(accountId: eg.selfAccount.id,
788-
child: BlockContentList(nodes: parseContent(html).nodes)))));
789-
await tester.pump(); // global store
790-
await tester.pump(); // per-account store
752+
await prepareContentBare(tester, plainContent(html),
753+
// We try to resolve image-emoji URLs on the self-account's realm.
754+
// For URLs on the self-account's realm, we include the auth credential.
755+
wrapWithPerAccountStoreWidget: true);
791756
}
792757

793758
testWidgets('smoke: custom emoji', (tester) async {

0 commit comments

Comments
 (0)