diff --git a/__tests__/components/brain/my-stream/layout/LayoutContext.test.tsx b/__tests__/components/brain/my-stream/layout/LayoutContext.test.tsx index 5873410011..14de060876 100644 --- a/__tests__/components/brain/my-stream/layout/LayoutContext.test.tsx +++ b/__tests__/components/brain/my-stream/layout/LayoutContext.test.tsx @@ -2,7 +2,18 @@ import React, { useEffect, useRef } from 'react'; import { render, screen } from '@testing-library/react'; import { LayoutProvider, useLayout } from '@/components/brain/my-stream/layout/LayoutContext'; -jest.mock('@/hooks/useCapacitor', () => ({ __esModule: true, default: () => ({ isCapacitor: false, isAndroid: false, isIos: false }) })); +// Mock useCapacitor hook with configurable values +let mockCapacitorValues = { isCapacitor: false, isAndroid: false, isIos: false }; +jest.mock('@/hooks/useCapacitor', () => ({ + __esModule: true, + default: () => mockCapacitorValues +})); + +// Mock useAndroidKeyboard hook with configurable values +let mockKeyboardValues = { isVisible: false, keyboardHeight: 0, isAndroid: false, getContainerStyle: jest.fn() }; +jest.mock('@/hooks/useAndroidKeyboard', () => ({ + useAndroidKeyboard: () => mockKeyboardValues +})); beforeAll(() => { // run RAF callbacks immediately @@ -19,6 +30,12 @@ afterAll(() => { delete (global as any).requestAnimationFrame; }); +beforeEach(() => { + // Reset mocks before each test + mockCapacitorValues = { isCapacitor: false, isAndroid: false, isIos: false }; + mockKeyboardValues = { isVisible: false, keyboardHeight: 0, isAndroid: false, getContainerStyle: jest.fn() }; +}); + function TestComponent() { const { registerRef, spaces, waveViewStyle } = useLayout(); const ref = useRef(null); @@ -39,7 +56,7 @@ function TestComponent() { describe('LayoutProvider', () => { it('calculates spaces and styles', () => { - Object.defineProperty(window, 'innerHeight', { value: 1000, configurable: true }); + Object.defineProperty(globalThis, 'innerHeight', { value: 1000, configurable: true }); render( @@ -49,4 +66,66 @@ describe('LayoutProvider', () => { expect(content.textContent).toBe('900'); expect(content.style.height).toContain('calc(100dvh - 100px'); }); + + it('applies 128px capSpace on Android when keyboard is closed', () => { + mockCapacitorValues = { isCapacitor: true, isAndroid: true, isIos: false }; + mockKeyboardValues = { isVisible: false, keyboardHeight: 0, isAndroid: true, getContainerStyle: jest.fn() }; + + Object.defineProperty(globalThis, 'innerHeight', { value: 1000, configurable: true }); + render( + + + + ); + const content = screen.getByTestId('content'); + // Should include 128px capSpace + expect(content.style.height).toContain('- 128px'); + }); + + it('removes capSpace and subtracts keyboard height on Android when keyboard is open', () => { + mockCapacitorValues = { isCapacitor: true, isAndroid: true, isIos: false }; + mockKeyboardValues = { isVisible: true, keyboardHeight: 350, isAndroid: true, getContainerStyle: jest.fn() }; + + Object.defineProperty(globalThis, 'innerHeight', { value: 1000, configurable: true }); + render( + + + + ); + const content = screen.getByTestId('content'); + // Should subtract keyboard height (350px) but not capSpace + expect(content.style.height).toContain('- 350px'); + expect(content.style.height).not.toContain('- 128px'); + }); + + it('applies 20px capSpace on iOS', () => { + mockCapacitorValues = { isCapacitor: true, isAndroid: false, isIos: true }; + mockKeyboardValues = { isVisible: false, keyboardHeight: 0, isAndroid: false, getContainerStyle: jest.fn() }; + + Object.defineProperty(globalThis, 'innerHeight', { value: 1000, configurable: true }); + render( + + + + ); + const content = screen.getByTestId('content'); + // Should include 20px capSpace for iOS + expect(content.style.height).toContain('- 20px'); + }); + + it('does not apply capSpace on desktop', () => { + mockCapacitorValues = { isCapacitor: false, isAndroid: false, isIos: false }; + mockKeyboardValues = { isVisible: false, keyboardHeight: 0, isAndroid: false, getContainerStyle: jest.fn() }; + + Object.defineProperty(globalThis, 'innerHeight', { value: 1000, configurable: true }); + render( + + + + ); + const content = screen.getByTestId('content'); + // Should not include any capSpace + expect(content.style.height).not.toContain('- 128px'); + expect(content.style.height).not.toContain('- 20px'); + }); }); diff --git a/__tests__/components/waves/drop/SingleWaveDropChat.test.tsx b/__tests__/components/waves/drop/SingleWaveDropChat.test.tsx index 301c1077e1..c802de3914 100644 --- a/__tests__/components/waves/drop/SingleWaveDropChat.test.tsx +++ b/__tests__/components/waves/drop/SingleWaveDropChat.test.tsx @@ -5,12 +5,26 @@ import { SingleWaveDropChat } from '@/components/waves/drop/SingleWaveDropChat'; jest.mock('@/hooks/useCapacitor', () => () => false); jest.mock('@/components/brain/my-stream/layout/LayoutContext', () => ({ useLayout: () => ({ spaces: { measurementsComplete: true, headerSpace: 10 } }) })); +// Mock useAndroidKeyboard with configurable values +let mockKeyboardVisible = false; +let mockGetContainerStyle = jest.fn((baseStyle: any) => baseStyle); + +jest.mock('@/hooks/useAndroidKeyboard', () => ({ + useAndroidKeyboard: () => ({ + isVisible: mockKeyboardVisible, + keyboardHeight: mockKeyboardVisible ? 350 : 0, + isAndroid: true, + getContainerStyle: mockGetContainerStyle, + }), +})); + let capturedProps: any; +let capturedCreatorProps: any; jest.mock('@/components/waves/drops/wave-drops-all', () => ({ __esModule: true, default: (props: any) => { capturedProps = props; return
; } })); -jest.mock('@/components/waves/CreateDropWaveWrapper', () => ({ CreateDropWaveWrapper: ({ children }: any) =>
{children}
, CreateDropWaveWrapperContext: { SINGLE_DROP: 'SINGLE_DROP' } })); +jest.mock('@/components/waves/CreateDropWaveWrapper', () => ({ CreateDropWaveWrapper: ({ children }: any) =>
{children}
, CreateDropWaveWrapperContext: { SINGLE_DROP: 'SINGLE_DROP' } })); -jest.mock('@/components/waves/PrivilegedDropCreator', () => ({ __esModule: true, default: (props: any) =>
, DropMode: { BOTH: 'BOTH' } })); +jest.mock('@/components/waves/PrivilegedDropCreator', () => ({ __esModule: true, default: (props: any) => { capturedCreatorProps = props; return