Describe the bug
Let's say I have a Widget that depends on FutureProvider A, and then FutureProvider A depends on FutureProvider B. The Widget doesn't know about FutureProvider B. If FutureProvider B returns an error, FutureProvider A will return an error as well to the Widget. When the Widget got an Error, it would show an option to refresh by calling WidgetRef.invalidate() on FutureProvider A.
I assumed when FutureProvider A got invalidated, it would get disposed, then since only FutureProvider A depends on/watches FutureProvider B, FutureProvider B would get disposed of as well, resulting in a recomputed value for FutureProvider B.
But in Riverpod 2.5.0 that I'm using in my project, it still return the previous error/value.
To Reproduce
This is the code that I use to reproduce it:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
const wholeSentence = 'a sentence + $number';
const number = 100;
void main() {
test('testing future provider', () async {
final container = createContainer();
// First throw an exception
container.updateOverrides([listenedProvider.overrideWith((ref) => throw Exception())]);
await expectLater(
container.read(listeningProvider.future),
throwsA(isA<Exception>()),
);
// Then expect to get new value after invalidate
container.updateOverrides([listenedProvider.overrideWith((ref) async => number)]);
container.invalidate(listeningProvider);
await expectLater(
container.read(listeningProvider.future),
completion(wholeSentence),
);
});
testWidgets('testing widget with future provider', (widgetTester) async {
await widgetTester.pumpWidget(
ProviderScope(
overrides: [
listenedProvider.overrideWith((ref) {
print('throwing Exception');
throw Exception();
}),
],
child: const SomeWidget(),
),
);
print('setting up container');
final element = widgetTester.element(find.byType(SomeWidget));
final container = ProviderScope.containerOf(element);
print('running first test');
await expectLater(
container.read(listeningProvider.future),
throwsA(isA<Exception>()),
);
print('invalidate then get new value from listenedProvider');
// container.invalidate(listenedProvider);
container.invalidate(listeningProvider);
container.updateOverrides([listenedProvider.overrideWith((ref) async => number)]);
await widgetTester.pumpAndSettle();
await expectLater(
container.read(listeningProvider.future),
completion(wholeSentence),
);
});
}
class SomeWidget extends ConsumerWidget {
const SomeWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final result = ref.watch(listeningProvider);
if (result.hasValue) {
return MaterialApp(home: Text(result.value!));
}
return Container();
}
}
final listenedProvider = FutureProvider.autoDispose<int>((ref) async {
throw UnimplementedError();
});
final listeningProvider = FutureProvider.autoDispose<String>((ref) async {
final number = await ref.watch(listenedProvider.future);
return 'a sentence + $number';
});
ProviderContainer createContainer() {
final container = ProviderContainer(
overrides: [
listenedProvider.overrideWith((ref) async {
return number;
}),
],
);
addTearDown(() => container.dispose());
return container;
}
Expected behavior
I expected both the unit test and widget test above should pass successfully. But in reality, it still throws an error. Only when I added ref.invalidate(listenedProvider) would it pass. But I don't want that, since it shouldn't know about listenedProvider/FutureProvider B
Describe the bug Let's say I have a Widget that depends on FutureProvider A, and then FutureProvider A depends on FutureProvider B. The Widget doesn't know about FutureProvider B. If FutureProvider B returns an error, FutureProvider A will return an error as well to the Widget. When the Widget got an Error, it would show an option to refresh by calling WidgetRef.invalidate() on FutureProvider A.
I assumed when FutureProvider A got invalidated, it would get disposed, then since only FutureProvider A depends on/watches FutureProvider B, FutureProvider B would get disposed of as well, resulting in a recomputed value for FutureProvider B.
But in Riverpod 2.5.0 that I'm using in my project, it still return the previous error/value.
To Reproduce
This is the code that I use to reproduce it:
Expected behavior I expected both the unit test and widget test above should pass successfully. But in reality, it still throws an error. Only when I added ref.invalidate(listenedProvider) would it pass. But I don't want that, since it shouldn't know about listenedProvider/FutureProvider B