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