import 'package:flutter/cupertino.dart' show CupertinoIcons; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:spotiflac_android/widgets/mornye_playback_button.dart'; void main() { Future pumpButton( WidgetTester tester, { required VoidCallback onPressed, IconData icon = CupertinoIcons.play_fill, bool reduceMotion = false, }) => tester.pumpWidget( MaterialApp( home: MediaQuery( data: MediaQueryData(disableAnimations: reduceMotion), child: Scaffold( body: Center( child: MornyePlaybackButton( icon: icon, tooltip: 'Playback action', color: Colors.white, onPressed: onPressed, ), ), ), ), ), ); testWidgets('press feedback keeps the tap target fixed and cancels safely', ( tester, ) async { var calls = 0; await pumpButton(tester, onPressed: () => calls++); final button = find.byType(IconButton); final icon = find.byIcon(CupertinoIcons.play_fill); final bounds = tester.getRect(button); final iconBounds = tester.getRect(icon); final press = await tester.startGesture(bounds.center); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 200)); expect(tester.getRect(icon).width, lessThan(iconBounds.width)); expect(tester.getRect(button), bounds); await press.up(); await tester.pumpAndSettle(); expect(calls, 1); expect(tester.getRect(icon), iconBounds); final cancelled = await tester.startGesture(bounds.center); await tester.pump(const Duration(milliseconds: 100)); await cancelled.cancel(); await tester.pumpAndSettle(); expect(calls, 1); expect(tester.getRect(icon), iconBounds); }); for (final icon in [ CupertinoIcons.forward_fill, CupertinoIcons.backward_fill, ]) { testWidgets( 'skip $icon animates without delaying repeated playback actions', (tester) async { var calls = 0; await pumpButton(tester, icon: icon, onPressed: () => calls++); final button = find.byType(IconButton); final bounds = tester.getRect(button); for (var index = 0; index < 3; index++) { await tester.tap(button); await tester.pump(const Duration(milliseconds: 60)); expect(calls, index + 1); expect(find.byIcon(CupertinoIcons.play_fill), findsNWidgets(3)); expect(tester.getRect(button), bounds); } await tester.pumpAndSettle(); expect(find.byIcon(icon), findsOneWidget); expect(find.byIcon(CupertinoIcons.play_fill), findsNothing); expect(tester.takeException(), isNull); }, ); } testWidgets('Reduce Motion keeps skip glyphs stationary and actions usable', ( tester, ) async { var calls = 0; await pumpButton( tester, icon: CupertinoIcons.forward_fill, reduceMotion: true, onPressed: () => calls++, ); final icon = find.byIcon(CupertinoIcons.forward_fill); final bounds = tester.getRect(icon); final press = await tester.startGesture(tester.getCenter(icon)); await tester.pump(const Duration(milliseconds: 200)); expect(tester.getRect(icon), bounds); await press.up(); await tester.pump(const Duration(milliseconds: 60)); expect(calls, 1); expect(find.byIcon(CupertinoIcons.play_fill), findsNothing); expect(tester.getRect(icon), bounds); await tester.pumpAndSettle(); }); }