From 84e66863386ea5f8ab39a82c8770cc9756ccbb40 Mon Sep 17 00:00:00 2001 From: fujidaiti Date: Sun, 21 Jul 2024 21:32:47 +0900 Subject: [PATCH] Add tests for sheet notifications --- .../foundation/sheet_notification_test.dart | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 package/test/foundation/sheet_notification_test.dart diff --git a/package/test/foundation/sheet_notification_test.dart b/package/test/foundation/sheet_notification_test.dart new file mode 100644 index 00000000..aa1541a4 --- /dev/null +++ b/package/test/foundation/sheet_notification_test.dart @@ -0,0 +1,306 @@ +import 'dart:async'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smooth_sheets/src/draggable/draggable_sheet.dart'; +import 'package:smooth_sheets/src/foundation/sheet_controller.dart'; +import 'package:smooth_sheets/src/foundation/sheet_extent.dart'; +import 'package:smooth_sheets/src/foundation/sheet_notification.dart'; +import 'package:smooth_sheets/src/foundation/sheet_physics.dart'; +import 'package:smooth_sheets/src/foundation/sheet_status.dart'; + +void main() { + testWidgets( + 'Drag gesture should dispatch drag start/update/end notifications in sequence', + (tester) async { + final reportedNotifications = []; + const targetKey = Key('target'); + + await tester.pumpWidget( + NotificationListener( + onNotification: (notification) { + reportedNotifications.add(notification); + return false; + }, + child: DraggableSheet( + minExtent: const Extent.pixels(0), + // Disable the snapping effect + physics: const ClampingSheetPhysics(), + child: Container( + key: targetKey, + color: Colors.white, + width: double.infinity, + height: 500, + ), + ), + ), + ); + + final gesturePointer = await tester.press(find.byKey(targetKey)); + await gesturePointer.moveBy(const Offset(0, 20)); + await tester.pump(); + expect(reportedNotifications, hasLength(2)); + expect( + reportedNotifications[0], + isA() + .having((e) => e.metrics.maybePixels, 'pixels', 500) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having((e) => e.dragDetails.kind, 'kind', PointerDeviceKind.touch) + .having( + (e) => e.dragDetails.localPosition, + 'localPosition', + const Offset(400, 250), + ) + .having( + (e) => e.dragDetails.globalPosition, + 'globalPosition', + const Offset(400, 350), + ), + ); + expect( + reportedNotifications[1], + isA() + .having((e) => e.metrics.maybePixels, 'pixels', 480) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having( + (e) => e.dragDetails.axisDirection, + 'axisDirection', + VerticalDirection.up, + ) + .having( + (e) => e.dragDetails.localPosition, + 'localPosition', + const Offset(400, 270), + ) + .having( + (e) => e.dragDetails.globalPosition, + 'globalPosition', + const Offset(400, 370), + ), + ); + + reportedNotifications.clear(); + await gesturePointer.moveBy(const Offset(0, 20)); + await tester.pump(); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.maybePixels, 'pixels', 460) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having( + (e) => e.dragDetails.axisDirection, + 'axisDirection', + VerticalDirection.up, + ) + .having( + (e) => e.dragDetails.localPosition, + 'localPosition', + const Offset(400, 290), + ) + .having( + (e) => e.dragDetails.globalPosition, + 'globalPosition', + const Offset(400, 390), + ), + ); + + reportedNotifications.clear(); + await gesturePointer.moveBy(const Offset(0, -20)); + await tester.pump(); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.maybePixels, 'pixels', 480) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having( + (e) => e.dragDetails.axisDirection, + 'axisDirection', + VerticalDirection.up, + ) + .having( + (e) => e.dragDetails.localPosition, + 'localPosition', + const Offset(400, 270), + ) + .having( + (e) => e.dragDetails.globalPosition, + 'globalPosition', + const Offset(400, 370), + ), + ); + + reportedNotifications.clear(); + await gesturePointer.up(); + await tester.pump(); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.maybePixels, 'pixels', 480) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having((e) => e.dragDetails.velocity, 'velocity', Velocity.zero) + .having( + (e) => e.dragDetails.axisDirection, + 'axisDirection', + VerticalDirection.up, + ), + ); + + reportedNotifications.clear(); + await tester.pumpAndSettle(); + expect(reportedNotifications, isEmpty, + reason: 'Once the drag is ended, ' + 'no notification should be dispatched.'); + }, + ); + + testWidgets( + 'Sheet animation should dispatch metrics update notifications', + (tester) async { + final reportedNotifications = []; + final controller = SheetController(); + + await tester.pumpWidget( + NotificationListener( + onNotification: (notification) { + reportedNotifications.add(notification); + return false; + }, + child: DraggableSheet( + controller: controller, + minExtent: const Extent.pixels(0), + // Disable the snapping effect + physics: const ClampingSheetPhysics(), + child: Container( + color: Colors.white, + width: double.infinity, + height: 600, + ), + ), + ), + ); + + unawaited( + controller.animateTo( + const Extent.pixels(0), + duration: const Duration(milliseconds: 300), + curve: Curves.linear, + ), + ); + await tester.pump(Duration.zero); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.pixels, 'pixels', moreOrLessEquals(600)) + .having((e) => e.status, 'status', SheetStatus.animating), + ); + + reportedNotifications.clear(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.pixels, 'pixels', moreOrLessEquals(400)) + .having((e) => e.status, 'status', SheetStatus.animating), + ); + + reportedNotifications.clear(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.pixels, 'pixels', moreOrLessEquals(200)) + .having((e) => e.status, 'status', SheetStatus.animating), + ); + + reportedNotifications.clear(); + await tester.pump(const Duration(seconds: 100)); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.pixels, 'pixels', moreOrLessEquals(0)) + .having((e) => e.status, 'status', SheetStatus.animating), + ); + + reportedNotifications.clear(); + await tester.pumpAndSettle(); + expect(reportedNotifications, isEmpty, + reason: 'Once the animation is finished, ' + 'no notification should be dispatched.'); + }, + ); + + testWidgets( + 'Over-darg gesture should dispatch both darg and overflow notifications', + (tester) async { + final reportedNotifications = []; + const targetKey = Key('target'); + + await tester.pumpWidget( + NotificationListener( + onNotification: (notification) { + reportedNotifications.add(notification); + return false; + }, + child: DraggableSheet( + // Make sure the sheet can't be dragged + minExtent: const Extent.proportional(1), + maxExtent: const Extent.proportional(1), + // Disable the snapping effect + physics: const ClampingSheetPhysics(), + child: Container( + key: targetKey, + color: Colors.white, + width: double.infinity, + height: 500, + ), + ), + ), + ); + + final gesturePointer = await tester.press(find.byKey(targetKey)); + await gesturePointer.moveBy(const Offset(0, 20)); + await tester.pump(); + expect(reportedNotifications, hasLength(2)); + expect( + reportedNotifications[0], + isA().having( + (e) => e.dragDetails.axisDirection, + 'axisDirection', + // Since the y-axis is upward and we are performing a downward drag, + // the sign of the overflowed delta should be negative. + VerticalDirection.up, + ), + ); + expect( + reportedNotifications[1], + isA() + .having((e) => e.metrics.pixels, 'pixels', 500) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having((e) => e.overflow, 'overflow', -20), + ); + + reportedNotifications.clear(); + await gesturePointer.moveBy(const Offset(0, 20)); + await tester.pump(); + expect( + reportedNotifications.single, + isA() + .having((e) => e.metrics.pixels, 'pixels', 500) + .having((e) => e.status, 'status', SheetStatus.dragging) + .having((e) => e.overflow, 'overflow', -20), + ); + + reportedNotifications.clear(); + await gesturePointer.up(); + await tester.pump(); + expect(reportedNotifications.single, isA()); + + reportedNotifications.clear(); + await tester.pumpAndSettle(); + expect(reportedNotifications, isEmpty, + reason: 'Once the drag is ended, ' + 'no notification should be dispatched.'); + }, + ); +}