diff --git a/packages/flutter/test/cupertino/action_sheet_test.dart b/packages/flutter/test/cupertino/action_sheet_test.dart index f5f3dde589..0dffe2d74b 100644 --- a/packages/flutter/test/cupertino/action_sheet_test.dart +++ b/packages/flutter/test/cupertino/action_sheet_test.dart @@ -31,7 +31,7 @@ void main() { await tester.tapAt(const Offset(20.0, 20.0)); await tester.pump(); expect(find.text('Action Sheet'), findsNothing); - }, leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed()); + }); testWidgetsWithLeakTracking('Verify that a tap on title section (not buttons) does not dismiss an action sheet', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/text_semantics_test.dart b/packages/flutter/test/widgets/text_semantics_test.dart index 190d2630d1..9bc76eeea8 100644 --- a/packages/flutter/test/widgets/text_semantics_test.dart +++ b/packages/flutter/test/widgets/text_semantics_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('SemanticsNode ids are stable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNode ids are stable', (WidgetTester tester) async { // Regression test for b/151732341. final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index fa09e584c5..c29ebdc734 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -9,11 +9,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Text respects media query', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects media query', (WidgetTester tester) async { await tester.pumpWidget(const MediaQuery( data: MediaQueryData(textScaleFactor: 1.3), child: Center( @@ -34,7 +35,7 @@ void main() { expect(text.textScaler, TextScaler.noScaling); }); - testWidgets('Text respects textScaleFactor with default font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects textScaleFactor with default font size', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Text('Hello', textDirection: TextDirection.ltr)), ); @@ -62,7 +63,7 @@ void main() { expect(largeSize.height, equals(21.0)); }); - testWidgets('Text respects textScaleFactor with explicit font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects textScaleFactor with explicit font size', (WidgetTester tester) async { await tester.pumpWidget(const Center( child: Text( 'Hello', @@ -102,7 +103,7 @@ void main() { expect(message, contains(' Text ')); }); - testWidgets('Text can be created from TextSpans and uses defaultTextStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text can be created from TextSpans and uses defaultTextStyle', (WidgetTester tester) async { await tester.pumpWidget( const DefaultTextStyle( style: TextStyle( @@ -132,7 +133,7 @@ void main() { expect(text.text.style!.fontSize, 20.0); }); - testWidgets('inline widgets works with ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets works with ellipsis', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/35869 const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -165,7 +166,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('inline widgets hitTest works with ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets hitTest works with ellipsis', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/68559 const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -201,7 +202,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('inline widgets works with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets works with textScaleFactor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59316 final UniqueKey key = UniqueKey(); double textScaleFactor = 1.0; @@ -265,7 +266,7 @@ void main() { expect(renderText.size.height, singleLineHeight * textScaleFactor * 3); }); - testWidgets("Inline widgets' scaled sizes are constrained", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Inline widgets' scaled sizes are constrained", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/130588 await tester.pumpWidget( const Directionality( @@ -282,7 +283,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('semanticsLabel can override text label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semanticsLabel can override text label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( const Text( @@ -328,7 +329,7 @@ void main() { semantics.dispose(); }); - testWidgets('semantics label is in order when uses widget span', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics label is in order when uses widget span', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -363,7 +364,7 @@ void main() { ); }); - testWidgets('semantics can handle some widget spans without semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle some widget spans without semantics', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -405,7 +406,7 @@ void main() { matchesSemantics(label: 'before \n mid\nfoo\n after')); }); - testWidgets('semantics can handle all widget spans without semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle all widget spans without semantics', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -447,7 +448,7 @@ void main() { matchesSemantics(label: 'before \n mid\n after')); }); - testWidgets('semantics can handle widget spans with explicit semantics node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle widget spans with explicit semantics node', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -482,7 +483,7 @@ void main() { ); }); - testWidgets('semanticsLabel can be shorter than text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semanticsLabel can be shorter than text', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -530,7 +531,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -584,13 +585,14 @@ void main() { semantics.dispose(); }); - testWidgets('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/100395. final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(fontSize: 200); const String onScreenText = 'onscreen\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'; const String offScreenText = 'off screen'; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( SingleChildScrollView( controller: controller, @@ -653,7 +655,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic node when TextSpan overflows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node when TextSpan overflows', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -704,7 +706,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic nodes with text span labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic nodes with text span labels', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -762,7 +764,7 @@ void main() { }); - testWidgets('recognizers split semantic node - bidi', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node - bidi', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -843,7 +845,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('TapGesture recognizers contribute link semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TapGesture recognizers contribute link semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -883,7 +885,7 @@ void main() { semantics.dispose(); }); - testWidgets('inline widgets generate semantic nodes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets generate semantic nodes', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -957,7 +959,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('inline widgets semantic nodes scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets semantic nodes scale', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -1037,7 +1039,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('receives fontFamilyFallback and package from root ThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('receives fontFamilyFallback and package from root ThemeData', (WidgetTester tester) async { const String fontFamily = 'fontFamily'; const String package = 'package_name'; final List fontFamilyFallback = ['font', 'family', 'fallback']; @@ -1070,7 +1072,7 @@ void main() { } }); - testWidgets('Overflow is clipping correctly - short text with overflow: clip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: clip', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.clip, @@ -1080,7 +1082,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: ellipsis', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.ellipsis, @@ -1093,7 +1095,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87878 - testWidgets('Overflow is clipping correctly - short text with overflow: ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: ellipsis', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.ellipsis, @@ -1103,7 +1105,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: fade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: fade', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.fade, @@ -1116,7 +1118,7 @@ void main() { ); }); - testWidgets('Overflow is clipping correctly - short text with overflow: fade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: fade', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.fade, @@ -1126,7 +1128,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: visible', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.visible, @@ -1136,7 +1138,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - short text with overflow: visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: visible', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.visible, @@ -1146,7 +1148,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('textWidthBasis affects the width of a Text widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textWidthBasis affects the width of a Text widget', (WidgetTester tester) async { Future createText(TextWidthBasis textWidthBasis) { return tester.pumpWidget( MaterialApp( @@ -1183,7 +1185,7 @@ void main() { expect(textSizeLongestLine.height, equals(fontHeight * 2)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44020 - testWidgets('textWidthBasis with textAlign still obeys parent alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textWidthBasis with textAlign still obeys parent alignment', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -1233,7 +1235,7 @@ void main() { expect(tester.getSize(find.text('RIGHT ALIGNED, LONGEST LINE')).width, equals(width)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44020 - testWidgets( + testWidgetsWithLeakTracking( 'textWidthBasis.longestLine confines the width of the paragraph ' 'when given loose constraints', (WidgetTester tester) async { @@ -1273,7 +1275,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44020 ); - testWidgets('Paragraph.getBoxesForRange returns nothing when selection range is zero length', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paragraph.getBoxesForRange returns nothing when selection range is zero length', (WidgetTester tester) async { final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle()); builder.addText('hello'); final ui.Paragraph paragraph = builder.build(); @@ -1283,7 +1285,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/65818 - testWidgets('WidgetSpans with no semantic information are elided from semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Without the fix for this bug the pump widget will throw a RangeError. await tester.pumpWidget( @@ -1331,7 +1333,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 2', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1382,7 +1384,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 3', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1445,7 +1447,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 4', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 4', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1515,7 +1517,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 - testWidgets('RenderParagraph intrinsic width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderParagraph intrinsic width', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1556,7 +1558,7 @@ void main() { expect(paragraph.getMinIntrinsicWidth(0.0), 200); }); - testWidgets('can compute intrinsic width and height for widget span with text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can compute intrinsic width and height for widget span with text scaling', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59316 const Key textKey = Key('RichText'); Widget textWithNestedInlineSpans({ required double textScaleFactor, required double screenWidth }) { @@ -1609,7 +1611,7 @@ void main() { ); }); - testWidgets('Text uses TextStyle.overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text uses TextStyle.overflow', (WidgetTester tester) async { const TextOverflow overflow = TextOverflow.fade; await tester.pumpWidget(const Text( @@ -1624,7 +1626,7 @@ void main() { expect(richText.text.style!.overflow, overflow); }); - testWidgets( + testWidgetsWithLeakTracking( 'Text can be hit-tested without layout or paint being called in a frame', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/85108. @@ -1660,7 +1662,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Mouse hovering over selectable Text uses SystemMouseCursor.text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse hovering over selectable Text uses SystemMouseCursor.text', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('Flutter'), @@ -1675,7 +1677,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('Mouse hovering over selectable Text uses default selection style mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse hovering over selectable Text uses default selection style mouse cursor', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( child: DefaultSelectionStyle.merge( diff --git a/packages/flutter/test/widgets/texture_test.dart b/packages/flutter/test/widgets/texture_test.dart index 4a5b1b774a..e0bf2dc09e 100644 --- a/packages/flutter/test/widgets/texture_test.dart +++ b/packages/flutter/test/widgets/texture_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Texture with freeze set to true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with freeze set to true', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1, freeze: true)), ); @@ -25,6 +26,7 @@ void main() { expect(textureBox.freeze, true); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -35,7 +37,7 @@ void main() { expect(textureLayer.freeze, true); }); - testWidgets('Texture with default FilterQuality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with default FilterQuality', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1)), ); @@ -53,6 +55,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.low); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -64,7 +67,7 @@ void main() { }); - testWidgets('Texture with FilterQuality.none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with FilterQuality.none', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1, filterQuality: FilterQuality.none)), ); @@ -82,6 +85,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.none); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -92,7 +96,7 @@ void main() { expect(textureLayer.filterQuality, FilterQuality.none); }); - testWidgets('Texture with FilterQuality.low', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with FilterQuality.low', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1)), ); @@ -110,6 +114,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.low); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; diff --git a/packages/flutter/test/widgets/ticker_mode_test.dart b/packages/flutter/test/widgets/ticker_mode_test.dart index aa09b8c9c2..75ac25e8db 100644 --- a/packages/flutter/test/widgets/ticker_mode_test.dart +++ b/packages/flutter/test/widgets/ticker_mode_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Nested TickerMode cannot turn tickers back on', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested TickerMode cannot turn tickers back on', (WidgetTester tester) async { int outerTickCount = 0; int innerTickCount = 0; @@ -99,7 +100,7 @@ void main() { expect(innerTickCount, 0); }); - testWidgets('Changing TickerMode does not rebuild widgets with SingleTickerProviderStateMixin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing TickerMode does not rebuild widgets with SingleTickerProviderStateMixin', (WidgetTester tester) async { Widget widgetUnderTest({required bool tickerEnabled}) { return TickerMode( enabled: tickerEnabled, @@ -121,7 +122,7 @@ void main() { expect(state().buildCount, 1); }); - testWidgets('Changing TickerMode does not rebuild widgets with TickerProviderStateMixin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing TickerMode does not rebuild widgets with TickerProviderStateMixin', (WidgetTester tester) async { Widget widgetUnderTest({required bool tickerEnabled}) { return TickerMode( enabled: tickerEnabled, @@ -143,7 +144,7 @@ void main() { expect(state().buildCount, 1); }); - testWidgets('Moving widgets with SingleTickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving widgets with SingleTickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { final GlobalKey tickingWidgetKey = GlobalKey(); Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { return TickerMode( @@ -164,7 +165,7 @@ void main() { expect(tickingState.ticker.isTicking, isFalse); }); - testWidgets('Moving widgets with TickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving widgets with TickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { final GlobalKey tickingWidgetKey = GlobalKey(); Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { return TickerMode( @@ -185,7 +186,7 @@ void main() { expect(tickingState.ticker.isTicking, isFalse); }); - testWidgets('Ticking widgets in old route do not rebuild when new route is pushed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticking widgets in old route do not rebuild when new route is pushed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( routes: { '/foo' : (BuildContext context) => const Text('New route'), diff --git a/packages/flutter/test/widgets/ticker_provider_test.dart b/packages/flutter/test/widgets/ticker_provider_test.dart index 2f342dae0b..1c65f075d7 100644 --- a/packages/flutter/test/widgets/ticker_provider_test.dart +++ b/packages/flutter/test/widgets/ticker_provider_test.dart @@ -6,9 +6,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TickerMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerMode', (WidgetTester tester) async { const Widget widget = TickerMode( enabled: false, child: CircularProgressIndicator(), @@ -34,7 +35,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('Navigation with TickerMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation with TickerMode', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: const LinearProgressIndicator(), routes: { @@ -56,7 +57,7 @@ void main() { expect(tester.binding.transientCallbackCount, 1); }); - testWidgets('SingleTickerProviderStateMixin can handle not being used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin can handle not being used', (WidgetTester tester) async { const Widget widget = BoringTickerTest(); expect(widget.toString, isNot(throwsException)); @@ -96,7 +97,7 @@ void main() { )); }); - testWidgets('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { final GlobalKey<_SingleTickerTestState> key = GlobalKey<_SingleTickerTestState>(); final Widget widget = _SingleTickerTest(key: key); await tester.pumpWidget(widget); @@ -136,7 +137,7 @@ void main() { } }); - testWidgets('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { final GlobalKey<_SingleTickerTestState> key = GlobalKey<_SingleTickerTestState>(); final Widget widget = _SingleTickerTest(key: key); await tester.pumpWidget(widget); @@ -176,7 +177,7 @@ void main() { } }); - testWidgets('TickerProviderStateMixin dispose while any ticker is active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerProviderStateMixin dispose while any ticker is active', (WidgetTester tester) async { final GlobalKey<_MultipleTickerTestState> key = GlobalKey<_MultipleTickerTestState>(); final Widget widget = _MultipleTickerTest(key: key); await tester.pumpWidget(widget); @@ -216,12 +217,12 @@ void main() { }); }); - testWidgets('SingleTickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { await tester.pumpWidget(const _SingleTickerTest()); expect(tester.state<_SingleTickerTestState>(find.byType(_SingleTickerTest)).toStringCount, 0); }); - testWidgets('TickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { await tester.pumpWidget(const _MultipleTickerTest()); expect(tester.state<_MultipleTickerTestState>(find.byType(_MultipleTickerTest)).toStringCount, 0); }); diff --git a/packages/flutter/test/widgets/title_test.dart b/packages/flutter/test/widgets/title_test.dart index 71dbf6f9e1..e61a2a86ec 100644 --- a/packages/flutter/test/widgets/title_test.dart +++ b/packages/flutter/test/widgets/title_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toString control test', (WidgetTester tester) async { final Widget widget = Title( color: const Color(0xFF00FF00), title: 'Awesome app', @@ -16,7 +17,7 @@ void main() { expect(widget.toString, isNot(throwsException)); }); - testWidgets('should handle having no title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should handle having no title', (WidgetTester tester) async { final Title widget = Title( color: const Color(0xFF00FF00), child: Container(), @@ -26,14 +27,14 @@ void main() { expect(widget.color, equals(const Color(0xFF00FF00))); }); - testWidgets('should not allow non-opaque color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should not allow non-opaque color', (WidgetTester tester) async { expect(() => Title( color: const Color(0x00000000), child: Container(), ), throwsAssertionError); }); - testWidgets('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async { final List log = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { diff --git a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart index 11a19f5362..fd76a6d0c4 100644 --- a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart +++ b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart @@ -4,10 +4,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TrackingScrollController saves offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TrackingScrollController saves offset', (WidgetTester tester) async { final TrackingScrollController controller = TrackingScrollController(); + addTearDown(controller.dispose); const double listItemHeight = 100.0; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/transformed_scrollable_test.dart b/packages/flutter/test/widgets/transformed_scrollable_test.dart index 5a57556d78..a11485de5d 100644 --- a/packages/flutter/test/widgets/transformed_scrollable_test.dart +++ b/packages/flutter/test/widgets/transformed_scrollable_test.dart @@ -6,10 +6,13 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Scrollable scaled up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable scaled up', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.scale( @@ -52,8 +55,10 @@ void main() { expect(controller.offset, 42.5); // 85.0 - (85.0 / 2) }); - testWidgets('Scrollable scaled down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable scaled down', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.scale( @@ -96,8 +101,10 @@ void main() { expect(controller.offset, 0.0); // 340.0 - (170.0 * 2) }); - testWidgets('Scrollable rotated 90 degrees', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable rotated 90 degrees', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.rotate( @@ -136,8 +143,10 @@ void main() { expect(controller.offset, 30.0); // 100.0 - 70.0 }); - testWidgets('Perspective transform on scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Perspective transform on scrollable', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform( diff --git a/packages/flutter/test/widgets/transitions_test.dart b/packages/flutter/test/widgets/transitions_test.dart index 9af19cf513..92f74baf60 100644 --- a/packages/flutter/test/widgets/transitions_test.dart +++ b/packages/flutter/test/widgets/transitions_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toString control test', (WidgetTester tester) async { const Widget widget = FadeTransition( opacity: kAlwaysCompleteAnimation, child: Text('Ready', textDirection: TextDirection.ltr), @@ -47,7 +48,7 @@ void main() { controller = AnimationController(vsync: const TestVSync()); }); - testWidgets('decoration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('decoration test', (WidgetTester tester) async { final DecoratedBoxTransition transitionUnderTest = DecoratedBoxTransition( decoration: decorationTween.animate(controller), @@ -95,7 +96,7 @@ void main() { expect(actualDecoration.boxShadow, null); }); - testWidgets('animations work with curves test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animations work with curves test', (WidgetTester tester) async { final Animation curvedDecorationAnimation = decorationTween.animate(CurvedAnimation( parent: controller, @@ -144,7 +145,7 @@ void main() { }); }); - testWidgets('AlignTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlignTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation alignmentTween = AlignmentTween( begin: Alignment.centerLeft, @@ -168,7 +169,7 @@ void main() { expect(actualAlignment, const Alignment(0.0, 0.5)); }); - testWidgets('RelativePositionedTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RelativePositionedTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation rectTween = RectTween( begin: const Rect.fromLTWH(0, 0, 30, 40), @@ -214,7 +215,7 @@ void main() { expect(renderBox.size, equals(const Size(665, 420))); }); - testWidgets('AlignTransition keeps width and height factors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlignTransition keeps width and height factors', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation alignmentTween = AlignmentTween( begin: Alignment.centerLeft, @@ -235,7 +236,7 @@ void main() { expect(actualAlign.heightFactor, 0.4); }); - testWidgets('SizeTransition clamps negative size factors - vertical axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizeTransition clamps negative size factors - vertical axis', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: -1.0, end: 1.0).animate(controller); @@ -265,7 +266,7 @@ void main() { expect(actualPositionedBox.heightFactor, 1.0); }); - testWidgets('SizeTransition clamps negative size factors - horizontal axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizeTransition clamps negative size factors - horizontal axis', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: -1.0, end: 1.0).animate(controller); @@ -296,7 +297,7 @@ void main() { expect(actualPositionedBox.widthFactor, 1.0); }); - testWidgets('MatrixTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MatrixTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = MatrixTransition( alignment: Alignment.topRight, @@ -336,7 +337,7 @@ void main() { ])..transpose()); }); - testWidgets('MatrixTransition maintains chosen alignment during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MatrixTransition maintains chosen alignment during animation', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = MatrixTransition( alignment: Alignment.topRight, @@ -357,7 +358,7 @@ void main() { expect(actualAlignment, Alignment.topRight); }); - testWidgets('RotationTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RotationTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = RotationTransition( alignment: Alignment.topRight, @@ -396,7 +397,7 @@ void main() { ])..transpose())); }); - testWidgets('RotationTransition maintains chosen alignment during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RotationTransition maintains chosen alignment during animation', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = RotationTransition( alignment: Alignment.topRight, @@ -426,7 +427,7 @@ void main() { ); return opacityWidget.opacity.value; } - testWidgets('animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -469,7 +470,7 @@ void main() { ); return opacityWidget.opacity.value; } - testWidgets('animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Localizations( @@ -519,7 +520,7 @@ void main() { }); group('MatrixTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -582,7 +583,7 @@ void main() { }); group('ScaleTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -635,7 +636,7 @@ void main() { }); group('RotationTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -688,9 +689,11 @@ void main() { }); group('Builders', () { - testWidgets('AnimatedBuilder rebuilds when changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedBuilder rebuilds when changed', (WidgetTester tester) async { final GlobalKey redrawKey = GlobalKey(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -716,10 +719,12 @@ void main() { expect(redrawKey.currentState!.redraws, equals(2)); }); - testWidgets("AnimatedBuilder doesn't rebuild the child", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AnimatedBuilder doesn't rebuild the child", (WidgetTester tester) async { final GlobalKey redrawKey = GlobalKey(); final GlobalKey redrawKeyChild = GlobalKey(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -750,9 +755,11 @@ void main() { expect(redrawKeyChild.currentState!.redraws, equals(1)); }); - testWidgets('ListenableBuilder rebuilds when changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListenableBuilder rebuilds when changed', (WidgetTester tester) async { final GlobalKey redrawKey = GlobalKey(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -778,10 +785,12 @@ void main() { expect(redrawKey.currentState!.redraws, equals(2)); }); - testWidgets("ListenableBuilder doesn't rebuild the child", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListenableBuilder doesn't rebuild the child", (WidgetTester tester) async { final GlobalKey redrawKey = GlobalKey(); final GlobalKey redrawKeyChild = GlobalKey(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/tree_shape_test.dart b/packages/flutter/test/widgets/tree_shape_test.dart index 306bacfb18..ab1c97ff92 100644 --- a/packages/flutter/test/widgets/tree_shape_test.dart +++ b/packages/flutter/test/widgets/tree_shape_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Providing a RenderObjectWidget directly to the RootWidget fails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Providing a RenderObjectWidget directly to the RootWidget fails', (WidgetTester tester) async { // No render tree exists to attach the RenderObjectWidget to. await pumpWidgetWithoutViewWrapper( tester: tester, @@ -23,7 +24,7 @@ void main() { )); }); - testWidgets('Moving a RenderObjectWidget to the RootWidget via GlobalKey fails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a RenderObjectWidget to the RootWidget via GlobalKey fails', (WidgetTester tester) async { final Widget globalKeyedWidget = ColoredBox( key: GlobalKey(), color: Colors.red, @@ -50,7 +51,7 @@ void main() { )); }); - testWidgets('A View cannot be a child of a render object widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A View cannot be a child of a render object widget', (WidgetTester tester) async { await tester.pumpWidget(Center( child: View( view: FakeView(tester.view), @@ -65,7 +66,7 @@ void main() { )); }); - testWidgets('The child of a ViewAnchor cannot be a View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The child of a ViewAnchor cannot be a View', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( child: View( @@ -82,7 +83,7 @@ void main() { )); }); - testWidgets('A View can not be moved via GlobalKey to be a child of a RenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A View can not be moved via GlobalKey to be a child of a RenderObject', (WidgetTester tester) async { final Widget globalKeyedView = View( key: GlobalKey(), view: FakeView(tester.view), @@ -110,7 +111,7 @@ void main() { )); }); - testWidgets('The view property of a ViewAnchor cannot be a render object widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The view property of a ViewAnchor cannot be a render object widget', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: const ColoredBox(color: Colors.red), @@ -125,7 +126,7 @@ void main() { )); }); - testWidgets('A RenderObject cannot be moved into the view property of a ViewAnchor via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A RenderObject cannot be moved into the view property of a ViewAnchor via GlobalKey', (WidgetTester tester) async { final Widget globalKeyedWidget = ColoredBox( key: GlobalKey(), color: Colors.red, @@ -152,7 +153,7 @@ void main() { )); }); - testWidgets('ViewAnchor cannot be used at the top of the widget tree (outside of View)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor cannot be used at the top of the widget tree (outside of View)', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: const ViewAnchor( @@ -167,7 +168,7 @@ void main() { )); }); - testWidgets('ViewAnchor cannot be moved to the top of the widget tree (outside of View) via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor cannot be moved to the top of the widget tree (outside of View) via GlobalKey', (WidgetTester tester) async { final Widget globalKeyedViewAnchor = ViewAnchor( key: GlobalKey(), child: const SizedBox(), @@ -194,7 +195,7 @@ void main() { )); }); - testWidgets('View can be used at the top of the widget tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be used at the top of the widget tree', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: View( @@ -206,7 +207,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('View can be moved to the top of the widget tree view GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be moved to the top of the widget tree view GlobalKey', (WidgetTester tester) async { final Widget globalKeyView = View( view: FakeView(tester.view), child: const ColoredBox(color: Colors.red), @@ -235,7 +236,7 @@ void main() { expect(find.byType(ColoredBox), findsOneWidget); }); - testWidgets('ViewCollection can be used at the top of the widget tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection can be used at the top of the widget tree', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -251,7 +252,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('ViewCollection cannot be used inside a View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection cannot be used inside a View', (WidgetTester tester) async { await tester.pumpWidget( ViewCollection( views: [ @@ -270,7 +271,7 @@ void main() { )); }); - testWidgets('ViewCollection can be used as ViewAnchor.view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection can be used as ViewAnchor.view', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: ViewCollection( @@ -288,7 +289,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('ViewCollection cannot have render object widgets as children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection cannot have render object widgets as children', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -305,7 +306,7 @@ void main() { )); }); - testWidgets('Views can be moved in and out of ViewCollections via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Views can be moved in and out of ViewCollections via GlobalKey', (WidgetTester tester) async { final Widget greenView = View( key: GlobalKey(debugLabel: 'green'), view: tester.view, @@ -350,7 +351,7 @@ void main() { expect(find.byType(ColoredBox), findsNWidgets(2)); }); - testWidgets('Can move stuff between views via global key: viewA -> viewB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff between views via global key: viewA -> viewB', (WidgetTester tester) async { final FlutterView greenView = tester.view; final FlutterView redView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( @@ -455,7 +456,7 @@ void main() { expect(leafRenderObject[redView.viewId], isA()); }); - testWidgets('Can move stuff between views via global key: viewB -> viewA', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff between views via global key: viewB -> viewA', (WidgetTester tester) async { final FlutterView greenView = tester.view; final FlutterView redView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( @@ -560,7 +561,7 @@ void main() { expect(leafRenderObject[greenView.viewId], isA()); }); - testWidgets('Can move stuff out of a view that is going away, viewA -> ViewB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is going away, viewA -> ViewB', (WidgetTester tester) async { final FlutterView greenView = tester.view; final Key greenKey = UniqueKey(); final FlutterView redView = FakeView(tester.view); @@ -641,7 +642,7 @@ void main() { ); }); - testWidgets('Can move stuff out of a view that is going away, viewB -> ViewA', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is going away, viewB -> ViewA', (WidgetTester tester) async { final FlutterView greenView = tester.view; final Key greenKey = UniqueKey(); final FlutterView redView = FakeView(tester.view); @@ -722,7 +723,7 @@ void main() { ); }); - testWidgets('Can move stuff out of a view that is moving itself, stuff ends up before view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is moving itself, stuff ends up before view', (WidgetTester tester) async { final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); final Key key3 = UniqueKey(); @@ -808,7 +809,7 @@ void main() { )); }); - testWidgets('Can move stuff out of a view that is moving itself, stuff ends up after view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is moving itself, stuff ends up after view', (WidgetTester tester) async { final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); final Key key3 = UniqueKey(); @@ -896,7 +897,7 @@ void main() { )); }); - testWidgets('Can globalkey move down the tree from a view that is going away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can globalkey move down the tree from a view that is going away', (WidgetTester tester) async { final FlutterView anchorView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( key: GlobalKey(), @@ -973,7 +974,7 @@ void main() { ); }); - testWidgets('RenderObjects are disposed when a view goes away from a ViewAnchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjects are disposed when a view goes away from a ViewAnchor', (WidgetTester tester) async { final FlutterView anchorView = FakeView(tester.view); await tester.pumpWidget( @@ -1003,7 +1004,7 @@ void main() { expect(box.debugDisposed, isTrue); }); - testWidgets('RenderObjects are disposed when a view goes away from a ViewCollection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjects are disposed when a view goes away from a ViewCollection', (WidgetTester tester) async { final FlutterView redView = tester.view; final FlutterView greenView = FakeView(tester.view); @@ -1044,7 +1045,7 @@ void main() { expect(box.debugDisposed, isTrue); }); - testWidgets('View can be wrapped and unwrapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be wrapped and unwrapped', (WidgetTester tester) async { final Widget view = View( view: tester.view, child: const SizedBox(), @@ -1077,7 +1078,7 @@ void main() { expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); }); - testWidgets('ViewAnchor with View can be wrapped and unwrapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor with View can be wrapped and unwrapped', (WidgetTester tester) async { final Widget viewAnchor = ViewAnchor( view: View( view: FakeView(tester.view), @@ -1102,7 +1103,7 @@ void main() { expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); }); - testWidgets('Moving a View keeps its semantics tree stable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a View keeps its semantics tree stable', (WidgetTester tester) async { final Widget view = View( // No explicit key, we rely on the implicit key of the underlying RawView. view: tester.view, diff --git a/packages/flutter/test/widgets/tween_animation_builder_test.dart b/packages/flutter/test/widgets/tween_animation_builder_test.dart index afad96ecfe..4c19cda2df 100644 --- a/packages/flutter/test/widgets/tween_animation_builder_test.dart +++ b/packages/flutter/test/widgets/tween_animation_builder_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Animates forward when built', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animates forward when built', (WidgetTester tester) async { final List values = []; int endCount = 0; await tester.pumpWidget( @@ -37,7 +38,7 @@ void main() { expect(values, [10, 60, 110]); }); - testWidgets('No initial animation when begin=null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No initial animation when begin=null', (WidgetTester tester) async { final List values = []; int endCount = 0; await tester.pumpWidget( @@ -61,7 +62,7 @@ void main() { }); - testWidgets('No initial animation when begin=end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No initial animation when begin=end', (WidgetTester tester) async { final List values = []; int endCount = 0; await tester.pumpWidget( @@ -84,7 +85,7 @@ void main() { expect(values, [100]); }); - testWidgets('Replace tween animates new tween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Replace tween animates new tween', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -112,7 +113,7 @@ void main() { expect(values, [0, 100, 100, 150, 200]); }); - testWidgets('Curve is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Curve is respected', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween, required Curve curve}) { return TweenAnimationBuilder( @@ -142,7 +143,7 @@ void main() { expect(values, [100, 150]); }); - testWidgets('Duration is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Duration is respected', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween, required Duration duration}) { return TweenAnimationBuilder( @@ -170,7 +171,7 @@ void main() { expect(values, [100, 125]); }); - testWidgets('Child is integrated into tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child is integrated into tree', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -189,7 +190,7 @@ void main() { }); group('Change tween gapless while', () { - testWidgets('running forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('running forward', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -224,7 +225,7 @@ void main() { values.clear(); }); - testWidgets('running forward and then reverse with same tween instance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('running forward and then reverse with same tween instance', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -254,7 +255,7 @@ void main() { }); }); - testWidgets('Changing tween while gapless tween change is in progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing tween while gapless tween change is in progress', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -294,7 +295,7 @@ void main() { expect(values, [175, 338, 501]); }); - testWidgets('Changing curve while no animation is running does not trigger animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing curve while no animation is running does not trigger animation', (WidgetTester tester) async { final List values = []; Widget buildWidget({required Curve curve}) { return TweenAnimationBuilder( @@ -323,7 +324,7 @@ void main() { expect(values, [100]); }); - testWidgets('Setting same tween and direction does not trigger animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting same tween and direction does not trigger animation', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -352,7 +353,7 @@ void main() { expect(values, everyElement(100)); }); - testWidgets('Setting same tween and direction while gapless animation is in progress works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting same tween and direction while gapless animation is in progress works', (WidgetTester tester) async { final List values = []; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder( @@ -388,7 +389,7 @@ void main() { expect(values, everyElement(300)); }); - testWidgets('Works with nullable tweens', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Works with nullable tweens', (WidgetTester tester) async { final List values = []; await tester.pumpWidget( TweenAnimationBuilder( diff --git a/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart b/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart index 9da89311ce..f1cb8d5c30 100644 --- a/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/gestures/monodrag.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'two_dimensional_utils.dart'; @@ -19,34 +20,40 @@ Widget? _testChildBuilder(BuildContext context, ChildVicinity vicinity) { void main() { group('TwoDimensionalScrollView',() { - testWidgets('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { + testWidgetsWithLeakTracking('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { final List exceptions = []; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { exceptions.add(details.exception); }; // Horizontal wrong + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate1 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), horizontalDetails: const ScrollableDetails.vertical(), // Horizontal has default const ScrollableDetails.horizontal() ), )); // Vertical wrong + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate2 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), verticalDetails: const ScrollableDetails.horizontal(), // Horizontal has default const ScrollableDetails.horizontal() ), )); // Both wrong + late final TwoDimensionalChildBuilderDelegate delegate3; + addTearDown(() => delegate3.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate3 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), verticalDetails: const ScrollableDetails.horizontal(), horizontalDetails: const ScrollableDetails.vertical(), ), @@ -60,15 +67,19 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('ScrollableDetails.controller can set initial scroll positions, modify within bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollableDetails.controller can set initial scroll positions, modify within bounds', (WidgetTester tester) async { final ScrollController verticalController = ScrollController(initialScrollOffset: 100); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(initialScrollOffset: 50); + addTearDown(horizontalController.dispose); + late final TwoDimensionalChildBuilderDelegate delegate; + addTearDown(() => delegate.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( verticalDetails: ScrollableDetails.vertical(controller: verticalController), horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController), - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, maxXIndex: 99, maxYIndex: 99, @@ -99,13 +110,20 @@ void main() { expect(horizontalController.position.pixels, 19200); }, variant: TargetPlatformVariant.all()); - testWidgets('Properly assigns the PrimaryScrollController to the main axis on the correct platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Properly assigns the PrimaryScrollController to the main axis on the correct platform', (WidgetTester tester) async { late ScrollController controller; Widget buildForPrimaryScrollController({ bool? explicitPrimary, Axis mainAxis = Axis.vertical, bool addControllerConflict = false, }) { + final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); + final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); + late final TwoDimensionalChildBuilderDelegate delegate; + addTearDown(() => delegate.dispose()); + return MaterialApp( home: PrimaryScrollController( controller: controller, @@ -114,15 +132,15 @@ void main() { primary: explicitPrimary, verticalDetails: ScrollableDetails.vertical( controller: addControllerConflict && mainAxis == Axis.vertical - ? ScrollController() + ? verticalController : null ), horizontalDetails: ScrollableDetails.horizontal( controller: addControllerConflict && mainAxis == Axis.horizontal - ? ScrollController() + ? horizontalController : null ), - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, maxXIndex: 99, maxYIndex: 99, @@ -134,6 +152,7 @@ void main() { // Horizontal default - horizontal never automatically adopts PSC controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, )); @@ -151,6 +170,7 @@ void main() { // Horizontal explicitly true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: true, @@ -171,6 +191,7 @@ void main() { // Horizontal explicitly false controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: false, @@ -190,6 +211,7 @@ void main() { // Vertical default controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController()); await tester.pumpAndSettle(); @@ -209,6 +231,7 @@ void main() { // Vertical explicitly true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: true, )); @@ -228,6 +251,7 @@ void main() { // Vertical explicitly false controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: false, )); @@ -253,6 +277,7 @@ void main() { // Vertical asserts ScrollableDetails.controller has not been provided if // primary is explicitly set controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: true, addControllerConflict: true, @@ -268,6 +293,7 @@ void main() { // Horizontal asserts ScrollableDetails.controller has not been provided // if primary is explicitly set true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: true, @@ -282,12 +308,14 @@ void main() { FlutterError.onError = oldHandler; }, variant: TargetPlatformVariant.all()); - testWidgets('TwoDimensionalScrollable receives the correct details from TwoDimensionalScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TwoDimensionalScrollable receives the correct details from TwoDimensionalScrollView', (WidgetTester tester) async { late BuildContext capturedContext; // Default + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate1 = TwoDimensionalChildBuilderDelegate( builder: (BuildContext context, ChildVicinity vicinity) { capturedContext = context; return Text(vicinity.toString()); @@ -305,13 +333,15 @@ void main() { expect(scrollable.widget.dragStartBehavior, DragStartBehavior.start); // Customized + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( verticalDetails: const ScrollableDetails.vertical(reverse: true), horizontalDetails: const ScrollableDetails.horizontal(reverse: true), diagonalDragBehavior: DiagonalDragBehavior.weightedContinuous, dragStartBehavior: DragStartBehavior.down, - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate2 = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, ), ), diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index e65f5319ba..903dfe8c00 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -7,16 +7,19 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'two_dimensional_utils.dart'; void main() { group('TwoDimensionalChildDelegate', () { group('TwoDimensionalChildBuilderDelegate', () { - testWidgets('repaintBoundaries', (WidgetTester tester) async { + testWidgetsWithLeakTracking('repaintBoundaries', (WidgetTester tester) async { // Default - adds repaint boundaries + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(simpleBuilderTest( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate1 = TwoDimensionalChildBuilderDelegate( // Only build 1 child maxXIndex: 0, maxYIndex: 0, @@ -43,8 +46,10 @@ void main() { } // None + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(simpleBuilderTest( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate2 = TwoDimensionalChildBuilderDelegate( // Only build 1 child maxXIndex: 0, maxYIndex: 0, @@ -72,7 +77,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('will return null from build for exceeding maxXIndex and maxYIndex', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will return null from build for exceeding maxXIndex and maxYIndex', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( // Only build 1 child @@ -88,6 +93,8 @@ void main() { ); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -185,7 +192,7 @@ void main() { ); }); - testWidgets('throws an error when builder throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('throws an error when builder throws', (WidgetTester tester) async { final List exceptions = []; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { @@ -200,6 +207,8 @@ void main() { throw 'Builder error!'; } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -211,13 +220,14 @@ void main() { expect(exceptions[0] as String, contains('Builder error!')); }, variant: TargetPlatformVariant.all()); - testWidgets('shouldRebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shouldRebuild', (WidgetTester tester) async { expect(builderDelegate.shouldRebuild(builderDelegate), isTrue); }, variant: TargetPlatformVariant.all()); - testWidgets('builder delegate supports automatic keep alive - default true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder delegate supports automatic keep alive - default true', (WidgetTester tester) async { const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final UniqueKey checkBoxKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -232,6 +242,7 @@ void main() { ); } ); + addTearDown(builderDelegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: builderDelegate, @@ -301,9 +312,10 @@ void main() { ); }); - testWidgets('builder delegate will not add automatic keep alives', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder delegate will not add automatic keep alives', (WidgetTester tester) async { const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final UniqueKey checkBoxKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -319,6 +331,7 @@ void main() { ); } ); + addTearDown(builderDelegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: builderDelegate, @@ -383,7 +396,7 @@ void main() { }); group('TwoDimensionalChildListDelegate', () { - testWidgets('repaintBoundaries', (WidgetTester tester) async { + testWidgetsWithLeakTracking('repaintBoundaries', (WidgetTester tester) async { final List> children = >[]; children.add([ const SizedBox( @@ -393,8 +406,10 @@ void main() { ) ]); // Default - adds repaint boundaries + late final TwoDimensionalChildListDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(simpleListTest( - delegate: TwoDimensionalChildListDelegate( + delegate: delegate1 = TwoDimensionalChildListDelegate( // Only builds 1 child children: children, ) @@ -426,8 +441,10 @@ void main() { } // None + late final TwoDimensionalChildListDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(simpleListTest( - delegate: TwoDimensionalChildListDelegate( + delegate: delegate2 = TwoDimensionalChildListDelegate( // Different children triggers rebuild children: >[[Container()]], addRepaintBoundaries: false, @@ -451,7 +468,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('will return null for a ChildVicinity outside of list bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will return null for a ChildVicinity outside of list bounds', (WidgetTester tester) async { final List> children = >[]; children.add([ const SizedBox( @@ -464,6 +481,7 @@ void main() { // Only builds 1 child children: children, ); + addTearDown(delegate.dispose); // X index expect( @@ -483,7 +501,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('shouldRebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shouldRebuild', (WidgetTester tester) async { final List> children = >[]; children.add([ const SizedBox( @@ -496,18 +514,20 @@ void main() { // Only builds 1 child children: children, ); + addTearDown(delegate.dispose); expect(delegate.shouldRebuild(delegate), isFalse); final List> newChildren = >[]; final TwoDimensionalChildListDelegate oldDelegate = TwoDimensionalChildListDelegate( children: newChildren, ); + addTearDown(oldDelegate.dispose); expect(delegate.shouldRebuild(oldDelegate), isTrue); }, variant: TargetPlatformVariant.all()); }); - testWidgets('list delegate supports automatic keep alive - default true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('list delegate supports automatic keep alive - default true', (WidgetTester tester) async { final UniqueKey checkBoxKey = UniqueKey(); final Widget originCell = SizedBox.square( dimension: 200, @@ -516,6 +536,7 @@ void main() { ); const Widget otherCell = SizedBox.square(dimension: 200); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( children: >[ [originCell, otherCell, otherCell, otherCell, otherCell], @@ -525,6 +546,7 @@ void main() { [otherCell, otherCell, otherCell, otherCell, otherCell], ], ); + addTearDown(listDelegate.dispose); await tester.pumpWidget(simpleListTest( delegate: listDelegate, @@ -594,7 +616,7 @@ void main() { ); }); - testWidgets('list delegate will not add automatic keep alives', (WidgetTester tester) async { + testWidgetsWithLeakTracking('list delegate will not add automatic keep alives', (WidgetTester tester) async { final UniqueKey checkBoxKey = UniqueKey(); final Widget originCell = SizedBox.square( dimension: 200, @@ -603,6 +625,7 @@ void main() { ); const Widget otherCell = SizedBox.square(dimension: 200); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( addAutomaticKeepAlives: false, children: >[ @@ -613,6 +636,7 @@ void main() { [otherCell, otherCell, otherCell, otherCell, otherCell], ], ); + addTearDown(listDelegate.dispose); await tester.pumpWidget(simpleListTest( delegate: listDelegate, @@ -677,7 +701,7 @@ void main() { }); group('TwoDimensionalScrollable', () { - testWidgets('.of, .maybeOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('.of, .maybeOf', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -687,6 +711,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -714,7 +740,7 @@ void main() { expect(TwoDimensionalScrollable.maybeOf(capturedContext), isNull); }, variant: TargetPlatformVariant.all()); - testWidgets('horizontal and vertical getters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('horizontal and vertical getters', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -724,6 +750,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -734,7 +762,7 @@ void main() { expect(scrollable.horizontalScrollable.position.pixels, 0.0); }, variant: TargetPlatformVariant.all()); - testWidgets('creates fallback ScrollControllers if not provided by ScrollableDetails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('creates fallback ScrollControllers if not provided by ScrollableDetails', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -744,6 +772,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -798,7 +828,7 @@ void main() { FlutterError.onError = oldHandler; }, variant: TargetPlatformVariant.all()); - testWidgets('correctly sets restorationIds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly sets restorationIds', (WidgetTester tester) async { late BuildContext capturedContext; // with restorationID set await tester.pumpWidget(WidgetsApp( @@ -868,7 +898,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('Restoration works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Restoration works', (WidgetTester tester) async { await tester.pumpWidget(WidgetsApp( color: const Color(0xFFFFFFFF), restorationScopeId: 'Test ID', @@ -893,7 +923,7 @@ void main() { await restoreScrollAndVerify(tester); }, variant: TargetPlatformVariant.all()); - testWidgets('Inner Scrollables receive the correct details from TwoDimensionalScrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inner Scrollables receive the correct details from TwoDimensionalScrollable', (WidgetTester tester) async { // Default late BuildContext capturedContext; await tester.pumpWidget(TwoDimensionalScrollable( @@ -939,7 +969,9 @@ void main() { // Customized final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); double calculator(_) => 0.0; await tester.pumpWidget(TwoDimensionalScrollable( incrementCalculator: calculator, @@ -1009,10 +1041,12 @@ void main() { }, variant: TargetPlatformVariant.all()); group('DiagonalDragBehavior', () { - testWidgets('none (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('none (default)', (WidgetTester tester) async { // Vertical and horizontal axes are locked. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1059,11 +1093,13 @@ void main() { expect(horizontalController.position.pixels, 140.0); }, variant: TargetPlatformVariant.all()); - testWidgets('weightedEvent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('weightedEvent', (WidgetTester tester) async { // For weighted event, the winning axis is locked for the duration of // the gesture. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1181,13 +1217,15 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.all()); - testWidgets('weightedContinuous', (WidgetTester tester) async { + testWidgetsWithLeakTracking('weightedContinuous', (WidgetTester tester) async { // For weighted continuous, the winning axis can change if the axis // differential for the gesture exceeds kTouchSlop. So it can lock, and // remain locked, if the user maintains a generally straight gesture, // otherwise it will unlock and re-evaluate. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1238,10 +1276,12 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.all()); - testWidgets('free', (WidgetTester tester) async { + testWidgetsWithLeakTracking('free', (WidgetTester tester) async { // For free, anything goes. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1283,7 +1323,7 @@ void main() { }); }); - testWidgets('TwoDimensionalViewport asserts against axes mismatch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TwoDimensionalViewport asserts against axes mismatch', (WidgetTester tester) async { // Horizontal mismatch expect( () { @@ -1458,7 +1498,7 @@ void main() { ); }); - testWidgets('getters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getters', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1467,6 +1507,7 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); final RenderSimpleBuilderTableViewport renderViewport = RenderSimpleBuilderTableViewport( verticalOffset: ViewportOffset.fixed(10.0), verticalAxisDirection: AxisDirection.down, @@ -1476,6 +1517,7 @@ void main() { mainAxis: Axis.vertical, childManager: _NullBuildContext(), ); + addTearDown(renderViewport.dispose); expect(renderViewport.clipBehavior, Clip.hardEdge); expect(renderViewport.cacheExtent, RenderAbstractViewport.defaultCacheExtent); @@ -1510,7 +1552,7 @@ void main() { expect(viewport.viewportDimension, const Size(800.0, 600.0)); }, variant: TargetPlatformVariant.all()); - testWidgets('Children are organized according to mainAxis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Children are organized according to mainAxis', (WidgetTester tester) async { final Map childKeys = {}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1520,6 +1562,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); TwoDimensionalViewportParentData parentDataOf(RenderBox child) { return child.parentData! as TwoDimensionalViewportParentData; } @@ -1596,7 +1639,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('sets up parent data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sets up parent data', (WidgetTester tester) async { // Also tests computeAbsolutePaintOffsetFor & computeChildPaintExtent // Regression test for https://github.com/flutter/flutter/issues/128723 final Map childKeys = {}; @@ -1608,6 +1651,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); // parent data is TwoDimensionalViewportParentData TwoDimensionalViewportParentData parentDataOf(RenderBox child) { @@ -1707,7 +1751,9 @@ void main() { // Change the scroll positions to test partially visible. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController), @@ -1727,7 +1773,7 @@ void main() { expect(childParentData.layoutOffset, const Offset(-50.0, -50.0)); }, variant: TargetPlatformVariant.all()); - testWidgets('debugDescribeChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugDescribeChildren', (WidgetTester tester) async { final Map childKeys = {}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1737,6 +1783,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -1798,7 +1845,7 @@ void main() { expect((exceptions[0] as FlutterError).message, contains('unbounded')); }, variant: TargetPlatformVariant.all()); - testWidgets('computeDryLayout asserts axes are bounded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('computeDryLayout asserts axes are bounded', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1807,6 +1854,8 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); + // Call computeDryLayout with unbounded constraints await tester.pumpWidget(simpleBuilderTest(delegate: delegate)); final RenderTwoDimensionalViewport viewport = getViewport( @@ -1827,7 +1876,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('correctly resizes dimensions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly resizes dimensions', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1836,6 +1885,8 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -1857,7 +1908,7 @@ void main() { tester.view.resetDevicePixelRatio(); }, variant: TargetPlatformVariant.all()); - testWidgets('Rebuilds when delegate changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rebuilds when delegate changes', (WidgetTester tester) async { final UniqueKey firstChildKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1867,6 +1918,8 @@ void main() { return SizedBox.square(key: firstChildKey, dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -1882,6 +1935,8 @@ void main() { return Container(key: newChildKey, height: 300, width: 300, color: const Color(0xFFFFFFFF)); } ); + addTearDown(() => newDelegate.dispose()); + await tester.pumpWidget(simpleBuilderTest( delegate: newDelegate, )); @@ -1892,7 +1947,7 @@ void main() { expect(viewport.firstChild, tester.renderObject(find.byKey(newChildKey))); }, variant: TargetPlatformVariant.all()); - testWidgets('hitTestChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTestChildren', (WidgetTester tester) async { final List taps = []; final Map childKeys = {}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( @@ -1913,6 +1968,7 @@ void main() { ); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -1961,7 +2017,7 @@ void main() { expect(taps.contains(const ChildVicinity(xIndex: 5, yIndex: 5)), isFalse); }, variant: TargetPlatformVariant.all()); - testWidgets('getChildFor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getChildFor', (WidgetTester tester) async { final Map childKeys = {}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1971,6 +2027,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2007,6 +2064,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2039,6 +2097,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not set dimensions @@ -2048,9 +2108,10 @@ void main() { expect(error.message, contains('was not given content dimensions')); }, variant: TargetPlatformVariant.all()); - testWidgets('will not rebuild a child if it can be reused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will not rebuild a child if it can be reused', (WidgetTester tester) async { final List builtChildren = []; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, maxYIndex: 5, @@ -2059,6 +2120,7 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2087,6 +2149,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not set the layoutOffset of @@ -2105,6 +2169,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not actually layout the @@ -2115,7 +2181,7 @@ void main() { expect(error.toString(), contains('child.hasSize')); }, variant: TargetPlatformVariant.all()); - testWidgets('does not support intrinsics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not support intrinsics', (WidgetTester tester) async { final Map childKeys = {}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -2125,6 +2191,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, diff --git a/packages/flutter/test/widgets/undo_history_test.dart b/packages/flutter/test/widgets/undo_history_test.dart index dffb059bfc..b5a80d09b4 100644 --- a/packages/flutter/test/widgets/undo_history_test.dart +++ b/packages/flutter/test/widgets/undo_history_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'editable_text_utils.dart'; @@ -30,9 +31,12 @@ void main() { Future sendUndo(WidgetTester tester) => sendUndoRedo(tester); Future sendRedo(WidgetTester tester) => sendUndoRedo(tester, true); - testWidgets('allows undo and redo to be called programmatically from the UndoHistoryController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows undo and redo to be called programmatically from the UndoHistoryController', (WidgetTester tester) async { final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -119,9 +123,12 @@ void main() { expect(controller.value.canRedo, false); }, variant: TargetPlatformVariant.all()); - testWidgets('allows undo and redo to be called using the keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows undo and redo to be called using the keyboard', (WidgetTester tester) async { final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -211,9 +218,12 @@ void main() { expect(controller.value.canRedo, false); }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('duplicate changes do not affect the undo history', (WidgetTester tester) async { + testWidgetsWithLeakTracking('duplicate changes do not affect the undo history', (WidgetTester tester) async { final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -261,11 +271,14 @@ void main() { expect(controller.value.canRedo, true); }, variant: TargetPlatformVariant.all()); - testWidgets('ignores value changes pushed during onTriggered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores value changes pushed during onTriggered', (WidgetTester tester) async { final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); int Function(int newValue) valueToUse = (int value) => value; final GlobalKey> key = GlobalKey>(); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -309,16 +322,20 @@ void main() { expect(() => key.currentState!.undo(), throwsAssertionError); }, variant: TargetPlatformVariant.all()); - testWidgets('changes should send setUndoState to the UndoManagerConnection on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('changes should send setUndoState to the UndoManagerConnection on iOS', (WidgetTester tester) async { final List log = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.undoManager, (MethodCall methodCall) async { log.add(methodCall); return null; }); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -378,9 +395,12 @@ void main() { expect(methodCall.arguments as Map, {'canUndo': false, 'canRedo': true}); }, variant: const TargetPlatformVariant({TargetPlatform.iOS}), skip: kIsWeb); // [intended] - testWidgets('handlePlatformUndo should undo or redo appropriately on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handlePlatformUndo should undo or redo appropriately on iOS', (WidgetTester tester) async { final ValueNotifier value = ValueNotifier(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory( @@ -465,9 +485,10 @@ void main() { }); group('UndoHistoryController', () { - testWidgets('UndoHistoryController notifies onUndo listeners onUndo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies onUndo listeners onUndo', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); controller.onUndo.addListener(() { calls++; }); @@ -482,9 +503,10 @@ void main() { expect(calls, 1); }); - testWidgets('UndoHistoryController notifies onRedo listeners onRedo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies onRedo listeners onRedo', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); controller.onRedo.addListener(() { calls++; }); @@ -499,9 +521,10 @@ void main() { expect(calls, 1); }); - testWidgets('UndoHistoryController notifies listeners on value change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies listeners on value change', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(value: const UndoHistoryValue(canUndo: true)); + addTearDown(controller.dispose); controller.addListener(() { calls++; }); diff --git a/packages/flutter/test/widgets/unique_widget_test.dart b/packages/flutter/test/widgets/unique_widget_test.dart index be060bc0ee..8fa7b3f174 100644 --- a/packages/flutter/test/widgets/unique_widget_test.dart +++ b/packages/flutter/test/widgets/unique_widget_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestUniqueWidget extends UniqueWidget { const TestUniqueWidget({ required super.key }); @@ -18,7 +19,7 @@ class TestUniqueWidgetState extends State { } void main() { - testWidgets('Unique widget control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unique widget control test', (WidgetTester tester) async { final TestUniqueWidget widget = TestUniqueWidget(key: GlobalKey()); await tester.pumpWidget(widget); diff --git a/packages/flutter/test/widgets/value_listenable_builder_test.dart b/packages/flutter/test/widgets/value_listenable_builder_test.dart index 4384ed408e..4354f0636e 100644 --- a/packages/flutter/test/widgets/value_listenable_builder_test.dart +++ b/packages/flutter/test/widgets/value_listenable_builder_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { late SpyStringValueNotifier valueListenable; @@ -32,21 +33,26 @@ void main() { textBuilderUnderTest = builderForValueListenable(valueListenable); }); - testWidgets('Null value is ok', (WidgetTester tester) async { + tearDown(() { + valueListenable.dispose(); + }); + + testWidgetsWithLeakTracking('Null value is ok', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); expect(find.byType(Placeholder), findsOneWidget); }); - testWidgets('Widget builds with initial value', (WidgetTester tester) async { - valueListenable = SpyStringValueNotifier('Bachman'); + testWidgetsWithLeakTracking('Widget builds with initial value', (WidgetTester tester) async { + final SpyStringValueNotifier valueListenable = SpyStringValueNotifier('Bachman'); + addTearDown(valueListenable.dispose); await tester.pumpWidget(builderForValueListenable(valueListenable)); expect(find.text('Bachman'), findsOneWidget); }); - testWidgets('Widget updates when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget updates when value changes', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; @@ -59,15 +65,15 @@ void main() { expect(find.text('Dinesh'), findsOneWidget); }); - testWidgets('Can change listenable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change listenable', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; await tester.pump(); expect(find.text('Gilfoyle'), findsOneWidget); - final ValueListenable differentListenable = - SpyStringValueNotifier('Hendricks'); + final SpyStringValueNotifier differentListenable = SpyStringValueNotifier('Hendricks'); + addTearDown(differentListenable.dispose); await tester.pumpWidget(builderForValueListenable(differentListenable)); @@ -75,15 +81,15 @@ void main() { expect(find.text('Hendricks'), findsOneWidget); }); - testWidgets('Stops listening to old listenable after changing listenable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stops listening to old listenable after changing listenable', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; await tester.pump(); expect(find.text('Gilfoyle'), findsOneWidget); - final ValueListenable differentListenable = - SpyStringValueNotifier('Hendricks'); + final SpyStringValueNotifier differentListenable = SpyStringValueNotifier('Hendricks'); + addTearDown(differentListenable.dispose); await tester.pumpWidget(builderForValueListenable(differentListenable)); @@ -98,7 +104,7 @@ void main() { expect(find.text('Hendricks'), findsOneWidget); }); - testWidgets('Self-cleans when removed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Self-cleans when removed', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; diff --git a/packages/flutter/test/widgets/view_test.dart b/packages/flutter/test/widgets/view_test.dart index b0a87c09ff..2fe695f0ae 100644 --- a/packages/flutter/test/widgets/view_test.dart +++ b/packages/flutter/test/widgets/view_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Widgets running with runApp can find View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets running with runApp can find View', (WidgetTester tester) async { FlutterView? viewOf; FlutterView? viewMaybeOf; @@ -29,7 +30,7 @@ void main() { expect(viewMaybeOf, isA()); }); - testWidgets('Widgets running with pumpWidget can find View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets running with pumpWidget can find View', (WidgetTester tester) async { FlutterView? view; FlutterView? viewMaybeOf; @@ -49,7 +50,7 @@ void main() { expect(viewMaybeOf, isA()); }); - testWidgets('cannot find View behind a LookupBoundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot find View behind a LookupBoundary', (WidgetTester tester) async { await tester.pumpWidget( LookupBoundary( child: Container(), @@ -69,7 +70,7 @@ void main() { ); }); - testWidgets('child of view finds view, parentPipelineOwner, mediaQuery', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child of view finds view, parentPipelineOwner, mediaQuery', (WidgetTester tester) async { FlutterView? outsideView; FlutterView? insideView; PipelineOwner? outsideParent; @@ -111,7 +112,7 @@ void main() { expect(pipelineOwners.single, equals(insideParent)); }); - testWidgets('cannot have multiple views with same FlutterView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot have multiple views with same FlutterView', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -138,11 +139,11 @@ void main() { ); }); - testWidgets('ViewCollection must have one view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection must have one view', (WidgetTester tester) async { expect(() => ViewCollection(views: const []), throwsAssertionError); }); - testWidgets('ViewAnchor.child does not see surrounding view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor.child does not see surrounding view', (WidgetTester tester) async { FlutterView? inside; FlutterView? outside; await tester.pumpWidget( @@ -165,7 +166,7 @@ void main() { expect(outside, isNotNull); }); - testWidgets('ViewAnchor layout order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor layout order', (WidgetTester tester) async { Finder findSpyWidget(int label) { return find.byWidgetPredicate((Widget w) => w is SpyRenderWidget && w.label == label); } @@ -192,7 +193,7 @@ void main() { expect(log, ['layout 1', 'layout 3', 'layout 2']); }); - testWidgets('visitChildren of ViewAnchor visits both children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visitChildren of ViewAnchor visits both children', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: View( @@ -221,7 +222,7 @@ void main() { expect(children, hasLength(1)); }); - testWidgets('visitChildren of ViewCollection visits all children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visitChildren of ViewCollection visits all children', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -267,7 +268,7 @@ void main() { }); group('renderObject getter', () { - testWidgets('ancestors of view see RenderView as renderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of view see RenderView as renderObject', (WidgetTester tester) async { late BuildContext builderContext; await pumpWidgetWithoutViewWrapper( tester: tester, @@ -289,7 +290,7 @@ void main() { expect(tester.element(find.byType(Builder)).renderObject, renderObject); }); - testWidgets('ancestors of ViewCollection get null for renderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of ViewCollection get null for renderObject', (WidgetTester tester) async { late BuildContext builderContext; await pumpWidgetWithoutViewWrapper( tester: tester, @@ -317,7 +318,7 @@ void main() { expect(tester.element(find.byType(Builder)).renderObject, isNull); }); - testWidgets('ancestors of a ViewAnchor see the right RenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of a ViewAnchor see the right RenderObject', (WidgetTester tester) async { late BuildContext builderContext; await tester.pumpWidget( Builder( @@ -342,7 +343,7 @@ void main() { }); }); - testWidgets('correctly switches between view configurations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly switches between view configurations', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: View( @@ -401,7 +402,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('attaches itself correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('attaches itself correctly', (WidgetTester tester) async { final Key viewKey = UniqueKey(); late final PipelineOwner parentPipelineOwner; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/visibility_test.dart b/packages/flutter/test/widgets/visibility_test.dart index cd11376111..0b2b6330f3 100644 --- a/packages/flutter/test/widgets/visibility_test.dart +++ b/packages/flutter/test/widgets/visibility_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -29,7 +30,7 @@ class _TestStateState extends State { } void main() { - testWidgets('Visibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List log = []; @@ -439,7 +440,7 @@ void main() { semantics.dispose(); }); - testWidgets('Visibility does not force compositing when visible and maintain*', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility does not force compositing when visible and maintain*', (WidgetTester tester) async { await tester.pumpWidget( const Visibility( maintainSize: true, @@ -455,7 +456,7 @@ void main() { expect(tester.layers.last, isA()); }); - testWidgets('SliverVisibility does not force compositing when visible and maintain*', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverVisibility does not force compositing when visible and maintain*', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -485,7 +486,7 @@ void main() { expect(tester.layers.last, isA()); }); - testWidgets('Visibility.of returns correct value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility.of returns correct value', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -518,7 +519,7 @@ void main() { expect(find.text('is visible ? false', skipOffstage: false), findsOneWidget); }); - testWidgets('Visibility.of works when multiple Visibility widgets are in hierarchy', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility.of works when multiple Visibility widgets are in hierarchy', (WidgetTester tester) async { bool didChangeDependencies = false; void handleDidChangeDependencies() { didChangeDependencies = true; diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart index 1a132ef025..41165288f9 100644 --- a/packages/flutter/test/widgets/wrap_test.dart +++ b/packages/flutter/test/widgets/wrap_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verify(WidgetTester tester, List answerKey) { final List testAnswers = tester.renderObjectList(find.byType(SizedBox)).map( @@ -14,7 +15,7 @@ void verify(WidgetTester tester, List answerKey) { } void main() { - testWidgets('Basic Wrap test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic Wrap test (LTR)', (WidgetTester tester) async { await tester.pumpWidget( const Wrap( textDirection: TextDirection.ltr, @@ -129,7 +130,7 @@ void main() { }); - testWidgets('Basic Wrap test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic Wrap test (RTL)', (WidgetTester tester) async { await tester.pumpWidget( const Wrap( textDirection: TextDirection.rtl, @@ -247,12 +248,12 @@ void main() { }); - testWidgets('Empty wrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty wrap', (WidgetTester tester) async { await tester.pumpWidget(const Center(child: Wrap(alignment: WrapAlignment.center))); expect(tester.renderObject(find.byType(Wrap)).size, equals(Size.zero)); }); - testWidgets('Wrap alignment (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap alignment (LTR)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( alignment: WrapAlignment.center, spacing: 5.0, @@ -322,7 +323,7 @@ void main() { ]); }); - testWidgets('Wrap alignment (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap alignment (RTL)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( alignment: WrapAlignment.center, spacing: 5.0, @@ -392,7 +393,7 @@ void main() { ]); }); - testWidgets('Wrap runAlignment (DOWN)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap runAlignment (DOWN)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( runAlignment: WrapAlignment.center, runSpacing: 5.0, @@ -479,7 +480,7 @@ void main() { }); - testWidgets('Wrap runAlignment (UP)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap runAlignment (UP)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( runAlignment: WrapAlignment.center, runSpacing: 5.0, @@ -570,7 +571,7 @@ void main() { }); - testWidgets('Shrink-wrapping Wrap test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shrink-wrapping Wrap test', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -620,7 +621,7 @@ void main() { ]); }); - testWidgets('Wrap spacing test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap spacing test', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -645,7 +646,7 @@ void main() { ]); }); - testWidgets('Vertical Wrap test with spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical Wrap test with spacing', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -704,7 +705,7 @@ void main() { ]); }); - testWidgets('Visual overflow generates a clip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visual overflow generates a clip', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( textDirection: TextDirection.ltr, children: [ @@ -726,7 +727,7 @@ void main() { expect(tester.renderObject(find.byType(Wrap)), paints..clipRect()); }); - testWidgets('Hit test children in wrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hit test children in wrap', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Wrap( @@ -762,14 +763,14 @@ void main() { expect(log, equals(['hit'])); }); - testWidgets('RenderWrap toStringShallow control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderWrap toStringShallow control test', (WidgetTester tester) async { await tester.pumpWidget(const Wrap(alignment: WrapAlignment.center)); final RenderBox wrap = tester.renderObject(find.byType(Wrap)); expect(wrap.toStringShallow(), hasOneLineDescription); }); - testWidgets('RenderWrap toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderWrap toString control test', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( direction: Axis.vertical, runSpacing: 7.0, @@ -787,7 +788,7 @@ void main() { expect(width, equals(2021)); }); - testWidgets('Wrap baseline control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap baseline control test', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: Baseline( @@ -815,7 +816,7 @@ void main() { ); }); - testWidgets('Spacing with slight overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Spacing with slight overflow', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( textDirection: TextDirection.ltr, spacing: 10.0, @@ -837,7 +838,7 @@ void main() { ]); }); - testWidgets('Object exactly matches container width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Object exactly matches container width', (WidgetTester tester) async { await tester.pumpWidget( const Column( children: [ @@ -879,7 +880,7 @@ void main() { ]); }); - testWidgets('Wrap can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(const Wrap(textDirection: TextDirection.ltr)); final RenderWrap renderObject = tester.allRenderObjects.whereType().first; expect(renderObject.clipBehavior, equals(Clip.none)); @@ -888,7 +889,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('Horizontal wrap - IntrinsicsHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal wrap - IntrinsicsHeight', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/48679. await tester.pumpWidget( const Directionality( @@ -920,7 +921,7 @@ void main() { expect(tester.getSize(find.byType(IntrinsicHeight)).height, 2 * 16 + 40); }); - testWidgets('Vertical wrap - IntrinsicsWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical wrap - IntrinsicsWidth', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/48679. await tester.pumpWidget( const Directionality(