diff --git a/lib/providers/discover_provider.dart b/lib/providers/discover_provider.dart index 2500111..55fe650 100644 --- a/lib/providers/discover_provider.dart +++ b/lib/providers/discover_provider.dart @@ -51,17 +51,28 @@ class DiscoverNotifier extends Notifier>> { } try { await _api.dismissRecommendation(id); + } on ApiException catch (e) { + // The recommendation is already gone (e.g. cleared by the staleness + // sweep, or by subscribing to it). The card's job is done — keep it + // removed rather than resurrecting it and alarming the user. + if (e.statusCode == 404) return; + _rollback(requestId, scope, previous); + rethrow; } catch (_) { - if (ref.mounted && - requestId == _requestId && - ref.read(activeSessionScopeProvider) == scope && - previous != null) { - state = AsyncValue.data(previous); - } + _rollback(requestId, scope, previous); rethrow; } } + void _rollback(int requestId, Object? scope, List? previous) { + if (ref.mounted && + requestId == _requestId && + ref.read(activeSessionScopeProvider) == scope && + previous != null) { + state = AsyncValue.data(previous); + } + } + Future refresh() async { final scope = ref.read(activeSessionScopeProvider); if (scope == null) { diff --git a/test/widgets/home_screen_recommendations_test.dart b/test/widgets/home_screen_recommendations_test.dart index 3abe5a2..477ead0 100644 --- a/test/widgets/home_screen_recommendations_test.dart +++ b/test/widgets/home_screen_recommendations_test.dart @@ -143,4 +143,49 @@ void main() { await tester.pump(const Duration(seconds: 5)); await tester.pumpAndSettle(); }); + + testWidgets( + 'a 404 when clearing the recommendation is treated as already-cleared', + (tester) async { + when(() => api.getRecommendations()).thenAnswer( + (_) async => [ + makeRecommendation( + id: 'r1', + channelName: 'Veritasium', + youtubeChannelId: 'UC-x', + ), + ], + ); + when(() => api.getChannels()).thenAnswer((_) async => const []); + when( + () => api.subscribeToChannel( + any(), + trackingMode: any(named: 'trackingMode'), + ), + ).thenAnswer((_) async {}); + // The recommendation is already gone server-side (e.g. cleared by the + // staleness sweep) — dismiss 404s. + when(() => api.dismissRecommendation(any())).thenThrow( + const ApiException( + message: 'Recommendation not found', + statusCode: 404, + ), + ); + + await pumpHome(tester); + await revealRecommendations(tester); + await tester.ensureVisible(find.text('Subscribe')); + await tester.pumpAndSettle(); + await tester.tap(find.text('Subscribe')); + await tester.pumpAndSettle(); + + // The card is cleared and NO "could not be cleared" error is shown. + expect(find.text('Subscribed to Veritasium'), findsOneWidget); + expect(find.text('Recommended for you'), findsNothing); + expect(find.textContaining('could not be cleared'), findsNothing); + + await tester.pump(const Duration(seconds: 5)); + await tester.pumpAndSettle(); + }, + ); }