Unverified Commit e6d160a5 authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

Cover more test/widgets tests with leak tracking #7 (#134943)

parent b0a90aee
...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'navigator_utils.dart'; import 'navigator_utils.dart';
...@@ -34,7 +35,7 @@ void main() { ...@@ -34,7 +35,7 @@ void main() {
.setMockMethodCallHandler(SystemChannels.platform, null); .setMockMethodCallHandler(SystemChannels.platform, null);
}); });
testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { testWidgetsWithLeakTracking('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async {
bool canPop = false; bool canPop = false;
late StateSetter setState; late StateSetter setState;
late BuildContext context; late BuildContext context;
...@@ -79,7 +80,7 @@ void main() { ...@@ -79,7 +80,7 @@ void main() {
variant: TargetPlatformVariant.all(), variant: TargetPlatformVariant.all(),
); );
testWidgets('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { testWidgetsWithLeakTracking('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async {
final GlobalKey<NavigatorState> nav = GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> nav = GlobalKey<NavigatorState>();
bool canPop = true; bool canPop = true;
late StateSetter setState; late StateSetter setState;
...@@ -247,7 +248,7 @@ void main() { ...@@ -247,7 +248,7 @@ void main() {
variant: TargetPlatformVariant.all(), variant: TargetPlatformVariant.all(),
); );
testWidgets('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { testWidgetsWithLeakTracking('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async {
bool usePopScope = true; bool usePopScope = true;
late StateSetter setState; late StateSetter setState;
late BuildContext context; late BuildContext context;
...@@ -299,7 +300,7 @@ void main() { ...@@ -299,7 +300,7 @@ void main() {
variant: TargetPlatformVariant.all(), variant: TargetPlatformVariant.all(),
); );
testWidgets('identical PopScopes', (WidgetTester tester) async { testWidgetsWithLeakTracking('identical PopScopes', (WidgetTester tester) async {
bool usePopScope1 = true; bool usePopScope1 = true;
bool usePopScope2 = true; bool usePopScope2 = true;
late StateSetter setState; late StateSetter setState;
......
...@@ -7,9 +7,10 @@ import 'dart:async'; ...@@ -7,9 +7,10 @@ import 'dart:async';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('Positioned constructors', (WidgetTester tester) async { testWidgetsWithLeakTracking('Positioned constructors', (WidgetTester tester) async {
final Widget child = Container(); final Widget child = Container();
final Positioned a = Positioned( final Positioned a = Positioned(
left: 101.0, left: 101.0,
...@@ -56,7 +57,7 @@ void main() { ...@@ -56,7 +57,7 @@ void main() {
expect(c.height, null); expect(c.height, null);
}); });
testWidgets('Can animate position data', (WidgetTester tester) async { testWidgetsWithLeakTracking('Can animate position data', (WidgetTester tester) async {
final RelativeRectTween rect = RelativeRectTween( final RelativeRectTween rect = RelativeRectTween(
begin: RelativeRect.fromRect( begin: RelativeRect.fromRect(
const Rect.fromLTRB(10.0, 20.0, 20.0, 30.0), const Rect.fromLTRB(10.0, 20.0, 20.0, 30.0),
......
...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
class ExpandingBox extends StatefulWidget { class ExpandingBox extends StatefulWidget {
const ExpandingBox({ super.key, required this.collapsedSize, required this.expandedSize }); const ExpandingBox({ super.key, required this.collapsedSize, required this.expandedSize });
...@@ -53,7 +54,7 @@ class _ExpandingBoxState extends State<ExpandingBox> with AutomaticKeepAliveClie ...@@ -53,7 +54,7 @@ class _ExpandingBoxState extends State<ExpandingBox> with AutomaticKeepAliveClie
} }
void main() { void main() {
testWidgets('shrink listview', (WidgetTester tester) async { testWidgetsWithLeakTracking('shrink listview', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: ListView.builder( home: ListView.builder(
itemBuilder: (BuildContext context, int index) => index == 0 itemBuilder: (BuildContext context, int index) => index == 0
...@@ -98,7 +99,7 @@ void main() { ...@@ -98,7 +99,7 @@ void main() {
expect(position.pixels, 100.0); expect(position.pixels, 100.0);
}); });
testWidgets('shrink listview while dragging', (WidgetTester tester) async { testWidgetsWithLeakTracking('shrink listview while dragging', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: ListView.builder( home: ListView.builder(
itemBuilder: (BuildContext context, int index) => index == 0 itemBuilder: (BuildContext context, int index) => index == 0
...@@ -157,7 +158,7 @@ void main() { ...@@ -157,7 +158,7 @@ void main() {
expect(position.pixels, 50.0); expect(position.pixels, 50.0);
}); });
testWidgets('shrink listview while ballistic', (WidgetTester tester) async { testWidgetsWithLeakTracking('shrink listview while ballistic', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: GestureDetector( home: GestureDetector(
onTap: () { assert(false); }, onTap: () { assert(false); },
...@@ -220,7 +221,7 @@ void main() { ...@@ -220,7 +221,7 @@ void main() {
expect(position.pixels, 0.0); expect(position.pixels, 0.0);
}); });
testWidgets('expanding page views', (WidgetTester tester) async { testWidgetsWithLeakTracking('expanding page views', (WidgetTester tester) async {
await tester.pumpWidget(const Padding(padding: EdgeInsets.only(right: 200.0), child: TabBarDemo())); await tester.pumpWidget(const Padding(padding: EdgeInsets.only(right: 200.0), child: TabBarDemo()));
await tester.tap(find.text('bike')); await tester.tap(find.text('bike'));
await tester.pump(); await tester.pump();
...@@ -231,7 +232,7 @@ void main() { ...@@ -231,7 +232,7 @@ void main() {
expect(bike2.center, bike1.shift(const Offset(100.0, 0.0)).center); expect(bike2.center, bike1.shift(const Offset(100.0, 0.0)).center);
}); });
testWidgets('changing the size of the viewport when overscrolled', (WidgetTester tester) async { testWidgetsWithLeakTracking('changing the size of the viewport when overscrolled', (WidgetTester tester) async {
Widget build(double height) { Widget build(double height) {
return Directionality( return Directionality(
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
...@@ -265,7 +266,7 @@ void main() { ...@@ -265,7 +266,7 @@ void main() {
expect(oldPosition, newPosition); expect(oldPosition, newPosition);
}); });
testWidgets('inserting and removing an item when overscrolled', (WidgetTester tester) async { testWidgetsWithLeakTracking('inserting and removing an item when overscrolled', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/62890 // Regression test for https://github.com/flutter/flutter/issues/62890
const double itemExtent = 100.0; const double itemExtent = 100.0;
......
...@@ -5,19 +5,22 @@ ...@@ -5,19 +5,22 @@
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('Can dispose without keyboard', (WidgetTester tester) async { testWidgetsWithLeakTracking('Can dispose without keyboard', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(); final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container()));
await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container()));
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
}); });
testWidgets('Fuchsia key event', (WidgetTester tester) async { testWidgetsWithLeakTracking('Fuchsia key event', (WidgetTester tester) async {
final List<RawKeyEvent> events = <RawKeyEvent>[]; final List<RawKeyEvent> events = <RawKeyEvent>[];
final FocusNode focusNode = FocusNode(); final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget( await tester.pumpWidget(
RawKeyboardListener( RawKeyboardListener(
...@@ -43,13 +46,13 @@ void main() { ...@@ -43,13 +46,13 @@ void main() {
expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue); expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue);
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
focusNode.dispose();
}, skip: isBrowser); // [intended] This is a Fuchsia-specific test. }, skip: isBrowser); // [intended] This is a Fuchsia-specific test.
testWidgets('Web key event', (WidgetTester tester) async { testWidgetsWithLeakTracking('Web key event', (WidgetTester tester) async {
final List<RawKeyEvent> events = <RawKeyEvent>[]; final List<RawKeyEvent> events = <RawKeyEvent>[];
final FocusNode focusNode = FocusNode(); final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget( await tester.pumpWidget(
RawKeyboardListener( RawKeyboardListener(
...@@ -74,13 +77,13 @@ void main() { ...@@ -74,13 +77,13 @@ void main() {
expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue); expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue);
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
focusNode.dispose();
}); });
testWidgets('Defunct listeners do not receive events', (WidgetTester tester) async { testWidgetsWithLeakTracking('Defunct listeners do not receive events', (WidgetTester tester) async {
final List<RawKeyEvent> events = <RawKeyEvent>[]; final List<RawKeyEvent> events = <RawKeyEvent>[];
final FocusNode focusNode = FocusNode(); final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget( await tester.pumpWidget(
RawKeyboardListener( RawKeyboardListener(
...@@ -108,6 +111,5 @@ void main() { ...@@ -108,6 +111,5 @@ void main() {
expect(events.length, 0); expect(events.length, 0);
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
focusNode.dispose();
}); });
} }
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('reassemble does not crash', (WidgetTester tester) async { testWidgetsWithLeakTracking('reassemble does not crash', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp( await tester.pumpWidget(const MaterialApp(
home: Text('Hello World'), home: Text('Hello World'),
)); ));
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
@immutable @immutable
class Pair<T> { class Pair<T> {
...@@ -239,7 +240,7 @@ class RenderSwapper extends RenderBox { ...@@ -239,7 +240,7 @@ class RenderSwapper extends RenderBox {
BoxParentData parentDataFor(RenderObject renderObject) => renderObject.parentData! as BoxParentData; BoxParentData parentDataFor(RenderObject renderObject) => renderObject.parentData! as BoxParentData;
void main() { void main() {
testWidgets('RenderObjectElement *RenderObjectChild methods get called with correct arguments', (WidgetTester tester) async { testWidgetsWithLeakTracking('RenderObjectElement *RenderObjectChild methods get called with correct arguments', (WidgetTester tester) async {
const Key redKey = ValueKey<String>('red'); const Key redKey = ValueKey<String>('red');
const Key blueKey = ValueKey<String>('blue'); const Key blueKey = ValueKey<String>('blue');
Widget widget() { Widget widget() {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
final BoxDecoration kBoxDecorationA = BoxDecoration(border: nonconst(null)); final BoxDecoration kBoxDecorationA = BoxDecoration(border: nonconst(null));
final BoxDecoration kBoxDecorationB = BoxDecoration(border: nonconst(null)); final BoxDecoration kBoxDecorationB = BoxDecoration(border: nonconst(null));
...@@ -75,7 +76,7 @@ class TestNonVisitingRenderObject extends RenderBox with RenderObjectWithChildMi ...@@ -75,7 +76,7 @@ class TestNonVisitingRenderObject extends RenderBox with RenderObjectWithChildMi
} }
void main() { void main() {
testWidgets('RenderObjectWidget smoke test', (WidgetTester tester) async { testWidgetsWithLeakTracking('RenderObjectWidget smoke test', (WidgetTester tester) async {
await tester.pumpWidget(DecoratedBox(decoration: kBoxDecorationA)); await tester.pumpWidget(DecoratedBox(decoration: kBoxDecorationA));
SingleChildRenderObjectElement element = SingleChildRenderObjectElement element =
tester.element(find.byElementType(SingleChildRenderObjectElement)); tester.element(find.byElementType(SingleChildRenderObjectElement));
...@@ -94,7 +95,7 @@ void main() { ...@@ -94,7 +95,7 @@ void main() {
expect(renderObject.position, equals(DecorationPosition.background)); expect(renderObject.position, equals(DecorationPosition.background));
}); });
testWidgets('RenderObjectWidget can add and remove children', (WidgetTester tester) async { testWidgetsWithLeakTracking('RenderObjectWidget can add and remove children', (WidgetTester tester) async {
void checkFullTree() { void checkFullTree() {
final SingleChildRenderObjectElement element = final SingleChildRenderObjectElement element =
...@@ -178,7 +179,7 @@ void main() { ...@@ -178,7 +179,7 @@ void main() {
childBareTree(); childBareTree();
}); });
testWidgets('Detached render tree is intact', (WidgetTester tester) async { testWidgetsWithLeakTracking('Detached render tree is intact', (WidgetTester tester) async {
await tester.pumpWidget(DecoratedBox( await tester.pumpWidget(DecoratedBox(
decoration: kBoxDecorationA, decoration: kBoxDecorationA,
...@@ -220,7 +221,7 @@ void main() { ...@@ -220,7 +221,7 @@ void main() {
expect(grandChild.child, isNull); expect(grandChild.child, isNull);
}); });
testWidgets('Can watch inherited widgets', (WidgetTester tester) async { testWidgetsWithLeakTracking('Can watch inherited widgets', (WidgetTester tester) async {
final Key boxKey = UniqueKey(); final Key boxKey = UniqueKey();
final TestOrientedBox box = TestOrientedBox(key: boxKey); final TestOrientedBox box = TestOrientedBox(key: boxKey);
...@@ -242,7 +243,7 @@ void main() { ...@@ -242,7 +243,7 @@ void main() {
expect(decoration.color, equals(const Color(0xFF0000FF))); expect(decoration.color, equals(const Color(0xFF0000FF)));
}); });
testWidgets('RenderObject not visiting children provides helpful error message', (WidgetTester tester) async { testWidgetsWithLeakTracking('RenderObject not visiting children provides helpful error message', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
TestNonVisitingWidget( TestNonVisitingWidget(
child: Container(color: const Color(0xFFED1D7F)), child: Container(color: const Color(0xFFED1D7F)),
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
// This is a regression test for https://github.com/flutter/flutter/issues/5588. // This is a regression test for https://github.com/flutter/flutter/issues/5588.
...@@ -92,7 +93,7 @@ class RekeyableDummyStatefulWidgetWrapperState extends State<RekeyableDummyState ...@@ -92,7 +93,7 @@ class RekeyableDummyStatefulWidgetWrapperState extends State<RekeyableDummyState
} }
void main() { void main() {
testWidgets('Handle GlobalKey reparenting in weird orders', (WidgetTester tester) async { testWidgetsWithLeakTracking('Handle GlobalKey reparenting in weird orders', (WidgetTester tester) async {
// This is a bit of a weird test so let's try to explain it a bit. // This is a bit of a weird test so let's try to explain it a bit.
// //
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
class StateMarker extends StatefulWidget { class StateMarker extends StatefulWidget {
const StateMarker({ super.key, this.child }); const StateMarker({ super.key, this.child });
...@@ -50,7 +51,7 @@ class DeactivateLoggerState extends State<DeactivateLogger> { ...@@ -50,7 +51,7 @@ class DeactivateLoggerState extends State<DeactivateLogger> {
} }
void main() { void main() {
testWidgets('can reparent state', (WidgetTester tester) async { testWidgetsWithLeakTracking('can reparent state', (WidgetTester tester) async {
final GlobalKey left = GlobalKey(); final GlobalKey left = GlobalKey();
final GlobalKey right = GlobalKey(); final GlobalKey right = GlobalKey();
...@@ -130,7 +131,7 @@ void main() { ...@@ -130,7 +131,7 @@ void main() {
expect(right.currentState, isNull); expect(right.currentState, isNull);
}); });
testWidgets('can reparent state with multichild widgets', (WidgetTester tester) async { testWidgetsWithLeakTracking('can reparent state with multichild widgets', (WidgetTester tester) async {
final GlobalKey left = GlobalKey(); final GlobalKey left = GlobalKey();
final GlobalKey right = GlobalKey(); final GlobalKey right = GlobalKey();
...@@ -198,7 +199,7 @@ void main() { ...@@ -198,7 +199,7 @@ void main() {
expect(right.currentState, isNull); expect(right.currentState, isNull);
}); });
testWidgets('can with scrollable list', (WidgetTester tester) async { testWidgetsWithLeakTracking('can with scrollable list', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
await tester.pumpWidget(StateMarker(key: key)); await tester.pumpWidget(StateMarker(key: key));
...@@ -231,7 +232,7 @@ void main() { ...@@ -231,7 +232,7 @@ void main() {
expect(keyState.marker, equals('marked')); expect(keyState.marker, equals('marked'));
}); });
testWidgets('Reparent during update children', (WidgetTester tester) async { testWidgetsWithLeakTracking('Reparent during update children', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
await tester.pumpWidget(Stack( await tester.pumpWidget(Stack(
...@@ -268,7 +269,7 @@ void main() { ...@@ -268,7 +269,7 @@ void main() {
expect(keyState.marker, equals('marked')); expect(keyState.marker, equals('marked'));
}); });
testWidgets('Reparent to child during update children', (WidgetTester tester) async { testWidgetsWithLeakTracking('Reparent to child during update children', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
await tester.pumpWidget(Stack( await tester.pumpWidget(Stack(
...@@ -330,7 +331,7 @@ void main() { ...@@ -330,7 +331,7 @@ void main() {
expect(keyState.marker, equals('marked')); expect(keyState.marker, equals('marked'));
}); });
testWidgets('Deactivate implies build', (WidgetTester tester) async { testWidgetsWithLeakTracking('Deactivate implies build', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
final List<String> log = <String>[]; final List<String> log = <String>[];
final DeactivateLogger logger = DeactivateLogger(key: key, log: log); final DeactivateLogger logger = DeactivateLogger(key: key, log: log);
...@@ -352,7 +353,7 @@ void main() { ...@@ -352,7 +353,7 @@ void main() {
expect(log, isEmpty); expect(log, isEmpty);
}); });
testWidgets('Reparenting with multiple moves', (WidgetTester tester) async { testWidgetsWithLeakTracking('Reparenting with multiple moves', (WidgetTester tester) async {
final GlobalKey key1 = GlobalKey(); final GlobalKey key1 = GlobalKey();
final GlobalKey key2 = GlobalKey(); final GlobalKey key2 = GlobalKey();
final GlobalKey key3 = GlobalKey(); final GlobalKey key3 = GlobalKey();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
// This is a regression test for https://github.com/flutter/flutter/issues/5840. // This is a regression test for https://github.com/flutter/flutter/issues/5840.
...@@ -65,7 +66,7 @@ class StatefulCreationCounterState extends State<StatefulCreationCounter> { ...@@ -65,7 +66,7 @@ class StatefulCreationCounterState extends State<StatefulCreationCounter> {
} }
void main() { void main() {
testWidgets('reparent state with layout builder', (WidgetTester tester) async { testWidgetsWithLeakTracking('reparent state with layout builder', (WidgetTester tester) async {
expect(StatefulCreationCounterState.creationCount, 0); expect(StatefulCreationCounterState.creationCount, 0);
await tester.pumpWidget(const Bar()); await tester.pumpWidget(const Bar());
expect(StatefulCreationCounterState.creationCount, 1); expect(StatefulCreationCounterState.creationCount, 1);
...@@ -75,7 +76,7 @@ void main() { ...@@ -75,7 +76,7 @@ void main() {
expect(StatefulCreationCounterState.creationCount, 1); expect(StatefulCreationCounterState.creationCount, 1);
}); });
testWidgets('Clean then reparent with dependencies', (WidgetTester tester) async { testWidgetsWithLeakTracking('Clean then reparent with dependencies', (WidgetTester tester) async {
int layoutBuilderBuildCount = 0; int layoutBuilderBuildCount = 0;
late StateSetter keyedSetState; late StateSetter keyedSetState;
......
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'restoration.dart'; import 'restoration.dart';
void main() { void main() {
testWidgets('claims bucket', (WidgetTester tester) async { testWidgetsWithLeakTracking('claims bucket', (WidgetTester tester) async {
const String id = 'hello world 1234'; const String id = 'hello world 1234';
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
expect(rawData, isEmpty); expect(rawData, isEmpty);
...@@ -35,8 +37,9 @@ void main() { ...@@ -35,8 +37,9 @@ void main() {
expect(state.restoreStateLog.single, isNull); expect(state.restoreStateLog.single, isNull);
}); });
testWidgets('claimed bucket with data', (WidgetTester tester) async { testWidgetsWithLeakTracking('claimed bucket with data', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
await tester.pumpWidget( await tester.pumpWidget(
...@@ -57,8 +60,9 @@ void main() { ...@@ -57,8 +60,9 @@ void main() {
expect(state.restoreStateLog.single, isNull); expect(state.restoreStateLog.single, isNull);
}); });
testWidgets('renames existing bucket when new ID is provided via widget', (WidgetTester tester) async { testWidgetsWithLeakTracking('renames existing bucket when new ID is provided via widget', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
await tester.pumpWidget( await tester.pumpWidget(
...@@ -99,8 +103,9 @@ void main() { ...@@ -99,8 +103,9 @@ void main() {
expect(state.toggleBucketLog, isEmpty); expect(state.toggleBucketLog, isEmpty);
}); });
testWidgets('renames existing bucket when didUpdateRestorationId is called', (WidgetTester tester) async { testWidgetsWithLeakTracking('renames existing bucket when didUpdateRestorationId is called', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
await tester.pumpWidget( await tester.pumpWidget(
...@@ -134,8 +139,9 @@ void main() { ...@@ -134,8 +139,9 @@ void main() {
expect(state.toggleBucketLog, isEmpty); expect(state.toggleBucketLog, isEmpty);
}); });
testWidgets('Disposing widget removes its data', (WidgetTester tester) async { testWidgetsWithLeakTracking('Disposing widget removes its data', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
...@@ -162,8 +168,9 @@ void main() { ...@@ -162,8 +168,9 @@ void main() {
expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse);
}); });
testWidgets('toggling id between null and non-null', (WidgetTester tester) async { testWidgetsWithLeakTracking('toggling id between null and non-null', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
...@@ -222,9 +229,10 @@ void main() { ...@@ -222,9 +229,10 @@ void main() {
expect(state.toggleBucketLog.single, same(bucket)); expect(state.toggleBucketLog.single, same(bucket));
}); });
testWidgets('move in and out of scope', (WidgetTester tester) async { testWidgetsWithLeakTracking('move in and out of scope', (WidgetTester tester) async {
final Key key = GlobalKey(); final Key key = GlobalKey();
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
...@@ -284,8 +292,9 @@ void main() { ...@@ -284,8 +292,9 @@ void main() {
expect(state.toggleBucketLog.single, same(bucket)); expect(state.toggleBucketLog.single, same(bucket));
}); });
testWidgets('moving scope moves its data', (WidgetTester tester) async { testWidgetsWithLeakTracking('moving scope moves its data', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
final Key key = GlobalKey(); final Key key = GlobalKey();
...@@ -349,7 +358,7 @@ void main() { ...@@ -349,7 +358,7 @@ void main() {
expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('moving-child'), isTrue); expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('moving-child'), isTrue);
}); });
testWidgets('restartAndRestore', (WidgetTester tester) async { testWidgetsWithLeakTracking('restartAndRestore', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -388,7 +397,7 @@ void main() { ...@@ -388,7 +397,7 @@ void main() {
expect(state.toggleBucketLog, isEmpty); expect(state.toggleBucketLog, isEmpty);
}); });
testWidgets('restore while running', (WidgetTester tester) async { testWidgetsWithLeakTracking('restore while running', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -427,7 +436,7 @@ void main() { ...@@ -427,7 +436,7 @@ void main() {
expect(state.toggleBucketLog, isEmpty); expect(state.toggleBucketLog, isEmpty);
}); });
testWidgets('can register additional property outside of restoreState', (WidgetTester tester) async { testWidgetsWithLeakTracking('can register additional property outside of restoreState', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -464,7 +473,7 @@ void main() { ...@@ -464,7 +473,7 @@ void main() {
expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); expect(state.property.log, <String>['fromPrimitives', 'initWithValue']);
}); });
testWidgets('cannot register same property twice', (WidgetTester tester) async { testWidgetsWithLeakTracking('cannot register same property twice', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -494,7 +503,7 @@ void main() { ...@@ -494,7 +503,7 @@ void main() {
expect(() => state.registerPropertyUnderSameId(), throwsAssertionError); expect(() => state.registerPropertyUnderSameId(), throwsAssertionError);
}); });
testWidgets('data of disabled property is not stored', (WidgetTester tester) async { testWidgetsWithLeakTracking('data of disabled property is not stored', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -534,7 +543,7 @@ void main() { ...@@ -534,7 +543,7 @@ void main() {
expect(state.property.value, 10); // Initialized to default value. expect(state.property.value, 10); // Initialized to default value.
}); });
testWidgets('Enabling property stores its data again', (WidgetTester tester) async { testWidgetsWithLeakTracking('Enabling property stores its data again', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -572,7 +581,7 @@ void main() { ...@@ -572,7 +581,7 @@ void main() {
expect(state.property.value, 40); expect(state.property.value, 40);
}); });
testWidgets('Unregistering a property removes its data', (WidgetTester tester) async { testWidgetsWithLeakTracking('Unregistering a property removes its data', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
...@@ -598,7 +607,7 @@ void main() { ...@@ -598,7 +607,7 @@ void main() {
expect(state.bucket!.read<int>('additional'), 11); expect(state.bucket!.read<int>('additional'), 11);
}); });
testWidgets('Disposing a property unregisters it, but keeps data', (WidgetTester tester) async { testWidgetsWithLeakTracking('Disposing a property unregisters it, but keeps data', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RootRestorationScope( const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
......
...@@ -4,12 +4,13 @@ ...@@ -4,12 +4,13 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'restoration.dart'; import 'restoration.dart';
void main() { void main() {
group('UnmanagedRestorationScope', () { group('UnmanagedRestorationScope', () {
testWidgets('makes bucket available to descendants', (WidgetTester tester) async { testWidgetsWithLeakTracking('makes bucket available to descendants', (WidgetTester tester) async {
final RestorationBucket bucket1 = RestorationBucket.empty( final RestorationBucket bucket1 = RestorationBucket.empty(
restorationId: 'foo', restorationId: 'foo',
debugOwner: 'owner', debugOwner: 'owner',
...@@ -39,7 +40,7 @@ void main() { ...@@ -39,7 +40,7 @@ void main() {
expect(state.bucket, bucket2); expect(state.bucket, bucket2);
}); });
testWidgets('null bucket disables restoration', (WidgetTester tester) async { testWidgetsWithLeakTracking('null bucket disables restoration', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const UnmanagedRestorationScope( const UnmanagedRestorationScope(
child: BucketSpy(), child: BucketSpy(),
...@@ -51,7 +52,7 @@ void main() { ...@@ -51,7 +52,7 @@ void main() {
}); });
group('RestorationScope', () { group('RestorationScope', () {
testWidgets('asserts when none is found', (WidgetTester tester) async { testWidgetsWithLeakTracking('asserts when none is found', (WidgetTester tester) async {
late BuildContext capturedContext; late BuildContext capturedContext;
await tester.pumpWidget(WidgetsApp( await tester.pumpWidget(WidgetsApp(
color: const Color(0xD0FF0000), color: const Color(0xD0FF0000),
...@@ -97,9 +98,10 @@ void main() { ...@@ -97,9 +98,10 @@ void main() {
expect(RestorationScope.of(capturedContext), scope.bucket); expect(RestorationScope.of(capturedContext), scope.bucket);
}); });
testWidgets('makes bucket available to descendants', (WidgetTester tester) async { testWidgetsWithLeakTracking('makes bucket available to descendants', (WidgetTester tester) async {
const String id = 'hello world 1234'; const String id = 'hello world 1234';
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
expect(rawData, isEmpty); expect(rawData, isEmpty);
...@@ -120,8 +122,9 @@ void main() { ...@@ -120,8 +122,9 @@ void main() {
expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey(id), isTrue); expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey(id), isTrue);
}); });
testWidgets('bucket for descendants contains data claimed from parent', (WidgetTester tester) async { testWidgetsWithLeakTracking('bucket for descendants contains data claimed from parent', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
await tester.pumpWidget( await tester.pumpWidget(
...@@ -140,8 +143,9 @@ void main() { ...@@ -140,8 +143,9 @@ void main() {
expect(state.bucket!.read<int>('foo'), 22); expect(state.bucket!.read<int>('foo'), 22);
}); });
testWidgets('renames existing bucket when new ID is provided', (WidgetTester tester) async { testWidgetsWithLeakTracking('renames existing bucket when new ID is provided', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
await tester.pumpWidget( await tester.pumpWidget(
...@@ -178,8 +182,9 @@ void main() { ...@@ -178,8 +182,9 @@ void main() {
expect(state.bucket, same(bucket)); expect(state.bucket, same(bucket));
}); });
testWidgets('Disposing a scope removes its data', (WidgetTester tester) async { testWidgetsWithLeakTracking('Disposing a scope removes its data', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
...@@ -207,8 +212,9 @@ void main() { ...@@ -207,8 +212,9 @@ void main() {
expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse);
}); });
testWidgets('no bucket for descendants when id is null', (WidgetTester tester) async { testWidgetsWithLeakTracking('no bucket for descendants when id is null', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{});
await tester.pumpWidget( await tester.pumpWidget(
...@@ -251,7 +257,7 @@ void main() { ...@@ -251,7 +257,7 @@ void main() {
expect(state.bucket, isNull); expect(state.bucket, isNull);
}); });
testWidgets('no bucket for descendants when scope is null', (WidgetTester tester) async { testWidgetsWithLeakTracking('no bucket for descendants when scope is null', (WidgetTester tester) async {
final Key scopeKey = GlobalKey(); final Key scopeKey = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
...@@ -266,6 +272,7 @@ void main() { ...@@ -266,6 +272,7 @@ void main() {
// Move it under a valid scope. // Move it under a valid scope.
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{});
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -293,7 +300,7 @@ void main() { ...@@ -293,7 +300,7 @@ void main() {
expect(state.bucket, isNull); expect(state.bucket, isNull);
}); });
testWidgets('no bucket for descendants when scope and id are null', (WidgetTester tester) async { testWidgetsWithLeakTracking('no bucket for descendants when scope and id are null', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const RestorationScope( const RestorationScope(
restorationId: null, restorationId: null,
...@@ -304,8 +311,9 @@ void main() { ...@@ -304,8 +311,9 @@ void main() {
expect(state.bucket, isNull); expect(state.bucket, isNull);
}); });
testWidgets('moving scope moves its data', (WidgetTester tester) async { testWidgetsWithLeakTracking('moving scope moves its data', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
final Key scopeKey = GlobalKey(); final Key scopeKey = GlobalKey();
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('widget moves scopes during restore', (WidgetTester tester) async { testWidgetsWithLeakTracking('widget moves scopes during restore', (WidgetTester tester) async {
await tester.pumpWidget(const RootRestorationScope( await tester.pumpWidget(const RootRestorationScope(
restorationId: 'root', restorationId: 'root',
child: Directionality( child: Directionality(
...@@ -68,7 +69,7 @@ void main() { ...@@ -68,7 +69,7 @@ void main() {
expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).toggleCount, 0); expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).toggleCount, 0);
}); });
testWidgets('restoration is turned on later', (WidgetTester tester) async { testWidgetsWithLeakTracking('restoration is turned on later', (WidgetTester tester) async {
tester.binding.restorationManager.disableRestoration(); tester.binding.restorationManager.disableRestoration();
await tester.pumpWidget(const RootRestorationScope( await tester.pumpWidget(const RootRestorationScope(
restorationId: 'root-child', restorationId: 'root-child',
......
...@@ -6,9 +6,10 @@ import 'package:flutter/gestures.dart'; ...@@ -6,9 +6,10 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('RichText with recognizers without handlers does not throw', (WidgetTester tester) async { testWidgetsWithLeakTracking('RichText with recognizers without handlers does not throw', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -40,7 +41,7 @@ void main() { ...@@ -40,7 +41,7 @@ void main() {
)); ));
}); });
testWidgets('TextSpan Locale works', (WidgetTester tester) async { testWidgetsWithLeakTracking('TextSpan Locale works', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -89,7 +90,7 @@ void main() { ...@@ -89,7 +90,7 @@ void main() {
)); ));
}); });
testWidgets('TextSpan spellOut works', (WidgetTester tester) async { testWidgetsWithLeakTracking('TextSpan spellOut works', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -138,7 +139,7 @@ void main() { ...@@ -138,7 +139,7 @@ void main() {
)); ));
}); });
testWidgets('WidgetSpan calculate correct intrinsic heights', (WidgetTester tester) async { testWidgetsWithLeakTracking('WidgetSpan calculate correct intrinsic heights', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -170,7 +171,7 @@ void main() { ...@@ -170,7 +171,7 @@ void main() {
expect(tester.getSize(find.byType(IntrinsicHeight)).height, 3 * 16); expect(tester.getSize(find.byType(IntrinsicHeight)).height, 3 * 16);
}); });
testWidgets('RichText implements debugFillProperties', (WidgetTester tester) async { testWidgetsWithLeakTracking('RichText implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
RichText( RichText(
text: const TextSpan(text: 'rich text'), text: const TextSpan(text: 'rich text'),
......
...@@ -7,6 +7,7 @@ import 'dart:async'; ...@@ -7,6 +7,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'restoration.dart'; import 'restoration.dart';
...@@ -17,8 +18,13 @@ void main() { ...@@ -17,8 +18,13 @@ void main() {
binding._restorationManager = MockRestorationManager(); binding._restorationManager = MockRestorationManager();
}); });
testWidgets('does not inject root bucket if inside scope', (WidgetTester tester) async { tearDown(() {
binding._restorationManager.dispose();
});
testWidgetsWithLeakTracking('does not inject root bucket if inside scope', (WidgetTester tester) async {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
expect(rawData, isEmpty); expect(rawData, isEmpty);
...@@ -47,7 +53,7 @@ void main() { ...@@ -47,7 +53,7 @@ void main() {
expect(find.text('Hello'), findsOneWidget); expect(find.text('Hello'), findsOneWidget);
}); });
testWidgets('waits for root bucket', (WidgetTester tester) async { testWidgetsWithLeakTracking('waits for root bucket', (WidgetTester tester) async {
final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>(); final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>();
binding.restorationManager.rootBucket = bucketCompleter.future; binding.restorationManager.rootBucket = bucketCompleter.future;
...@@ -83,7 +89,7 @@ void main() { ...@@ -83,7 +89,7 @@ void main() {
expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue);
}); });
testWidgets('no delay when root is available synchronously', (WidgetTester tester) async { testWidgetsWithLeakTracking('no delay when root is available synchronously', (WidgetTester tester) async {
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
...@@ -109,7 +115,7 @@ void main() { ...@@ -109,7 +115,7 @@ void main() {
expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue);
}); });
testWidgets('does not insert root when restoration id is null', (WidgetTester tester) async { testWidgetsWithLeakTracking('does not insert root when restoration id is null', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const Directionality( const Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -175,9 +181,10 @@ void main() { ...@@ -175,9 +181,10 @@ void main() {
expect(state.bucket, isNull); expect(state.bucket, isNull);
}); });
testWidgets('injects root bucket when moved out of scope', (WidgetTester tester) async { testWidgetsWithLeakTracking('injects root bucket when moved out of scope', (WidgetTester tester) async {
final Key rootScopeKey = GlobalKey(); final Key rootScopeKey = GlobalKey();
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose);
final Map<String, dynamic> inScopeRawData = <String, dynamic>{}; final Map<String, dynamic> inScopeRawData = <String, dynamic>{};
final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData); final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData);
...@@ -257,7 +264,7 @@ void main() { ...@@ -257,7 +264,7 @@ void main() {
expect((inScopeRawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); expect((inScopeRawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue);
}); });
testWidgets('injects new root when old one is decommissioned', (WidgetTester tester) async { testWidgetsWithLeakTracking('injects new root when old one is decommissioned', (WidgetTester tester) async {
final Map<String, dynamic> firstRawData = <String, dynamic>{}; final Map<String, dynamic> firstRawData = <String, dynamic>{};
final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData); final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot);
...@@ -300,7 +307,7 @@ void main() { ...@@ -300,7 +307,7 @@ void main() {
expect(state.bucket!.read<int>('foo'), 22); expect(state.bucket!.read<int>('foo'), 22);
}); });
testWidgets('injects null when rootBucket is null', (WidgetTester tester) async { testWidgetsWithLeakTracking('injects null when rootBucket is null', (WidgetTester tester) async {
final Completer<RestorationBucket?> completer = Completer<RestorationBucket?>(); final Completer<RestorationBucket?> completer = Completer<RestorationBucket?>();
binding.restorationManager.rootBucket = completer.future; binding.restorationManager.rootBucket = completer.future;
...@@ -337,7 +344,7 @@ void main() { ...@@ -337,7 +344,7 @@ void main() {
expect(state.bucket, isNotNull); expect(state.bucket, isNotNull);
}); });
testWidgets('can switch to null', (WidgetTester tester) async { testWidgetsWithLeakTracking('can switch to null', (WidgetTester tester) async {
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('Rotated box control test', (WidgetTester tester) async { testWidgetsWithLeakTracking('Rotated box control test', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
final Key rotatedBoxKey = UniqueKey(); final Key rotatedBoxKey = UniqueKey();
......
...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; ...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
class OnTapPage extends StatelessWidget { class OnTapPage extends StatelessWidget {
const OnTapPage({super.key, required this.id, required this.onTap}); const OnTapPage({super.key, required this.id, required this.onTap});
...@@ -32,7 +33,7 @@ class OnTapPage extends StatelessWidget { ...@@ -32,7 +33,7 @@ class OnTapPage extends StatelessWidget {
} }
void main() { void main() {
testWidgets('Push and Pop should send platform messages', (WidgetTester tester) async { testWidgetsWithLeakTracking('Push and Pop should send platform messages', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => OnTapPage( '/': (BuildContext context) => OnTapPage(
id: '/', id: '/',
...@@ -107,7 +108,7 @@ void main() { ...@@ -107,7 +108,7 @@ void main() {
); );
}); });
testWidgets('Navigator does not report route name by default', (WidgetTester tester) async { testWidgetsWithLeakTracking('Navigator does not report route name by default', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[]; final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall); log.add(methodCall);
...@@ -141,7 +142,7 @@ void main() { ...@@ -141,7 +142,7 @@ void main() {
expect(log, hasLength(0)); expect(log, hasLength(0));
}); });
testWidgets('Replace should send platform messages', (WidgetTester tester) async { testWidgetsWithLeakTracking('Replace should send platform messages', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => OnTapPage( '/': (BuildContext context) => OnTapPage(
id: '/', id: '/',
...@@ -217,7 +218,7 @@ void main() { ...@@ -217,7 +218,7 @@ void main() {
); );
}); });
testWidgets('Nameless routes should send platform messages', (WidgetTester tester) async { testWidgetsWithLeakTracking('Nameless routes should send platform messages', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[]; final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall); log.add(methodCall);
...@@ -261,7 +262,7 @@ void main() { ...@@ -261,7 +262,7 @@ void main() {
expect(log, isEmpty); expect(log, isEmpty);
}); });
testWidgets('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async { testWidgetsWithLeakTracking('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[]; final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall); log.add(methodCall);
...@@ -273,12 +274,14 @@ void main() { ...@@ -273,12 +274,14 @@ void main() {
uri: Uri.parse('initial'), uri: Uri.parse('initial'),
), ),
); );
addTearDown(provider.dispose);
final SimpleRouterDelegate delegate = SimpleRouterDelegate( final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true, reportConfiguration: true,
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.uri.toString()); return Text(information.uri.toString());
}, },
); );
addTearDown(delegate.dispose);
await tester.pumpWidget(MaterialApp.router( await tester.pumpWidget(MaterialApp.router(
routeInformationProvider: provider, routeInformationProvider: provider,
...@@ -313,7 +316,12 @@ void main() { ...@@ -313,7 +316,12 @@ void main() {
'replace': false, 'replace': false,
}), }),
]); ]);
}); },
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
} }
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation); typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
......
This diff is collapsed.
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('Padding RTL', (WidgetTester tester) async { testWidgetsWithLeakTracking('Padding RTL', (WidgetTester tester) async {
const Widget child = Padding( const Widget child = Padding(
padding: EdgeInsetsDirectional.only(start: 10.0), padding: EdgeInsetsDirectional.only(start: 10.0),
child: Placeholder(), child: Placeholder(),
...@@ -43,7 +44,7 @@ void main() { ...@@ -43,7 +44,7 @@ void main() {
); );
}); });
testWidgets('Container padding/margin RTL', (WidgetTester tester) async { testWidgetsWithLeakTracking('Container padding/margin RTL', (WidgetTester tester) async {
final Widget child = Container( final Widget child = Container(
padding: const EdgeInsetsDirectional.only(start: 6.0), padding: const EdgeInsetsDirectional.only(start: 6.0),
margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0), margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0),
...@@ -63,7 +64,7 @@ void main() { ...@@ -63,7 +64,7 @@ void main() {
expect(tester.getTopRight(find.byType(Placeholder)), const Offset(790.0, 0.0)); expect(tester.getTopRight(find.byType(Placeholder)), const Offset(790.0, 0.0));
}); });
testWidgets('Container padding/margin mixed RTL/absolute', (WidgetTester tester) async { testWidgetsWithLeakTracking('Container padding/margin mixed RTL/absolute', (WidgetTester tester) async {
final Widget child = Container( final Widget child = Container(
padding: const EdgeInsets.only(left: 6.0), padding: const EdgeInsets.only(left: 6.0),
margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0), margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0),
...@@ -83,7 +84,7 @@ void main() { ...@@ -83,7 +84,7 @@ void main() {
expect(tester.getTopRight(find.byType(Placeholder)), const Offset(796.0, 0.0)); expect(tester.getTopRight(find.byType(Placeholder)), const Offset(796.0, 0.0));
}); });
testWidgets('EdgeInsetsDirectional without Directionality', (WidgetTester tester) async { testWidgetsWithLeakTracking('EdgeInsetsDirectional without Directionality', (WidgetTester tester) async {
await tester.pumpWidget(const Padding(padding: EdgeInsetsDirectional.zero)); await tester.pumpWidget(const Padding(padding: EdgeInsetsDirectional.zero));
expect(tester.takeException(), isAssertionError); expect(tester.takeException(), isAssertionError);
}); });
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
testWidgets('runApp inside onPressed does not throw', (WidgetTester tester) async { testWidgetsWithLeakTracking('runApp inside onPressed does not throw', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() { void main() {
group('SafeArea', () { group('SafeArea', () {
testWidgets('SafeArea - basic', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea - basic', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MediaQuery( const MediaQuery(
data: MediaQueryData(padding: EdgeInsets.all(20.0)), data: MediaQueryData(padding: EdgeInsets.all(20.0)),
...@@ -22,7 +23,7 @@ void main() { ...@@ -22,7 +23,7 @@ void main() {
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0)); expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0));
}); });
testWidgets('SafeArea - with minimums', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea - with minimums', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MediaQuery( const MediaQuery(
data: MediaQueryData(padding: EdgeInsets.all(20.0)), data: MediaQueryData(padding: EdgeInsets.all(20.0)),
...@@ -37,7 +38,7 @@ void main() { ...@@ -37,7 +38,7 @@ void main() {
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 570.0)); expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 570.0));
}); });
testWidgets('SafeArea - nested', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea - nested', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MediaQuery( const MediaQuery(
data: MediaQueryData(padding: EdgeInsets.all(20.0)), data: MediaQueryData(padding: EdgeInsets.all(20.0)),
...@@ -54,7 +55,7 @@ void main() { ...@@ -54,7 +55,7 @@ void main() {
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0)); expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0));
}); });
testWidgets('SafeArea - changing', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea - changing', (WidgetTester tester) async {
const Widget child = SafeArea( const Widget child = SafeArea(
bottom: false, bottom: false,
child: SafeArea( child: SafeArea(
...@@ -85,7 +86,7 @@ void main() { ...@@ -85,7 +86,7 @@ void main() {
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0));
}); });
testWidgets('SafeArea - properties', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea - properties', (WidgetTester tester) async {
final SafeArea child = SafeArea( final SafeArea child = SafeArea(
right: false, right: false,
bottom: false, bottom: false,
...@@ -112,7 +113,7 @@ void main() { ...@@ -112,7 +113,7 @@ void main() {
); );
} }
testWidgets('SafeArea alone.', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea alone.', (WidgetTester tester) async {
final Widget child = boilerplate(const SafeArea( final Widget child = boilerplate(const SafeArea(
maintainBottomViewPadding: true, maintainBottomViewPadding: true,
child: Column( child: Column(
...@@ -147,7 +148,7 @@ void main() { ...@@ -147,7 +148,7 @@ void main() {
expect(initialPoint, finalPoint); expect(initialPoint, finalPoint);
}); });
testWidgets('SafeArea alone - partial ViewInsets consume Padding', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea alone - partial ViewInsets consume Padding', (WidgetTester tester) async {
final Widget child = boilerplate(const SafeArea( final Widget child = boilerplate(const SafeArea(
maintainBottomViewPadding: true, maintainBottomViewPadding: true,
child: Column( child: Column(
...@@ -180,7 +181,7 @@ void main() { ...@@ -180,7 +181,7 @@ void main() {
expect(initialPoint, finalPoint); expect(initialPoint, finalPoint);
}); });
testWidgets('SafeArea with nested Scaffold', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea with nested Scaffold', (WidgetTester tester) async {
final Widget child = boilerplate(const SafeArea( final Widget child = boilerplate(const SafeArea(
maintainBottomViewPadding: true, maintainBottomViewPadding: true,
child: Scaffold( child: Scaffold(
...@@ -218,7 +219,7 @@ void main() { ...@@ -218,7 +219,7 @@ void main() {
expect(initialPoint, finalPoint); expect(initialPoint, finalPoint);
}); });
testWidgets('SafeArea with nested Scaffold - partial ViewInsets consume Padding', (WidgetTester tester) async { testWidgetsWithLeakTracking('SafeArea with nested Scaffold - partial ViewInsets consume Padding', (WidgetTester tester) async {
final Widget child = boilerplate(const SafeArea( final Widget child = boilerplate(const SafeArea(
maintainBottomViewPadding: true, maintainBottomViewPadding: true,
child: Scaffold( child: Scaffold(
...@@ -258,12 +259,15 @@ void main() { ...@@ -258,12 +259,15 @@ void main() {
group('SliverSafeArea', () { group('SliverSafeArea', () {
Widget buildWidget(EdgeInsets mediaPadding, Widget sliver) { Widget buildWidget(EdgeInsets mediaPadding, Widget sliver) {
late final ViewportOffset offset;
addTearDown(() => offset.dispose());
return MediaQuery( return MediaQuery(
data: MediaQueryData(padding: mediaPadding), data: MediaQueryData(padding: mediaPadding),
child: Directionality( child: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: Viewport( child: Viewport(
offset: ViewportOffset.fixed(0.0), offset: offset = ViewportOffset.fixed(0.0),
slivers: <Widget>[ slivers: <Widget>[
const SliverToBoxAdapter(child: SizedBox(width: 800.0, height: 100.0, child: Text('before'))), const SliverToBoxAdapter(child: SizedBox(width: 800.0, height: 100.0, child: Text('before'))),
sliver, sliver,
...@@ -285,7 +289,7 @@ void main() { ...@@ -285,7 +289,7 @@ void main() {
expect(testAnswers, equals(expectedRects)); expect(testAnswers, equals(expectedRects));
} }
testWidgets('SliverSafeArea - basic', (WidgetTester tester) async { testWidgetsWithLeakTracking('SliverSafeArea - basic', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildWidget( buildWidget(
const EdgeInsets.all(20.0), const EdgeInsets.all(20.0),
...@@ -302,7 +306,7 @@ void main() { ...@@ -302,7 +306,7 @@ void main() {
]); ]);
}); });
testWidgets('SliverSafeArea - basic', (WidgetTester tester) async { testWidgetsWithLeakTracking('SliverSafeArea - basic', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildWidget( buildWidget(
const EdgeInsets.all(20.0), const EdgeInsets.all(20.0),
...@@ -320,7 +324,7 @@ void main() { ...@@ -320,7 +324,7 @@ void main() {
]); ]);
}); });
testWidgets('SliverSafeArea - nested', (WidgetTester tester) async { testWidgetsWithLeakTracking('SliverSafeArea - nested', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildWidget( buildWidget(
const EdgeInsets.all(20.0), const EdgeInsets.all(20.0),
...@@ -340,7 +344,7 @@ void main() { ...@@ -340,7 +344,7 @@ void main() {
]); ]);
}); });
testWidgets('SliverSafeArea - changing', (WidgetTester tester) async { testWidgetsWithLeakTracking('SliverSafeArea - changing', (WidgetTester tester) async {
const Widget sliver = SliverSafeArea( const Widget sliver = SliverSafeArea(
bottom: false, bottom: false,
sliver: SliverSafeArea( sliver: SliverSafeArea(
...@@ -379,7 +383,7 @@ void main() { ...@@ -379,7 +383,7 @@ void main() {
}); });
}); });
testWidgets('SliverSafeArea - properties', (WidgetTester tester) async { testWidgetsWithLeakTracking('SliverSafeArea - properties', (WidgetTester tester) async {
const SliverSafeArea child = SliverSafeArea( const SliverSafeArea child = SliverSafeArea(
right: false, right: false,
bottom: false, bottom: false,
......
...@@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
List<Widget> children(int n) { List<Widget> children(int n) {
return List<Widget>.generate(n, (int i) { return List<Widget>.generate(n, (int i) {
...@@ -14,8 +15,9 @@ List<Widget> children(int n) { ...@@ -14,8 +15,9 @@ List<Widget> children(int n) {
} }
void main() { void main() {
testWidgets('Scrolling with list view changes, leaving the overscroll', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scrolling with list view changes, leaving the overscroll', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30))));
final double thirty = controller.position.maxScrollExtent; final double thirty = controller.position.maxScrollExtent;
controller.jumpTo(thirty); controller.jumpTo(thirty);
...@@ -28,8 +30,9 @@ void main() { ...@@ -28,8 +30,9 @@ void main() {
expect(controller.position.pixels, thirty + 100.0); // and ends up at the end expect(controller.position.pixels, thirty + 100.0); // and ends up at the end
}); });
testWidgets('Scrolling with list view changes, remaining overscrolled', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scrolling with list view changes, remaining overscrolled', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30))));
final double thirty = controller.position.maxScrollExtent; final double thirty = controller.position.maxScrollExtent;
controller.jumpTo(thirty); controller.jumpTo(thirty);
...@@ -42,7 +45,7 @@ void main() { ...@@ -42,7 +45,7 @@ void main() {
expect(controller.position.pixels, thirty + 100.0); // and ends up at the end expect(controller.position.pixels, thirty + 100.0); // and ends up at the end
}); });
testWidgets('Ability to keep a PageView at the end manually (issue 62209)', (WidgetTester tester) async { testWidgetsWithLeakTracking('Ability to keep a PageView at the end manually (issue 62209)', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: PageView62209())); await tester.pumpWidget(const MaterialApp(home: PageView62209()));
expect(find.text('Page 1'), findsOneWidget); expect(find.text('Page 1'), findsOneWidget);
expect(find.text('Page 100'), findsNothing); expect(find.text('Page 100'), findsNothing);
...@@ -129,8 +132,9 @@ void main() { ...@@ -129,8 +132,9 @@ void main() {
expect(find.text('Page 9'), findsOneWidget); expect(find.text('Page 9'), findsOneWidget);
}); });
testWidgets('Pointer is not ignored during trackpad scrolling.', (WidgetTester tester) async { testWidgetsWithLeakTracking('Pointer is not ignored during trackpad scrolling.', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
int? lastTapped; int? lastTapped;
int? lastHovered; int? lastHovered;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
......
...@@ -6,6 +6,7 @@ import 'dart:ui' as ui show Image; ...@@ -6,6 +6,7 @@ import 'dart:ui' as ui show Image;
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../painting/image_test_utils.dart'; import '../painting/image_test_utils.dart';
...@@ -17,6 +18,10 @@ void main() { ...@@ -17,6 +18,10 @@ void main() {
testImage = await createTestImage(width: 10, height: 10); testImage = await createTestImage(width: 10, height: 10);
}); });
tearDownAll(() {
testImage.dispose();
});
tearDown(() { tearDown(() {
imageCache.clear(); imageCache.clear();
}); });
...@@ -29,7 +34,7 @@ void main() { ...@@ -29,7 +34,7 @@ void main() {
return Scrollable.of(find.byType(TestWidget).evaluate().first).position; return Scrollable.of(find.byType(TestWidget).evaluate().first).position;
} }
testWidgets('ScrollAwareImageProvider does not delay if widget is not in scrollable', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if widget is not in scrollable', (WidgetTester tester) async {
final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>();
await tester.pumpWidget(TestWidget(key)); await tester.pumpWidget(TestWidget(key));
...@@ -56,7 +61,7 @@ void main() { ...@@ -56,7 +61,7 @@ void main() {
expect(imageCache.currentSize, 1); expect(imageCache.currentSize, 1);
}); });
testWidgets('ScrollAwareImageProvider does not delay if in scrollable that is not scrolling', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if in scrollable that is not scrolling', (WidgetTester tester) async {
final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>();
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -92,9 +97,10 @@ void main() { ...@@ -92,9 +97,10 @@ void main() {
expect(findPhysics<RecordingPhysics>(tester).velocities, <double>[0]); expect(findPhysics<RecordingPhysics>(tester).velocities, <double>[0]);
}); });
testWidgets('ScrollAwareImageProvider does not delay if in scrollable that is scrolling slowly', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if in scrollable that is scrolling slowly', (WidgetTester tester) async {
final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[];
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
...@@ -149,9 +155,10 @@ void main() { ...@@ -149,9 +155,10 @@ void main() {
expect(imageCache.currentSize, 1); expect(imageCache.currentSize, 1);
}); });
testWidgets('ScrollAwareImageProvider delays if in scrollable that is scrolling fast', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider delays if in scrollable that is scrolling fast', (WidgetTester tester) async {
final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[];
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
...@@ -216,9 +223,10 @@ void main() { ...@@ -216,9 +223,10 @@ void main() {
expect(imageCache.currentSize, 1); expect(imageCache.currentSize, 1);
}); });
testWidgets('ScrollAwareImageProvider delays if in scrollable that is scrolling fast and fizzles if disposed', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider delays if in scrollable that is scrolling fast and fizzles if disposed', (WidgetTester tester) async {
final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[];
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
...@@ -285,9 +293,10 @@ void main() { ...@@ -285,9 +293,10 @@ void main() {
expect(imageCache.currentSize, 0); expect(imageCache.currentSize, 0);
}); });
testWidgets('ScrollAwareImageProvider resolves from ImageCache and does not set completer twice', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider resolves from ImageCache and does not set completer twice', (WidgetTester tester) async {
final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>();
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: SingleChildScrollView( child: SingleChildScrollView(
...@@ -333,12 +342,13 @@ void main() { ...@@ -333,12 +342,13 @@ void main() {
expect(stream.completer, null); expect(stream.completer, null);
}); });
testWidgets('ScrollAwareImageProvider does not block LRU updates to image cache', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollAwareImageProvider does not block LRU updates to image cache', (WidgetTester tester) async {
final int oldSize = imageCache.maximumSize; final int oldSize = imageCache.maximumSize;
imageCache.maximumSize = 1; imageCache.maximumSize = 1;
final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>();
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
addTearDown(scrollController.dispose);
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: SingleChildScrollView( child: SingleChildScrollView(
......
...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
late GestureVelocityTrackerBuilder lastCreatedBuilder; late GestureVelocityTrackerBuilder lastCreatedBuilder;
class TestScrollBehavior extends ScrollBehavior { class TestScrollBehavior extends ScrollBehavior {
...@@ -33,7 +34,7 @@ class TestScrollBehavior extends ScrollBehavior { ...@@ -33,7 +34,7 @@ class TestScrollBehavior extends ScrollBehavior {
} }
void main() { void main() {
testWidgets('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async { testWidgetsWithLeakTracking('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async {
const ScrollBehavior defaultBehavior = ScrollBehavior(); const ScrollBehavior defaultBehavior = ScrollBehavior();
late BuildContext capturedContext; late BuildContext capturedContext;
...@@ -75,14 +76,14 @@ void main() { ...@@ -75,14 +76,14 @@ void main() {
}, variant: TargetPlatformVariant.all()); }, variant: TargetPlatformVariant.all());
// Regression test for https://github.com/flutter/flutter/issues/89681 // Regression test for https://github.com/flutter/flutter/issues/89681
testWidgets('_WrappedScrollBehavior shouldNotify test', (WidgetTester tester) async { testWidgetsWithLeakTracking('_WrappedScrollBehavior shouldNotify test', (WidgetTester tester) async {
final ScrollBehavior behavior1 = const ScrollBehavior().copyWith(); final ScrollBehavior behavior1 = const ScrollBehavior().copyWith();
final ScrollBehavior behavior2 = const ScrollBehavior().copyWith(); final ScrollBehavior behavior2 = const ScrollBehavior().copyWith();
expect(behavior1.shouldNotify(behavior2), false); expect(behavior1.shouldNotify(behavior2), false);
}); });
testWidgets('Inherited ScrollConfiguration changed', (WidgetTester tester) async { testWidgetsWithLeakTracking('Inherited ScrollConfiguration changed', (WidgetTester tester) async {
final GlobalKey key = GlobalKey(debugLabel: 'scrollable'); final GlobalKey key = GlobalKey(debugLabel: 'scrollable');
TestScrollBehavior? behavior; TestScrollBehavior? behavior;
late ScrollPositionWithSingleContext position; late ScrollPositionWithSingleContext position;
...@@ -131,7 +132,7 @@ void main() { ...@@ -131,7 +132,7 @@ void main() {
expect(metrics.viewportDimension, equals(600.0)); expect(metrics.viewportDimension, equals(600.0));
}); });
testWidgets('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -155,7 +156,7 @@ void main() { ...@@ -155,7 +156,7 @@ void main() {
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); }, variant: TargetPlatformVariant.only(TargetPlatform.android));
group('ScrollBehavior configuration is maintained over multiple copies', () { group('ScrollBehavior configuration is maintained over multiple copies', () {
testWidgets('dragDevices', (WidgetTester tester) async { testWidgetsWithLeakTracking('dragDevices', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/91673 // Regression test for https://github.com/flutter/flutter/issues/91673
const ScrollBehavior defaultBehavior = ScrollBehavior(); const ScrollBehavior defaultBehavior = ScrollBehavior();
expect(defaultBehavior.dragDevices, <PointerDeviceKind>{ expect(defaultBehavior.dragDevices, <PointerDeviceKind>{
...@@ -177,7 +178,7 @@ void main() { ...@@ -177,7 +178,7 @@ void main() {
expect(twiceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet()); expect(twiceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet());
}); });
testWidgets('physics', (WidgetTester tester) async { testWidgetsWithLeakTracking('physics', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/91673 // Regression test for https://github.com/flutter/flutter/issues/91673
late ScrollPhysics defaultPhysics; late ScrollPhysics defaultPhysics;
late ScrollPhysics onceCopiedPhysics; late ScrollPhysics onceCopiedPhysics;
...@@ -219,7 +220,7 @@ void main() { ...@@ -219,7 +220,7 @@ void main() {
expect(twiceCopiedPhysics, const BouncingScrollPhysics()); expect(twiceCopiedPhysics, const BouncingScrollPhysics());
}); });
testWidgets('platform', (WidgetTester tester) async { testWidgetsWithLeakTracking('platform', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/91673 // Regression test for https://github.com/flutter/flutter/issues/91673
late TargetPlatform defaultPlatform; late TargetPlatform defaultPlatform;
late TargetPlatform onceCopiedPlatform; late TargetPlatform onceCopiedPlatform;
...@@ -276,7 +277,7 @@ void main() { ...@@ -276,7 +277,7 @@ void main() {
); );
} }
testWidgets('scrollbar', (WidgetTester tester) async { testWidgetsWithLeakTracking('scrollbar', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/91673 // Regression test for https://github.com/flutter/flutter/issues/91673
const ScrollBehavior defaultBehavior = ScrollBehavior(); const ScrollBehavior defaultBehavior = ScrollBehavior();
await tester.pumpWidget(wrap(defaultBehavior)); await tester.pumpWidget(wrap(defaultBehavior));
...@@ -296,7 +297,7 @@ void main() { ...@@ -296,7 +297,7 @@ void main() {
// For default scrollbars // For default scrollbars
}, variant: TargetPlatformVariant.desktop()); }, variant: TargetPlatformVariant.desktop());
testWidgets('overscroll', (WidgetTester tester) async { testWidgetsWithLeakTracking('overscroll', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/91673 // Regression test for https://github.com/flutter/flutter/issues/91673
const ScrollBehavior defaultBehavior = ScrollBehavior(); const ScrollBehavior defaultBehavior = ScrollBehavior();
await tester.pumpWidget(wrap(defaultBehavior)); await tester.pumpWidget(wrap(defaultBehavior));
......
...@@ -11,8 +11,9 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; ...@@ -11,8 +11,9 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'states.dart'; import 'states.dart';
void main() { void main() {
testWidgets('ScrollController control test', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollController control test', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
...@@ -77,6 +78,7 @@ void main() { ...@@ -77,6 +78,7 @@ void main() {
expect(realOffset(), equals(controller.offset)); expect(realOffset(), equals(controller.offset));
final ScrollController controller2 = ScrollController(); final ScrollController controller2 = ScrollController();
addTearDown(controller2.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
...@@ -132,10 +134,11 @@ void main() { ...@@ -132,10 +134,11 @@ void main() {
expect(realOffset(), equals(controller2.offset)); expect(realOffset(), equals(controller2.offset));
}); });
testWidgets('ScrollController control test', (WidgetTester tester) async { testWidgetsWithLeakTracking('ScrollController control test', (WidgetTester tester) async {
final ScrollController controller = ScrollController( final ScrollController controller = ScrollController(
initialScrollOffset: 209.0, initialScrollOffset: 209.0,
); );
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
...@@ -177,8 +180,9 @@ void main() { ...@@ -177,8 +180,9 @@ void main() {
expect(realOffset(), equals(controller.offset)); expect(realOffset(), equals(controller.offset));
}); });
testWidgets('DrivenScrollActivity ending after dispose', (WidgetTester tester) async { testWidgetsWithLeakTracking('DrivenScrollActivity ending after dispose', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
...@@ -198,14 +202,17 @@ void main() { ...@@ -198,14 +202,17 @@ void main() {
await tester.pumpWidget(Container(), const Duration(seconds: 2)); await tester.pumpWidget(Container(), const Duration(seconds: 2));
}); });
testWidgets('Read operations on ScrollControllers with no positions fail', (WidgetTester tester) async { testWidgetsWithLeakTracking('Read operations on ScrollControllers with no positions fail', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
expect(() => controller.offset, throwsAssertionError); expect(() => controller.offset, throwsAssertionError);
expect(() => controller.position, throwsAssertionError); expect(() => controller.position, throwsAssertionError);
}); });
testWidgets('Read operations on ScrollControllers with more than one position fail', (WidgetTester tester) async { testWidgetsWithLeakTracking('Read operations on ScrollControllers with more than one position fail', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -238,14 +245,17 @@ void main() { ...@@ -238,14 +245,17 @@ void main() {
expect(() => controller.position, throwsAssertionError); expect(() => controller.position, throwsAssertionError);
}); });
testWidgets('Write operations on ScrollControllers with no positions fail', (WidgetTester tester) async { testWidgetsWithLeakTracking('Write operations on ScrollControllers with no positions fail', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
expect(() => controller.animateTo(1.0, duration: const Duration(seconds: 1), curve: Curves.linear), throwsAssertionError); expect(() => controller.animateTo(1.0, duration: const Duration(seconds: 1), curve: Curves.linear), throwsAssertionError);
expect(() => controller.jumpTo(1.0), throwsAssertionError); expect(() => controller.jumpTo(1.0), throwsAssertionError);
}); });
testWidgets('Write operations on ScrollControllers with more than one position do not throw', (WidgetTester tester) async { testWidgetsWithLeakTracking('Write operations on ScrollControllers with more than one position do not throw', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -279,7 +289,7 @@ void main() { ...@@ -279,7 +289,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
}); });
testWidgets('Scroll controllers notify when the position changes', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll controllers notify when the position changes', (WidgetTester tester) async {
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
final List<double> log = <double>[]; final List<double> log = <double>[];
...@@ -313,7 +323,7 @@ void main() { ...@@ -313,7 +323,7 @@ void main() {
expect(log, isEmpty); expect(log, isEmpty);
}); });
testWidgets('keepScrollOffset', (WidgetTester tester) async { testWidgetsWithLeakTracking('keepScrollOffset', (WidgetTester tester) async {
final PageStorageBucket bucket = PageStorageBucket(); final PageStorageBucket bucket = PageStorageBucket();
Widget buildFrame(ScrollController controller) { Widget buildFrame(ScrollController controller) {
...@@ -341,6 +351,7 @@ void main() { ...@@ -341,6 +351,7 @@ void main() {
// The initialScrollOffset is used in this case, because there's no saved // The initialScrollOffset is used in this case, because there's no saved
// scroll offset. // scroll offset.
ScrollController controller = ScrollController(initialScrollOffset: 200.0); ScrollController controller = ScrollController(initialScrollOffset: 200.0);
addTearDown(controller.dispose);
await tester.pumpWidget(buildFrame(controller)); await tester.pumpWidget(buildFrame(controller));
expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 2')), Offset.zero); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 2')), Offset.zero);
...@@ -351,6 +362,7 @@ void main() { ...@@ -351,6 +362,7 @@ void main() {
// The initialScrollOffset isn't used in this case, because the scrolloffset // The initialScrollOffset isn't used in this case, because the scrolloffset
// can be restored. // can be restored.
controller = ScrollController(initialScrollOffset: 25.0); controller = ScrollController(initialScrollOffset: 25.0);
addTearDown(controller.dispose);
await tester.pumpWidget(buildFrame(controller)); await tester.pumpWidget(buildFrame(controller));
expect(controller.offset, 2000.0); expect(controller.offset, 2000.0);
expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 20')), Offset.zero); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 20')), Offset.zero);
...@@ -360,13 +372,14 @@ void main() { ...@@ -360,13 +372,14 @@ void main() {
// the initialScrollOffset is used. // the initialScrollOffset is used.
controller = ScrollController(keepScrollOffset: false, initialScrollOffset: 100.0); controller = ScrollController(keepScrollOffset: false, initialScrollOffset: 100.0);
addTearDown(controller.dispose);
await tester.pumpWidget(buildFrame(controller)); await tester.pumpWidget(buildFrame(controller));
expect(controller.offset, 100.0); expect(controller.offset, 100.0);
expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 1')), Offset.zero); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 1')), Offset.zero);
}); });
testWidgets('isScrollingNotifier works with pointer scroll', (WidgetTester tester) async { testWidgetsWithLeakTracking('isScrollingNotifier works with pointer scroll', (WidgetTester tester) async {
Widget buildFrame(ScrollController controller) { Widget buildFrame(ScrollController controller) {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -381,6 +394,7 @@ void main() { ...@@ -381,6 +394,7 @@ void main() {
bool isScrolling = false; bool isScrolling = false;
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
controller.addListener((){ controller.addListener((){
isScrolling = controller.position.isScrollingNotifier.value; isScrolling = controller.position.isScrollingNotifier.value;
}); });
...@@ -396,6 +410,6 @@ void main() { ...@@ -396,6 +410,6 @@ void main() {
}); });
test('$ScrollController dispatches object creation in constructor', () { test('$ScrollController dispatches object creation in constructor', () {
expect(()=> ScrollController().dispose(), dispatchesMemoryEvents(ScrollController)); expect(() => ScrollController().dispose(), dispatchesMemoryEvents(ScrollController));
}); });
} }
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
Widget _buildScroller({ required List<String> log }) { Widget _buildScroller({ required List<String> log }) {
return NotificationListener<ScrollNotification>( return NotificationListener<ScrollNotification>(
...@@ -38,7 +39,7 @@ void main() { ...@@ -38,7 +39,7 @@ void main() {
scrollable.position.jumpTo(newScrollOffset); scrollable.position.jumpTo(newScrollOffset);
} }
testWidgets('Scroll event drag', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll event drag', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -57,7 +58,7 @@ void main() { ...@@ -57,7 +58,7 @@ void main() {
expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end'])); expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
}); });
testWidgets('Scroll animateTo', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll animateTo', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -74,7 +75,7 @@ void main() { ...@@ -74,7 +75,7 @@ void main() {
expect(completer.isCompleted, isTrue); expect(completer.isCompleted, isTrue);
}); });
testWidgets('Scroll jumpTo', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll jumpTo', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -85,7 +86,7 @@ void main() { ...@@ -85,7 +86,7 @@ void main() {
expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end'])); expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end']));
}); });
testWidgets('Scroll jumpTo during animation', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll jumpTo during animation', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -110,7 +111,7 @@ void main() { ...@@ -110,7 +111,7 @@ void main() {
expect(completer.isCompleted, isTrue); expect(completer.isCompleted, isTrue);
}); });
testWidgets('Scroll scrollTo during animation', (WidgetTester tester) async { testWidgetsWithLeakTracking('Scroll scrollTo during animation', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -134,7 +135,7 @@ void main() { ...@@ -134,7 +135,7 @@ void main() {
expect(completer.isCompleted, isTrue); expect(completer.isCompleted, isTrue);
}); });
testWidgets('fling, fling generates two start/end pairs', (WidgetTester tester) async { testWidgetsWithLeakTracking('fling, fling generates two start/end pairs', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -157,7 +158,7 @@ void main() { ...@@ -157,7 +158,7 @@ void main() {
expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end'])); expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end']));
}); });
testWidgets('fling, pause, fling generates two start/end pairs', (WidgetTester tester) async { testWidgetsWithLeakTracking('fling, pause, fling generates two start/end pairs', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
...@@ -176,7 +177,7 @@ void main() { ...@@ -176,7 +177,7 @@ void main() {
expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end'])); expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end']));
}); });
testWidgets('fling up ends', (WidgetTester tester) async { testWidgetsWithLeakTracking('fling up ends', (WidgetTester tester) async {
final List<String> log = <String>[]; final List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log)); await tester.pumpWidget(_buildScroller(log: log));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment