Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/src/tests/single-feature-tests/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ScenarioGroup } from '@apps/tests/shared/helpers';

import BottomAccessoryScenario from './bottom-accessory-layout';
import OverrideScrollViewContentInsetScenario from './override-scroll-view-content-inset';
import TestTabsOverrideScrollViewContentInset from './test-tabs-override-scroll-view-content-inset-ios';
import TestTabsTabBarHidden from './test-tabs-tab-bar-hidden';
import TabsScreenOrientationScenario from './tabs-screen-orientation';
import TabBarAppearanceDefinedBySelectedTabScenario from './test-tabs-appearance-defined-by-selected-tab';
Expand All @@ -18,7 +18,7 @@ import TestTabsSpecialEffectsScrollToTop from './test-tabs-special-effects-scrol

const scenarios = {
BottomAccessoryScenario,
OverrideScrollViewContentInsetScenario,
TestTabsOverrideScrollViewContentInset,
TabBarAppearanceDefinedBySelectedTabScenario,
TestTabsTabBarHidden,
TabsScreenOrientationScenario,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { createScenario } from '@apps/tests/shared/helpers';

const scenarioDescription: ScenarioDescription = {
name: 'Override ScrollView Content Inset',
key: 'override-scroll-view-content-inset',
key: 'test-tabs-override-scroll-view-content-inset-ios',
details:
'Tests overrideScrollViewContentInsetAdjustmentBehavior with different static values per tab. ' +
'False: content scrolls behind bars. True/Default: content is inset from bars.',
Expand All @@ -19,9 +19,15 @@ const scenarioDescription: ScenarioDescription = {

const ITEM_COUNT = 30;

function ScrollContent({ label }: { label: string }) {
export function ScrollContent({
label,
testID,
}: {
label: string;
testID: string;
}) {
return (
<ScrollView style={styles.scrollView}>
<ScrollView style={styles.scrollView} testID={testID}>
<View style={styles.header}>
<Text style={styles.headerText}>
overrideScrollViewContentInsetAdjustmentBehavior: {label}
Expand All @@ -36,19 +42,34 @@ function ScrollContent({ label }: { label: string }) {
);
}

function FalseTab() {
return <ScrollContent label="false" />;
export function FalseTab() {
return (
<ScrollContent
label="false"
testID="override-inset-false-scrollview"
/>
);
}

function TrueTab() {
return <ScrollContent label="true" />;
export function TrueTab() {
return (
<ScrollContent
label="true"
testID="override-inset-true-scrollview"
/>
);
}

function DefaultTab() {
return <ScrollContent label="(not set, defaults to true)" />;
return (
<ScrollContent
label="(not set, defaults to true)"
testID="override-inset-default-scrollview"
/>
);
}

export function App() {
export export function App() {
return (
<NavigationIndependentTree>
<NavigationContainer>
Expand All @@ -59,6 +80,7 @@ export function App() {
Component: FalseTab,
options: {
title: 'False',
tabBarItemAccessibilityLabel: 'override-inset-tab-false',
ios: {
overrideScrollViewContentInsetAdjustmentBehavior: false,
icon: { type: 'sfSymbol', name: 'xmark.circle' },
Expand All @@ -70,6 +92,7 @@ export function App() {
Component: TrueTab,
options: {
title: 'True',
tabBarItemTestID: 'override-inset-tab-true',
ios: {
overrideScrollViewContentInsetAdjustmentBehavior: true,
icon: { type: 'sfSymbol', name: 'checkmark.circle' },
Expand All @@ -81,6 +104,7 @@ export function App() {
Component: DefaultTab,
options: {
title: 'Default',
tabBarItemTestID: 'override-inset-tab-default',
ios: { icon: { type: 'sfSymbol', name: 'circle.dashed' } },
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Test Scenario: overrideScrollViewContentInsetAdjustmentBehavior

## Details

**Description:** Validates the
`overrideScrollViewContentInsetAdjustmentBehavior` prop on `TabsScreen`
(iOS only). By default, React Native sets ScrollView's
`contentInsetAdjustmentBehavior` to `never`, which prevents the scroll
view from respecting navigation bar and tab bar insets. When this prop
is `true` (the default), the behavior is overridden back to UIKit's
`automatic`, so content is inset from the bars. When set to `false`,
the content scrolls behind the bars without insets.
The test verifies that the three tabs — **False**, **True**, and
**Default** — each exhibit the expected inset behavior and that the
**Default** tab (prop omitted) matches the **True** tab.

**OS test creation version:** iOS: 18.6 and 26.2

## E2E test

Other: Ongoing research.

## Prerequisites

- iOS device or simulator (iPhone)

## Note

- "Content scrolls behind bars" means list items are visible underneath
the navigation bar and/or tab bar when scrolled to the top or bottom
of the list.
- "Content inset from bars" means the first and last list items are
fully visible and never hidden behind a bar, even when the scroll
view is at its extreme positions.
- The navigation bar at the top and the tab bar at the bottom are both
relevant reference points for inset verification.

## Steps

### Baseline

1. Launch the app and navigate to the
**Override Scroll View Content Inset** screen.

- [ ] Expected: Three tabs are displayed in the tab bar: **False**,
**True**, and **Default**. The **False** tab is selected and shows
a scrollable list of 30 items.

---

### `false` — content scrolls behind bars

2. Confirm the **False** tab is active and scroll the list to the bottom.

- [ ] Expected: The last item in the list is partially or fully
obscured behind the tab bar, confirming that no bottom inset is
applied.

3. Scroll the list to the top.

- [ ] Expected: The text label
`overrideScrollViewContentInsetAdjustmentBehavior: false` at
the top of the scroll content is partially or fully obscured
behind the navigation bar, because
`overrideScrollViewContentInsetAdjustmentBehavior` is `false`
and the scroll view uses
`contentInsetAdjustmentBehavior: never`.

---

### `true` — content inset from bars

4. Tap the **True** tab.

- [ ] Expected: The **True** tab becomes active and shows a
scrollable list of 30 items.

5. Scroll the list to the bottom.

- [ ] Expected: The last item is fully visible and is not obscured by
the tab bar. The scroll view respects the bottom inset.

6. Scroll the list to the top.

- [ ] Expected: The text label
`overrideScrollViewContentInsetAdjustmentBehavior: true`
at the top of the scroll content is fully visible below the
navigation bar and not obscured behind it. The scroll view
respects the top inset
(`contentInsetAdjustmentBehavior: automatic`).

---

### Default (prop omitted) — same as `true`

7. Tap the **Default** tab.

- [ ] Expected: The **Default** tab becomes active and shows a
scrollable list of 30 items.

8. Scroll the list to the bottom.

- [ ] Expected: The last item is fully visible and not obscured by
the tab bar — identical behavior to the **True** tab.

9. Scroll the list to the top.

- [ ] Expected: The text label
`overrideScrollViewContentInsetAdjustmentBehavior: (not set, defaults to true)`
at the top of the scroll content
is fully visible below the navigation bar and not obscured
behind it — identical behavior to the **True** tab.

---

### Cross-tab comparison

10. Switch between the **True** tab and the **Default** tab several
times while keeping each list scrolled to the top.

- [ ] Expected: Both tabs show the text label
`overrideScrollViewContentInsetAdjustmentBehavior:` with value `true`
or `(not set, defaults to true)` at the top of the scroll content
is fully visible below the navigation bar and not obscured
behind it. No layout jump or
visual difference between the two tabs.

11. Switch to the **False** tab and scroll to the top, then
immediately switch to the **True** tab.

- [ ] Expected: The **True** tab correctly shows the the text label
inset from the navigation bar. No crash or blank screen occurs
during the switch.
Loading