@hanzogui/kitchen-sink 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.detoxrc.js +130 -0
- package/.env.production +2 -0
- package/.maestro/config.yaml +4 -0
- package/.maestro/flows/shorthand-variables.yaml +23 -0
- package/.watchmanconfig +1 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/app.json +43 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash.png +0 -0
- package/babel.config.js +25 -0
- package/e2e/CompilerExtraction.test.ts +147 -0
- package/e2e/GroupPressNative.test.ts +167 -0
- package/e2e/MediaQueryGtMd.test.ts +71 -0
- package/e2e/NativePortal.test.ts +113 -0
- package/e2e/PointerEvents.test.ts +116 -0
- package/e2e/PressStyleNative.noRngh.test.ts +191 -0
- package/e2e/PressStyleNative.test.ts +231 -0
- package/e2e/SafeArea.test.ts +57 -0
- package/e2e/SelectAndroidOnPress.test.ts +181 -0
- package/e2e/SelectRemount.test.ts +137 -0
- package/e2e/SheetDragResist.test.ts +370 -0
- package/e2e/SheetKeyboardDrag.test.ts +249 -0
- package/e2e/SheetScrollableDrag.test.ts +560 -0
- package/e2e/ShorthandVariables.test.ts +53 -0
- package/e2e/ThemeChangeBasic.test.ts +123 -0
- package/e2e/ThemeMutation.test.ts +80 -0
- package/e2e/check-rngh-status.test.ts +31 -0
- package/e2e/jest.config.js +19 -0
- package/e2e/utils/colors.ts +75 -0
- package/e2e/utils/navigation.ts +53 -0
- package/eas.json +22 -0
- package/flows/AlertDialog.yaml +17 -0
- package/flows/OpenApp.yaml +25 -0
- package/flows/Select.yaml +13 -0
- package/flows/Sheet.yaml +12 -0
- package/flows/Tabs.yaml +13 -0
- package/flows/Toast.yaml +14 -0
- package/flows/WarmUp.yaml +24 -0
- package/index.html +21 -0
- package/index.js +17 -0
- package/metro.config.js +64 -0
- package/next-router-shim.ts +9 -0
- package/package.json +118 -0
- package/plans/toast-2.md +471 -0
- package/playwright.config.ts +71 -0
- package/plugins/expo-modules-core-swift6.js +76 -0
- package/pod-install.sh +7 -0
- package/public/favicon.svg +70 -0
- package/public/fonts/inter.css +15 -0
- package/public/fonts/noto-cn.otf +0 -0
- package/public/gui-icon.svg +68 -0
- package/run-detox.sh +230 -0
- package/run-native-tests.sh +4 -0
- package/run-tests-parallel.ts +195 -0
- package/screenshots/Screenshotter.test.tsx +48 -0
- package/src/AnimationDemos.tsx +131 -0
- package/src/App.native.tsx +121 -0
- package/src/App.tsx +121 -0
- package/src/Navigation.tsx +98 -0
- package/src/Sandbox.tsx +87 -0
- package/src/TestDynamicEval.tsx +33 -0
- package/src/TestNativeSheet.tsx +100 -0
- package/src/components/TimedRender.tsx +18 -0
- package/src/constants/test-ids.ts +52 -0
- package/src/features/demos/demo-screen.tsx +72 -0
- package/src/features/home/ColorSchemeListItem.tsx +41 -0
- package/src/features/home/TestBuildAButton.tsx +102 -0
- package/src/features/home/TestSeparator.tsx +0 -0
- package/src/features/home/screen.tsx +285 -0
- package/src/features/testcases/screen.tsx +59 -0
- package/src/features/testcases/test-screen.tsx +50 -0
- package/src/generatedV5Theme.ts +112 -0
- package/src/gui.config.ts +411 -0
- package/src/guy.png +0 -0
- package/src/index.tsx +6 -0
- package/src/provider/index.tsx +18 -0
- package/src/test-gui-stack.tsx +11 -0
- package/src/test.tsx +3 -0
- package/src/useKitchenSinkTheme.tsx +15 -0
- package/src/usecases/ActionsSheetComparison.tsx +194 -0
- package/src/usecases/AnimatePresenceEnterExitCase.tsx +255 -0
- package/src/usecases/AnimatePresenceExitTest.tsx +69 -0
- package/src/usecases/AnimatedByProp.tsx +39 -0
- package/src/usecases/AnimationComprehensiveCase.tsx +2515 -0
- package/src/usecases/AnimationValueLoggingCase.tsx +526 -0
- package/src/usecases/AnimationsWithMediaQueriesCase.tsx +110 -0
- package/src/usecases/Benchmark.tsx +148 -0
- package/src/usecases/BenchmarkSelect.tsx +34 -0
- package/src/usecases/ButtonCircular.tsx +3 -0
- package/src/usecases/ButtonCustom.tsx +33 -0
- package/src/usecases/ButtonIconColor.tsx +18 -0
- package/src/usecases/ButtonInverse.tsx +30 -0
- package/src/usecases/ButtonUnstyled.tsx +31 -0
- package/src/usecases/CheckboxDisabledOnPress.tsx +62 -0
- package/src/usecases/ClickDuringEnterCase.tsx +59 -0
- package/src/usecases/CodeExamplesInput.tsx +9 -0
- package/src/usecases/ColorTokenFallback.tsx +52 -0
- package/src/usecases/CompilerExtraction.tsx +380 -0
- package/src/usecases/ComplexVariants.tsx +164 -0
- package/src/usecases/CrashAdaptSheet.tsx +98 -0
- package/src/usecases/CustomStyledAnimatedPopover.tsx +42 -0
- package/src/usecases/CustomStyledAnimatedTooltip.tsx +72 -0
- package/src/usecases/DOMNodeAPIs.tsx +154 -0
- package/src/usecases/DialogFocusScopeCase.tsx +277 -0
- package/src/usecases/DialogFocusScopeDebug.tsx +85 -0
- package/src/usecases/DialogNestedCase.tsx +121 -0
- package/src/usecases/DialogOpenControlled.tsx +49 -0
- package/src/usecases/DialogPointerEventsCase.tsx +58 -0
- package/src/usecases/DialogScopedCase.tsx +106 -0
- package/src/usecases/DialogSheetAdaptCase.tsx +178 -0
- package/src/usecases/DialogSheetAdaptResizeCase.tsx +98 -0
- package/src/usecases/DismissLayerStackingCase.tsx +223 -0
- package/src/usecases/DriverDisableAnimationPropsCase.tsx +44 -0
- package/src/usecases/Example.tsx +10 -0
- package/src/usecases/ExitCompletionCase.tsx +713 -0
- package/src/usecases/FocusVisibleButton.tsx +14 -0
- package/src/usecases/FocusVisibleButtonPointer.tsx +13 -0
- package/src/usecases/FocusVisibleButtonWithFocusStyle.tsx +16 -0
- package/src/usecases/FocusWithinCase.tsx +55 -0
- package/src/usecases/FontTokensInVariants.tsx +14 -0
- package/src/usecases/FormButtonTypeCase.tsx +34 -0
- package/src/usecases/GlobalScopedTriggerIsolationCase.tsx +178 -0
- package/src/usecases/GroupHoverMobile.tsx +39 -0
- package/src/usecases/GroupPressInVariant.tsx +92 -0
- package/src/usecases/GroupPressNative.tsx +200 -0
- package/src/usecases/GroupProp.tsx +96 -0
- package/src/usecases/GroupPseudoVariantOverride.tsx +56 -0
- package/src/usecases/GroupUseCases.tsx +94 -0
- package/src/usecases/HeightMediaQueryOverrideCase.tsx +183 -0
- package/src/usecases/InputAutoFocusAfterMenuCase.tsx +105 -0
- package/src/usecases/InputAutoFocusStyledCase.tsx +39 -0
- package/src/usecases/KeyboardControllerTest.tsx +146 -0
- package/src/usecases/ListItem.tsx +123 -0
- package/src/usecases/MediaQueriesV5.tsx +137 -0
- package/src/usecases/MediaQueryGtMd.tsx +73 -0
- package/src/usecases/MenuAboveDialogCase.tsx +75 -0
- package/src/usecases/MenuAccessibilityCase.tsx +133 -0
- package/src/usecases/MenuAnimatePositionCase.tsx +41 -0
- package/src/usecases/MenuArrowAnimatePresenceCase.tsx +98 -0
- package/src/usecases/MenuAsChildPositionCase.tsx +24 -0
- package/src/usecases/MenuAutoResizeCase.tsx +57 -0
- package/src/usecases/MenuBottomCase.tsx +55 -0
- package/src/usecases/MenuFocusLeaveCase.tsx +135 -0
- package/src/usecases/MenuHighlightCase.tsx +44 -0
- package/src/usecases/MenuItemFocusCase.tsx +79 -0
- package/src/usecases/MenuItemPseudoOverrideCase.tsx +270 -0
- package/src/usecases/MenuMultiTriggerCase.tsx +47 -0
- package/src/usecases/MenuOverflowCase.tsx +60 -0
- package/src/usecases/MenuSubCase.tsx +223 -0
- package/src/usecases/MenuSubLeftCase.tsx +178 -0
- package/src/usecases/MenuSubNestedPositionCase.tsx +171 -0
- package/src/usecases/MenuSubStyledCase.tsx +145 -0
- package/src/usecases/MenuThemeCase.tsx +50 -0
- package/src/usecases/MenuUnstyledCase.tsx +52 -0
- package/src/usecases/MultiDriverAnimation.tsx +118 -0
- package/src/usecases/NativePortalTest.tsx +179 -0
- package/src/usecases/NewInputBasic.tsx +16 -0
- package/src/usecases/NewInputEvents.tsx +29 -0
- package/src/usecases/NonGuiTextStyledType.tsx +23 -0
- package/src/usecases/OnLayoutCase.tsx +134 -0
- package/src/usecases/OnLayoutScaleCase.tsx +88 -0
- package/src/usecases/OnLayoutStressCase.tsx +353 -0
- package/src/usecases/OpacityModifierCase.tsx +113 -0
- package/src/usecases/OverlayStyled.tsx +66 -0
- package/src/usecases/ParagraphSpanFontInheritance.tsx +53 -0
- package/src/usecases/PlaceholderTextColor.tsx +20 -0
- package/src/usecases/PointerEventsCase.tsx +100 -0
- package/src/usecases/PopoverAndMenuMultiTriggerCase.tsx +138 -0
- package/src/usecases/PopoverCase.tsx +222 -0
- package/src/usecases/PopoverContentStyledPlusAnimations.tsx +44 -0
- package/src/usecases/PopoverFocusScopeCase.tsx +171 -0
- package/src/usecases/PopoverHoverableCase.tsx +167 -0
- package/src/usecases/PopoverHoverableDisableClickCase.tsx +118 -0
- package/src/usecases/PopoverHoverableRapidCase.tsx +103 -0
- package/src/usecases/PopoverHoverableScopedCase.tsx +135 -0
- package/src/usecases/PopoverScopedCase.tsx +76 -0
- package/src/usecases/PopoverTriggerIsolationCase.tsx +80 -0
- package/src/usecases/PressStyleNative.tsx +143 -0
- package/src/usecases/PseudoStyleMerge.tsx +25 -0
- package/src/usecases/PseudoTransitionCase.tsx +174 -0
- package/src/usecases/RawAnimatedValueCase.tsx +231 -0
- package/src/usecases/RemoveScrollCase.tsx +66 -0
- package/src/usecases/RenderPropCase.tsx +263 -0
- package/src/usecases/SafeAreaCase.tsx +236 -0
- package/src/usecases/ScrollViewRefCase.tsx +88 -0
- package/src/usecases/SecondPage.tsx +5 -0
- package/src/usecases/SelectAndroidOnPress.tsx +129 -0
- package/src/usecases/SelectFocusScopeCase.tsx +270 -0
- package/src/usecases/SelectRemount.tsx +136 -0
- package/src/usecases/Shadows.tsx +5 -0
- package/src/usecases/SheetAnimationCase.tsx +155 -0
- package/src/usecases/SheetDragCase.tsx +183 -0
- package/src/usecases/SheetDragResistCase.tsx +433 -0
- package/src/usecases/SheetDragResistCase.web.tsx +359 -0
- package/src/usecases/SheetKeyboardDragCase.tsx +328 -0
- package/src/usecases/SheetKeyboardFitContentCase.tsx +165 -0
- package/src/usecases/SheetOnAnimationCompleteCase.tsx +54 -0
- package/src/usecases/SheetScrollLockCase.tsx +166 -0
- package/src/usecases/SheetScrollableDrag.tsx +249 -0
- package/src/usecases/SheetSnapPointsFitCase.tsx +393 -0
- package/src/usecases/ShorthandVariables.tsx +49 -0
- package/src/usecases/SlowThemeReRender.tsx +48 -0
- package/src/usecases/SpinnerCustomColors.tsx +34 -0
- package/src/usecases/StackZIndex.tsx +82 -0
- package/src/usecases/StressPage.tsx +301 -0
- package/src/usecases/StylePlatform.tsx +30 -0
- package/src/usecases/StyleProp.tsx +29 -0
- package/src/usecases/StyledAnchor.tsx +27 -0
- package/src/usecases/StyledButtonAnimationAuto.tsx +99 -0
- package/src/usecases/StyledButtonTheme.tsx +63 -0
- package/src/usecases/StyledButtonVariantPseudo.tsx +25 -0
- package/src/usecases/StyledButtonVariantPseudoMerge.tsx +77 -0
- package/src/usecases/StyledCheckboxTheme.tsx +23 -0
- package/src/usecases/StyledContextColor.tsx +246 -0
- package/src/usecases/StyledContextTokens.tsx +147 -0
- package/src/usecases/StyledHOCNamed.tsx +20 -0
- package/src/usecases/StyledHtmlCase.tsx +144 -0
- package/src/usecases/StyledIconColor.tsx +19 -0
- package/src/usecases/StyledInputFocusStyle.tsx +21 -0
- package/src/usecases/StyledInputOnFocus.tsx +30 -0
- package/src/usecases/StyledMediaQueryMerge.tsx +95 -0
- package/src/usecases/StyledOverridePsuedo.tsx +26 -0
- package/src/usecases/StyledRNW.tsx +61 -0
- package/src/usecases/StyledStyleableInputOnFocus.tsx +34 -0
- package/src/usecases/StyledStyleableInputVariant.tsx +48 -0
- package/src/usecases/StyledStyledStyleableInputOnFocus.tsx +36 -0
- package/src/usecases/StyledVariantTextColor.tsx +25 -0
- package/src/usecases/StyledViewOnFocus.tsx +32 -0
- package/src/usecases/TabHoverAnimationCase.tsx +212 -0
- package/src/usecases/TextNestedInheritance.tsx +80 -0
- package/src/usecases/ThemeChange.tsx +100 -0
- package/src/usecases/ThemeChangeBasic.tsx +52 -0
- package/src/usecases/ThemeComponentResolution.tsx +119 -0
- package/src/usecases/ThemeConditionalName.tsx +31 -0
- package/src/usecases/ThemeMediaAnimationCase.tsx +39 -0
- package/src/usecases/ThemeMutation.tsx +86 -0
- package/src/usecases/ThemeNested.tsx +103 -0
- package/src/usecases/ThemeReset.tsx +62 -0
- package/src/usecases/ThemeShallowCase.tsx +83 -0
- package/src/usecases/ToastCase.tsx +46 -0
- package/src/usecases/ToggleGroupActiveProps.tsx +40 -0
- package/src/usecases/ToggleGroupXGroupCase.tsx +104 -0
- package/src/usecases/TooltipAnimationCase.tsx +99 -0
- package/src/usecases/TooltipCase.tsx +32 -0
- package/src/usecases/TooltipGlobalPatternCase.tsx +83 -0
- package/src/usecases/TooltipGroupCase.tsx +102 -0
- package/src/usecases/TooltipMultiTriggerCase.tsx +88 -0
- package/src/usecases/TooltipPositionJumpCase.tsx +91 -0
- package/src/usecases/TooltipTriggerInlineCase.tsx +60 -0
- package/src/usecases/TransformMediaQueryMerge.tsx +98 -0
- package/src/usecases/UseCases.tsx +409 -0
- package/src/usecases/UseTheme.tsx +41 -0
- package/src/usecases/V5ThemeBuilderOutput.tsx +231 -0
- package/src/usecases/VariantFontFamily.tsx +25 -0
- package/src/usecases/VariantsOrder.tsx +117 -0
- package/src/usecases/ZIndex.tsx +155 -0
- package/src/usecases/helpers.tsx +44 -0
- package/src/usecases/index.native.ts +122 -0
- package/src/usecases/index.ts +3 -0
- package/src/usecases/index.web.ts +177 -0
- package/tests/AnimatePresenceEnterExit.animated.test.tsx +176 -0
- package/tests/AnimatedByProp.animated.test.tsx +138 -0
- package/tests/AnimationBehavior.animated.test.tsx +543 -0
- package/tests/AnimationTiming.animated.test.tsx +195 -0
- package/tests/AnimationsWithMediaQueries.animated.test.tsx +154 -0
- package/tests/BuildAButton.test.tsx +87 -0
- package/tests/ButtonCircular.test.tsx +17 -0
- package/tests/ButtonCustom.test.tsx +17 -0
- package/tests/ButtonIconColor.test.tsx +23 -0
- package/tests/ButtonUnstyled.test.tsx +56 -0
- package/tests/ClickDuringEnter.animated.test.tsx +174 -0
- package/tests/ColorTokenFallback.test.tsx +45 -0
- package/tests/DOMNodeAPIs.test.tsx +161 -0
- package/tests/DialogFocusScope.animated.test.tsx +309 -0
- package/tests/DialogNested.test.tsx +128 -0
- package/tests/DialogOpenControlled.test.tsx +42 -0
- package/tests/DialogPointerEvents.animated.test.tsx +108 -0
- package/tests/DialogScoped.test.tsx +137 -0
- package/tests/DialogSheetAdapt.test.tsx +68 -0
- package/tests/DialogSheetAdaptResize.test.tsx +161 -0
- package/tests/DismissLayerStacking.test.tsx +292 -0
- package/tests/DriverDisableAnimationProps.animated.test.tsx +157 -0
- package/tests/ExitCompletion.animated.test.tsx +425 -0
- package/tests/ExitTimingCheck.animated.test.ts +34 -0
- package/tests/FocusVisibleButton.test.tsx +41 -0
- package/tests/FocusVisibleButtonPointerFocus.test.tsx +23 -0
- package/tests/FocusVisibleButtonPointerFocusWithFocusStyle.test.tsx +40 -0
- package/tests/FocusWithinStyle.animated.test.tsx +66 -0
- package/tests/FocusWithinStyle.test.tsx +60 -0
- package/tests/FormButtonType.test.tsx +42 -0
- package/tests/GlobalScopedTriggerIsolation.test.tsx +89 -0
- package/tests/GroupHoverMobile.test.tsx +52 -0
- package/tests/GroupPressInVariant.test.tsx +82 -0
- package/tests/GroupProp.test.tsx +30 -0
- package/tests/GroupPseudoVariantOverride.test.tsx +57 -0
- package/tests/GroupUseCases.test.tsx +111 -0
- package/tests/GuiSiteMotion.test.ts +481 -0
- package/tests/HeightMediaQueryOverride.test.tsx +112 -0
- package/tests/InputAutoFocusAfterMenu.test.tsx +55 -0
- package/tests/InputAutoFocusStyled.test.tsx +22 -0
- package/tests/ListItem.test.tsx +129 -0
- package/tests/MediaQueriesV5.test.tsx +113 -0
- package/tests/MediaQueryGtMd.test.tsx +84 -0
- package/tests/MenuAboveDialog.test.tsx +108 -0
- package/tests/MenuAccessibility.test.tsx +346 -0
- package/tests/MenuAnimatePosition.animated.test.tsx +57 -0
- package/tests/MenuArrowAnimatePresence.animated.test.tsx +71 -0
- package/tests/MenuAsChildPosition.test.tsx +16 -0
- package/tests/MenuAutoResize.test.tsx +54 -0
- package/tests/MenuFocusLeave.test.tsx +181 -0
- package/tests/MenuHighlight.test.tsx +165 -0
- package/tests/MenuHoverKeyboardBugs.test.tsx +252 -0
- package/tests/MenuItemFocus.test.tsx +59 -0
- package/tests/MenuItemPseudoOverride.test.tsx +231 -0
- package/tests/MenuMultiTrigger.test.tsx +101 -0
- package/tests/MenuOverflow.test.tsx +93 -0
- package/tests/MenuStayInFrame.test.tsx +102 -0
- package/tests/MenuSubKeyboardFocus.test.tsx +220 -0
- package/tests/MenuSubLeftSafePolygon.test.tsx +88 -0
- package/tests/MenuSubNestedPosition.test.tsx +48 -0
- package/tests/MenuSubSafePolygon.test.tsx +97 -0
- package/tests/MenuSubStyled.test.tsx +40 -0
- package/tests/MenuTheme.test.tsx +34 -0
- package/tests/MenuUnstyled.test.tsx +56 -0
- package/tests/MultiDriverAnimation.test.tsx +207 -0
- package/tests/NewInputBasic.test.tsx +50 -0
- package/tests/NewInputEvents.test.tsx +55 -0
- package/tests/OnLayout.test.tsx +163 -0
- package/tests/OnLayoutScale.test.tsx +100 -0
- package/tests/OnLayoutStress.test.tsx +304 -0
- package/tests/ParagraphSpanFontInheritance.test.tsx +73 -0
- package/tests/PointerEvents.test.tsx +123 -0
- package/tests/Popover.animated.test.tsx +234 -0
- package/tests/PopoverAndMenuMultiTrigger.test.tsx +184 -0
- package/tests/PopoverAnimatePosition.animated.test.tsx +51 -0
- package/tests/PopoverClickDuringEnter.animated.test.tsx +197 -0
- package/tests/PopoverFocusScope.test.tsx +242 -0
- package/tests/PopoverHoverable.test.tsx +383 -0
- package/tests/PopoverHoverableDisableClick.test.tsx +106 -0
- package/tests/PopoverHoverableRapid.test.tsx +129 -0
- package/tests/PopoverHoverableReposition.test.tsx +111 -0
- package/tests/PopoverHoverableScoped.animated.test.tsx +103 -0
- package/tests/PopoverHoverableStress.test.tsx +169 -0
- package/tests/PopoverInitialPosition.animated.test.tsx +82 -0
- package/tests/PopoverMiddlewareSkipRegression.animated.test.tsx +221 -0
- package/tests/PopoverScoped.test.tsx +128 -0
- package/tests/PopoverScopedPositionGlitch.animated.test.tsx +184 -0
- package/tests/PopoverTriggerIsolation.test.tsx +62 -0
- package/tests/PseudoTransition.animated.test.tsx +319 -0
- package/tests/RawAnimatedValue.test.tsx +147 -0
- package/tests/RemoveScroll.test.tsx +223 -0
- package/tests/RenderProp.test.tsx +293 -0
- package/tests/ScrollViewRef.test.tsx +39 -0
- package/tests/SelectClickHold.test.tsx +147 -0
- package/tests/SelectFocusScope.test.tsx +176 -0
- package/tests/SelectInnerPositioning.test.tsx +82 -0
- package/tests/SelectKeyboardNav.test.tsx +173 -0
- package/tests/SelectPositioning.test.tsx +56 -0
- package/tests/SelectTypeahead.test.tsx +63 -0
- package/tests/Shadows.test.tsx +14 -0
- package/tests/SheetAnimation.animated.test.tsx +413 -0
- package/tests/SheetDrag.animated.test.tsx +223 -0
- package/tests/SheetDragResist.animated.test.tsx +393 -0
- package/tests/SheetOnAnimationComplete.animated.test.tsx +62 -0
- package/tests/SheetScrollLock.animated.test.tsx +287 -0
- package/tests/SheetScrollableDrag.animated.test.tsx +1264 -0
- package/tests/SheetSnapPointsFit.animated.test.tsx +259 -0
- package/tests/ShorthandVariables.test.tsx +44 -0
- package/tests/SpinnerCustomColors.test.tsx +67 -0
- package/tests/StackZIndex.test.tsx +51 -0
- package/tests/StressPagePerf.test.tsx +76 -0
- package/tests/StylePlatform.test.tsx +38 -0
- package/tests/StyleProp.test.tsx +20 -0
- package/tests/StyledAnchor.test.tsx +17 -0
- package/tests/StyledButtonTheme.test.tsx +22 -0
- package/tests/StyledButtonVariantPseudo.test.tsx +20 -0
- package/tests/StyledButtonVariantPseudoMerge.animated.test.tsx +33 -0
- package/tests/StyledCheckboxTheme.test.tsx +16 -0
- package/tests/StyledContextColor.test.tsx +119 -0
- package/tests/StyledContextTokens.test.tsx +56 -0
- package/tests/StyledHOCNamed.test.tsx +16 -0
- package/tests/StyledHtml.test.tsx +161 -0
- package/tests/StyledIconColor.test.tsx +32 -0
- package/tests/StyledInputFocusStyle.test.tsx +19 -0
- package/tests/StyledInputOnFocus.test.tsx +27 -0
- package/tests/StyledMediaQueryMerge.test.tsx +66 -0
- package/tests/StyledRNW.test.tsx +17 -0
- package/tests/StyledStyleableInputOnFocus.test.tsx +27 -0
- package/tests/StyledStyleableInputVariant.test.tsx +22 -0
- package/tests/StyledStyledStyleableInputOnFocus.test.tsx +27 -0
- package/tests/StyledVariantTextColor.test.tsx +24 -0
- package/tests/StyledViewOnFocus.test.tsx +27 -0
- package/tests/TabHoverAnimation.animated.test.tsx +468 -0
- package/tests/TabHoverPositionSmooth.animated.test.tsx +129 -0
- package/tests/TextNestedInheritance.test.tsx +93 -0
- package/tests/ThemeChange.test.tsx +70 -0
- package/tests/ThemeComponentResolution.test.tsx +82 -0
- package/tests/ThemeConditionalName.test.tsx +34 -0
- package/tests/ThemeMediaAnimation.test.tsx +65 -0
- package/tests/ThemeNested.test.tsx +141 -0
- package/tests/ThemeReset.test.tsx +63 -0
- package/tests/ThemeShallow.test.tsx +95 -0
- package/tests/Toast.test.tsx +106 -0
- package/tests/ToggleGroup.test.tsx +61 -0
- package/tests/ToggleGroupActiveProps.test.tsx +38 -0
- package/tests/ToggleGroupXGroup.test.tsx +172 -0
- package/tests/TooltipAnimation.animated.test.tsx +260 -0
- package/tests/TooltipEnterInterrupt.animated.test.tsx +76 -0
- package/tests/TooltipGlobalPattern.animated.test.tsx +208 -0
- package/tests/TooltipGroup.animated.test.tsx +79 -0
- package/tests/TooltipMultiTrigger.test.tsx +116 -0
- package/tests/TooltipPositionJump.animated.test.tsx +229 -0
- package/tests/TooltipPositionJumpNotes.md +219 -0
- package/tests/TooltipRapidSwitch.animated.test.tsx +399 -0
- package/tests/TooltipTriggerInline.test.tsx +65 -0
- package/tests/TransformMediaQueryMerge.test.tsx +104 -0
- package/tests/TransitionEnterExit.animated.test.tsx +311 -0
- package/tests/UseTheme.test.tsx +16 -0
- package/tests/V5ThemeBuilderOutput.test.tsx +164 -0
- package/tests/VariantFontFamily.test.tsx +11 -0
- package/tests/VariantsOrder.test.tsx +53 -0
- package/tests/_debug_position.mjs +52 -0
- package/tests/test-utils.ts +106 -0
- package/tests/utils.tsx +54 -0
- package/tsconfig.json +45 -0
- package/vite-env.d.ts +1 -0
- package/vite.config.ts +14 -0
- package/webpack.config.js +139 -0
|
@@ -0,0 +1,1264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright E2E Test for Sheet + ScrollView gesture coordination
|
|
3
|
+
*
|
|
4
|
+
* Ported from Detox tests to verify web implementation matches native quality.
|
|
5
|
+
*
|
|
6
|
+
* Tests the smooth handoff behavior between sheet dragging and scrollview scrolling:
|
|
7
|
+
* 1. At top snap point + swipe up → scroll content naturally
|
|
8
|
+
* 2. At top snap point + swipe down → drag sheet down (NOT scroll)
|
|
9
|
+
* 3. Scrolled down + drag down → scroll to top THEN hand off to sheet drag
|
|
10
|
+
* 4. Dragging up + hit sheet top → continue into scrolling
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
14
|
+
import { setupPage } from './test-utils'
|
|
15
|
+
|
|
16
|
+
// mobile viewport with touch support for realistic sheet testing
|
|
17
|
+
test.use({
|
|
18
|
+
viewport: { width: 390, height: 844 },
|
|
19
|
+
hasTouch: true,
|
|
20
|
+
isMobile: true,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test.beforeEach(async ({ page }) => {
|
|
24
|
+
// capture console logs for debugging
|
|
25
|
+
page.on('console', (msg) => {
|
|
26
|
+
if (
|
|
27
|
+
msg.text().includes('[Sheet') ||
|
|
28
|
+
msg.text().includes('[ScrollView') ||
|
|
29
|
+
msg.text().includes('[gesture')
|
|
30
|
+
) {
|
|
31
|
+
console.log(`BROWSER: ${msg.text()}`)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
await setupPage(page, { name: 'SheetScrollableDrag', type: 'useCase' })
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* perform a drag gesture using touch events via touchscreen API
|
|
39
|
+
* this properly triggers touch events which our gesture handlers listen for
|
|
40
|
+
*
|
|
41
|
+
* use mode: 'touch' for scrollview/content areas (synthetic touch events)
|
|
42
|
+
* use mode: 'mouse' for handle/frame areas (PanResponder uses mouse events on web)
|
|
43
|
+
*/
|
|
44
|
+
async function dragSheet(
|
|
45
|
+
page: Page,
|
|
46
|
+
startX: number,
|
|
47
|
+
startY: number,
|
|
48
|
+
deltaY: number,
|
|
49
|
+
options: { steps?: number; stepDelay?: number; mode?: 'touch' | 'mouse' } = {}
|
|
50
|
+
) {
|
|
51
|
+
const { steps = 20, stepDelay = 16, mode = 'touch' } = options
|
|
52
|
+
|
|
53
|
+
if (mode === 'mouse') {
|
|
54
|
+
// use mouse events for PanResponder-based elements (handle, frame)
|
|
55
|
+
await page.mouse.move(startX, startY)
|
|
56
|
+
await page.mouse.down()
|
|
57
|
+
|
|
58
|
+
for (let i = 1; i <= steps; i++) {
|
|
59
|
+
await page.mouse.move(startX, startY + (deltaY * i) / steps)
|
|
60
|
+
await page.waitForTimeout(stepDelay)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await page.mouse.up()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// touch mode for ScrollView areas
|
|
68
|
+
const endY = startY + deltaY
|
|
69
|
+
|
|
70
|
+
// touchscreen doesn't have a direct swipe, so we use evaluate to dispatch touch events
|
|
71
|
+
await page.evaluate(
|
|
72
|
+
({ startX, startY, endY, steps, stepDelay }) => {
|
|
73
|
+
return new Promise<void>((resolve) => {
|
|
74
|
+
const target = document.elementFromPoint(startX, startY)
|
|
75
|
+
if (!target) {
|
|
76
|
+
resolve()
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const dispatchTouch = (type: string, x: number, y: number) => {
|
|
81
|
+
const touch = new Touch({
|
|
82
|
+
identifier: 0,
|
|
83
|
+
target,
|
|
84
|
+
clientX: x,
|
|
85
|
+
clientY: y,
|
|
86
|
+
pageX: x,
|
|
87
|
+
pageY: y,
|
|
88
|
+
})
|
|
89
|
+
const touchEvent = new TouchEvent(type, {
|
|
90
|
+
bubbles: true,
|
|
91
|
+
cancelable: true,
|
|
92
|
+
touches: type === 'touchend' ? [] : [touch],
|
|
93
|
+
targetTouches: type === 'touchend' ? [] : [touch],
|
|
94
|
+
changedTouches: [touch],
|
|
95
|
+
})
|
|
96
|
+
target.dispatchEvent(touchEvent)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// touchstart
|
|
100
|
+
dispatchTouch('touchstart', startX, startY)
|
|
101
|
+
|
|
102
|
+
let step = 0
|
|
103
|
+
const interval = setInterval(() => {
|
|
104
|
+
step++
|
|
105
|
+
const progress = step / steps
|
|
106
|
+
const currentY = startY + (endY - startY) * progress
|
|
107
|
+
dispatchTouch('touchmove', startX, currentY)
|
|
108
|
+
|
|
109
|
+
if (step >= steps) {
|
|
110
|
+
clearInterval(interval)
|
|
111
|
+
dispatchTouch('touchend', startX, endY)
|
|
112
|
+
resolve()
|
|
113
|
+
}
|
|
114
|
+
}, stepDelay)
|
|
115
|
+
})
|
|
116
|
+
},
|
|
117
|
+
{ startX, startY, endY, steps, stepDelay }
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
test.describe('SheetScrollableDrag - RNGH Web Equivalent', () => {
|
|
122
|
+
test('should open sheet at position 0', async ({ page }) => {
|
|
123
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
124
|
+
await page.waitForTimeout(600)
|
|
125
|
+
|
|
126
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
127
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
128
|
+
|
|
129
|
+
// should be at position 0 (top snap)
|
|
130
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
131
|
+
'Sheet position: 0'
|
|
132
|
+
)
|
|
133
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
134
|
+
'ScrollView Y: 0'
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('Case 1: drag DOWN at scrollY=0 should drag sheet, NOT scroll', async ({
|
|
139
|
+
page,
|
|
140
|
+
}) => {
|
|
141
|
+
// open sheet
|
|
142
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
143
|
+
await page.waitForTimeout(600)
|
|
144
|
+
|
|
145
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
146
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
147
|
+
|
|
148
|
+
// verify starting state
|
|
149
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
150
|
+
'Sheet position: 0'
|
|
151
|
+
)
|
|
152
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
153
|
+
'ScrollView Y: 0'
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
// get the scrollview for dragging
|
|
157
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
158
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
159
|
+
expect(scrollviewBox).toBeTruthy()
|
|
160
|
+
|
|
161
|
+
// drag DOWN on scrollview - should drag sheet, NOT scroll
|
|
162
|
+
await dragSheet(
|
|
163
|
+
page,
|
|
164
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
165
|
+
scrollviewBox!.y + scrollviewBox!.height / 3,
|
|
166
|
+
200,
|
|
167
|
+
{ steps: 25, stepDelay: 16 }
|
|
168
|
+
)
|
|
169
|
+
await page.waitForTimeout(600)
|
|
170
|
+
|
|
171
|
+
// EXPECTED: sheet moved to position 1, scroll stayed at 0
|
|
172
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
173
|
+
'Sheet position: 1'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
// scroll should still be at 0 (or very close to it)
|
|
177
|
+
const scrollY = await page.getByTestId('sheet-scrollable-drag-scroll-y').textContent()
|
|
178
|
+
const scrollVal = parseInt(scrollY?.replace('ScrollView Y: ', '') || '0', 10)
|
|
179
|
+
expect(scrollVal).toBeLessThanOrEqual(5) // allow small tolerance
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('STRESS: multiple handoffs starting from scroll', async ({ page }) => {
|
|
183
|
+
// stress test: scroll → drag → scroll → drag (4x)
|
|
184
|
+
// each handoff should work cleanly without jitter
|
|
185
|
+
if (process.env.CI) test.slow() // triple timeout for CI runners
|
|
186
|
+
|
|
187
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
188
|
+
await page.waitForTimeout(800)
|
|
189
|
+
|
|
190
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
191
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
192
|
+
|
|
193
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
194
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
195
|
+
expect(scrollviewBox).toBeTruthy()
|
|
196
|
+
|
|
197
|
+
const cx = scrollviewBox!.x + scrollviewBox!.width / 2
|
|
198
|
+
const cy = scrollviewBox!.y + scrollviewBox!.height / 2
|
|
199
|
+
|
|
200
|
+
for (let i = 0; i < 4; i++) {
|
|
201
|
+
// 1. scroll down (drag up gesture)
|
|
202
|
+
await dragSheet(page, cx, cy, -150, { steps: 20, stepDelay: 12 })
|
|
203
|
+
await page.waitForTimeout(400)
|
|
204
|
+
|
|
205
|
+
// verify scroll happened, sheet still at 0
|
|
206
|
+
const scrollY1 = await page
|
|
207
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
208
|
+
.textContent()
|
|
209
|
+
const scrollVal1 = parseInt(scrollY1?.replace('ScrollView Y: ', '') || '0', 10)
|
|
210
|
+
expect(scrollVal1).toBeGreaterThan(20)
|
|
211
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
212
|
+
'Sheet position: 0'
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
// 2. drag down past scroll=0 to pull sheet
|
|
216
|
+
await dragSheet(page, cx, cy, 300, { steps: 30, stepDelay: 12 })
|
|
217
|
+
await page.waitForTimeout(400)
|
|
218
|
+
|
|
219
|
+
// verify sheet moved, scroll at 0
|
|
220
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
221
|
+
'Sheet position: 1'
|
|
222
|
+
)
|
|
223
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
224
|
+
'ScrollView Y: 0'
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
// 3. drag up to bring sheet back (no scroll should happen here)
|
|
228
|
+
await dragSheet(page, cx, cy, -200, { steps: 25, stepDelay: 12 })
|
|
229
|
+
await page.waitForTimeout(400)
|
|
230
|
+
|
|
231
|
+
// verify sheet back at 0, scroll still 0
|
|
232
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
233
|
+
'Sheet position: 0'
|
|
234
|
+
)
|
|
235
|
+
const scrollY2 = await page
|
|
236
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
237
|
+
.textContent()
|
|
238
|
+
const scrollVal2 = parseInt(scrollY2?.replace('ScrollView Y: ', '') || '0', 10)
|
|
239
|
+
expect(scrollVal2).toBeLessThanOrEqual(10)
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
test('STRESS: multiple handoffs starting from drag', async ({ page }) => {
|
|
244
|
+
// stress test: drag → scroll → drag → scroll (4x)
|
|
245
|
+
// start by dragging sheet down first
|
|
246
|
+
|
|
247
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
248
|
+
await page.waitForTimeout(800)
|
|
249
|
+
|
|
250
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
251
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
252
|
+
|
|
253
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
254
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
255
|
+
expect(scrollviewBox).toBeTruthy()
|
|
256
|
+
|
|
257
|
+
const cx = scrollviewBox!.x + scrollviewBox!.width / 2
|
|
258
|
+
const cy = scrollviewBox!.y + scrollviewBox!.height / 2
|
|
259
|
+
|
|
260
|
+
for (let i = 0; i < 4; i++) {
|
|
261
|
+
// 1. drag down to pull sheet (scrollY=0, so pan takes over)
|
|
262
|
+
// use touch mode on scrollview - this should work via our touch handler
|
|
263
|
+
await dragSheet(page, cx, cy, 200, { steps: 25, stepDelay: 12 })
|
|
264
|
+
await page.waitForTimeout(400)
|
|
265
|
+
|
|
266
|
+
// verify sheet moved, scroll still 0
|
|
267
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
268
|
+
'Sheet position: 1'
|
|
269
|
+
)
|
|
270
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
271
|
+
'ScrollView Y: 0'
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
// wait for animation to settle
|
|
275
|
+
await page.waitForTimeout(400)
|
|
276
|
+
|
|
277
|
+
// 2. drag up to bring sheet back - this should work via touch handler
|
|
278
|
+
// sheet not at top + dragging up = pan owns
|
|
279
|
+
await dragSheet(page, cx, cy, -250, { steps: 30, stepDelay: 12 })
|
|
280
|
+
await page.waitForTimeout(400)
|
|
281
|
+
|
|
282
|
+
// verify sheet at 0
|
|
283
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
284
|
+
'Sheet position: 0'
|
|
285
|
+
)
|
|
286
|
+
// scroll should still be 0 (no scroll during drag up when sheet not at top)
|
|
287
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
288
|
+
'ScrollView Y: 0'
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
test('CRITICAL: single gesture - scroll, pull sheet, reverse to push sheet up - no scroll during push', async ({
|
|
294
|
+
page,
|
|
295
|
+
}) => {
|
|
296
|
+
// ONE CONTINUOUS GESTURE with direction changes:
|
|
297
|
+
// 1. drag up to scroll
|
|
298
|
+
// 2. reverse to drag down (scroll back to 0, then pull sheet)
|
|
299
|
+
// 3. reverse again to drag up (push sheet back up)
|
|
300
|
+
// BUG: step 3 was scrolling when it should only move sheet
|
|
301
|
+
|
|
302
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
303
|
+
await page.waitForTimeout(600)
|
|
304
|
+
|
|
305
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
306
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
307
|
+
|
|
308
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
309
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
310
|
+
expect(scrollviewBox).toBeTruthy()
|
|
311
|
+
|
|
312
|
+
const cx = scrollviewBox!.x + scrollviewBox!.width / 2
|
|
313
|
+
const startY = scrollviewBox!.y + scrollviewBox!.height / 2
|
|
314
|
+
|
|
315
|
+
// single continuous gesture with direction changes
|
|
316
|
+
await page.evaluate(
|
|
317
|
+
({ cx, startY }) => {
|
|
318
|
+
return new Promise<void>((resolve) => {
|
|
319
|
+
const target = document.elementFromPoint(cx, startY)
|
|
320
|
+
if (!target) {
|
|
321
|
+
resolve()
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const dispatchTouch = (type: string, x: number, y: number) => {
|
|
326
|
+
const touch = new Touch({
|
|
327
|
+
identifier: 0,
|
|
328
|
+
target,
|
|
329
|
+
clientX: x,
|
|
330
|
+
clientY: y,
|
|
331
|
+
pageX: x,
|
|
332
|
+
pageY: y,
|
|
333
|
+
})
|
|
334
|
+
const touchEvent = new TouchEvent(type, {
|
|
335
|
+
bubbles: true,
|
|
336
|
+
cancelable: true,
|
|
337
|
+
touches: type === 'touchend' ? [] : [touch],
|
|
338
|
+
targetTouches: type === 'touchend' ? [] : [touch],
|
|
339
|
+
changedTouches: [touch],
|
|
340
|
+
})
|
|
341
|
+
target.dispatchEvent(touchEvent)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// touchstart
|
|
345
|
+
dispatchTouch('touchstart', cx, startY)
|
|
346
|
+
|
|
347
|
+
let step = 0
|
|
348
|
+
const moves = [
|
|
349
|
+
// cycle 1
|
|
350
|
+
// phase 1: drag up to scroll (20 steps, -5px each = -100px)
|
|
351
|
+
...Array(20).fill(-5),
|
|
352
|
+
// phase 2: drag down to scroll back and pull sheet (40 steps, +8px each = +320px)
|
|
353
|
+
...Array(40).fill(8),
|
|
354
|
+
// phase 3: drag up to push sheet back (30 steps, -6px each = -180px)
|
|
355
|
+
// THIS SHOULD NOT SCROLL
|
|
356
|
+
...Array(30).fill(-6),
|
|
357
|
+
// cycle 2 - repeat to catch bugs that only show on 2nd+ cycle
|
|
358
|
+
...Array(20).fill(-5),
|
|
359
|
+
...Array(40).fill(8),
|
|
360
|
+
...Array(30).fill(-6),
|
|
361
|
+
// cycle 3
|
|
362
|
+
...Array(20).fill(-5),
|
|
363
|
+
...Array(40).fill(8),
|
|
364
|
+
...Array(30).fill(-6),
|
|
365
|
+
// cycle 4
|
|
366
|
+
...Array(20).fill(-5),
|
|
367
|
+
...Array(40).fill(8),
|
|
368
|
+
...Array(30).fill(-6),
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
let currentY = startY
|
|
372
|
+
const interval = setInterval(() => {
|
|
373
|
+
if (step >= moves.length) {
|
|
374
|
+
clearInterval(interval)
|
|
375
|
+
dispatchTouch('touchend', cx, currentY)
|
|
376
|
+
resolve()
|
|
377
|
+
return
|
|
378
|
+
}
|
|
379
|
+
currentY += moves[step]
|
|
380
|
+
dispatchTouch('touchmove', cx, currentY)
|
|
381
|
+
step++
|
|
382
|
+
}, 16)
|
|
383
|
+
})
|
|
384
|
+
},
|
|
385
|
+
{ cx, startY }
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
await page.waitForTimeout(400)
|
|
389
|
+
|
|
390
|
+
// check maxScrollY - this captures if scroll happened at ANY point during "push up" phases
|
|
391
|
+
// if scroll happened during push up, maxScrollY will be > what it should be
|
|
392
|
+
const maxScrollY = await page
|
|
393
|
+
.getByTestId('sheet-scrollable-drag-max-scroll-y')
|
|
394
|
+
.textContent()
|
|
395
|
+
const maxScrollVal = parseInt(maxScrollY?.replace('Max scroll Y: ', '') || '0', 10)
|
|
396
|
+
|
|
397
|
+
console.log('maxScrollVal:', maxScrollVal)
|
|
398
|
+
// the key assertion: maxScrollY should be around 100 (from the initial scroll phase)
|
|
399
|
+
// if it's significantly higher, scroll happened during "push sheet up" phases
|
|
400
|
+
// each scroll phase does ~100px, so 4 cycles should still be ~100 max if working correctly
|
|
401
|
+
// if broken, we'd see 200+ because scroll happens during push-up phases too
|
|
402
|
+
expect(maxScrollVal).toBeLessThanOrEqual(150)
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
test('CRITICAL: from pos 1, single gesture drag up past top then reverse down - no mid-gesture snap', async ({
|
|
406
|
+
page,
|
|
407
|
+
}) => {
|
|
408
|
+
// BUG: sheet at position 1, one continuous gesture:
|
|
409
|
+
// 1. drag up to move sheet to top (pan owns, sheet moves up)
|
|
410
|
+
// 2. continue dragging up past top (pan→scroll handoff)
|
|
411
|
+
// 3. reverse to drag down (scroll→pan handoff)
|
|
412
|
+
//
|
|
413
|
+
// the bug: during the pan→scroll handoff in step 2, snapToPosition(0) is
|
|
414
|
+
// called MID-GESTURE. this triggers setPosition(0) → useEffect →
|
|
415
|
+
// setScrollEnabled → animateTo which fights with the active gesture,
|
|
416
|
+
// causing snap, broken state, and "Maximum update depth exceeded".
|
|
417
|
+
//
|
|
418
|
+
// snapToPosition should NEVER be called during a continuous gesture.
|
|
419
|
+
// position changes should only happen on release (touchend).
|
|
420
|
+
|
|
421
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
422
|
+
await page.waitForTimeout(600)
|
|
423
|
+
|
|
424
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
425
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
426
|
+
|
|
427
|
+
// get sheet to position 1 via handle drag
|
|
428
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
429
|
+
let handleBox = await handle.boundingBox()
|
|
430
|
+
expect(handleBox).toBeTruthy()
|
|
431
|
+
|
|
432
|
+
await dragSheet(
|
|
433
|
+
page,
|
|
434
|
+
handleBox!.x + handleBox!.width / 2,
|
|
435
|
+
handleBox!.y + handleBox!.height / 2,
|
|
436
|
+
200,
|
|
437
|
+
{ steps: 25, stepDelay: 16, mode: 'mouse' }
|
|
438
|
+
)
|
|
439
|
+
await page.waitForTimeout(600)
|
|
440
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
441
|
+
'Sheet position: 1'
|
|
442
|
+
)
|
|
443
|
+
await page.waitForTimeout(400)
|
|
444
|
+
|
|
445
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
446
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
447
|
+
expect(scrollviewBox).toBeTruthy()
|
|
448
|
+
|
|
449
|
+
const cx = scrollviewBox!.x + scrollviewBox!.width / 2
|
|
450
|
+
const startY = scrollviewBox!.y + scrollviewBox!.height / 2
|
|
451
|
+
|
|
452
|
+
// listen for errors
|
|
453
|
+
const errors: string[] = []
|
|
454
|
+
page.on('pageerror', (err) => errors.push(err.message))
|
|
455
|
+
|
|
456
|
+
// set up a MutationObserver to track position changes DURING the gesture.
|
|
457
|
+
// the position text element updates when setPosition is called.
|
|
458
|
+
// any position change between touchstart and touchend is a mid-gesture snap (the bug).
|
|
459
|
+
await page.evaluate(() => {
|
|
460
|
+
const posEl = document.querySelector(
|
|
461
|
+
'[data-testid="sheet-scrollable-drag-position"]'
|
|
462
|
+
)
|
|
463
|
+
if (!posEl) return
|
|
464
|
+
;(window as any).__midGestureSnaps = []
|
|
465
|
+
;(window as any).__gestureActive = false
|
|
466
|
+
|
|
467
|
+
// track touch state
|
|
468
|
+
document.addEventListener(
|
|
469
|
+
'touchstart',
|
|
470
|
+
() => {
|
|
471
|
+
;(window as any).__gestureActive = true
|
|
472
|
+
},
|
|
473
|
+
{ capture: true }
|
|
474
|
+
)
|
|
475
|
+
document.addEventListener(
|
|
476
|
+
'touchend',
|
|
477
|
+
() => {
|
|
478
|
+
;(window as any).__gestureActive = false
|
|
479
|
+
},
|
|
480
|
+
{ capture: true }
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
// observe position text changes
|
|
484
|
+
const observer = new MutationObserver(() => {
|
|
485
|
+
if ((window as any).__gestureActive) {
|
|
486
|
+
const text = posEl.textContent || ''
|
|
487
|
+
;(window as any).__midGestureSnaps.push(text)
|
|
488
|
+
}
|
|
489
|
+
})
|
|
490
|
+
observer.observe(posEl, { childList: true, characterData: true, subtree: true })
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
// single continuous gesture: drag up past top, then reverse down
|
|
494
|
+
await page.evaluate(
|
|
495
|
+
({ cx, startY }) => {
|
|
496
|
+
return new Promise<void>((resolve) => {
|
|
497
|
+
const target = document.elementFromPoint(cx, startY)
|
|
498
|
+
if (!target) {
|
|
499
|
+
resolve()
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const dispatchTouch = (type: string, x: number, y: number) => {
|
|
504
|
+
const touch = new Touch({
|
|
505
|
+
identifier: 0,
|
|
506
|
+
target,
|
|
507
|
+
clientX: x,
|
|
508
|
+
clientY: y,
|
|
509
|
+
pageX: x,
|
|
510
|
+
pageY: y,
|
|
511
|
+
})
|
|
512
|
+
target.dispatchEvent(
|
|
513
|
+
new TouchEvent(type, {
|
|
514
|
+
bubbles: true,
|
|
515
|
+
cancelable: true,
|
|
516
|
+
touches: type === 'touchend' ? [] : [touch],
|
|
517
|
+
targetTouches: type === 'touchend' ? [] : [touch],
|
|
518
|
+
changedTouches: [touch],
|
|
519
|
+
})
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
dispatchTouch('touchstart', cx, startY)
|
|
524
|
+
|
|
525
|
+
let step = 0
|
|
526
|
+
const moves = [
|
|
527
|
+
// phase 1: drag up - moves sheet from pos 1 to top (30 steps, -8px = -240px)
|
|
528
|
+
...Array(30).fill(-8),
|
|
529
|
+
// phase 2: continue up past top - should start scrolling (20 steps, -5px = -100px)
|
|
530
|
+
// THIS is where the pan→scroll handoff happens and snapToPosition(0) is called
|
|
531
|
+
...Array(20).fill(-5),
|
|
532
|
+
// phase 3: reverse down - scroll back then pull sheet (40 steps, +8px = +320px)
|
|
533
|
+
...Array(40).fill(8),
|
|
534
|
+
]
|
|
535
|
+
|
|
536
|
+
let currentY = startY
|
|
537
|
+
const interval = setInterval(() => {
|
|
538
|
+
if (step >= moves.length) {
|
|
539
|
+
clearInterval(interval)
|
|
540
|
+
dispatchTouch('touchend', cx, currentY)
|
|
541
|
+
resolve()
|
|
542
|
+
return
|
|
543
|
+
}
|
|
544
|
+
currentY += moves[step]
|
|
545
|
+
dispatchTouch('touchmove', cx, currentY)
|
|
546
|
+
step++
|
|
547
|
+
}, 16)
|
|
548
|
+
})
|
|
549
|
+
},
|
|
550
|
+
{ cx, startY }
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
await page.waitForTimeout(600)
|
|
554
|
+
|
|
555
|
+
// no Maximum update depth exceeded
|
|
556
|
+
expect(errors.filter((e) => e.includes('Maximum update depth'))).toHaveLength(0)
|
|
557
|
+
|
|
558
|
+
// CRITICAL: no position changes should happen during the gesture
|
|
559
|
+
// snapToPosition should only be called on release, not mid-gesture
|
|
560
|
+
const midGestureSnaps = await page.evaluate(
|
|
561
|
+
() => (window as any).__midGestureSnaps || []
|
|
562
|
+
)
|
|
563
|
+
console.log('mid-gesture snaps:', midGestureSnaps)
|
|
564
|
+
expect(midGestureSnaps).toHaveLength(0)
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
test('CRITICAL: from pos 1, drag up past top then back down - should snap to pos 1 not dismiss', async ({
|
|
568
|
+
page,
|
|
569
|
+
}) => {
|
|
570
|
+
// BUG: from pos 1, single continuous gesture:
|
|
571
|
+
// 1. drag up (pan moves sheet to top)
|
|
572
|
+
// 2. continue up past top (pan→scroll handoff, scroll owns)
|
|
573
|
+
// 3. reverse down past scroll=0 (scroll→pan handoff, pan owns)
|
|
574
|
+
// 4. release just below where pos 1 would be
|
|
575
|
+
//
|
|
576
|
+
// expected: sheet snaps to position 1
|
|
577
|
+
// actual bug: if touchend fires while owner='scroll', release() is never
|
|
578
|
+
// called. the sheet's animated position is stranded and it dismisses.
|
|
579
|
+
|
|
580
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
581
|
+
await page.waitForTimeout(600)
|
|
582
|
+
|
|
583
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
584
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
585
|
+
|
|
586
|
+
// get sheet to position 1
|
|
587
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
588
|
+
let handleBox = await handle.boundingBox()
|
|
589
|
+
expect(handleBox).toBeTruthy()
|
|
590
|
+
|
|
591
|
+
await dragSheet(
|
|
592
|
+
page,
|
|
593
|
+
handleBox!.x + handleBox!.width / 2,
|
|
594
|
+
handleBox!.y + handleBox!.height / 2,
|
|
595
|
+
200,
|
|
596
|
+
{ steps: 25, stepDelay: 16, mode: 'mouse' }
|
|
597
|
+
)
|
|
598
|
+
await page.waitForTimeout(600)
|
|
599
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
600
|
+
'Sheet position: 1'
|
|
601
|
+
)
|
|
602
|
+
await page.waitForTimeout(400)
|
|
603
|
+
|
|
604
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
605
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
606
|
+
expect(scrollviewBox).toBeTruthy()
|
|
607
|
+
|
|
608
|
+
const cx = scrollviewBox!.x + scrollviewBox!.width / 2
|
|
609
|
+
const startY = scrollviewBox!.y + scrollviewBox!.height / 2
|
|
610
|
+
|
|
611
|
+
// single continuous gesture: drag up past top, scroll a bit, reverse down to ~pos 1
|
|
612
|
+
await page.evaluate(
|
|
613
|
+
({ cx, startY }) => {
|
|
614
|
+
return new Promise<void>((resolve) => {
|
|
615
|
+
const target = document.elementFromPoint(cx, startY)
|
|
616
|
+
if (!target) {
|
|
617
|
+
resolve()
|
|
618
|
+
return
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const dispatchTouch = (type: string, x: number, y: number) => {
|
|
622
|
+
const touch = new Touch({
|
|
623
|
+
identifier: 0,
|
|
624
|
+
target,
|
|
625
|
+
clientX: x,
|
|
626
|
+
clientY: y,
|
|
627
|
+
pageX: x,
|
|
628
|
+
pageY: y,
|
|
629
|
+
})
|
|
630
|
+
target.dispatchEvent(
|
|
631
|
+
new TouchEvent(type, {
|
|
632
|
+
bubbles: true,
|
|
633
|
+
cancelable: true,
|
|
634
|
+
touches: type === 'touchend' ? [] : [touch],
|
|
635
|
+
targetTouches: type === 'touchend' ? [] : [touch],
|
|
636
|
+
changedTouches: [touch],
|
|
637
|
+
})
|
|
638
|
+
)
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
dispatchTouch('touchstart', cx, startY)
|
|
642
|
+
|
|
643
|
+
let step = 0
|
|
644
|
+
const moves = [
|
|
645
|
+
// phase 1: drag up - moves sheet from pos 1 to top
|
|
646
|
+
// pos 1 → pos 0 is ~300px, so need ~40 steps × -8px = -320px
|
|
647
|
+
...Array(40).fill(-8),
|
|
648
|
+
// phase 2: continue up past top - should start scrolling (20 steps, -5px = -100px)
|
|
649
|
+
...Array(20).fill(-5),
|
|
650
|
+
// phase 3: reverse down - scroll back to 0, then pull sheet down (50 steps, +8px = +400px)
|
|
651
|
+
// this should end near where pos 1 is
|
|
652
|
+
...Array(50).fill(8),
|
|
653
|
+
]
|
|
654
|
+
|
|
655
|
+
let currentY = startY
|
|
656
|
+
const interval = setInterval(() => {
|
|
657
|
+
if (step >= moves.length) {
|
|
658
|
+
clearInterval(interval)
|
|
659
|
+
dispatchTouch('touchend', cx, currentY)
|
|
660
|
+
resolve()
|
|
661
|
+
return
|
|
662
|
+
}
|
|
663
|
+
currentY += moves[step]
|
|
664
|
+
dispatchTouch('touchmove', cx, currentY)
|
|
665
|
+
step++
|
|
666
|
+
}, 16)
|
|
667
|
+
})
|
|
668
|
+
},
|
|
669
|
+
{ cx, startY }
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
await page.waitForTimeout(800)
|
|
673
|
+
|
|
674
|
+
// the bug: stale startY in release() causes it to compute a position way
|
|
675
|
+
// below the screen. with dismissOnSnapToBottom, this triggers setOpen(false)
|
|
676
|
+
// which dismisses the sheet unexpectedly.
|
|
677
|
+
const unexpectedClose = await page
|
|
678
|
+
.getByTestId('sheet-scrollable-drag-unexpected-close')
|
|
679
|
+
.textContent()
|
|
680
|
+
console.log('unexpected close:', unexpectedClose)
|
|
681
|
+
|
|
682
|
+
// the sheet should NOT have been dismissed during this gesture
|
|
683
|
+
expect(unexpectedClose).toContain('no')
|
|
684
|
+
})
|
|
685
|
+
|
|
686
|
+
test('Case 1b: scroll, drag down, drag UP - scroll should NOT happen during drag up', async ({
|
|
687
|
+
page,
|
|
688
|
+
}) => {
|
|
689
|
+
// This tests: scroll down, drag sheet down, then drag UP
|
|
690
|
+
// During drag UP (bringing sheet back), scroll should NOT change
|
|
691
|
+
|
|
692
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
693
|
+
await page.waitForTimeout(600)
|
|
694
|
+
|
|
695
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
696
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
697
|
+
|
|
698
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
699
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
700
|
+
expect(scrollviewBox).toBeTruthy()
|
|
701
|
+
|
|
702
|
+
// 1. scroll down
|
|
703
|
+
await page.mouse.move(
|
|
704
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
705
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
706
|
+
)
|
|
707
|
+
await page.mouse.wheel(0, 150)
|
|
708
|
+
await page.waitForTimeout(300)
|
|
709
|
+
|
|
710
|
+
// 2. drag DOWN to pull sheet (this scrolls back to 0, then drags sheet)
|
|
711
|
+
await dragSheet(
|
|
712
|
+
page,
|
|
713
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
714
|
+
scrollviewBox!.y + scrollviewBox!.height / 3,
|
|
715
|
+
300,
|
|
716
|
+
{ steps: 30, stepDelay: 16 }
|
|
717
|
+
)
|
|
718
|
+
await page.waitForTimeout(400)
|
|
719
|
+
|
|
720
|
+
// sheet should be at position 1
|
|
721
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
722
|
+
'Sheet position: 1'
|
|
723
|
+
)
|
|
724
|
+
// scroll should be 0
|
|
725
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
726
|
+
'ScrollView Y: 0'
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
// 3. NOW drag UP - this should bring sheet back to position 0
|
|
730
|
+
// scroll should NOT change during this drag
|
|
731
|
+
await dragSheet(
|
|
732
|
+
page,
|
|
733
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
734
|
+
scrollviewBox!.y + scrollviewBox!.height / 2,
|
|
735
|
+
-250,
|
|
736
|
+
{ steps: 30, stepDelay: 16 }
|
|
737
|
+
)
|
|
738
|
+
await page.waitForTimeout(300)
|
|
739
|
+
|
|
740
|
+
// sheet should be at position 0
|
|
741
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
742
|
+
'Sheet position: 0'
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
// CRITICAL: scroll should still be 0 - no scrolling during drag up
|
|
746
|
+
const scrollAfter = await page
|
|
747
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
748
|
+
.textContent()
|
|
749
|
+
const scrollVal = parseInt(scrollAfter?.replace('ScrollView Y: ', '') || '0', 10)
|
|
750
|
+
expect(scrollVal).toBeLessThanOrEqual(5) // allow tiny tolerance
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
test('Case 1c: scroll then drag DOWN - scroll should NOT change during drag', async ({
|
|
754
|
+
page,
|
|
755
|
+
}) => {
|
|
756
|
+
// This tests the basic jitter scenario:
|
|
757
|
+
// 1. Scroll content down (scrollY > 0)
|
|
758
|
+
// 2. Drag down to pull sheet
|
|
759
|
+
// 3. During the drag, scrollY should NOT change (no jitter)
|
|
760
|
+
|
|
761
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
762
|
+
await page.waitForTimeout(600)
|
|
763
|
+
|
|
764
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
765
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
766
|
+
|
|
767
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
768
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
769
|
+
expect(scrollviewBox).toBeTruthy()
|
|
770
|
+
|
|
771
|
+
// first scroll down with wheel
|
|
772
|
+
await page.mouse.move(
|
|
773
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
774
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
775
|
+
)
|
|
776
|
+
await page.mouse.wheel(0, 150)
|
|
777
|
+
await page.waitForTimeout(300)
|
|
778
|
+
|
|
779
|
+
// verify we scrolled
|
|
780
|
+
const scrollBefore = await page
|
|
781
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
782
|
+
.textContent()
|
|
783
|
+
const scrollValBefore = parseInt(
|
|
784
|
+
scrollBefore?.replace('ScrollView Y: ', '') || '0',
|
|
785
|
+
10
|
|
786
|
+
)
|
|
787
|
+
expect(scrollValBefore).toBeGreaterThan(30)
|
|
788
|
+
|
|
789
|
+
// now do a long drag DOWN - should first scroll back to 0, then drag sheet
|
|
790
|
+
// but DURING the sheet drag portion, scroll should stay at 0
|
|
791
|
+
await dragSheet(
|
|
792
|
+
page,
|
|
793
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
794
|
+
scrollviewBox!.y + scrollviewBox!.height / 3,
|
|
795
|
+
400, // long drag to ensure we hit both scroll-back and sheet-drag phases
|
|
796
|
+
{ steps: 40, stepDelay: 16 }
|
|
797
|
+
)
|
|
798
|
+
await page.waitForTimeout(100)
|
|
799
|
+
|
|
800
|
+
// check final scroll position - should be 0 (scrolled back) not negative or jumping around
|
|
801
|
+
const scrollAfter = await page
|
|
802
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
803
|
+
.textContent()
|
|
804
|
+
const scrollValAfter = parseInt(scrollAfter?.replace('ScrollView Y: ', '') || '0', 10)
|
|
805
|
+
|
|
806
|
+
// scroll should be at 0 (not negative, not jumping around)
|
|
807
|
+
expect(scrollValAfter).toBe(0)
|
|
808
|
+
|
|
809
|
+
// sheet should have moved to position 1
|
|
810
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
811
|
+
'Sheet position: 1'
|
|
812
|
+
)
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
test('Case 2: at top snap, drag UP should scroll content', async ({ page }) => {
|
|
816
|
+
// open sheet
|
|
817
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
818
|
+
await page.waitForTimeout(600)
|
|
819
|
+
|
|
820
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
821
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
822
|
+
|
|
823
|
+
// verify starting state - at top, scroll at 0
|
|
824
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
825
|
+
'Sheet position: 0'
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
// get the scrollview
|
|
829
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
830
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
831
|
+
expect(scrollviewBox).toBeTruthy()
|
|
832
|
+
|
|
833
|
+
// use wheel event to scroll content (more reliable than drag for scroll)
|
|
834
|
+
await page.mouse.move(
|
|
835
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
836
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
837
|
+
)
|
|
838
|
+
await page.mouse.wheel(0, 200)
|
|
839
|
+
await page.waitForTimeout(400)
|
|
840
|
+
|
|
841
|
+
// EXPECTED: sheet stays at position 0, content scrolled
|
|
842
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
843
|
+
'Sheet position: 0'
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
// scroll should have increased
|
|
847
|
+
const scrollY = await page.getByTestId('sheet-scrollable-drag-scroll-y').textContent()
|
|
848
|
+
const scrollVal = parseInt(scrollY?.replace('ScrollView Y: ', '') || '0', 10)
|
|
849
|
+
expect(scrollVal).toBeGreaterThan(50)
|
|
850
|
+
})
|
|
851
|
+
|
|
852
|
+
test('Case 3: drag sheet up from position 1 should NOT scroll simultaneously', async ({
|
|
853
|
+
page,
|
|
854
|
+
}) => {
|
|
855
|
+
// open sheet
|
|
856
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
857
|
+
await page.waitForTimeout(600)
|
|
858
|
+
|
|
859
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
860
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
861
|
+
|
|
862
|
+
// get handle for dragging
|
|
863
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
864
|
+
let handleBox = await handle.boundingBox()
|
|
865
|
+
expect(handleBox).toBeTruthy()
|
|
866
|
+
|
|
867
|
+
// first drag down to position 1 (use mouse for handle)
|
|
868
|
+
await dragSheet(
|
|
869
|
+
page,
|
|
870
|
+
handleBox!.x + handleBox!.width / 2,
|
|
871
|
+
handleBox!.y + handleBox!.height / 2,
|
|
872
|
+
200,
|
|
873
|
+
{ steps: 25, stepDelay: 16, mode: 'mouse' }
|
|
874
|
+
)
|
|
875
|
+
await page.waitForTimeout(600)
|
|
876
|
+
|
|
877
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
878
|
+
'Sheet position: 1'
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
// verify scroll is still at 0 after first drag
|
|
882
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
883
|
+
'ScrollView Y: 0'
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
// wait for animation to settle
|
|
887
|
+
await page.waitForTimeout(400)
|
|
888
|
+
|
|
889
|
+
// get new handle position
|
|
890
|
+
handleBox = await handle.boundingBox()
|
|
891
|
+
expect(handleBox).toBeTruthy()
|
|
892
|
+
|
|
893
|
+
// now drag UP back to position 0
|
|
894
|
+
await dragSheet(
|
|
895
|
+
page,
|
|
896
|
+
handleBox!.x + handleBox!.width / 2,
|
|
897
|
+
handleBox!.y + handleBox!.height / 2,
|
|
898
|
+
-250,
|
|
899
|
+
{ steps: 30, stepDelay: 16 }
|
|
900
|
+
)
|
|
901
|
+
await page.waitForTimeout(600)
|
|
902
|
+
|
|
903
|
+
// EXPECTED: sheet back at position 0, scroll should still be 0 (no simultaneous scroll)
|
|
904
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
905
|
+
'Sheet position: 0'
|
|
906
|
+
)
|
|
907
|
+
})
|
|
908
|
+
|
|
909
|
+
test('Case 4: scroll down, then drag down should scroll back first', async ({
|
|
910
|
+
page,
|
|
911
|
+
}) => {
|
|
912
|
+
// open sheet
|
|
913
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
914
|
+
await page.waitForTimeout(600)
|
|
915
|
+
|
|
916
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
917
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
918
|
+
|
|
919
|
+
// get the scrollview
|
|
920
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
921
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
922
|
+
expect(scrollviewBox).toBeTruthy()
|
|
923
|
+
|
|
924
|
+
// first scroll down (wheel up to scroll content down)
|
|
925
|
+
await page.mouse.move(
|
|
926
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
927
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
928
|
+
)
|
|
929
|
+
await page.mouse.wheel(0, 200)
|
|
930
|
+
await page.waitForTimeout(400)
|
|
931
|
+
|
|
932
|
+
// verify we scrolled
|
|
933
|
+
const scrollBefore = await page
|
|
934
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
935
|
+
.textContent()
|
|
936
|
+
const scrollValBefore = parseInt(
|
|
937
|
+
scrollBefore?.replace('ScrollView Y: ', '') || '0',
|
|
938
|
+
10
|
|
939
|
+
)
|
|
940
|
+
expect(scrollValBefore).toBeGreaterThan(50)
|
|
941
|
+
|
|
942
|
+
// now drag DOWN - should scroll back first before dragging sheet
|
|
943
|
+
await dragSheet(
|
|
944
|
+
page,
|
|
945
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
946
|
+
scrollviewBox!.y + scrollviewBox!.height / 3,
|
|
947
|
+
300,
|
|
948
|
+
{ steps: 30, stepDelay: 16 }
|
|
949
|
+
)
|
|
950
|
+
await page.waitForTimeout(600)
|
|
951
|
+
|
|
952
|
+
// either scroll absorbed the swipe (scroll at 0 or close) OR sheet moved
|
|
953
|
+
const scrollAfter = await page
|
|
954
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
955
|
+
.textContent()
|
|
956
|
+
const scrollValAfter = parseInt(scrollAfter?.replace('ScrollView Y: ', '') || '0', 10)
|
|
957
|
+
|
|
958
|
+
const posAfter = await page
|
|
959
|
+
.getByTestId('sheet-scrollable-drag-position')
|
|
960
|
+
.textContent()
|
|
961
|
+
const posValAfter = parseInt(posAfter?.replace('Sheet position: ', '') || '0', 10)
|
|
962
|
+
|
|
963
|
+
// success if either: scroll went back to 0, or sheet moved to position 1
|
|
964
|
+
expect(scrollValAfter < scrollValBefore || posValAfter === 1).toBeTruthy()
|
|
965
|
+
})
|
|
966
|
+
|
|
967
|
+
test('Case 5: HANDOFF - scroll to 0 then drag sheet in one gesture', async ({
|
|
968
|
+
page,
|
|
969
|
+
}) => {
|
|
970
|
+
// open sheet
|
|
971
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
972
|
+
await page.waitForTimeout(600)
|
|
973
|
+
|
|
974
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
975
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
976
|
+
|
|
977
|
+
// get the scrollview
|
|
978
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
979
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
980
|
+
expect(scrollviewBox).toBeTruthy()
|
|
981
|
+
|
|
982
|
+
// first scroll down a bit
|
|
983
|
+
await page.mouse.move(
|
|
984
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
985
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
986
|
+
)
|
|
987
|
+
await page.mouse.wheel(0, 100)
|
|
988
|
+
await page.waitForTimeout(300)
|
|
989
|
+
|
|
990
|
+
// verify we scrolled
|
|
991
|
+
const scrollBefore = await page
|
|
992
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
993
|
+
.textContent()
|
|
994
|
+
const scrollValBefore = parseInt(
|
|
995
|
+
scrollBefore?.replace('ScrollView Y: ', '') || '0',
|
|
996
|
+
10
|
|
997
|
+
)
|
|
998
|
+
expect(scrollValBefore).toBeGreaterThan(0)
|
|
999
|
+
|
|
1000
|
+
// long drag down - should scroll to 0 then drag sheet
|
|
1001
|
+
await dragSheet(
|
|
1002
|
+
page,
|
|
1003
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
1004
|
+
scrollviewBox!.y + scrollviewBox!.height / 4,
|
|
1005
|
+
350,
|
|
1006
|
+
{ steps: 40, stepDelay: 16 }
|
|
1007
|
+
)
|
|
1008
|
+
await page.waitForTimeout(600)
|
|
1009
|
+
|
|
1010
|
+
// EXPECTED: scroll should be at 0, sheet should have moved to position 1
|
|
1011
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
1012
|
+
'ScrollView Y: 0'
|
|
1013
|
+
)
|
|
1014
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1015
|
+
'Sheet position: 1'
|
|
1016
|
+
)
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
test('Case 6: multiple direction changes without getting stuck', async ({ page }) => {
|
|
1020
|
+
// open sheet
|
|
1021
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
1022
|
+
await page.waitForTimeout(600)
|
|
1023
|
+
|
|
1024
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
1025
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
1026
|
+
|
|
1027
|
+
// verify starting state
|
|
1028
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1029
|
+
'Sheet position: 0'
|
|
1030
|
+
)
|
|
1031
|
+
|
|
1032
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
1033
|
+
let handleBox = await handle.boundingBox()
|
|
1034
|
+
expect(handleBox).toBeTruthy()
|
|
1035
|
+
|
|
1036
|
+
// 1. drag down to position 1
|
|
1037
|
+
await dragSheet(
|
|
1038
|
+
page,
|
|
1039
|
+
handleBox!.x + handleBox!.width / 2,
|
|
1040
|
+
handleBox!.y + handleBox!.height / 2,
|
|
1041
|
+
200,
|
|
1042
|
+
{ steps: 25, stepDelay: 16 }
|
|
1043
|
+
)
|
|
1044
|
+
await page.waitForTimeout(600)
|
|
1045
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1046
|
+
'Sheet position: 1'
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
// 2. drag up back to position 0
|
|
1050
|
+
handleBox = await handle.boundingBox()
|
|
1051
|
+
expect(handleBox).toBeTruthy()
|
|
1052
|
+
await dragSheet(
|
|
1053
|
+
page,
|
|
1054
|
+
handleBox!.x + handleBox!.width / 2,
|
|
1055
|
+
handleBox!.y + handleBox!.height / 2,
|
|
1056
|
+
-250,
|
|
1057
|
+
{ steps: 30, stepDelay: 16 }
|
|
1058
|
+
)
|
|
1059
|
+
await page.waitForTimeout(600)
|
|
1060
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1061
|
+
'Sheet position: 0'
|
|
1062
|
+
)
|
|
1063
|
+
|
|
1064
|
+
// 3. now scroll up (content should scroll since at top snap)
|
|
1065
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
1066
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
1067
|
+
expect(scrollviewBox).toBeTruthy()
|
|
1068
|
+
|
|
1069
|
+
await page.mouse.move(
|
|
1070
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
1071
|
+
scrollviewBox!.y + scrollviewBox!.height / 2
|
|
1072
|
+
)
|
|
1073
|
+
await page.mouse.wheel(0, 150)
|
|
1074
|
+
await page.waitForTimeout(400)
|
|
1075
|
+
|
|
1076
|
+
const scrollAfter = await page
|
|
1077
|
+
.getByTestId('sheet-scrollable-drag-scroll-y')
|
|
1078
|
+
.textContent()
|
|
1079
|
+
const scrollVal = parseInt(scrollAfter?.replace('ScrollView Y: ', '') || '0', 10)
|
|
1080
|
+
expect(scrollVal).toBeGreaterThan(30)
|
|
1081
|
+
|
|
1082
|
+
// 4. drag down - should scroll back first, then drag sheet
|
|
1083
|
+
await dragSheet(
|
|
1084
|
+
page,
|
|
1085
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
1086
|
+
scrollviewBox!.y + scrollviewBox!.height / 3,
|
|
1087
|
+
350,
|
|
1088
|
+
{ steps: 40, stepDelay: 16 }
|
|
1089
|
+
)
|
|
1090
|
+
await page.waitForTimeout(600)
|
|
1091
|
+
|
|
1092
|
+
// should have scrolled to 0
|
|
1093
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
1094
|
+
'ScrollView Y: 0'
|
|
1095
|
+
)
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
test('Case 7: drag UP from position 1 - scroll locked during drag, final position 0', async ({
|
|
1099
|
+
page,
|
|
1100
|
+
}) => {
|
|
1101
|
+
// open sheet
|
|
1102
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
1103
|
+
await page.waitForTimeout(600)
|
|
1104
|
+
|
|
1105
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
1106
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
1107
|
+
|
|
1108
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
1109
|
+
let handleBox = await handle.boundingBox()
|
|
1110
|
+
expect(handleBox).toBeTruthy()
|
|
1111
|
+
|
|
1112
|
+
// first drag down to position 1 (use mouse for handle)
|
|
1113
|
+
await dragSheet(
|
|
1114
|
+
page,
|
|
1115
|
+
handleBox!.x + handleBox!.width / 2,
|
|
1116
|
+
handleBox!.y + handleBox!.height / 2,
|
|
1117
|
+
200,
|
|
1118
|
+
{ steps: 25, stepDelay: 16, mode: 'mouse' }
|
|
1119
|
+
)
|
|
1120
|
+
await page.waitForTimeout(600)
|
|
1121
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1122
|
+
'Sheet position: 1'
|
|
1123
|
+
)
|
|
1124
|
+
|
|
1125
|
+
// verify scroll is at 0
|
|
1126
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
1127
|
+
'ScrollView Y: 0'
|
|
1128
|
+
)
|
|
1129
|
+
|
|
1130
|
+
await page.waitForTimeout(400)
|
|
1131
|
+
|
|
1132
|
+
// drag UP via scrollview area - sheet moves to position 0
|
|
1133
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
1134
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
1135
|
+
expect(scrollviewBox).toBeTruthy()
|
|
1136
|
+
|
|
1137
|
+
await dragSheet(
|
|
1138
|
+
page,
|
|
1139
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
1140
|
+
scrollviewBox!.y + scrollviewBox!.height / 2,
|
|
1141
|
+
-250,
|
|
1142
|
+
{ steps: 30, stepDelay: 16 }
|
|
1143
|
+
)
|
|
1144
|
+
await page.waitForTimeout(600)
|
|
1145
|
+
|
|
1146
|
+
// sheet should be at position 0
|
|
1147
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1148
|
+
'Sheet position: 0'
|
|
1149
|
+
)
|
|
1150
|
+
// scroll should still be 0 (locked during drag)
|
|
1151
|
+
const scrollY = await page.getByTestId('sheet-scrollable-drag-scroll-y').textContent()
|
|
1152
|
+
const scrollVal = parseInt(scrollY?.replace('ScrollView Y: ', '') || '0', 10)
|
|
1153
|
+
expect(scrollVal).toBeLessThanOrEqual(5)
|
|
1154
|
+
})
|
|
1155
|
+
|
|
1156
|
+
test('Case 8: rubber band at top - dragging up keeps sheet at top', async ({
|
|
1157
|
+
page,
|
|
1158
|
+
}) => {
|
|
1159
|
+
// open sheet
|
|
1160
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
1161
|
+
await page.waitForTimeout(600)
|
|
1162
|
+
|
|
1163
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
1164
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
1165
|
+
|
|
1166
|
+
// verify at position 0 (top snap)
|
|
1167
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1168
|
+
'Sheet position: 0'
|
|
1169
|
+
)
|
|
1170
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
1171
|
+
'ScrollView Y: 0'
|
|
1172
|
+
)
|
|
1173
|
+
|
|
1174
|
+
// drag UP on handle - should NOT scroll content, should show resistance
|
|
1175
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
1176
|
+
const handleBox = await handle.boundingBox()
|
|
1177
|
+
expect(handleBox).toBeTruthy()
|
|
1178
|
+
|
|
1179
|
+
// use mouse mode for handle (PanResponder-based element)
|
|
1180
|
+
await dragSheet(
|
|
1181
|
+
page,
|
|
1182
|
+
handleBox!.x + handleBox!.width / 2,
|
|
1183
|
+
handleBox!.y + handleBox!.height / 2,
|
|
1184
|
+
-150,
|
|
1185
|
+
{ steps: 20, stepDelay: 16, mode: 'mouse' }
|
|
1186
|
+
)
|
|
1187
|
+
await page.waitForTimeout(600)
|
|
1188
|
+
|
|
1189
|
+
// sheet should still be at position 0 after rubber band release
|
|
1190
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1191
|
+
'Sheet position: 0'
|
|
1192
|
+
)
|
|
1193
|
+
// frame should still be visible (sheet didn't disappear)
|
|
1194
|
+
await expect(frame).toBeVisible()
|
|
1195
|
+
// scroll should NOT have happened during drag
|
|
1196
|
+
const maxScrollY = await page
|
|
1197
|
+
.getByTestId('sheet-scrollable-drag-max-scroll-y')
|
|
1198
|
+
.textContent()
|
|
1199
|
+
const maxScrollVal = parseInt(maxScrollY?.replace('Max scroll Y: ', '') || '0', 10)
|
|
1200
|
+
expect(maxScrollVal).toBeLessThanOrEqual(5)
|
|
1201
|
+
})
|
|
1202
|
+
|
|
1203
|
+
test('Case 9: HANDOFF UP - drag UP from position 1, continue into scroll', async ({
|
|
1204
|
+
page,
|
|
1205
|
+
}) => {
|
|
1206
|
+
// open sheet
|
|
1207
|
+
await page.getByTestId('sheet-scrollable-drag-trigger').click()
|
|
1208
|
+
await page.waitForTimeout(600)
|
|
1209
|
+
|
|
1210
|
+
const frame = page.getByTestId('sheet-scrollable-drag-frame')
|
|
1211
|
+
await expect(frame).toBeVisible({ timeout: 5000 })
|
|
1212
|
+
|
|
1213
|
+
const handle = page.getByTestId('sheet-scrollable-drag-handle')
|
|
1214
|
+
let handleBox = await handle.boundingBox()
|
|
1215
|
+
expect(handleBox).toBeTruthy()
|
|
1216
|
+
|
|
1217
|
+
// first drag down to position 1 (use mouse for handle)
|
|
1218
|
+
await dragSheet(
|
|
1219
|
+
page,
|
|
1220
|
+
handleBox!.x + handleBox!.width / 2,
|
|
1221
|
+
handleBox!.y + handleBox!.height / 2,
|
|
1222
|
+
200,
|
|
1223
|
+
{ steps: 25, stepDelay: 16, mode: 'mouse' }
|
|
1224
|
+
)
|
|
1225
|
+
await page.waitForTimeout(600)
|
|
1226
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1227
|
+
'Sheet position: 1'
|
|
1228
|
+
)
|
|
1229
|
+
await expect(page.getByTestId('sheet-scrollable-drag-scroll-y')).toContainText(
|
|
1230
|
+
'ScrollView Y: 0'
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
await page.waitForTimeout(400)
|
|
1234
|
+
|
|
1235
|
+
// CRITICAL: one LONG drag UP - should:
|
|
1236
|
+
// 1. Move sheet from position 1 to position 0
|
|
1237
|
+
// 2. Continue into scrolling without lifting finger
|
|
1238
|
+
const scrollview = page.getByTestId('sheet-scrollable-drag-scrollview')
|
|
1239
|
+
const scrollviewBox = await scrollview.boundingBox()
|
|
1240
|
+
expect(scrollviewBox).toBeTruthy()
|
|
1241
|
+
|
|
1242
|
+
await dragSheet(
|
|
1243
|
+
page,
|
|
1244
|
+
scrollviewBox!.x + scrollviewBox!.width / 2,
|
|
1245
|
+
scrollviewBox!.y + scrollviewBox!.height / 2,
|
|
1246
|
+
-400,
|
|
1247
|
+
{ steps: 50, stepDelay: 12 } // longer, faster drag for handoff
|
|
1248
|
+
)
|
|
1249
|
+
await page.waitForTimeout(300)
|
|
1250
|
+
|
|
1251
|
+
// sheet should be at position 0
|
|
1252
|
+
await expect(page.getByTestId('sheet-scrollable-drag-position')).toContainText(
|
|
1253
|
+
'Sheet position: 0'
|
|
1254
|
+
)
|
|
1255
|
+
|
|
1256
|
+
// AND scroll should have happened (handoff successful)
|
|
1257
|
+
// check maxScrollY instead of current scrollY because scroll may bounce back
|
|
1258
|
+
const maxScrollY = await page
|
|
1259
|
+
.getByTestId('sheet-scrollable-drag-max-scroll-y')
|
|
1260
|
+
.textContent()
|
|
1261
|
+
const maxScrollVal = parseInt(maxScrollY?.replace('Max scroll Y: ', '') || '0', 10)
|
|
1262
|
+
expect(maxScrollVal).toBeGreaterThan(30) // handoff occurred
|
|
1263
|
+
})
|
|
1264
|
+
})
|