diff --git a/tests/unit/components/Explore/ExploreV2/screens/UniversalSearch.test.js b/tests/unit/components/Explore/ExploreV2/screens/UniversalSearch.test.js
index a71e32f25..80d31890d 100644
--- a/tests/unit/components/Explore/ExploreV2/screens/UniversalSearch.test.js
+++ b/tests/unit/components/Explore/ExploreV2/screens/UniversalSearch.test.js
@@ -1,4 +1,5 @@
import { useNetInfo } from "@react-native-community/netinfo";
+import { BottomTabBarHeightContext } from "@react-navigation/bottom-tabs";
import {
act, fireEvent, screen, userEvent, waitFor,
} from "@testing-library/react-native";
@@ -6,7 +7,7 @@ import UniversalSearch from "components/Explore/ExploreV2/screens/UniversalSearc
import initI18next from "i18n/initI18next";
import i18next from "i18next";
import React from "react";
-import { Keyboard } from "react-native";
+import { Keyboard, StyleSheet } from "react-native";
import { renderComponent } from "tests/helpers/render";
const mockNavigate = jest.fn( );
@@ -71,6 +72,12 @@ jest.mock( "sharedHooks/useIconicTaxa", ( ) => ( {
} ) );
const useIconicTaxa = require( "sharedHooks/useIconicTaxa" ).default;
+jest.mock( "sharedHooks/useKeyboardInfo", ( ) => ( {
+ __esModule: true,
+ default: jest.fn( ),
+} ) );
+const useKeyboardInfo = require( "sharedHooks/useKeyboardInfo" ).default;
+
const ICONIC_TAXA = [
{
id: 47126,
@@ -160,6 +167,18 @@ const focusLocation = ( ) => {
fireEvent( screen.getByTestId( "UniversalSearch.locationInput" ), "focus" );
};
+const KEYBOARD_HIDDEN = { keyboardHeight: 0, keyboardShown: false };
+
+const measureButtonBar = height => {
+ fireEvent( screen.getByTestId( "UniversalSearch.buttonBar" ), "layout", {
+ nativeEvent: { layout: { height } },
+ } );
+};
+
+const listPaddingBottom = ( ) => StyleSheet.flatten(
+ screen.getByTestId( "UniversalSearch.results" ).props.contentContainerStyle,
+)?.paddingBottom;
+
beforeAll( async ( ) => {
await initI18next( );
} );
@@ -183,6 +202,7 @@ beforeEach( ( ) => {
useIconicTaxa.mockReturnValue( ICONIC_TAXA );
useUniversalSearch.mockReturnValue( { results: [], isLoading: false, refetch: jest.fn( ) } );
useLocationSearch.mockReturnValue( { results: [], isLoading: false, refetch: jest.fn( ) } );
+ useKeyboardInfo.mockReturnValue( KEYBOARD_HIDDEN );
// Default to online; the offline tests override this per-case.
useNetInfo.mockReturnValue( { isConnected: true } );
} );
@@ -625,6 +645,52 @@ describe( "UniversalSearch screen", ( ) => {
);
} );
+ describe( "keeping results clear of the keyboard", ( ) => {
+ it( "adds no padding while the keyboard is dismissed", ( ) => {
+ useKeyboardInfo.mockReturnValue( { keyboardHeight: 300, keyboardShown: false } );
+ renderComponent( );
+
+ measureButtonBar( 80 );
+
+ expect( listPaddingBottom( ) ).toEqual( 0 );
+ } );
+
+ it( "pads the list by the keyboard height minus the button bar", ( ) => {
+ useKeyboardInfo.mockReturnValue( { keyboardHeight: 300, keyboardShown: true } );
+ renderComponent( );
+
+ expect( listPaddingBottom( ) ).toEqual( 300 );
+
+ measureButtonBar( 80 );
+ expect( listPaddingBottom( ) ).toEqual( 220 );
+ } );
+
+ it( "also subtracts the tab bar height when the screen has one", ( ) => {
+ useKeyboardInfo.mockReturnValue( { keyboardHeight: 300, keyboardShown: true } );
+ renderComponent(
+
+
+ ,
+ );
+
+ measureButtonBar( 80 );
+ expect( listPaddingBottom( ) ).toEqual( 170 );
+ } );
+
+ it( "never pads by a negative amount", ( ) => {
+ useKeyboardInfo.mockReturnValue( { keyboardHeight: 100, keyboardShown: true } );
+ renderComponent(
+
+
+ ,
+ );
+
+ measureButtonBar( 80 );
+
+ expect( listPaddingBottom( ) ).toEqual( 0 );
+ } );
+ } );
+
it( "navigates to Advanced Search", async ( ) => {
renderComponent( );