forked from flutter/packages
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Failure to construct ErrorWidget for build errors does not destroy tr…
…ee (#117090)
- Loading branch information
1 parent
7b19b4d
commit dbc9306
Showing
2 changed files
with
101 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
void main() { | ||
testWidgets('ErrorWidget displays actual error when throwing during build', (WidgetTester tester) async { | ||
final Key container = UniqueKey(); | ||
const String errorText = 'Oh no, there was a crash!!1'; | ||
|
||
await tester.pumpWidget( | ||
Container( | ||
key: container, | ||
color: Colors.red, | ||
padding: const EdgeInsets.all(10), | ||
child: Builder( | ||
builder: (BuildContext context) { | ||
throw UnsupportedError(errorText); | ||
}, | ||
), | ||
), | ||
); | ||
|
||
expect( | ||
tester.takeException(), | ||
isA<UnsupportedError>().having((UnsupportedError error) => error.message, 'message', contains(errorText)), | ||
); | ||
|
||
final ErrorWidget errorWidget = tester.widget(find.byType(ErrorWidget)); | ||
expect(errorWidget.message, contains(errorText)); | ||
|
||
// Failure in one widget shouldn't ripple through the entire tree and effect | ||
// ancestors. Those should still be in the tree. | ||
expect(find.byKey(container), findsOneWidget); | ||
}); | ||
|
||
testWidgets('when constructing an ErrorWidget due to a build failure throws an error, fail gracefully', (WidgetTester tester) async { | ||
final Key container = UniqueKey(); | ||
await tester.pumpWidget( | ||
Container( | ||
key: container, | ||
color: Colors.red, | ||
padding: const EdgeInsets.all(10), | ||
// This widget throws during build, which causes the construction of an | ||
// ErrorWidget with the build error. However, during construction of | ||
// that ErrorWidget, another error is thrown. | ||
child: const MyDoubleThrowingWidget(), | ||
), | ||
); | ||
|
||
expect( | ||
tester.takeException(), | ||
isA<UnsupportedError>().having((UnsupportedError error) => error.message, 'message', contains(MyThrowingElement.debugFillPropertiesErrorMessage)), | ||
); | ||
|
||
final ErrorWidget errorWidget = tester.widget(find.byType(ErrorWidget)); | ||
expect(errorWidget.message, contains(MyThrowingElement.debugFillPropertiesErrorMessage)); | ||
|
||
// Failure in one widget shouldn't ripple through the entire tree and effect | ||
// ancestors. Those should still be in the tree. | ||
expect(find.byKey(container), findsOneWidget); | ||
}); | ||
} | ||
|
||
// This widget throws during its regular build and then again when the | ||
// ErrorWidget is constructed, which calls MyThrowingElement.debugFillProperties. | ||
class MyDoubleThrowingWidget extends StatelessWidget { | ||
const MyDoubleThrowingWidget({super.key}); | ||
|
||
@override | ||
StatelessElement createElement() => MyThrowingElement(this); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
throw UnsupportedError('You cannot build me!'); | ||
} | ||
} | ||
|
||
class MyThrowingElement extends StatelessElement { | ||
MyThrowingElement(super.widget); | ||
|
||
static const String debugFillPropertiesErrorMessage = 'Crash during debugFillProperties'; | ||
|
||
@override | ||
void debugFillProperties(DiagnosticPropertiesBuilder properties) { | ||
super.debugFillProperties(properties); | ||
throw UnsupportedError(debugFillPropertiesErrorMessage); | ||
} | ||
} |