riverpod
riverpod copied to clipboard
Tried to read [Provider] from a place where one of its dependencies were overridden but the provider is not. When using 2 ProviderScope
Hello
Describe the bug When trying to override a provider in tests, if I have 2 ProviderScope in my widget tree, I get the error message:
Tried to read AutoDisposeProvider<String>#cc8cc(hello world) from a place where one of its
dependencies were overridden but the provider is not.
To fix this error, you can add add "dependencies" to AutoDisposeProvider<String>#cc8cc(hello world)
such that we have:
final a = Provider(...);
final b = Provider((ref) => ref.watch(a), dependencies: [a]);
To Reproduce
Here's the code:
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final a = Provider.family.autoDispose<String, String>((ref, value) {
return value;
});
final b = Provider.family.autoDispose<String, String>((ref, value) {
return ref.watch(a(value));
}, dependencies: [a]);
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
home: Text(ref.watch(b('hello world'))),
);
}
}
// widget_test.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod_family_dependencies/main.dart';
void main() {
testWidgets('Test scoping provider', (WidgetTester tester) async {
const text = 'please help me Remi';
await tester.pumpWidget(
ProviderScope( // If I remove this one, then the test will pass
child: ProviderScope(
overrides: [a('hello world').overrideWithValue(text)],
child: const MyApp(),
),
),
);
expect(find.text(text), findsOneWidget);
});
}
I've created a sample repo with 2 branches which both have the issue.
- main is using ^1.0.4
- 2.1.1 is using... ^2.1.1 https://github.com/GP4cK/riverpod_family_dependencies
Expected behavior I would expect to be able to override a provider even if I have multiple ProviderScope in the widget tree as long as the ProviderScope that does the override is higher than the widget which is reading the provider.
BTW I created a mini PR to remove the double "add" in the error message: https://github.com/rrousselGit/riverpod/pull/1870
I also did 2 additional tests with overrideWith. The difference is in the way I override a
.
So it must be an issue with family. But I struggle to understand the code of readProviderElement
and what the assert is checking :/
// This passes:
testWidgets('test scoping family provider with overrideWith', (tester) async {
const text = 'hello riverpod';
const family = 'hello world';
final a =
Provider.family.autoDispose<String, String>((ref, value) => value);
final b = Provider.family.autoDispose<String, String>(
(ref, value) => ref.watch(a(value)),
dependencies: [a],
);
await tester.pumpWidget(
ProviderScope(
child: ProviderScope(
overrides: [a.overrideWith((ref, value) => text)], // Overrides `a` entirely.
child: Consumer(
builder: (_, ref, __) => Text(
ref.watch(b(family)),
textDirection: TextDirection.ltr,
),
),
),
),
);
expect(find.text(text), findsOneWidget);
});
// This fails:
testWidgets('test scoping a provider with overrideWith', (tester) async {
const text = 'hello riverpod';
const family = 'hello world';
final a =
Provider.family.autoDispose<String, String>((ref, value) => value);
final b = Provider.family.autoDispose<String, String>(
(ref, value) => ref.watch(a(value)),
dependencies: [a],
);
await tester.pumpWidget(
ProviderScope(
child: ProviderScope(
overrides: [a(family).overrideWith((ref) => text)], // Only override a(family).
child: Consumer(
builder: (_, ref, __) => Text(
ref.watch(b(family)),
textDirection: TextDirection.ltr,
),
),
),
),
);
expect(find.text(text), findsOneWidget);
});
Thanks for the detailed report.
It seems this example is fixed in version 2.3.2
. The test is passing with 2 ProviderScope
s
Mmm I created a branch with 2.3.2 and the tests still fail for me...
Any update on this?
I can reproduce. I'll try to fix it this week
This appears specific to overrides: [family('arg').overrideWith(...)]
Doing overrides: [family.overrideWith((ref, arg) => '...')]
works fine.
I found the problem, but this is quite the complex problem to fix. I have some ideas on a solution, but for now I'd suggest using the workaround mentioned above.
I'm probably not going to fix this before 3.0 as it requires a few internal changes and is fairly minor with a workaround.