Compare SemanticsHandler# at end of test to value at beginning of test (#18183)
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index abca235..66b5759 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart
@@ -822,7 +822,12 @@ SemanticsOwner get semanticsOwner => _semanticsOwner; SemanticsOwner _semanticsOwner; - int _outstandingSemanticsHandle = 0; + /// The number of clients registered to listen for semantics. + /// + /// The number is increased whenever [ensureSemantics] is called and decreased + /// when [SemanticsHandle.dispose] is called. + int get debugOutstandingSemanticsHandles => _outstandingSemanticsHandles; + int _outstandingSemanticsHandles = 0; /// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree /// updates. @@ -837,8 +842,8 @@ /// objects for a given [PipelineOwner] are closed, the [PipelineOwner] stops /// maintaining the semantics tree. SemanticsHandle ensureSemantics({ VoidCallback listener }) { - _outstandingSemanticsHandle += 1; - if (_outstandingSemanticsHandle == 1) { + _outstandingSemanticsHandles += 1; + if (_outstandingSemanticsHandles == 1) { assert(_semanticsOwner == null); _semanticsOwner = new SemanticsOwner(); if (onSemanticsOwnerCreated != null) @@ -849,8 +854,8 @@ void _didDisposeSemanticsHandle() { assert(_semanticsOwner != null); - _outstandingSemanticsHandle -= 1; - if (_outstandingSemanticsHandle == 0) { + _outstandingSemanticsHandles -= 1; + if (_outstandingSemanticsHandles == 0) { _semanticsOwner.dispose(); _semanticsOwner = null; if (onSemanticsOwnerDisposed != null)
diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart index f8d8ee7..53bf6ea 100644 --- a/packages/flutter_test/lib/src/widget_tester.dart +++ b/packages/flutter_test/lib/src/widget_tester.dart
@@ -57,9 +57,10 @@ final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); final WidgetTester tester = new WidgetTester._(binding); timeout ??= binding.defaultTestTimeout; - test_package.test( + test_package.test( description, () { + tester._recordNumberOfSemanticsHandles(); test_package.addTearDown(binding.postTest); return binding.runTest( () => callback(tester), @@ -125,6 +126,7 @@ final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); assert(binding is! AutomatedTestWidgetsFlutterBinding); final WidgetTester tester = new WidgetTester._(binding); + tester._recordNumberOfSemanticsHandles(); return binding.runTest( () => callback(tester), tester._endOfTestVerifications, @@ -523,7 +525,8 @@ } void _verifySemanticsHandlesWereDisposed() { - if (binding.pipelineOwner.semanticsOwner != null) { + assert(_lastRecordedSemanticsHandles != null); + if (binding.pipelineOwner.debugOutstandingSemanticsHandles > _lastRecordedSemanticsHandles) { throw new FlutterError( 'A SemanticsHandle was active at the end of the test.\n' 'All SemanticsHandle instances must be disposed by calling dispose() on ' @@ -532,6 +535,13 @@ 'existing handle will leak into another test and alter its behavior.' ); } + _lastRecordedSemanticsHandles = null; + } + + int _lastRecordedSemanticsHandles; + + void _recordNumberOfSemanticsHandles() { + _lastRecordedSemanticsHandles = binding.pipelineOwner.debugOutstandingSemanticsHandles; } /// Returns the TestTextInput singleton.