mirror of
https://github.com/block/buzz.git
synced 2026-11-06 09:21:45 +00:00
test(mobile): lock in invite-page and bare-host community link entry (#9047)
Both mobile community-link fields (Add community and the welcome/onboarding "Enter a community link" page) already accept a typed or pasted `https://<host>/invite/<code>` link and keep the code. They also read a bare host as `wss://`. This PR adds regression coverage for both. **It doesn't change any production code.** Companion: block/buzz-app#2412 fixes the same two inputs in buzz-app's Join a community. ## What's covered - **`community_link_input_test.dart`** - The address loop is now an input → relay table, with two new rows: `secondary.example` and `relay.example.com:8443` (the port is kept). - The invite case now uses `https://primary.example/invite/fixture`, and expects relay `wss://primary.example` with code `fixture`. - Two new rejected inputs: `ws://secondary.example`, and the invite path with a trailing slash, which the relay doesn't serve. - **`onboarding_entry_routes_test.dart`**: before the bare-host step, the journey pastes the invite link into the Add route's field. It expects the app-level `InviteJoinSheet` to show host `primary.example` and code `fixture`. ## Shown to catch a regression I removed the invite/add-community short-circuit in `parseCommunityLinkInput`. Both the invite unit case and the new journey step then failed. ## Not in this PR Two parser differences are left for a separate decision, along with the tests that depend on them: - `buzz://connect?relay=…`: mobile rejects it in the fields and silently drops it as an OS link, but buzz-app, desktop and the web repo browser's Connect button all use it. - An invite-page link with a query string: mobile accepts it and throws the query away, but buzz-app rejects it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Matt Toohey <contact@matttoohey.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,24 +4,26 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('normalizes addresses through the existing community parser', () {
|
||||
for (final value in [
|
||||
' team.communities.buzz.xyz ',
|
||||
'https://team.communities.buzz.xyz/',
|
||||
'wss://team.communities.buzz.xyz',
|
||||
for (final (value, relay) in [
|
||||
(' team.communities.buzz.xyz ', 'wss://team.communities.buzz.xyz'),
|
||||
('https://team.communities.buzz.xyz/', 'wss://team.communities.buzz.xyz'),
|
||||
('wss://team.communities.buzz.xyz', 'wss://team.communities.buzz.xyz'),
|
||||
('secondary.example', 'wss://secondary.example'),
|
||||
('relay.example.com:8443', 'wss://relay.example.com:8443'),
|
||||
]) {
|
||||
final uri = parseCommunityLinkInput(value)!;
|
||||
final link = parseBuzzDeepLink(uri) as AddCommunityDeepLink;
|
||||
expect(link.relayUrl, 'wss://team.communities.buzz.xyz');
|
||||
expect(link.relayUrl, relay, reason: value);
|
||||
}
|
||||
});
|
||||
|
||||
test('preserves the invite and its destination', () {
|
||||
final uri = parseCommunityLinkInput(
|
||||
'https://community.example.com/invite/abc123',
|
||||
'https://primary.example/invite/fixture',
|
||||
)!;
|
||||
final link = parseBuzzDeepLink(uri) as InviteDeepLink;
|
||||
expect(link.code, 'abc123');
|
||||
expect(link.relayUrl, 'wss://community.example.com');
|
||||
expect(link.code, 'fixture');
|
||||
expect(link.relayUrl, 'wss://primary.example');
|
||||
});
|
||||
|
||||
test('rejects unrelated actions and unsafe or incomplete addresses', () {
|
||||
@@ -29,9 +31,11 @@ void main() {
|
||||
'',
|
||||
'not a link',
|
||||
'http://community.example.com',
|
||||
'ws://secondary.example',
|
||||
'https://user:secret@community.example.com',
|
||||
'https://community.example.com/other',
|
||||
'https://community.example.com/invite/',
|
||||
'https://primary.example/invite/fixture/',
|
||||
'https://community.example.com#secret',
|
||||
'https://community.example.com?token=secret',
|
||||
'https://127.0.0.1',
|
||||
|
||||
@@ -5,6 +5,8 @@ import 'dart:convert';
|
||||
|
||||
import 'package:buzz/features/channels/channel.dart';
|
||||
import 'package:buzz/features/channels/channels_provider.dart';
|
||||
import 'package:buzz/features/invites/invite_join_provider.dart';
|
||||
import 'package:buzz/features/invites/invite_join_sheet.dart';
|
||||
import 'package:buzz/features/onboarding/hosted_connect_page.dart';
|
||||
import 'package:buzz/features/onboarding/self_hosted_entry_sheet.dart';
|
||||
import 'package:buzz/hosted_app_gate.dart';
|
||||
@@ -243,6 +245,25 @@ void main() {
|
||||
find.text('Enter a valid community address or invite link.'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// A pasted invite-page link keeps its code through to the join sheet.
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('community-link-input')).hitTestable(),
|
||||
'https://primary.example/invite/fixture',
|
||||
);
|
||||
await tester.tap(find.text('Continue').hitTestable());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(InviteJoinSheet), findsOneWidget);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(InviteJoinSheet),
|
||||
matching: find.text('primary.example'),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(container.read(inviteJoinProvider).invite?.code, 'fixture');
|
||||
await tester.tap(find.text('Cancel').hitTestable());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(InviteJoinSheet), findsNothing);
|
||||
// Drive the real deep-link dispatcher, sheet, service and auth persistence.
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('community-link-input')).hitTestable(),
|
||||
|
||||
Reference in New Issue
Block a user