mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
Hide the iOS Notifications settings section for communities that have not enabled push unless their relay advertises valid push support. A build with a configured gateway previously showed the switch even when the relay could not support push. Communities where push is already enabled retain an off switch and iOS Settings recovery during discovery or when push support is unavailable. The section explains that support is unavailable instead of claiming notifications will arrive. Capability discovery keeps its existing refresh behavior. Returning after at least five seconds in the background reconnects the session and fetches capability again. Tom explicitly chose this behavior without new retries, polling, or refresh triggers. Companion client change for squareup/buzz-releases#104. Related: #7826 (broader notification availability diagnostics). ### Validation Settings widget tests cover hidden first-time opt-in during loading, absent capability, and discovery errors. Recovery tests exercise the real off switch for already-enabled communities in all three states, verifying persisted opt-out, the native snapshot writer, a durable pending relay tombstone after failure, and the iOS Settings link. They also verify that pending recovery stays visible after a relay failure and disappears only after opt-out confirmation. Tests without a gateway definition verify hidden first-time settings and disabled native registration. Mobile analysis and the mobile test suite passed. --------- Signed-off-by: Tom Brow <tomb@block.xyz>
117 lines
4.4 KiB
Dart
117 lines
4.4 KiB
Dart
import 'package:buzz/features/settings/settings_page.dart';
|
|
import 'package:buzz/shared/community/community.dart';
|
|
import 'package:buzz/shared/community/community_provider.dart';
|
|
import 'package:buzz/shared/push/dev_push_lease.dart';
|
|
import 'package:buzz/shared/push/push_bootstrap.dart';
|
|
import 'package:buzz/shared/push/push_bridge.dart';
|
|
import 'package:buzz/shared/push/push_relay_capability_provider.dart';
|
|
import 'package:buzz/shared/relay/relay_provider.dart';
|
|
import 'package:buzz/shared/relay/relay_session.dart';
|
|
import 'package:buzz/shared/theme/theme.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
group('artifact without a gateway define', () {
|
|
test(
|
|
'does not discover push capability or enter the opted-in lifecycle',
|
|
() async {
|
|
final container = ProviderContainer(
|
|
overrides: [
|
|
relaySessionProvider.overrideWith(
|
|
() => throw StateError('must not start relay discovery'),
|
|
),
|
|
],
|
|
);
|
|
addTearDown(container.dispose);
|
|
expect(
|
|
await container.read(currentRelayPushDescriptorProvider.future),
|
|
isNull,
|
|
);
|
|
expect(
|
|
buzzPushLifecycleEnabled(
|
|
community: Community.create(
|
|
name: 'Team',
|
|
relayUrl: 'wss://relay.example',
|
|
).copyWith(pushNotificationsEnabled: true),
|
|
descriptor: const BuzzPushLeaseDescriptor(
|
|
origin: 'wss://relay.example',
|
|
executorKeyId: 'key',
|
|
executorPubkey: 'pubkey',
|
|
transport: 'apns',
|
|
maxLeaseTtlSeconds: 3600,
|
|
maxContentLength: 4096,
|
|
maxPlaintextLength: 4096,
|
|
maxEndpointLength: 2048,
|
|
maxStringLength: 512,
|
|
),
|
|
),
|
|
isFalse,
|
|
);
|
|
},
|
|
);
|
|
|
|
test('never requests native registration or gateway grants', () async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
|
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
|
const channel = MethodChannel('buzz/push');
|
|
final calls = <String>[];
|
|
final messenger =
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger;
|
|
messenger.setMockMethodCallHandler(channel, (call) async {
|
|
calls.add(call.method);
|
|
return null;
|
|
});
|
|
addTearDown(() => messenger.setMockMethodCallHandler(channel, null));
|
|
await startBuzzPushRegistration();
|
|
expect(await readBuzzPushEndpointGrants(), isEmpty);
|
|
expect(calls, isEmpty);
|
|
});
|
|
|
|
testWidgets('Settings hides notifications without push capability', (
|
|
tester,
|
|
) async {
|
|
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
|
|
addTearDown(() => debugDefaultTargetPlatformOverride = null);
|
|
SharedPreferences.setMockInitialValues({});
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
savedPrefsProvider.overrideWithValue(prefs),
|
|
activeCommunityProvider.overrideWith(
|
|
(ref) async => Community.create(
|
|
name: 'Team',
|
|
relayUrl: 'wss://relay.example',
|
|
),
|
|
),
|
|
buzzPushAuthorizationStatusReaderProvider.overrideWithValue(
|
|
() async =>
|
|
throw StateError('must not query notification permission'),
|
|
),
|
|
],
|
|
child: MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: SettingsPage(
|
|
profileHeader: const SizedBox.shrink(),
|
|
invitePageBuilder: (_) => const SizedBox.shrink(),
|
|
identityRecoveryPageBuilder: (_) => const SizedBox.shrink(),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Notifications'), findsNothing);
|
|
expect(find.text('Push notifications'), findsNothing);
|
|
expect(find.byType(Switch), findsNothing);
|
|
expect(tester.takeException(), isNull);
|
|
debugDefaultTargetPlatformOverride = null;
|
|
});
|
|
}, skip: Env.pushGatewayConfigured);
|
|
}
|