Skip to content
Closed
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: 4 additions & 0 deletions apps/src/tests/single-feature-tests/form-sheet/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { ScenarioGroup } from '@apps/tests/shared/helpers';
import TestFormSheetBase from './test-form-sheet-base-ios';
import TestFormSheetBackgroundComponent from './test-form-sheet-background-component-ios';
import TestFormSheetExpandScrollView from './test-form-sheet-expand-scroll-view-ios';
import TestFormSheetFitToContents from './test-form-sheet-fit-to-contents-ios';
import TestFormSheetGrabberVisible from './test-form-sheet-grabber-visible-ios';
import TestFormSheetInitialDetentIndex from './test-form-sheet-initial-detent-index-ios';
import TestFormSheetLargestUndimmedDetentIndex from './test-form-sheet-largest-undimmed-detent-index-ios';
Expand All @@ -10,7 +12,9 @@ import TestFormSheetPresentationState from './test-form-sheet-presentation-state

const scenarios = {
TestFormSheetBase,
TestFormSheetBackgroundComponent,
TestFormSheetExpandScrollView,
TestFormSheetFitToContents,
TestFormSheetGrabberVisible,
TestFormSheetInitialDetentIndex,
TestFormSheetLargestUndimmedDetentIndex,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import React, { useState } from 'react';
import {
Button,
StyleSheet,
Text,
View,
Image,
Dimensions,
TouchableOpacity,
} from 'react-native';
import { FormSheet } from 'react-native-screens/experimental';
import { scenarioDescription } from './scenario-description';
import { createScenario } from '@apps/tests/shared/helpers';
import { Colors } from '@apps/shared/styling';

const SCREEN_WIDTH = Dimensions.get('window').width;

type BackgroundType = 'none' | 'solid' | 'composed' | 'image';

export function App() {
const [isOpen, setIsOpen] = useState(false);
const [bgType, setBgType] = useState<BackgroundType>('image');

const handleDismiss = () => {
setIsOpen(false);
};

const SolidBackground = (
<View
style={[
StyleSheet.absoluteFill,
{ backgroundColor: Colors.PurpleLight100 },
]}
/>
);

const ComposedBackground = (
<View
style={[
StyleSheet.absoluteFill,
{ backgroundColor: Colors.NavyLight80 },
]}>
<View style={styles.composedTopBar} />
<View style={styles.composedBottomBar} />
</View>
);

const ImageBackground = (
<Image
source={{
uri: 'https://fastly.picsum.photos/id/541/900/600.jpg?hmac=W6n9QTOEWat4-wHywp8az4ZqvcDzUMWWR1XDq3kS9sI',
height: 600,
width: SCREEN_WIDTH,
}}
style={StyleSheet.absoluteFill}
/>
);

const renderBackground = () => {
switch (bgType) {
case 'solid':
return SolidBackground;
case 'composed':
return ComposedBackground;
case 'image':
return ImageBackground;
case 'none':
default:
return undefined;
}
};

const isDarkBg = bgType !== 'none';

return (
<View style={styles.container}>
<Text style={styles.title}>FormSheet Background</Text>

<View style={styles.controlsContainer}>
<Text style={styles.controlsLabel}>Select Background Type:</Text>
<View style={styles.buttonRow}>
{(['none', 'solid', 'composed', 'image'] as BackgroundType[]).map(
type => (
<TouchableOpacity
key={type}
style={[
styles.optionButton,
bgType === type && styles.optionButtonActive,
]}
onPress={() => setBgType(type)}>
<Text
style={[
styles.optionText,
bgType === type && styles.optionTextActive,
]}>
{type.toUpperCase()}
</Text>
</TouchableOpacity>
),
)}
</View>
</View>

<View style={styles.spacing} />

<Button
title="Open FormSheet"
color={Colors.primary}
onPress={() => setIsOpen(true)}
/>

<FormSheet
isOpen={isOpen}
onNativeDismiss={handleDismiss}
detents='fitToContents'
backgroundComponent={renderBackground()}>
<View style={styles.sheetContent}>
<Text style={[styles.sheetTitle, isDarkBg && styles.textWhite]}>
Custom Background
</Text>

<Text style={[styles.description, isDarkBg && styles.textWhite]}>
Currently displaying: {bgType.toUpperCase()}. The background should
stretch to fill the entire native sheet, including the bottom safe
area.
</Text>

<View style={styles.spacing} />

<Button
title="Dismiss from JS"
color={isDarkBg ? Colors.White : Colors.primary}
onPress={handleDismiss}
/>
</View>
</FormSheet>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: Colors.offBackground,
},
title: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 20,
color: Colors.text,
},
controlsContainer: {
paddingHorizontal: 16,
width: '100%',
alignItems: 'center',
},
controlsLabel: {
fontSize: 14,
color: Colors.text,
marginBottom: 8,
},
buttonRow: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
gap: 8,
},
optionButton: {
paddingVertical: 6,
paddingHorizontal: 12,
borderRadius: 16,
borderWidth: 1,
borderColor: Colors.primary,
},
optionButtonActive: {
backgroundColor: Colors.primary,
},
optionText: {
fontSize: 12,
color: Colors.primary,
fontWeight: '600',
},
optionTextActive: {
color: Colors.White,
},
sheetContent: {
padding: 24,
justifyContent: 'center',
alignItems: 'center',
},
sheetTitle: {
fontSize: 22,
fontWeight: '600',
marginBottom: 12,
color: Colors.text,
},
description: {
fontSize: 16,
textAlign: 'center',
color: Colors.text,
paddingHorizontal: 16,
},
textWhite: {
color: Colors.White,
textShadowColor: Colors.NavyLightTransparent,
textShadowOffset: { width: 0, height: 1 },
textShadowRadius: 2,
},
spacing: {
height: 24,
},
composedTopBar: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: 12,
backgroundColor: Colors.GreenLight100,
},
composedBottomBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 40,
backgroundColor: Colors.RedLight100,
},
});

export default createScenario(App, scenarioDescription);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ScenarioDescription } from '@apps/tests/shared/helpers';

export const scenarioDescription: ScenarioDescription = {
name: 'Background component',
key: 'test-form-sheet-background-component-ios',
details:
'Allows to test the custom background component rendering of the FormSheet.',
platforms: ['ios'],
e2eCoverage: 'tbd',
smokeTest: false,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Test Scenario: Background component

## Details

**Description:** Verify the `backgroundComponent` functionality of the `FormSheet` component. This test ensures that the custom background component correctly renders beneath the content layer and fully extends to cover the entire native bounds of the sheet, including the un-collapsible bottom safe area injected by UIKit.

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

## E2E test

Other: Planned, but will be implemented separately.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following new naming (described in RFC), if we are planning to implement e2e test I would change this line to:

Suggested change
Other: Planned, but will be implemented separately.
TBD: Planned, but will be implemented separately.


## Prerequisites

- iOS device or simulator

## Steps

### Baseline

1. Launch the app and navigate to the **Background component** screen.

- [ ] Expected: Content with the button "Open FormSheet" and background selection controls is shown.

---

### Verification: "NONE" Background

2. Select the "NONE" background type and tap the "Open FormSheet" button.

- [ ] Expected: The FormSheet opens smoothly.
- [ ] Expected: The background is the default system color (e.g., white or dark depending on the theme).
Comment on lines +31 to +32
Copy link
Copy Markdown
Collaborator

@LKuchno LKuchno May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should duplicate the Expected field. We could either combine both points into a single sentence, or list them as bullets under one Expected label, like this:

  • Expected:
  • The FormSheet opens smoothly.
  • The background is the default system color (e.g., white or dark depending on the theme).

OR
Expected:

  • The FormSheet opens smoothly.
  • The background is the default system color (e.g., white or dark depending on the theme).

Either way, I think we should align on one convention as a team so we have a clear reference going forward.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will follow the second approach and omit "Expected:". It is redundant, as we can assume that any checkbox under a step represents the expected behavior to be verified.

Copy link
Copy Markdown
Collaborator

@LKuchno LKuchno May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


3. Tap the "Dismiss from JS" button.

- [ ] Expected: The FormSheet dismisses smoothly.

---

### Verification: "SOLID" Background

4. Select the "SOLID" background type and tap the "Open FormSheet" button.

- [ ] Expected: The FormSheet opens smoothly.
- [ ] Expected: A solid purple background is visible behind the text content.
- [ ] Expected: The purple background extends all the way to the absolute bottom edge of the screen.

5. Tap the "Dismiss from JS" button.

- [ ] Expected: The FormSheet dismisses smoothly.

---

### Verification: "COMPOSED" Background

6. Select the "COMPOSED" background type and tap the "Open FormSheet" button.

- [ ] Expected: The FormSheet opens smoothly.
- [ ] Expected: A navy background is visible behind the text content.
- [ ] Expected: A thin green bar is visible at the top edge.
- [ ] Expected: A red bar is visible at the very bottom edge of the screen, successfully rendering underneath the navigation bar.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navigation bar disappears after some time so referencing it here might be a bit confusing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same below.


7. Tap the "Dismiss from JS" button.

- [ ] Expected: The FormSheet dismisses smoothly.

---

### Verification: "IMAGE" Background

8. Select the "IMAGE" background type and tap the "Open FormSheet" button.

- [ ] Expected: The FormSheet opens smoothly.
- [ ] Expected: An image background is visible behind the text content.
- [ ] Expected: The image fully covers the native sheet bounds, extending completely under the navigation bar.

9. Tap the "Dismiss from JS" button.

- [ ] Expected: The FormSheet dismisses smoothly and returns the user to the underlying main screen.
Loading