Skip to content

Commit 76a9f68

Browse files
authored
Add more to error message of RestorationScope.of (#126444)
Fixes flutter/flutter#126443
1 parent 41abe99 commit 76a9f68

2 files changed

Lines changed: 66 additions & 9 deletions

File tree

packages/flutter/lib/src/widgets/restoration.dart

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,26 @@ class RestorationScope extends StatefulWidget {
106106
final RestorationBucket? bucket = maybeOf(context);
107107
assert(() {
108108
if (bucket == null) {
109-
throw FlutterError(
110-
'RestorationScope.of() was called with a context that does not contain a '
111-
'RestorationScope widget.\n'
112-
'No RestorationScope widget ancestor could be found starting from the '
113-
'context that was passed to RestorationScope.of(). This can happen '
114-
'because you are using a widget that looks for a RestorationScope '
115-
'ancestor, but no such ancestor exists.\n'
116-
'The context used was:\n'
117-
' $context',
109+
throw FlutterError.fromParts(<DiagnosticsNode>[
110+
ErrorSummary(
111+
'RestorationScope.of() was called with a context that does not '
112+
'contain a RestorationScope widget. '
113+
),
114+
ErrorDescription(
115+
'No RestorationScope widget ancestor could be found starting from '
116+
'the context that was passed to RestorationScope.of(). This can '
117+
'happen because you are using a widget that looks for a '
118+
'RestorationScope ancestor, but no such ancestor exists.\n'
119+
'The context used was:\n'
120+
' $context'
121+
),
122+
ErrorHint(
123+
'State restoration must be enabled for a RestorationScope to exist. '
124+
'This can be done by passing a restorationScopeId to MaterialApp, '
125+
'CupertinoApp, or WidgetsApp at the root of the widget tree or by '
126+
'wrapping the widget tree in a RootRestorationScope.'
127+
),
128+
],
118129
);
119130
}
120131
return true;

packages/flutter/test/widgets/restoration_scope_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,52 @@ void main() {
5151
});
5252

5353
group('RestorationScope', () {
54+
testWidgets('asserts when none is found', (WidgetTester tester) async {
55+
late BuildContext capturedContext;
56+
await tester.pumpWidget(WidgetsApp(
57+
color: const Color(0xD0FF0000),
58+
builder: (_, __) {
59+
return RestorationScope(
60+
restorationId: 'test',
61+
child: Builder(
62+
builder: (BuildContext context) {
63+
capturedContext = context;
64+
return Container();
65+
}
66+
)
67+
);
68+
},
69+
));
70+
expect(
71+
() {
72+
RestorationScope.of(capturedContext);
73+
},
74+
throwsA(isA<FlutterError>().having(
75+
(FlutterError error) => error.message,
76+
'message',
77+
contains('State restoration must be enabled for a RestorationScope'),
78+
)),
79+
);
80+
81+
await tester.pumpWidget(WidgetsApp(
82+
restorationScopeId: 'test scope',
83+
color: const Color(0xD0FF0000),
84+
builder: (_, __) {
85+
return RestorationScope(
86+
restorationId: 'test',
87+
child: Builder(
88+
builder: (BuildContext context) {
89+
capturedContext = context;
90+
return Container();
91+
}
92+
)
93+
);
94+
},
95+
));
96+
final UnmanagedRestorationScope scope = tester.widget(find.byType(UnmanagedRestorationScope).last);
97+
expect(RestorationScope.of(capturedContext), scope.bucket);
98+
});
99+
54100
testWidgets('makes bucket available to descendants', (WidgetTester tester) async {
55101
const String id = 'hello world 1234';
56102
final MockRestorationManager manager = MockRestorationManager();

0 commit comments

Comments
 (0)