| // 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/cupertino.dart'; |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| // Constants taken from _ContextMenuActionState. |
| const kBackgroundColor = CupertinoDynamicColor.withBrightness( |
| color: Color(0xFFF1F1F1), |
| darkColor: Color(0xFF212122), |
| ); |
| const kBackgroundColorPressed = CupertinoDynamicColor.withBrightness( |
| color: Color(0xFFDDDDDD), |
| darkColor: Color(0xFF3F3F40), |
| ); |
| const Color kDestructiveActionColor = CupertinoColors.destructiveRed; |
| const FontWeight kDefaultActionWeight = FontWeight.w600; |
| |
| Widget getApp({ |
| VoidCallback? onPressed, |
| bool isDestructiveAction = false, |
| bool isDefaultAction = false, |
| Brightness? brightness, |
| }) { |
| final actionKey = UniqueKey(); |
| final action = CupertinoContextMenuAction( |
| key: actionKey, |
| onPressed: onPressed, |
| trailingIcon: CupertinoIcons.home, |
| isDestructiveAction: isDestructiveAction, |
| isDefaultAction: isDefaultAction, |
| child: const Text('I am a CupertinoContextMenuAction'), |
| ); |
| |
| return CupertinoApp( |
| theme: CupertinoThemeData(brightness: brightness ?? Brightness.light), |
| home: CupertinoPageScaffold(child: Center(child: action)), |
| ); |
| } |
| |
| TextStyle getTextStyle(WidgetTester tester) { |
| final Finder finder = find.descendant( |
| of: find.byType(CupertinoContextMenuAction), |
| matching: find.byType(DefaultTextStyle), |
| ); |
| expect(finder, findsOneWidget); |
| final DefaultTextStyle defaultStyle = tester.widget(finder); |
| return defaultStyle.style; |
| } |
| |
| Icon getIcon(WidgetTester tester) { |
| final Finder finder = find.descendant( |
| of: find.byType(CupertinoContextMenuAction), |
| matching: find.byType(Icon), |
| ); |
| expect(finder, findsOneWidget); |
| final Icon icon = tester.widget(finder); |
| return icon; |
| } |
| |
| testWidgets('responds to taps', (WidgetTester tester) async { |
| var wasPressed = false; |
| await tester.pumpWidget( |
| getApp( |
| onPressed: () { |
| wasPressed = true; |
| }, |
| ), |
| ); |
| |
| expect(wasPressed, false); |
| await tester.tap(find.byType(CupertinoContextMenuAction)); |
| expect(wasPressed, true); |
| }); |
| |
| testWidgets('turns grey when pressed and held', (WidgetTester tester) async { |
| await tester.pumpWidget(getApp()); |
| expect(find.byType(CupertinoContextMenuAction), paints..rect(color: kBackgroundColor.color)); |
| |
| final Offset actionCenterLight = tester.getCenter(find.byType(CupertinoContextMenuAction)); |
| final TestGesture gestureLight = await tester.startGesture(actionCenterLight); |
| await tester.pump(); |
| expect( |
| find.byType(CupertinoContextMenuAction), |
| paints..rect(color: kBackgroundColorPressed.color), |
| ); |
| |
| await gestureLight.up(); |
| await tester.pump(); |
| expect(find.byType(CupertinoContextMenuAction), paints..rect(color: kBackgroundColor.color)); |
| |
| await tester.pumpWidget(getApp(brightness: Brightness.dark)); |
| expect( |
| find.byType(CupertinoContextMenuAction), |
| paints..rect(color: kBackgroundColor.darkColor), |
| ); |
| |
| final Offset actionCenterDark = tester.getCenter(find.byType(CupertinoContextMenuAction)); |
| final TestGesture gestureDark = await tester.startGesture(actionCenterDark); |
| await tester.pump(); |
| expect( |
| find.byType(CupertinoContextMenuAction), |
| paints..rect(color: kBackgroundColorPressed.darkColor), |
| ); |
| |
| await gestureDark.up(); |
| await tester.pump(); |
| expect( |
| find.byType(CupertinoContextMenuAction), |
| paints..rect(color: kBackgroundColor.darkColor), |
| ); |
| }); |
| |
| testWidgets('icon and textStyle colors are correct out of the box', (WidgetTester tester) async { |
| await tester.pumpWidget(getApp()); |
| expect(getTextStyle(tester).color, CupertinoColors.label); |
| expect(getIcon(tester).color, CupertinoColors.label); |
| }); |
| |
| testWidgets('icon and textStyle colors are correct for destructive actions', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget(getApp(isDestructiveAction: true)); |
| expect(getTextStyle(tester).color, kDestructiveActionColor); |
| expect(getIcon(tester).color, kDestructiveActionColor); |
| }); |
| |
| testWidgets('textStyle is correct for defaultAction for Brightness.light', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget(getApp(isDefaultAction: true)); |
| expect(getTextStyle(tester).fontWeight, kDefaultActionWeight); |
| final Element context = tester.element(find.byType(CupertinoContextMenuAction)); |
| // The dynamic color should have been resolved. |
| expect(getTextStyle(tester).color, CupertinoColors.label.resolveFrom(context)); |
| }); |
| |
| testWidgets('textStyle is correct for defaultAction for Brightness.dark', ( |
| WidgetTester tester, |
| ) async { |
| // Regression test for https://github.com/flutter/flutter/issues/144492. |
| await tester.pumpWidget(getApp(isDefaultAction: true, brightness: Brightness.dark)); |
| expect(getTextStyle(tester).fontWeight, kDefaultActionWeight); |
| final Element context = tester.element(find.byType(CupertinoContextMenuAction)); |
| // The dynamic color should have been resolved. |
| expect(getTextStyle(tester).color, CupertinoColors.label.resolveFrom(context)); |
| }); |
| |
| testWidgets('Hovering over Cupertino context menu action updates cursor to clickable on Web', ( |
| WidgetTester tester, |
| ) async { |
| /// Cupertino context menu action without "onPressed" callback. |
| await tester.pumpWidget(getApp()); |
| final Offset contextMenuAction = tester.getCenter( |
| find.text('I am a CupertinoContextMenuAction'), |
| ); |
| final TestGesture gesture = await tester.createGesture( |
| kind: PointerDeviceKind.mouse, |
| pointer: 1, |
| ); |
| await gesture.addPointer(location: contextMenuAction); |
| await tester.pumpAndSettle(); |
| expect( |
| RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), |
| SystemMouseCursors.basic, |
| ); |
| |
| // / Cupertino context menu action with "onPressed" callback. |
| await tester.pumpWidget(getApp(onPressed: () {})); |
| await gesture.moveTo(const Offset(10, 10)); |
| await tester.pumpAndSettle(); |
| expect( |
| RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), |
| SystemMouseCursors.basic, |
| ); |
| |
| await gesture.moveTo(contextMenuAction); |
| await tester.pumpAndSettle(); |
| expect( |
| RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), |
| kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic, |
| ); |
| }); |
| |
| testWidgets('CupertinoContextMenuAction does not crash at zero area', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: SizedBox.shrink(child: CupertinoContextMenuAction(child: Text('X'))), |
| ), |
| ), |
| ); |
| expect(tester.getSize(find.byType(CupertinoContextMenuAction)), Size.zero); |
| }); |
| } |