diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 378a38bb93e..e5fde935508 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -3248,7 +3248,7 @@ class SemanticsOwner extends ChangeNotifier { } // Default actions if no [handler] was provided. - if (action == SemanticsAction.showOnScreen && _nodes[id]!._showOnScreen != null) { + if (action == SemanticsAction.showOnScreen && _nodes[id]?._showOnScreen != null) { _nodes[id]!._showOnScreen!(); } } diff --git a/packages/flutter/test/semantics/semantics_owner_test.dart b/packages/flutter/test/semantics/semantics_owner_test.dart new file mode 100644 index 00000000000..142e847575a --- /dev/null +++ b/packages/flutter/test/semantics/semantics_owner_test.dart @@ -0,0 +1,48 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../widgets/semantics_tester.dart'; + +void main() { + testWidgets('Performing SemanticsAction.showOnScreen does not crash if node no longer exist', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/100358. + + final SemanticsTester semantics = SemanticsTester(tester); + addTearDown(semantics.dispose); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Semantics( + explicitChildNodes: true, + child: const Text('Hello World'), + ), + ), + ); + + final int nodeId = tester.semantics.find(find.bySemanticsLabel('Hello World')).id; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Container(), + ), + ); + + // Node with $nodeId is no longer in the tree. + expect(semantics, isNot(hasSemantics(TestSemantics(id: nodeId)))); + + // Executing SemanticsAction.showOnScreen on that node does not crash. + // (A platform may not have processed the semantics update yet and send + // actions for no longer existing nodes.) + tester.binding.performSemanticsAction(SemanticsActionEvent( + type: SemanticsAction.showOnScreen, + nodeId: nodeId, + )); + }); +}