Add mouseCursor parameter to Chips (#159422)

Part of https://github.com/flutter/flutter/issues/58192

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
This commit is contained in:
Valentin Vignal 2024-12-04 12:56:01 +08:00 committed by GitHub
parent a9ed692396
commit 628ab7f493
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 404 additions and 1 deletions

View File

@ -120,6 +120,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
this.iconTheme,
this.avatarBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.flat;
@ -156,6 +157,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
this.iconTheme,
this.avatarBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.elevated;
@ -208,6 +210,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
final BoxConstraints? avatarBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
@override
bool get isEnabled => onPressed != null;
@ -247,6 +251,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
iconTheme: iconTheme,
avatarBoxConstraints: avatarBoxConstraints,
chipAnimationStyle: chipAnimationStyle,
mouseCursor: mouseCursor,
);
}
}

View File

@ -278,6 +278,19 @@ abstract interface class ChipAttributes {
/// ** See code in examples/api/lib/material/chip/chip_attributes.chip_animation_style.0.dart **
/// {@end-tool}
ChipAnimationStyle? get chipAnimationStyle;
/// The cursor for a mouse pointer when it enters or is hovering over the
/// widget.
///
/// If [mouseCursor] is a [WidgetStateMouseCursor],
/// [WidgetStateProperty.resolve] is used for the following [WidgetState]s:
///
/// * [WidgetState.hovered].
/// * [WidgetState.focused].
/// * [WidgetState.disabled].
///
/// If this property is null, [WidgetStateMouseCursor.clickable] will be used.
MouseCursor? get mouseCursor;
}
/// An interface for Material Design chips that can be deleted.
@ -704,6 +717,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
this.avatarBoxConstraints,
this.deleteIconBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(elevation == null || elevation >= 0.0);
@override
@ -756,6 +770,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
final BoxConstraints? deleteIconBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
@override
Widget build(BuildContext context) {
@ -787,6 +803,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
avatarBoxConstraints: avatarBoxConstraints,
deleteIconBoxConstraints: deleteIconBoxConstraints,
chipAnimationStyle: chipAnimationStyle,
mouseCursor: mouseCursor,
);
}
}
@ -877,6 +894,7 @@ class RawChip extends StatefulWidget
this.avatarBoxConstraints,
this.deleteIconBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
@ -962,6 +980,8 @@ class RawChip extends StatefulWidget
final BoxConstraints? deleteIconBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
/// If set, this indicates that the chip should be disabled if all of the
/// tap callbacks ([onSelected], [onPressed]) are null.
@ -1407,6 +1427,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
onTapDown: canTap ? _handleTapDown : null,
onTapCancel: canTap ? _handleTapCancel : null,
onHover: canTap ? updateMaterialState(MaterialState.hovered) : null,
mouseCursor: widget.mouseCursor,
hoverColor: (widget.color ?? chipTheme.color) == null ? null : Colors.transparent,
customBorder: resolvedShape,
child: AnimatedBuilder(

View File

@ -101,6 +101,7 @@ class ChoiceChip extends StatelessWidget
this.avatarBorder = const CircleBorder(),
this.avatarBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.flat;
@ -143,6 +144,7 @@ class ChoiceChip extends StatelessWidget
this.avatarBorder = const CircleBorder(),
this.avatarBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.elevated;
@ -207,6 +209,8 @@ class ChoiceChip extends StatelessWidget
final BoxConstraints? avatarBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
@override
bool get isEnabled => onSelected != null;
@ -253,6 +257,7 @@ class ChoiceChip extends StatelessWidget
iconTheme: iconTheme,
avatarBoxConstraints: avatarBoxConstraints,
chipAnimationStyle: chipAnimationStyle,
mouseCursor: mouseCursor,
);
}
}

View File

@ -113,6 +113,7 @@ class FilterChip extends StatelessWidget
this.avatarBoxConstraints,
this.deleteIconBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.flat;
@ -160,6 +161,7 @@ class FilterChip extends StatelessWidget
this.avatarBoxConstraints,
this.deleteIconBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0),
_chipVariant = _ChipVariant.elevated;
@ -234,6 +236,8 @@ class FilterChip extends StatelessWidget
final BoxConstraints? deleteIconBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
@override
bool get isEnabled => onSelected != null;
@ -286,6 +290,7 @@ class FilterChip extends StatelessWidget
avatarBoxConstraints: avatarBoxConstraints,
deleteIconBoxConstraints: deleteIconBoxConstraints,
chipAnimationStyle: chipAnimationStyle,
mouseCursor: mouseCursor,
);
}
}

View File

@ -132,6 +132,7 @@ class InputChip extends StatelessWidget
this.avatarBoxConstraints,
this.deleteIconBoxConstraints,
this.chipAnimationStyle,
this.mouseCursor,
}) : assert(pressElevation == null || pressElevation >= 0.0),
assert(elevation == null || elevation >= 0.0);
@ -209,6 +210,8 @@ class InputChip extends StatelessWidget
final BoxConstraints? deleteIconBoxConstraints;
@override
final ChipAnimationStyle? chipAnimationStyle;
@override
final MouseCursor? mouseCursor;
@override
Widget build(BuildContext context) {
@ -257,6 +260,7 @@ class InputChip extends StatelessWidget
avatarBoxConstraints: avatarBoxConstraints,
deleteIconBoxConstraints: deleteIconBoxConstraints,
chipAnimationStyle: chipAnimationStyle,
mouseCursor: mouseCursor,
);
}
}

View File

@ -516,7 +516,7 @@ void main() {
home: Center(
child: CupertinoCheckbox(
value: value,
onChanged: enabled ? (bool? value) => true : null,
onChanged: enabled ? (bool? value) {} : null,
mouseCursor: const _CheckboxMouseCursor(),
focusNode: focusNode
),

View File

@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
/// Adds the basic requirements for a Chip.
@ -529,4 +533,77 @@ void main() {
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
});
testWidgets('ActionChip mouse cursor behavior', (WidgetTester tester) async {
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
await tester.pumpWidget(wrapForChip(
child: const Center(
child: ActionChip(
mouseCursor: customCursor,
label: Text('Chip'),
),
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: const Offset(10, 10));
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.basic,
);
final Offset chip = tester.getCenter(find.text('Chip'));
await gesture.moveTo(chip);
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
customCursor,
);
});
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
addTearDown(focusNode.dispose);
Widget buildChip({ required bool enabled }) {
return wrapForChip(
child: Center(
child: ActionChip(
mouseCursor: const WidgetStateMouseCursor.fromMap(
<WidgetStatesConstraint, MouseCursor>{
WidgetState.disabled: SystemMouseCursors.forbidden,
WidgetState.focused: SystemMouseCursors.grab,
WidgetState.any: SystemMouseCursors.basic,
},
),
focusNode: focusNode,
label: const Text('Chip'),
onPressed: enabled ? () {} : null,
),
),
);
}
await tester.pumpWidget(buildChip(enabled: true));
// Unfocused case.
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
addTearDown(gesture1.removePointer);
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
await tester.pump();
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
// Focused case.
focusNode.requestFocus();
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
// Disabled case.
await tester.pumpWidget(buildChip(enabled: false));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
});
}

View File

@ -12,6 +12,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import '../widgets/feedback_tester.dart';
import '../widgets/semantics_tester.dart';
@ -6082,6 +6083,61 @@ void main() {
isNot(paints..rrect(color: hoverColor)..rect(color: themeDataHoverColor)),
);
});
testWidgets('Chip mouse cursor behavior', (WidgetTester tester) async {
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
await tester.pumpWidget(wrapForChip(
child: const Center(
child: Chip(
mouseCursor: customCursor,
label: Text('Chip'),
),
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: const Offset(10, 10));
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.basic,
);
final Offset chip = tester.getCenter(find.text('Chip'));
await gesture.moveTo(chip);
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
customCursor,
);
});
testWidgets('Mouse cursor resolves in disabled states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
await tester.pumpWidget(
wrapForChip(
child: const Center(
child: Chip(
mouseCursor: WidgetStateMouseCursor.fromMap(
<WidgetStatesConstraint, MouseCursor>{
WidgetState.disabled: SystemMouseCursors.forbidden,
},
),
label: Text('Chip'),
),
),
),
);
// Unfocused case.
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
addTearDown(gesture1.removePointer);
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
await tester.pump();
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
});
}
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {

View File

@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
RenderBox getMaterialBox(WidgetTester tester, Finder type) {
@ -813,4 +817,79 @@ void main() {
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
});
testWidgets('ChoiceChip mouse cursor behavior', (WidgetTester tester) async {
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
await tester.pumpWidget(wrapForChip(
child: const Center(
child: ChoiceChip(
selected: false,
mouseCursor: customCursor,
label: Text('Chip'),
),
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: const Offset(10, 10));
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.basic,
);
final Offset chip = tester.getCenter(find.text('Chip'));
await gesture.moveTo(chip);
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
customCursor,
);
});
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
addTearDown(focusNode.dispose);
Widget buildChip({ required bool enabled }) {
return wrapForChip(
child: Center(
child: ChoiceChip(
mouseCursor: const WidgetStateMouseCursor.fromMap(
<WidgetStatesConstraint, MouseCursor>{
WidgetState.disabled: SystemMouseCursors.forbidden,
WidgetState.focused: SystemMouseCursors.grab,
WidgetState.selected: SystemMouseCursors.click,
WidgetState.any: SystemMouseCursors.basic,
},
),
focusNode: focusNode,
label: const Text('Chip'),
onSelected: enabled ? (bool value) {} : null,
selected: false,
),
),
);
}
// Unfocused case.
await tester.pumpWidget(buildChip(enabled: true));
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
addTearDown(gesture1.removePointer);
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
await tester.pump();
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
// Focused case.
focusNode.requestFocus();
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
// Disabled case.
await tester.pumpWidget(buildChip(enabled: false));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
});
}

View File

@ -10,6 +10,8 @@ library;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import '../widgets/feedback_tester.dart';
@ -1324,4 +1326,78 @@ void main() {
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
});
testWidgets('FilterChip mouse cursor behavior', (WidgetTester tester) async {
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
await tester.pumpWidget(wrapForChip(
child: Center(
child: FilterChip(
mouseCursor: customCursor,
label: const Text('Chip'),
onSelected: (bool value) {},
),
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: const Offset(10, 10));
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.basic,
);
final Offset chip = tester.getCenter(find.text('Chip'));
await gesture.moveTo(chip);
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
customCursor,
);
});
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
addTearDown(focusNode.dispose);
Widget buildChip({ required bool enabled }) {
return wrapForChip(
child: Center(
child: FilterChip(
mouseCursor: const WidgetStateMouseCursor.fromMap(
<WidgetStatesConstraint, MouseCursor>{
WidgetState.disabled: SystemMouseCursors.forbidden,
WidgetState.focused: SystemMouseCursors.grab,
WidgetState.selected: SystemMouseCursors.click,
WidgetState.any: SystemMouseCursors.basic,
},
),
focusNode: focusNode,
label: const Text('Chip'),
onSelected: enabled ? (bool value) {} : null,
),
),
);
}
// Unfocused case.
await tester.pumpWidget(buildChip(enabled: true));
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
addTearDown(gesture1.removePointer);
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
await tester.pump();
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
// Focused case.
focusNode.requestFocus();
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
// Disabled case.
await tester.pumpWidget(buildChip(enabled: false));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
});
}

View File

@ -9,6 +9,8 @@ library;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
/// Adds the basic requirements for a Chip.
@ -617,4 +619,77 @@ void main() {
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
});
testWidgets('InputChip mouse cursor behavior', (WidgetTester tester) async {
const SystemMouseCursor customCursor = SystemMouseCursors.grab;
await tester.pumpWidget(wrapForChip(
child: const Center(
child: InputChip(
mouseCursor: customCursor,
label: Text('Chip'),
),
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: const Offset(10, 10));
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.basic,
);
final Offset chip = tester.getCenter(find.text('Chip'));
await gesture.moveTo(chip);
await tester.pump();
expect(
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
customCursor,
);
});
testWidgets('Mouse cursor resolves in focused/unfocused/disabled states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final FocusNode focusNode = FocusNode(debugLabel: 'Chip');
addTearDown(focusNode.dispose);
Widget buildChip({ required bool enabled }) {
return wrapForChip(
child: Center(
child: InputChip(
mouseCursor: const WidgetStateMouseCursor.fromMap(
<WidgetStatesConstraint, MouseCursor>{
WidgetState.disabled: SystemMouseCursors.forbidden,
WidgetState.focused: SystemMouseCursors.grab,
WidgetState.selected: SystemMouseCursors.click,
WidgetState.any: SystemMouseCursors.basic,
},
),
focusNode: focusNode,
label: const Text('Chip'),
onSelected: enabled ? (bool value) {} : null,
),
),
);
}
// Unfocused case.
await tester.pumpWidget(buildChip(enabled: true));
final TestGesture gesture1 = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
addTearDown(gesture1.removePointer);
await gesture1.addPointer(location: tester.getCenter(find.text('Chip')));
await tester.pump();
await gesture1.moveTo(tester.getCenter(find.text('Chip')));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
// Focused case.
focusNode.requestFocus();
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
// Disabled case.
await tester.pumpWidget(buildChip(enabled: false));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
});
}