diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index 89f781fc946..cf5170711f5 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -161,7 +161,10 @@ class _DropdownMenuItemButtonState extends State<_DropdownMenuItemButton> } static final Map _webShortcuts ={ - LogicalKeySet(LogicalKeyboardKey.enter): const ActivateIntent(), + // On the web, up/down don't change focus, *except* in a - // element, which is what a dropdown emulates. child = Shortcuts( shortcuts: _webShortcuts, child: child, diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index bedac096f1a..61ee8934dc2 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -2601,7 +2601,7 @@ void main() { final Element element = tester.element(find.byKey(const ValueKey('two')).last); final FocusNode node = Focus.of(element); expect(node.hasFocus, isTrue); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320 + }); testWidgets('Selected element is correctly focused with dropdown that more items than fit on the screen', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton'); @@ -2664,7 +2664,7 @@ void main() { final Element element = tester.element(find.byKey(const ValueKey(42)).last); final FocusNode node = Focus.of(element); expect(node.hasFocus, isTrue); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320 + }); testWidgets("Having a focused element doesn't interrupt scroll when flung by touch", (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton'); @@ -2738,7 +2738,66 @@ void main() { // Scrolling to the top again has removed the one the focus was on from the // tree, causing it to lose focus. expect(Focus.of(tester.element(find.byKey(const ValueKey(91)).last)).hasPrimaryFocus, isFalse); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55320 + }); + + testWidgets('DropdownButton changes selected item with arrow keys', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton'); + String? value = 'one'; + + Widget buildFrame() { + return MaterialApp( + home: Scaffold( + body: Center( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return DropdownButton( + focusNode: focusNode, + autofocus: true, + onChanged: (String? newValue) { + setState(() { + value = newValue; + }); + }, + value: value, + itemHeight: null, + items: menuItems.map>((String item) { + return DropdownMenuItem( + key: ValueKey(item), + value: item, + child: Text(item, key: ValueKey(item + 'Text')), + ); + }).toList(), + ); + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame()); + await tester.pump(); // Pump a frame for autofocus to take effect. + expect(focusNode.hasPrimaryFocus, isTrue); + + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); // finish the menu animation + expect(value, equals('one')); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Focus 'two'. + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Focus 'three'. + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); // Back to 'two'. + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.enter); // Select 'two'. + await tester.pump(); + + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); // finish the menu animation + + expect(value, equals('two')); + }); testWidgets('DropdownButton onTap callback is called when defined', (WidgetTester tester) async { int dropdownButtonTapCounter = 0;