Check that State.initState and State.didUpdateWidget don't return Futures (#15183)
* add a debug check that the returned Type of State.initState and State.didUpdateWidget are not Futures * add test to verify that async lifecycles throw FlutterErrors * address some feedback, match implementation of setState check * address feedback from hixie * fix odd spacing in test
This commit is contained in:
parent
f8ac23cd86
commit
419fef3f8b
@ -3731,7 +3731,18 @@ class StatefulElement extends ComponentElement {
|
||||
assert(_state._debugLifecycleState == _StateLifecycle.created);
|
||||
try {
|
||||
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
|
||||
_state.initState();
|
||||
final dynamic debugCheckForReturnedFuture = _state.initState() as dynamic;
|
||||
assert(() {
|
||||
if (debugCheckForReturnedFuture is Future) {
|
||||
throw new FlutterError(
|
||||
'${_state.runtimeType}.initState() returned a Future.\n'
|
||||
'State.initState() must be a void method without an `async` keyword.\n'
|
||||
'Rather than awaiting on asynchronous work directly inside of initState,\n'
|
||||
'call a separate method to do this work without awaiting it.'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
} finally {
|
||||
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
|
||||
}
|
||||
@ -3753,7 +3764,18 @@ class StatefulElement extends ComponentElement {
|
||||
_state._widget = widget;
|
||||
try {
|
||||
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
|
||||
_state.didUpdateWidget(oldWidget);
|
||||
final dynamic debugCheckForReturnedFuture = _state.didUpdateWidget(oldWidget) as dynamic;
|
||||
assert(() {
|
||||
if (debugCheckForReturnedFuture is Future) {
|
||||
throw new FlutterError(
|
||||
'${_state.runtimeType}.didUpdateWidget() returned a Future.\n'
|
||||
'State.didUpdateWidget() must be a void method without an `async` keyword.\n'
|
||||
'Rather than awaiting on asynchronous work directly inside of didUpdateWidget,\n'
|
||||
'call a separate method to do this work without awaiting it.'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
} finally {
|
||||
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
|
||||
}
|
||||
|
57
packages/flutter/test/widgets/async_lifecycle_test.dart
Normal file
57
packages/flutter/test/widgets/async_lifecycle_test.dart
Normal file
@ -0,0 +1,57 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class InvalidOnInitLifecycleWidget extends StatefulWidget {
|
||||
const InvalidOnInitLifecycleWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
InvalidOnInitLifecycleWidgetState createState() => new InvalidOnInitLifecycleWidgetState();
|
||||
}
|
||||
|
||||
class InvalidOnInitLifecycleWidgetState extends State<InvalidOnInitLifecycleWidget> {
|
||||
@override
|
||||
void initState() async {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Container();
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidDidUpdateWidgetLifecycleWidget extends StatefulWidget {
|
||||
const InvalidDidUpdateWidgetLifecycleWidget({Key key, this.id}) : super(key: key);
|
||||
|
||||
final int id;
|
||||
|
||||
@override
|
||||
InvalidDidUpdateWidgetLifecycleWidgetState createState() => new InvalidDidUpdateWidgetLifecycleWidgetState();
|
||||
}
|
||||
|
||||
class InvalidDidUpdateWidgetLifecycleWidgetState extends State<InvalidDidUpdateWidgetLifecycleWidget> {
|
||||
@override
|
||||
void didUpdateWidget(InvalidDidUpdateWidgetLifecycleWidget oldWidget) async {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Container();
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('async onInit throws FlutterError', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const InvalidOnInitLifecycleWidget());
|
||||
|
||||
expect(tester.takeException(), isFlutterError);
|
||||
});
|
||||
|
||||
testWidgets('async didUpdateWidget throws FlutterError', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const InvalidDidUpdateWidgetLifecycleWidget(id: 1));
|
||||
await tester.pumpWidget(const InvalidDidUpdateWidgetLifecycleWidget(id: 2));
|
||||
|
||||
expect(tester.takeException(), isFlutterError);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user