Skip to content

Commit

Permalink
internal_links: Add variable realmUrlWithSlash to add '/'
Browse files Browse the repository at this point in the history
Updates the URL construction to include a trailing slash
before the fragment identifier. This ensures that the URL
is properly formatted and makes the url linkified.
Co-authored-by: Greg Price <greg@zulip.com>

Fixes: #845
  • Loading branch information
satyam372 committed Oct 14, 2024
1 parent 6979b50 commit d4733c3
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 4 deletions.
6 changes: 5 additions & 1 deletion lib/model/internal_link.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
fragment.write('/near/$nearMessageId');
}

return store.realmUrl.replace(fragment: fragment.toString());
final realmUrlWithSlash = store.realmUrl.path.isNotEmpty
? store.realmUrl
: store.realmUrl.replace(path: '${store.realmUrl.path}/');

return realmUrlWithSlash.replace(fragment: fragment.toString());
}

/// A [Narrow] from a given URL, on `store`'s realm.
Expand Down
85 changes: 82 additions & 3 deletions test/widgets/action_sheet_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ late FakeApiConnection connection;
Future<void> setupToMessageActionSheet(WidgetTester tester, {
required Message message,
required Narrow narrow,
Account? account,
}) async {
addTearDown(testBinding.reset);

await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
account ??= eg.selfAccount;
final initialSnapshot = eg.initialSnapshot();
await testBinding.globalStore.add(account, initialSnapshot);
final store = await testBinding.globalStore.perAccount(account.id);
await store.addUser(eg.user(userId: message.senderId));
if (message is StreamMessage) {
final stream = eg.stream(streamId: message.streamId);
Expand All @@ -61,7 +64,7 @@ Future<void> setupToMessageActionSheet(WidgetTester tester, {
messages: [message],
).toJson());

await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id,
await tester.pumpWidget(TestZulipApp(accountId: account.id,
child: MessageListPage(initNarrow: narrow)));

// global store, per-account store, and message list get loaded
Expand Down Expand Up @@ -553,6 +556,82 @@ void main() {
});
});

group('Message link verbatim URL tests', () {
Future<void> tapCopyMessageLinkButton(WidgetTester tester) async {
await tester.ensureVisible(find.byIcon(Icons.link, skipOffstage: false));
await tester.tap(find.byIcon(Icons.link));
await tester.pump(); // [MenuItemButton.onPressed] called in a post-frame callback: flutter/flutter@e4a39fa2e
}

Future<void> testMessageLink({
required WidgetTester tester,
required String realmUrl,
required String topic,
required String expectedLink,
}) async {
final stream = eg.stream(streamId: 42, name: 'stream 42');
final message = eg.streamMessage(id: 12345, stream: stream, topic: topic);
final narrow = TopicNarrow.ofMessage(message);
final account = eg.selfAccount.copyWith(realmUrl: Uri.parse(realmUrl));
await setupToMessageActionSheet(
tester, message: message, narrow: narrow, account: account);

final store = await testBinding.globalStore.perAccount(account.id);
if (!store.streams.containsKey(stream.streamId)) {
await store.addStream(stream);
}

await tapCopyMessageLinkButton(tester);
await tester.pump(Duration.zero);
check(await Clipboard.getData('text/plain')).isNotNull().text.equals(expectedLink);
}

testWidgets('Copies link with custom realm path', (tester) async {
await testMessageLink(
tester: tester,
realmUrl: 'https://chat.example/foo',
topic: 'test topic',
expectedLink: 'https://chat.example/foo#narrow/stream/42-stream-42/topic/test.20topic/near/12345',
);
});

testWidgets('Copies link with realm URL without path', (tester) async {
await testMessageLink(
tester: tester,
realmUrl: 'https://chat.zulip.org',
topic: 'test topic',
expectedLink: 'https://chat.zulip.org/#narrow/stream/42-stream-42/topic/test.20topic/near/12345',
);
});

testWidgets('Copies link with special characters in topic', (tester) async {
await testMessageLink(
tester: tester,
realmUrl: 'https://chat.zulip.org',
topic: 'What\'s up? 123!',
expectedLink: 'https://chat.zulip.org/#narrow/stream/42-stream-42/topic/What\'s.20up.3F.20123!/near/12345',
);
});

testWidgets('Copies link with realm URL ending in path', (tester) async {
await testMessageLink(
tester: tester,
realmUrl: 'https://chat.zulip.org/path',
topic: 'Numbers & Symbols: 100%',
expectedLink: 'https://chat.zulip.org/path#narrow/stream/42-stream-42/topic/Numbers.20.26.20Symbols.3A.20100.25/near/12345',
);
});

testWidgets('Copies link with realm URL ending in slash', (tester) async {
await testMessageLink(
tester: tester,
realmUrl: 'https://chat.zulip.org/',
topic: 'Regular topic',
expectedLink: 'https://chat.zulip.org/#narrow/stream/42-stream-42/topic/Regular.20topic/near/12345',
);
});
});

group('ShareButton', () {
// Tests should call this.
MockSharePlus setupMockSharePlus() {
Expand Down

0 comments on commit d4733c3

Please sign in to comment.