mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
This repo could never sync. There was NO merge-base with tamagui — 372 commits
here against 15,791 there, unrelated histories — because it began as a
copy-paste rebrand with a flattened layout. Every "sync" since was a hand
re-application that drifted, which is why the tree sat on 7.3.1 while upstream
shipped fixes we then rediscovered by hand.
This commit's PARENT IS TAMAGUI. A future sync is `git merge tama/main` then
`node scripts/rebrand.mjs` — a real merge, because the history is now shared.
174 packages: 166 upstream, our 8 restored (chrome, shell, telemetry, recipes,
get, font-geist-{sans,mono}, @hanzo/booker), bento-get gained. 170/170 build.
Our patches to files UPSTREAM ALSO OWNS are carried, which the package-level
delta missed and which was where the value actually was:
- useMedia's server snapshot (`initState ?? getMedia()`). Upstream still
returns undefined there, so every Tamagui Dialog kills a prerender — the
exact crash hanzo.app spent a day on.
- data-slot on web host nodes, absent upstream entirely.
Both applied ONTO upstream's newer files (it rewrote useMedia +150/-63 and
createComponent +160/-55), marked `PATCH (ours, carried across the transplant)`.
Seven traps are encoded in scripts/rebrand.mjs, each found by a gate:
skip itself and lockfiles; special-case the double-branded names in BOTH scoped
and bare form; map path strings, not just paths; drop a level for the flattened
group; check disk rather than a stale index.
Rust build artifacts are NOT committed. An earlier draft of this commit swept
apps/desktop/src-tauri/target/debug in via `git add -A` — 3,859 files including
a 272MB .a, over GitHub's 100MB cap, so the push could never have landed. They
are gitignored now.
Co-Authored-By: Hanzo Dev <[email protected]>
372 lines
13 KiB
TypeScript
372 lines
13 KiB
TypeScript
/**
|
|
* Detox E2E tests for Sheet drag resistance behavior
|
|
*
|
|
* Tests three scenarios:
|
|
* 1. Sheet without ScrollView - drag up should show resistance
|
|
* 2. Sheet with ScrollView but NO scrollable content - drag should move sheet, not scroll
|
|
* 3. Sheet with ScrollView and scrollable content - drag up at top should show resistance
|
|
*
|
|
* These tests validate the bugs:
|
|
* - Bug #1: if has scrollview but content not scrollable, dragging wasn't moving the sheet
|
|
* - Bug #2: drag up past end / resist isn't moving much
|
|
* - Bug #3: no scrollview also drag up / resist not doing much
|
|
*/
|
|
|
|
import { by, device, element, expect, waitFor } from 'detox'
|
|
import { remountDirectUseCase } from './utils/navigation'
|
|
import { safeLaunchApp } from './utils/detox'
|
|
|
|
// only run on iOS - RNGH gesture handling differs on Android
|
|
const isAndroid = () => device.getPlatform() === 'android'
|
|
|
|
describe('SheetDragResist', () => {
|
|
beforeAll(async () => {
|
|
if (isAndroid()) return
|
|
await safeLaunchApp({
|
|
newInstance: true,
|
|
launchArgs: { directUseCase: 'SheetDragResistCase' },
|
|
})
|
|
await waitFor(element(by.id('sheet-drag-resist-screen')))
|
|
.toExist()
|
|
.withTimeout(180000)
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
if (isAndroid()) return
|
|
await remountDirectUseCase('sheet-drag-resist-screen')
|
|
// disable sync AFTER remount to avoid hang on spring animations during tests
|
|
await device.disableSynchronization()
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (isAndroid()) return
|
|
await device.enableSynchronization()
|
|
})
|
|
|
|
it('should navigate to SheetDragResistCase test case', async () => {
|
|
if (isAndroid()) return
|
|
// the screen may not be fully visible due to scroll position, use toExist instead
|
|
await expect(element(by.id('sheet-drag-resist-screen'))).toExist()
|
|
await expect(element(by.id('no-scroll-trigger'))).toBeVisible()
|
|
await expect(element(by.id('non-scrollable-trigger'))).toBeVisible()
|
|
await expect(element(by.id('scrollable-trigger'))).toBeVisible()
|
|
})
|
|
|
|
describe('Bug #3: Sheet without ScrollView - drag up resistance', () => {
|
|
/**
|
|
* BUG #3 TEST: Drag up on sheet without ScrollView should show resistance
|
|
*
|
|
* Expected: When at top snap point, dragging up should apply resistance
|
|
* (sheet moves slightly then springs back, showing visual rubber band effect)
|
|
*
|
|
* BUG: Currently dragging up doesn't show much/any movement at all
|
|
*/
|
|
it('should show resistance when dragging up on handle at top position', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('no-scroll-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('no-scroll-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify we're at position 0 (top snap point)
|
|
await expect(element(by.id('no-scroll-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// drag UP on handle - this should show resistance and spring back
|
|
await element(by.id('no-scroll-handle')).swipe('up', 'slow', 0.8)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// sheet should still be at position 0 (didn't dismiss or change snap)
|
|
await expect(element(by.id('no-scroll-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
// frame should still be visible (sheet didn't disappear)
|
|
await expect(element(by.id('no-scroll-frame'))).toBeVisible()
|
|
})
|
|
|
|
it('should show resistance when dragging up on frame content', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('no-scroll-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('no-scroll-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify at position 0
|
|
await expect(element(by.id('no-scroll-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
|
|
// reset tracking
|
|
await element(by.id('no-scroll-reset')).tap()
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// drag UP on frame content - should show resistance
|
|
await element(by.id('no-scroll-frame')).swipe('up', 'slow', 0.9)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// sheet should snap back to position 0
|
|
await expect(element(by.id('no-scroll-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
|
|
// check the max drag indicator - should be > 0 if resistance was working
|
|
// (the test component tracks maximum upward drag distance)
|
|
const attrs = await element(by.id('no-scroll-drag-indicator')).getAttributes()
|
|
console.log('Bug #3 - Max upward drag detected:', (attrs as any).text)
|
|
})
|
|
})
|
|
|
|
describe('Bug #1: Sheet with non-scrollable ScrollView', () => {
|
|
/**
|
|
* BUG #1 TEST: Non-scrollable ScrollView content should let sheet drag through
|
|
*
|
|
* Expected: When ScrollView has content that fits (not scrollable), dragging
|
|
* down should move the sheet to the next snap point.
|
|
*
|
|
* NOTE: These tests document a DETOX LIMITATION, not a Gui bug.
|
|
* Detox's swipe() doesn't trigger RNGH gestures when ScrollView content
|
|
* is non-scrollable. The feature has been MANUALLY VERIFIED to work.
|
|
* - Manual test via XcodeBuildMCP: swiping down moves sheet from position 0 to 1 ✓
|
|
* - react-native-actions-sheet comparison test also fails (confirming Detox issue)
|
|
* See: https://github.com/wix/Detox/issues/2886
|
|
*/
|
|
it.skip('should drag sheet DOWN when ScrollView content is not scrollable', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('non-scrollable-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('non-scrollable-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// reset counters
|
|
await element(by.id('non-scrollable-reset')).tap()
|
|
|
|
// verify we start at position 0
|
|
await expect(element(by.id('non-scrollable-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// swipe DOWN on the scrollview (matching SheetScrollableDrag.test.ts pattern)
|
|
// at scrollY=0 with non-scrollable content, this should drag the sheet
|
|
await element(by.id('non-scrollable-scrollview')).swipe('down', 'slow', 0.5)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// check results
|
|
const posAttr = await element(
|
|
by.id('non-scrollable-snap-indicator')
|
|
).getAttributes()
|
|
const statusAttr = await element(by.id('non-scrollable-status')).getAttributes()
|
|
console.log(
|
|
'Bug #1 result - Position:',
|
|
(posAttr as any).text,
|
|
'Status:',
|
|
(statusAttr as any).text
|
|
)
|
|
|
|
// EXPECTED: position changes to 1 (sheet moved down to lower snap)
|
|
// BUGGY: position stays 0 but scroll events fired
|
|
await expect(element(by.id('non-scrollable-snap-indicator'))).toHaveText(
|
|
'Current snap point: 1'
|
|
)
|
|
})
|
|
|
|
// Also skipped due to same Detox limitation - handle swipe also fails with non-scrollable content
|
|
it.skip('should let handle always be draggable regardless of ScrollView', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('non-scrollable-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('non-scrollable-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify we start at position 0
|
|
await expect(element(by.id('non-scrollable-snap-indicator'))).toHaveText(
|
|
'Current snap point: 0'
|
|
)
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// swipe down on handle - this should ALWAYS work
|
|
// using 'fast' speed like Case 8 in SheetScrollableDrag.test.ts
|
|
await element(by.id('non-scrollable-handle')).swipe('down', 'fast', 0.5)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// handle drag should move the sheet
|
|
await expect(element(by.id('non-scrollable-snap-indicator'))).toHaveText(
|
|
'Current snap point: 1'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('Bug #2: Sheet with scrollable ScrollView - drag up resistance', () => {
|
|
/**
|
|
* BUG #2 TEST: At scroll top and sheet top, dragging up should show resistance
|
|
*
|
|
* Expected: When scrollY=0 and sheet at top snap point, dragging up should
|
|
* apply resistance (rubber band effect) rather than doing nothing.
|
|
*
|
|
* BUG: Dragging up at this position doesn't move much at all
|
|
*/
|
|
it('should show resistance when dragging up at scroll top and sheet top', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('scrollable-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('scrollable-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// reset tracking
|
|
await element(by.id('scrollable-reset')).tap()
|
|
|
|
// ensure we're at scroll top and position 0
|
|
await expect(element(by.id('scrollable-at-top'))).toHaveText('At scroll top: YES')
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// drag UP on handle - at scroll top + sheet top, should show resistance
|
|
await element(by.id('scrollable-handle')).swipe('up', 'slow', 0.8)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// after rubber band, should still be at scroll top (no scroll happened)
|
|
await expect(element(by.id('scrollable-at-top'))).toHaveText('At scroll top: YES')
|
|
|
|
// frame should still be visible (sheet didn't disappear)
|
|
await expect(element(by.id('scrollable-frame'))).toBeVisible()
|
|
|
|
// check max drag indicator
|
|
const attrs = await element(by.id('scrollable-status')).getAttributes()
|
|
console.log('Bug #2 - Max upward drag:', (attrs as any).text)
|
|
})
|
|
|
|
it('should scroll content when swiping up inside scrollable sheet', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('scrollable-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('scrollable-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify starting state - at scroll top
|
|
await expect(element(by.id('scrollable-at-top'))).toHaveText('At scroll top: YES')
|
|
|
|
// swipe UP on scrollview content - should scroll content (not move sheet)
|
|
await element(by.id('scrollable-scrollview')).swipe('up', 'slow', 0.5)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 300))
|
|
|
|
// scroll Y should now be > 0
|
|
await expect(element(by.id('scrollable-at-top'))).toHaveText('At scroll top: NO')
|
|
})
|
|
|
|
it('should drag sheet DOWN via handle when at scroll top', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('scrollable-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('scrollable-frame')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify at scroll top
|
|
await expect(element(by.id('scrollable-at-top'))).toHaveText('At scroll top: YES')
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// drag DOWN on handle - should move sheet to position 1
|
|
await element(by.id('scrollable-handle')).swipe('down', 'slow', 0.8)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// sheet should be at lower snap point (or dismissed)
|
|
// verify animation completes without crash
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
})
|
|
})
|
|
|
|
describe('Comparison: react-native-actions-sheet', () => {
|
|
/**
|
|
* Reference test using react-native-actions-sheet to verify Detox
|
|
* can properly trigger RNGH gestures.
|
|
*
|
|
* RESULT: This test ALSO FAILS, confirming that Detox's swipe() cannot
|
|
* trigger RNGH gestures when content is non-scrollable. This is a Detox
|
|
* limitation, not a bug in either Gui or actions-sheet.
|
|
*/
|
|
it.skip('should drag actions-sheet DOWN with non-scrollable content', async () => {
|
|
if (isAndroid()) return
|
|
|
|
await element(by.id('actions-sheet-trigger')).tap()
|
|
|
|
await waitFor(element(by.id('actions-sheet-content')))
|
|
.toBeVisible()
|
|
.withTimeout(5000)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// verify at snap index 0
|
|
await expect(element(by.id('actions-sheet-snap-indicator'))).toHaveText(
|
|
'Snap index: 0'
|
|
)
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// swipe DOWN on content - should move sheet
|
|
await element(by.id('actions-sheet-content')).swipe('down', 'slow', 0.5)
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
|
|
// screenshot removed for CI speed
|
|
|
|
// if actions-sheet can move via Detox swipe, expect snap index 1
|
|
await expect(element(by.id('actions-sheet-snap-indicator'))).toHaveText(
|
|
'Snap index: 1'
|
|
)
|
|
})
|
|
})
|
|
})
|