@@ -8,13 +8,21 @@ import 'package:flutter_test/flutter_test.dart';
8
8
import 'package:url_launcher/url_launcher.dart' ;
9
9
import 'package:zulip/api/core.dart' ;
10
10
import 'package:zulip/model/content.dart' ;
11
+ import 'package:zulip/model/narrow.dart' ;
11
12
import 'package:zulip/widgets/content.dart' ;
13
+ import 'package:zulip/widgets/message_list.dart' ;
14
+ import 'package:zulip/widgets/page.dart' ;
12
15
import 'package:zulip/widgets/store.dart' ;
13
16
17
+ import '../api/fake_api.dart' ;
14
18
import '../example_data.dart' as eg;
15
19
import '../model/binding.dart' ;
20
+ import '../model/message_list_test.dart' ;
16
21
import '../test_images.dart' ;
22
+ import '../test_navigation.dart' ;
17
23
import 'dialog_checks.dart' ;
24
+ import 'message_list_checks.dart' ;
25
+ import 'page_checks.dart' ;
18
26
19
27
void main () {
20
28
TestZulipBinding .ensureInitialized ();
@@ -158,6 +166,78 @@ void main() {
158
166
});
159
167
});
160
168
169
+ group ('Internal links' , () {
170
+ Future <List <Route <dynamic >>> prepareContentWithNavigator (WidgetTester tester, {
171
+ required String html,
172
+ }) async {
173
+ addTearDown (testBinding.reset);
174
+ final pushedRoutes = < Route <dynamic >> [];
175
+ final testNavObserver = TestNavigatorObserver ()
176
+ ..onPushed = (route, prevRoute) => pushedRoutes.add (route);
177
+ await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot (
178
+ streams: [eg.stream (streamId: 1 , name: 'check' )],
179
+ ));
180
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
181
+ final connection = store.connection as FakeApiConnection ;
182
+ connection.prepare (json: newestResult (
183
+ foundOldest: true ,
184
+ messages: [],
185
+ ).toJson ());
186
+ await tester.pumpWidget (GlobalStoreWidget (child: MaterialApp (
187
+ navigatorObservers: [testNavObserver],
188
+ home: PerAccountStoreWidget (accountId: eg.selfAccount.id,
189
+ child: BlockContentList (nodes: parseContent (html).nodes)))));
190
+ await tester.pump ();
191
+ assert (pushedRoutes.length == 1 );
192
+ pushedRoutes.removeLast ();
193
+ return pushedRoutes;
194
+ }
195
+
196
+ testWidgets ('internal links are resolved: StreamNarrow' , (tester) async {
197
+ final pushedRoutes = await prepareContentWithNavigator (tester,
198
+ html: '<p><a href="/#narrow/stream/1-check">stream</a></p>' );
199
+
200
+ await tester.tap (find.text ('stream' ));
201
+ check (testBinding.takeLaunchUrlCalls ()).isEmpty ();
202
+ check (pushedRoutes).single.isA <WidgetRoute >()
203
+ .page.isA <MessageListPage >()
204
+ .narrow.equals (const StreamNarrow (1 ));
205
+ });
206
+
207
+ testWidgets ('internal links are resolved: TopicNarrow' , (tester) async {
208
+ final pushedRoutes = await prepareContentWithNavigator (tester,
209
+ html: '<p><a href="/#narrow/stream/1-check/topic/my.20topic">topic</a></p>' );
210
+
211
+ await tester.tap (find.text ('topic' ));
212
+ check (testBinding.takeLaunchUrlCalls ()).isEmpty ();
213
+ check (pushedRoutes).single.isA <WidgetRoute >()
214
+ .page.isA <MessageListPage >()
215
+ .narrow.equals (const TopicNarrow (1 , 'my topic' ));
216
+ });
217
+
218
+ testWidgets ('internal links are resolved: DmNarrow' , (tester) async {
219
+ final pushedRoutes = await prepareContentWithNavigator (tester,
220
+ html: '<p><a href="/#narrow/dm/1-123-group">dm</a></p>' );
221
+
222
+ await tester.tap (find.text ('dm' ));
223
+ check (testBinding.takeLaunchUrlCalls ()).isEmpty ();
224
+ check (pushedRoutes).single.isA <WidgetRoute >()
225
+ .page.isA <MessageListPage >()
226
+ .narrow.equals (DmNarrow .withUser (1 , selfUserId: eg.selfUser.userId));
227
+ });
228
+
229
+ testWidgets ('invalid internal links are not followed' , (tester) async {
230
+ final pushedRoutes = await prepareContentWithNavigator (tester,
231
+ html: '<p><a href="/#narrow/stream/1-check/topic">invalid</a></p>' );
232
+
233
+ await tester.tap (find.text ('invalid' ));
234
+ final expectedUrl = Uri .parse ('${eg .realmUrl }#narrow/stream/1-check/topic' );
235
+ check (testBinding.takeLaunchUrlCalls ())
236
+ .single.equals ((url: expectedUrl, mode: LaunchMode .externalApplication));
237
+ check (pushedRoutes).isEmpty ();
238
+ });
239
+ });
240
+
161
241
group ('UnicodeEmoji' , () {
162
242
Future <void > prepareContent (WidgetTester tester, String html) async {
163
243
await tester.pumpWidget (MaterialApp (home: BlockContentList (nodes: parseContent (html).nodes)));
0 commit comments