mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

This patch makes a number of changes: 1) buildDirtyComponents now prevents all calls to setState, not just those higher in the tree. This change is necessary for consistency with MixedViewport and HomogeneousViewport because those widgets already build subwidgets with that restriction. If the "normal" build didn't enforce that rule, then some widgets would break when put inside a mixed or homogeneous viewport. 2) We now notify global key listeners in a microtask after beginFrame. That means setState is legal in these callbacks and that we'll produce another frame if someone calls setState in such a callback.
127 lines
3.2 KiB
Dart
127 lines
3.2 KiB
Dart
import 'package:sky/src/fn3.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../fn3/widget_tester.dart';
|
|
import '../fn3/test_widgets.dart';
|
|
|
|
class ProbeWidget extends StatefulComponent {
|
|
ProbeWidgetState createState() => new ProbeWidgetState();
|
|
}
|
|
|
|
class ProbeWidgetState extends State<ProbeWidget> {
|
|
static int buildCount = 0;
|
|
|
|
void initState(BuildContext context) {
|
|
super.initState(context);
|
|
setState(() {});
|
|
}
|
|
|
|
void didUpdateConfig(ProbeWidget oldConfig) {
|
|
setState(() {});
|
|
}
|
|
|
|
Widget build(BuildContext context) {
|
|
setState(() {});
|
|
buildCount++;
|
|
return new Container();
|
|
}
|
|
}
|
|
|
|
class BadWidget extends StatelessComponent {
|
|
BadWidget(this.parentState);
|
|
|
|
final State parentState;
|
|
|
|
Widget build(BuildContext context) {
|
|
parentState.setState(() {});
|
|
return new Container();
|
|
}
|
|
}
|
|
|
|
class BadWidgetParent extends StatefulComponent {
|
|
BadWidgetParentState createState() => new BadWidgetParentState();
|
|
}
|
|
|
|
class BadWidgetParentState extends State<BadWidgetParent> {
|
|
Widget build(BuildContext context) {
|
|
return new BadWidget(this);
|
|
}
|
|
}
|
|
|
|
class BadDisposeWidget extends StatefulComponent {
|
|
BadDisposeWidgetState createState() => new BadDisposeWidgetState();
|
|
}
|
|
|
|
class BadDisposeWidgetState extends State<BadDisposeWidget> {
|
|
Widget build(BuildContext context) {
|
|
return new Container();
|
|
}
|
|
|
|
void dispose() {
|
|
setState(() {});
|
|
super.dispose();
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
dynamic cachedException;
|
|
|
|
setUp(() {
|
|
assert(cachedException == null);
|
|
debugWidgetsExceptionHandler = (String context, dynamic exception, StackTrace stack) {
|
|
cachedException = exception;
|
|
};
|
|
});
|
|
|
|
tearDown(() {
|
|
assert(cachedException == null);
|
|
cachedException = null;
|
|
debugWidgetsExceptionHandler = null;
|
|
});
|
|
|
|
test('Legal times for setState', () {
|
|
WidgetTester tester = new WidgetTester();
|
|
|
|
GlobalKey flipKey = new GlobalKey();
|
|
expect(ProbeWidgetState.buildCount, equals(0));
|
|
tester.pumpFrame(new ProbeWidget());
|
|
expect(ProbeWidgetState.buildCount, equals(1));
|
|
tester.pumpFrame(new ProbeWidget());
|
|
expect(ProbeWidgetState.buildCount, equals(2));
|
|
tester.pumpFrame(new FlipComponent(
|
|
key: flipKey,
|
|
left: new Container(),
|
|
right: new ProbeWidget()
|
|
));
|
|
expect(ProbeWidgetState.buildCount, equals(2));
|
|
(flipKey.currentState as FlipComponentState).flip();
|
|
tester.pumpFrameWithoutChange();
|
|
expect(ProbeWidgetState.buildCount, equals(3));
|
|
(flipKey.currentState as FlipComponentState).flip();
|
|
tester.pumpFrameWithoutChange();
|
|
expect(ProbeWidgetState.buildCount, equals(3));
|
|
tester.pumpFrame(new Container());
|
|
expect(ProbeWidgetState.buildCount, equals(3));
|
|
});
|
|
|
|
test('Setting parent state during build is forbidden', () {
|
|
WidgetTester tester = new WidgetTester();
|
|
|
|
expect(cachedException, isNull);
|
|
tester.pumpFrame(new BadWidgetParent());
|
|
expect(cachedException, isNotNull);
|
|
cachedException = null;
|
|
tester.pumpFrame(new Container());
|
|
expect(cachedException, isNull);
|
|
});
|
|
|
|
test('Setting state during dispose is forbidden', () {
|
|
WidgetTester tester = new WidgetTester();
|
|
|
|
tester.pumpFrame(new BadDisposeWidget());
|
|
expect(() {
|
|
tester.pumpFrame(new Container());
|
|
}, throws);
|
|
});
|
|
}
|