Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@Skip(
'This file is skipped due to a cross-import that needs to be fixed. Tracked in https://github.com/flutter/flutter/issues/177028.',
)
// reduced-test-set:
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
Expand All @@ -18,8 +15,6 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../widgets/semantics_tester.dart';

void main() {
testWidgets('Radio control test', (WidgetTester tester) async {
final Key key = UniqueKey();
Expand Down Expand Up @@ -146,7 +141,7 @@ void main() {
});

testWidgets('Radio selected semantics - platform adaptive', (WidgetTester tester) async {
final semantics = SemanticsTester(tester);
final SemanticsHandle handle = tester.ensureSemantics();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using addTearDown(handle.dispose) immediately after tester.ensureSemantics() is recommended to ensure that the SemanticsHandle is always disposed of, even if the test fails or throws an exception before reaching the end of the test.

    final SemanticsHandle handle = tester.ensureSemantics();
    addTearDown(handle.dispose);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how the test was previously structured, no addTearDown was previously used. Also explanation from gemini below as to why the test fails if we do use addTearDown(handle.dispose).

From gemini:

Flutter's TestWidgetsFlutterBinding runs its end-of-test leak verifications (specifically _verifySemanticsHandlesWereDisposed) inside the test body execution flow, immediately after your test callback completes, but before returning control to the Dart test runner:

1. [Test Runner] Starts test
2.   [Flutter Binding] Runs test body (your async callback)
3.     Your test code executes...
4.     Your test code completes.
5.   [Flutter Binding] Runs _endOfTestVerifications()  <-- CRITICAL POINT
6.     Checking active SemanticsHandles... 
       ERROR: "A SemanticsHandle was active at the end of the test."
7. [Test Runner] Runs addTearDown callbacks            <-- TOO LATE!
8.   handle.dispose() is called here.

Because the verification (Step 5) happens before the test runner runs the teardown callbacks (Step 7), the binding sees that the SemanticsHandle is still active and throws a FlutterError, failing the test.


await tester.pumpWidget(
CupertinoApp(
Expand All @@ -158,29 +153,26 @@ void main() {
defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS;
expect(
semantics,
includesNodeWith(
flags: <SemanticsFlag>[
SemanticsFlag.isInMutuallyExclusiveGroup,
SemanticsFlag.hasCheckedState,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isEnabled,
SemanticsFlag.isFocusable,
SemanticsFlag.isChecked,
if (isApple) SemanticsFlag.hasSelectedState,
if (isApple) SemanticsFlag.isSelected,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
if (defaultTargetPlatform != TargetPlatform.iOS) SemanticsAction.focus,
],
),
);
semantics.dispose();
tester.getSemantics(find.byType(CupertinoRadio<int>)),
isSemantics(
isInMutuallyExclusiveGroup: true,
hasCheckedState: true,
hasEnabledState: true,
isEnabled: true,
isFocusable: true,
isChecked: true,
hasSelectedState: isApple ? true : null,
isSelected: isApple ? true : null,
hasTapAction: true,
hasFocusAction: defaultTargetPlatform != TargetPlatform.iOS ? true : null,
),
);

handle.dispose();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since addTearDown(handle.dispose) is used to automatically dispose of the SemanticsHandle at the end of the test, this manual call to handle.dispose() can be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}, variant: TargetPlatformVariant.all());

testWidgets('Radio semantics', (WidgetTester tester) async {
final semantics = SemanticsTester(tester);
final SemanticsHandle handle = tester.ensureSemantics();

await tester.pumpWidget(
CupertinoApp(
Expand Down Expand Up @@ -262,11 +254,12 @@ void main() {
),
);

semantics.dispose();
handle.dispose();
});

testWidgets('has semantic events', (WidgetTester tester) async {
final semantics = SemanticsTester(tester);
final SemanticsHandle handle = tester.ensureSemantics();

final Key key = UniqueKey();
dynamic semanticEvent;
int? radioValue = 2;
Expand Down Expand Up @@ -303,7 +296,7 @@ void main() {
});
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);

semantics.dispose();
handle.dispose();
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(
SystemChannels.accessibility,
null,
Expand Down
Loading