Unverified Commit 397da064 authored by derdilla's avatar derdilla Committed by GitHub

leak track tab_scaffold_test.dart (#135309)

parent 4b98bfcd
...@@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../image_data.dart'; import '../image_data.dart';
import '../rendering/rendering_tester.dart' show TestCallbackPainter; import '../rendering/rendering_tester.dart' show TestCallbackPainter;
...@@ -50,7 +51,7 @@ void main() { ...@@ -50,7 +51,7 @@ void main() {
); );
} }
testWidgets('Tab switching', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab switching', (WidgetTester tester) async {
final List<int> tabsPainted = <int>[]; final List<int> tabsPainted = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
...@@ -104,7 +105,7 @@ void main() { ...@@ -104,7 +105,7 @@ void main() {
expect(selectedTabs, const <int>[1, 0]); expect(selectedTabs, const <int>[1, 0]);
}); });
testWidgets('Tabs are lazy built and moved offstage when inactive', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tabs are lazy built and moved offstage when inactive', (WidgetTester tester) async {
final List<int> tabsBuilt = <int>[]; final List<int> tabsBuilt = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
...@@ -139,12 +140,15 @@ void main() { ...@@ -139,12 +140,15 @@ void main() {
expect(find.text('Page 2', skipOffstage: false), isOffstage); expect(find.text('Page 2', skipOffstage: false), isOffstage);
}); });
testWidgets('Last tab gets focus', (WidgetTester tester) async { testWidgetsWithLeakTracking('Last tab gets focus', (WidgetTester tester) async {
// 2 nodes for 2 tabs // 2 nodes for 2 tabs
final List<FocusNode> focusNodes = <FocusNode>[ final List<FocusNode> focusNodes = <FocusNode>[
FocusNode(debugLabel: 'Node 1'), FocusNode(debugLabel: 'Node 1'),
FocusNode(debugLabel: 'Node 2'), FocusNode(debugLabel: 'Node 2'),
]; ];
for (final FocusNode focusNode in focusNodes) {
addTearDown(focusNode.dispose);
}
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -175,13 +179,16 @@ void main() { ...@@ -175,13 +179,16 @@ void main() {
expect(focusNodes[1].hasFocus, isFalse); expect(focusNodes[1].hasFocus, isFalse);
}); });
testWidgets('Do not affect focus order in the route', (WidgetTester tester) async { testWidgetsWithLeakTracking('Do not affect focus order in the route', (WidgetTester tester) async {
final List<FocusNode> focusNodes = <FocusNode>[ final List<FocusNode> focusNodes = <FocusNode>[
FocusNode(debugLabel: 'Node 1'), FocusNode(debugLabel: 'Node 1'),
FocusNode(debugLabel: 'Node 2'), FocusNode(debugLabel: 'Node 2'),
FocusNode(debugLabel: 'Node 3'), FocusNode(debugLabel: 'Node 3'),
FocusNode(debugLabel: 'Node 4'), FocusNode(debugLabel: 'Node 4'),
]; ];
for (final FocusNode focusNode in focusNodes) {
addTearDown(focusNode.dispose);
}
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -238,8 +245,9 @@ void main() { ...@@ -238,8 +245,9 @@ void main() {
); );
}); });
testWidgets('Programmatic tab switching by changing the index of an existing controller', (WidgetTester tester) async { testWidgetsWithLeakTracking('Programmatic tab switching by changing the index of an existing controller', (WidgetTester tester) async {
final CupertinoTabController controller = CupertinoTabController(initialIndex: 1); final CupertinoTabController controller = CupertinoTabController(initialIndex: 1);
addTearDown(controller.dispose);
final List<int> tabsPainted = <int>[]; final List<int> tabsPainted = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
...@@ -276,7 +284,7 @@ void main() { ...@@ -276,7 +284,7 @@ void main() {
expect(selectedTabs, const <int>[1]); expect(selectedTabs, const <int>[1]);
}); });
testWidgets('Programmatic tab switching by passing in a new controller', (WidgetTester tester) async { testWidgetsWithLeakTracking('Programmatic tab switching by passing in a new controller', (WidgetTester tester) async {
final List<int> tabsPainted = <int>[]; final List<int> tabsPainted = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
...@@ -297,11 +305,13 @@ void main() { ...@@ -297,11 +305,13 @@ void main() {
expect(tabsPainted, const <int>[0]); expect(tabsPainted, const <int>[0]);
final CupertinoTabController controller = CupertinoTabController(initialIndex: 1);
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: CupertinoTabScaffold( home: CupertinoTabScaffold(
tabBar: _buildTabBar(), tabBar: _buildTabBar(),
controller: CupertinoTabController(initialIndex: 1), // Programmatically change the tab now. controller: controller, // Programmatically change the tab now.
tabBuilder: (BuildContext context, int index) { tabBuilder: (BuildContext context, int index) {
return CustomPaint( return CustomPaint(
painter: TestCallbackPainter( painter: TestCallbackPainter(
...@@ -326,7 +336,7 @@ void main() { ...@@ -326,7 +336,7 @@ void main() {
expect(selectedTabs, const <int>[0]); expect(selectedTabs, const <int>[0]);
}); });
testWidgets('Tab bar respects themes', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab bar respects themes', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: CupertinoTabScaffold( home: CupertinoTabScaffold(
...@@ -384,7 +394,7 @@ void main() { ...@@ -384,7 +394,7 @@ void main() {
expect(tab2.text.style!.color, isSameColorAs(CupertinoColors.systemRed.darkColor)); expect(tab2.text.style!.color, isSameColorAs(CupertinoColors.systemRed.darkColor));
}); });
testWidgets('Tab contents are padded when there are view insets', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab contents are padded when there are view insets', (WidgetTester tester) async {
late BuildContext innerContext; late BuildContext innerContext;
await tester.pumpWidget( await tester.pumpWidget(
...@@ -410,7 +420,7 @@ void main() { ...@@ -410,7 +420,7 @@ void main() {
expect(MediaQuery.of(innerContext).padding.bottom, 0); expect(MediaQuery.of(innerContext).padding.bottom, 0);
}); });
testWidgets('Tab contents are not inset when resizeToAvoidBottomInset overridden', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab contents are not inset when resizeToAvoidBottomInset overridden', (WidgetTester tester) async {
late BuildContext innerContext; late BuildContext innerContext;
await tester.pumpWidget( await tester.pumpWidget(
...@@ -437,7 +447,7 @@ void main() { ...@@ -437,7 +447,7 @@ void main() {
expect(MediaQuery.of(innerContext).padding.bottom, 50); expect(MediaQuery.of(innerContext).padding.bottom, 50);
}); });
testWidgets('Tab contents bottom padding are not consumed by viewInsets when resizeToAvoidBottomInset overridden', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab contents bottom padding are not consumed by viewInsets when resizeToAvoidBottomInset overridden', (WidgetTester tester) async {
final Widget child = Localizations( final Widget child = Localizations(
locale: const Locale('en', 'US'), locale: const Locale('en', 'US'),
delegates: const <LocalizationsDelegate<dynamic>>[ delegates: const <LocalizationsDelegate<dynamic>>[
...@@ -485,7 +495,7 @@ void main() { ...@@ -485,7 +495,7 @@ void main() {
expect(initialPoint, finalPoint); expect(initialPoint, finalPoint);
}); });
testWidgets( testWidgetsWithLeakTracking(
'Opaque tab bar consumes bottom padding while non opaque tab bar does not', 'Opaque tab bar consumes bottom padding while non opaque tab bar does not',
(WidgetTester tester) async { (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/43581. // Regression test for https://github.com/flutter/flutter/issues/43581.
...@@ -517,7 +527,7 @@ void main() { ...@@ -517,7 +527,7 @@ void main() {
}, },
); );
testWidgets('Tab and page scaffolds do not double stack view insets', (WidgetTester tester) async { testWidgetsWithLeakTracking('Tab and page scaffolds do not double stack view insets', (WidgetTester tester) async {
late BuildContext innerContext; late BuildContext innerContext;
await tester.pumpWidget( await tester.pumpWidget(
...@@ -547,7 +557,7 @@ void main() { ...@@ -547,7 +557,7 @@ void main() {
expect(MediaQuery.of(innerContext).padding.bottom, 0); expect(MediaQuery.of(innerContext).padding.bottom, 0);
}); });
testWidgets('Deleting tabs after selecting them should switch to the last available tab', (WidgetTester tester) async { testWidgetsWithLeakTracking('Deleting tabs after selecting them should switch to the last available tab', (WidgetTester tester) async {
final List<int> tabsBuilt = <int>[]; final List<int> tabsBuilt = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
...@@ -617,9 +627,10 @@ void main() { ...@@ -617,9 +627,10 @@ void main() {
}); });
// Regression test for https://github.com/flutter/flutter/issues/33455 // Regression test for https://github.com/flutter/flutter/issues/33455
testWidgets('Adding new tabs does not crash the app', (WidgetTester tester) async { testWidgetsWithLeakTracking('Adding new tabs does not crash the app', (WidgetTester tester) async {
final List<int> tabsPainted = <int>[]; final List<int> tabsPainted = <int>[];
final CupertinoTabController controller = CupertinoTabController(); final CupertinoTabController controller = CupertinoTabController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -671,13 +682,14 @@ void main() { ...@@ -671,13 +682,14 @@ void main() {
expect(tabsPainted, const <int>[0, 0, 18]); expect(tabsPainted, const <int>[0, 0, 18]);
}); });
testWidgets( testWidgetsWithLeakTracking(
'If a controller is initially provided then the parent stops doing so for rebuilds, ' 'If a controller is initially provided then the parent stops doing so for rebuilds, '
'a new instance of CupertinoTabController should be created and used by the widget, ' 'a new instance of CupertinoTabController should be created and used by the widget, '
"while preserving the previous controller's tab index", "while preserving the previous controller's tab index",
(WidgetTester tester) async { (WidgetTester tester) async {
final List<int> tabsPainted = <int>[]; final List<int> tabsPainted = <int>[];
final CupertinoTabController oldController = CupertinoTabController(); final CupertinoTabController oldController = CupertinoTabController();
addTearDown(oldController.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -735,11 +747,12 @@ void main() { ...@@ -735,11 +747,12 @@ void main() {
}, },
); );
testWidgets( testWidgetsWithLeakTracking(
'Do not call dispose on a controller that we do not own ' 'Do not call dispose on a controller that we do not own '
'but do remove from its listeners when done listening to it', 'but do remove from its listeners when done listening to it',
(WidgetTester tester) async { (WidgetTester tester) async {
final MockCupertinoTabController mockController = MockCupertinoTabController(initialIndex: 0); final MockCupertinoTabController mockController = MockCupertinoTabController(initialIndex: 0);
addTearDown(mockController.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -772,7 +785,7 @@ void main() { ...@@ -772,7 +785,7 @@ void main() {
}, },
); );
testWidgets('The owner can dispose the old controller', (WidgetTester tester) async { testWidgetsWithLeakTracking('The owner can dispose the old controller', (WidgetTester tester) async {
CupertinoTabController controller = CupertinoTabController(initialIndex: 2); CupertinoTabController controller = CupertinoTabController(initialIndex: 2);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -792,6 +805,7 @@ void main() { ...@@ -792,6 +805,7 @@ void main() {
controller.dispose(); controller.dispose();
controller = CupertinoTabController(); controller = CupertinoTabController();
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: CupertinoTabScaffold( home: CupertinoTabScaffold(
...@@ -810,7 +824,7 @@ void main() { ...@@ -810,7 +824,7 @@ void main() {
expect(find.text('Tab 3'), findsNothing); expect(find.text('Tab 3'), findsNothing);
}); });
testWidgets('A controller can control more than one CupertinoTabScaffold, ' testWidgetsWithLeakTracking('A controller can control more than one CupertinoTabScaffold, '
'removal of listeners does not break the controller', 'removal of listeners does not break the controller',
(WidgetTester tester) async { (WidgetTester tester) async {
final List<int> tabsPainted0 = <int>[]; final List<int> tabsPainted0 = <int>[];
...@@ -893,7 +907,9 @@ void main() { ...@@ -893,7 +907,9 @@ void main() {
expect(controller.numOfListeners, 1); expect(controller.numOfListeners, 1);
// Replacing controller works. // Replacing controller works.
controller.dispose();
controller = MockCupertinoTabController(initialIndex: 2); controller = MockCupertinoTabController(initialIndex: 2);
addTearDown(controller.dispose);
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: CupertinoPageScaffold( home: CupertinoPageScaffold(
...@@ -923,8 +939,9 @@ void main() { ...@@ -923,8 +939,9 @@ void main() {
}, },
); );
testWidgets('Assert when current tab index >= number of tabs', (WidgetTester tester) async { testWidgetsWithLeakTracking('Assert when current tab index >= number of tabs', (WidgetTester tester) async {
final CupertinoTabController controller = CupertinoTabController(initialIndex: 2); final CupertinoTabController controller = CupertinoTabController(initialIndex: 2);
addTearDown(controller.dispose);
try { try {
await tester.pumpWidget( await tester.pumpWidget(
...@@ -964,10 +981,16 @@ void main() { ...@@ -964,10 +981,16 @@ void main() {
expect(message, contains('with 3 tabs')); expect(message, contains('with 3 tabs'));
}); });
testWidgets("Don't replace focus nodes for existing tabs when changing tab count", (WidgetTester tester) async { testWidgetsWithLeakTracking("Don't replace focus nodes for existing tabs when changing tab count", (WidgetTester tester) async {
final CupertinoTabController controller = CupertinoTabController(initialIndex: 2); final CupertinoTabController controller = CupertinoTabController(initialIndex: 2);
addTearDown(controller.dispose);
final List<FocusScopeNode> scopes = List<FocusScopeNode>.filled(5, FocusScopeNode()); final List<FocusScopeNode> scopes = <FocusScopeNode>[];
for (int i = 0; i < 5; i++) {
final FocusScopeNode scope = FocusScopeNode();
addTearDown(scope.dispose);
scopes.add(scope);
}
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: CupertinoTabScaffold( home: CupertinoTabScaffold(
...@@ -1013,7 +1036,7 @@ void main() { ...@@ -1013,7 +1036,7 @@ void main() {
expect(scopes.sublist(0, 3), equals(newScopes.sublist(0, 3))); expect(scopes.sublist(0, 3), equals(newScopes.sublist(0, 3)));
}); });
testWidgets('Current tab index cannot go below zero or be null', (WidgetTester tester) async { testWidgetsWithLeakTracking('Current tab index cannot go below zero or be null', (WidgetTester tester) async {
void expectAssertionError(VoidCallback callback, String errorMessage) { void expectAssertionError(VoidCallback callback, String errorMessage) {
try { try {
callback(); callback();
...@@ -1025,11 +1048,12 @@ void main() { ...@@ -1025,11 +1048,12 @@ void main() {
expectAssertionError(() => CupertinoTabController(initialIndex: -1), '>= 0'); expectAssertionError(() => CupertinoTabController(initialIndex: -1), '>= 0');
final CupertinoTabController controller = CupertinoTabController(); final CupertinoTabController controller = CupertinoTabController();
addTearDown(controller.dispose);
expectAssertionError(() => controller.index = -1, '>= 0'); expectAssertionError(() => controller.index = -1, '>= 0');
}); });
testWidgets('Does not lose state when focusing on text input', (WidgetTester tester) async { testWidgetsWithLeakTracking('Does not lose state when focusing on text input', (WidgetTester tester) async {
// Regression testing for https://github.com/flutter/flutter/issues/28457. // Regression testing for https://github.com/flutter/flutter/issues/28457.
await tester.pumpWidget( await tester.pumpWidget(
...@@ -1071,7 +1095,7 @@ void main() { ...@@ -1071,7 +1095,7 @@ void main() {
expect(find.text("don't lose me"), findsOneWidget); expect(find.text("don't lose me"), findsOneWidget);
}); });
testWidgets('textScaleFactor is set to 1.0', (WidgetTester tester) async { testWidgetsWithLeakTracking('textScaleFactor is set to 1.0', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: Builder(builder: (BuildContext context) { home: Builder(builder: (BuildContext context) {
...@@ -1113,7 +1137,7 @@ void main() { ...@@ -1113,7 +1137,7 @@ void main() {
expect(contents, isNot(contains(predicate((RichText t) => t.textScaler != const TextScaler.linear(99.0))))); expect(contents, isNot(contains(predicate((RichText t) => t.textScaler != const TextScaler.linear(99.0)))));
}); });
testWidgets('state restoration', (WidgetTester tester) async { testWidgetsWithLeakTracking('state restoration', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
restorationScopeId: 'app', restorationScopeId: 'app',
...@@ -1168,7 +1192,7 @@ void main() { ...@@ -1168,7 +1192,7 @@ void main() {
expect(find.text('Content 3'), findsNothing); expect(find.text('Content 3'), findsNothing);
}); });
testWidgets('switch from internal to external controller with state restoration', (WidgetTester tester) async { testWidgetsWithLeakTracking('switch from internal to external controller with state restoration', (WidgetTester tester) async {
Widget buildWidget({CupertinoTabController? controller}) { Widget buildWidget({CupertinoTabController? controller}) {
return CupertinoApp( return CupertinoApp(
restorationScopeId: 'app', restorationScopeId: 'app',
...@@ -1202,6 +1226,7 @@ void main() { ...@@ -1202,6 +1226,7 @@ void main() {
expect(find.text('Content 3'), findsNothing); expect(find.text('Content 3'), findsNothing);
final CupertinoTabController controller = CupertinoTabController(initialIndex: 3); final CupertinoTabController controller = CupertinoTabController(initialIndex: 3);
addTearDown(controller.dispose);
await tester.pumpWidget(buildWidget(controller: controller)); await tester.pumpWidget(buildWidget(controller: controller));
expect(find.text('Content 0'), findsNothing); expect(find.text('Content 0'), findsNothing);
...@@ -1242,7 +1267,7 @@ void main() { ...@@ -1242,7 +1267,7 @@ void main() {
.setMockMethodCallHandler(SystemChannels.platform, null); .setMockMethodCallHandler(SystemChannels.platform, null);
}); });
testWidgets('System back navigation inside of tabs', (WidgetTester tester) async { testWidgetsWithLeakTracking('System back navigation inside of tabs', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: MediaQuery( home: MediaQuery(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment