mirror of
https://github.com/flutter/flutter
synced 2024-09-19 16:21:58 +00:00
245d6d45a1
Assert that runApp is called in the same zone as binding.ensureInitialized
193 lines
6 KiB
Dart
193 lines
6 KiB
Dart
// 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/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/scheduler.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
// This test is very fragile and bypasses some zone-related checks.
|
|
// It is written this way to verify some invariants that would otherwise
|
|
// be difficult to check.
|
|
// Do not use this test as a guide for writing good Flutter code.
|
|
|
|
class TestBinding extends WidgetsFlutterBinding {
|
|
@override
|
|
void initInstances() {
|
|
super.initInstances();
|
|
_instance = this;
|
|
}
|
|
|
|
@override
|
|
bool debugCheckZone(String entryPoint) { return true; }
|
|
|
|
static TestBinding get instance => BindingBase.checkInstance(_instance);
|
|
static TestBinding? _instance;
|
|
|
|
static TestBinding ensureInitialized() {
|
|
if (TestBinding._instance == null) {
|
|
TestBinding();
|
|
}
|
|
return TestBinding.instance;
|
|
}
|
|
}
|
|
|
|
class CountButton extends StatefulWidget {
|
|
const CountButton({super.key});
|
|
|
|
@override
|
|
State<CountButton> createState() => _CountButtonState();
|
|
}
|
|
|
|
class _CountButtonState extends State<CountButton> {
|
|
int counter = 0;
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ElevatedButton(
|
|
child: Text('Counter $counter'),
|
|
onPressed: () {
|
|
setState(() {
|
|
counter += 1;
|
|
});
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class AnimateSample extends StatefulWidget {
|
|
const AnimateSample({super.key});
|
|
|
|
@override
|
|
State<AnimateSample> createState() => _AnimateSampleState();
|
|
}
|
|
|
|
class _AnimateSampleState extends State<AnimateSample>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(seconds: 1),
|
|
)..forward();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _controller,
|
|
builder: (BuildContext context, _) => Text('Value: ${_controller.value}'),
|
|
);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
TestBinding.ensureInitialized();
|
|
|
|
test('Test pump on LiveWidgetController', () async {
|
|
runApp(const MaterialApp(home: Center(child: CountButton())));
|
|
|
|
await SchedulerBinding.instance.endOfFrame;
|
|
final WidgetController controller =
|
|
LiveWidgetController(WidgetsBinding.instance);
|
|
await controller.tap(find.text('Counter 0'));
|
|
expect(find.text('Counter 0'), findsOneWidget);
|
|
expect(find.text('Counter 1'), findsNothing);
|
|
await controller.pump();
|
|
expect(find.text('Counter 0'), findsNothing);
|
|
expect(find.text('Counter 1'), findsOneWidget);
|
|
});
|
|
|
|
test('Test pumpAndSettle on LiveWidgetController', () async {
|
|
runApp(const MaterialApp(home: Center(child: AnimateSample())));
|
|
await SchedulerBinding.instance.endOfFrame;
|
|
final WidgetController controller =
|
|
LiveWidgetController(WidgetsBinding.instance);
|
|
expect(find.text('Value: 1.0'), findsNothing);
|
|
await controller.pumpAndSettle();
|
|
expect(find.text('Value: 1.0'), findsOneWidget);
|
|
});
|
|
|
|
test('Input event array on LiveWidgetController', () async {
|
|
final List<String> logs = <String>[];
|
|
runApp(
|
|
MaterialApp(
|
|
home: Listener(
|
|
onPointerDown: (PointerDownEvent event) => logs.add('down ${event.buttons}'),
|
|
onPointerMove: (PointerMoveEvent event) => logs.add('move ${event.buttons}'),
|
|
onPointerUp: (PointerUpEvent event) => logs.add('up ${event.buttons}'),
|
|
child: const Text('test'),
|
|
),
|
|
),
|
|
);
|
|
await SchedulerBinding.instance.endOfFrame;
|
|
final WidgetController controller =
|
|
LiveWidgetController(WidgetsBinding.instance);
|
|
|
|
final Offset location = controller.getCenter(find.text('test'));
|
|
final List<PointerEventRecord> records = <PointerEventRecord>[
|
|
PointerEventRecord(Duration.zero, <PointerEvent>[
|
|
// Typically PointerAddedEvent is not used in testers, but for records
|
|
// captured on a device it is usually what starts a gesture.
|
|
PointerAddedEvent(
|
|
position: location,
|
|
),
|
|
PointerDownEvent(
|
|
position: location,
|
|
buttons: kSecondaryMouseButton,
|
|
pointer: 1,
|
|
),
|
|
]),
|
|
...<PointerEventRecord>[
|
|
for (Duration t = const Duration(milliseconds: 5);
|
|
t < const Duration(milliseconds: 80);
|
|
t += const Duration(milliseconds: 16))
|
|
PointerEventRecord(t, <PointerEvent>[
|
|
PointerMoveEvent(
|
|
timeStamp: t - const Duration(milliseconds: 1),
|
|
position: location,
|
|
buttons: kSecondaryMouseButton,
|
|
pointer: 1,
|
|
),
|
|
]),
|
|
],
|
|
PointerEventRecord(const Duration(milliseconds: 80), <PointerEvent>[
|
|
PointerUpEvent(
|
|
timeStamp: const Duration(milliseconds: 79),
|
|
position: location,
|
|
buttons: kSecondaryMouseButton,
|
|
pointer: 1,
|
|
),
|
|
]),
|
|
];
|
|
final List<Duration> timeDiffs =
|
|
await controller.handlePointerEventRecord(records);
|
|
|
|
expect(timeDiffs.length, records.length);
|
|
for (final Duration diff in timeDiffs) {
|
|
// Allow some freedom of time delay in real world.
|
|
// TODO(pdblasi-google): The expected wiggle room should be -1, but occasional
|
|
// results were reaching -6. This assert has been adjusted to reduce flakiness,
|
|
// but the root cause is still unknown. (https://github.com/flutter/flutter/issues/109638)
|
|
assert(diff.inMilliseconds > -7, 'timeDiffs were: $timeDiffs (offending time was ${diff.inMilliseconds}ms)');
|
|
}
|
|
|
|
const String b = '$kSecondaryMouseButton';
|
|
expect(logs.first, 'down $b');
|
|
for (int i = 1; i < logs.length - 1; i++) {
|
|
expect(logs[i], 'move $b');
|
|
}
|
|
expect(logs.last, 'up $b');
|
|
});
|
|
}
|