Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions lib/providers/discover_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,28 @@ class DiscoverNotifier extends Notifier<AsyncValue<List<Recommendation>>> {
}
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<Recommendation>? previous) {
if (ref.mounted &&
requestId == _requestId &&
ref.read(activeSessionScopeProvider) == scope &&
previous != null) {
state = AsyncValue.data(previous);
}
}

Future<void> refresh() async {
final scope = ref.read(activeSessionScopeProvider);
if (scope == null) {
Expand Down
45 changes: 45 additions & 0 deletions test/widgets/home_screen_recommendations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Channel>[]);
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();
},
);
}
Loading