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
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { expect as jestExpect } from '@jest/globals';
import { device, expect, element, by } from 'detox';
import { AndroidElementAttributes } from 'detox/detox';
import {
describeIfAndroid,
selectSingleFeatureTestsScreen,
} from '../../e2e-utils';

async function getTabBarItemAttrs(): Promise<AndroidElementAttributes> {
const attrs = (await element(
by.id('ime-insets-config-tab-item'),
).getAttributes()) as AndroidElementAttributes;
return attrs;
}
async function getTextAttrs(): Promise<AndroidElementAttributes> {
const attrs = (await element(
by.id('tabs-screen-bottom-text'),
).getAttributes()) as AndroidElementAttributes;
return attrs;
}

describeIfAndroid('Tabs: tabBarRespectsIMEInsets', () => {
beforeAll(async () => {
await device.reloadReactNative();
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-ime-insets-android',
);
});

it('should display default switch states and bottom text on load', async () => {
await expect(element(by.id('safe-area-bottom-edge-switch'))).toBeVisible();
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toBeVisible();
await expect(element(by.id('ime-insets-text-input'))).toBeVisible();

await expect(element(by.id('safe-area-bottom-edge-switch'))).toHaveLabel(
'safeAreaViewBottomEdgeEnabled: true',
);
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toHaveLabel('tabBarRespectsIMEInsets: false');

await expect(element(by.id('tabs-screen-bottom-text'))).toBeVisible();
});

it('tabBarRespectsIMEInsets: false — tab bar Y stays constant when keyboard opens', async () => {
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toHaveLabel('tabBarRespectsIMEInsets: false');

const yTabBefore = (await getTabBarItemAttrs()).frame.y;
const yTextBefore = (await getTextAttrs()).frame.y;

await element(by.id('ime-insets-text-input')).tap();

const yTabAfter = (await getTabBarItemAttrs()).frame.y;
const yTextAfter = (await getTextAttrs()).frame.y;

jestExpect(yTabAfter).toEqual(yTabBefore);
jestExpect(yTextAfter).toEqual(yTextBefore);

await device.pressBack();
});

it('tabBarRespectsIMEInsets: true — tab bar shifts above keyboard when keyboard opens', async () => {
await element(by.id('tab-bar-respects-ime-insets-switch')).tap();
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toHaveLabel('tabBarRespectsIMEInsets: true');

const yTabBefore = (await getTabBarItemAttrs()).frame.y;
const yTextBefore = (await getTextAttrs()).frame.y;

await element(by.id('ime-insets-text-input')).tap();

const yTabAfter = (await getTabBarItemAttrs()).frame.y;
const yTextAfter = (await getTextAttrs()).frame.y;

jestExpect(yTabAfter).toBeLessThan(yTabBefore);
jestExpect(yTextAfter).toBeLessThan(yTextBefore);
jestExpect(yTextAfter).toBeLessThan(yTabAfter);

await device.pressBack();

const yTabRestored = (await getTabBarItemAttrs()).frame.y;

jestExpect(yTabRestored).toEqual(yTabBefore);
});

it('safeAreaViewBottomEdgeEnabled: false + tabBarRespectsIMEInsets: true — tab bar still shifts above keyboard', async () => {
await element(by.id('safe-area-bottom-edge-switch')).tap();
await expect(element(by.id('safe-area-bottom-edge-switch'))).toHaveLabel(
'safeAreaViewBottomEdgeEnabled: false',
);
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toHaveLabel('tabBarRespectsIMEInsets: true');

const yTabBefore = (await getTabBarItemAttrs()).frame.y;
const yTextBefore = (await getTextAttrs()).frame.y;

jestExpect(yTextBefore).toBeGreaterThan(yTabBefore);

await element(by.id('ime-insets-text-input')).tap();

const yTabAfter = (await getTabBarItemAttrs()).frame.y;
const yTextAfter = (await getTextAttrs()).frame.y;

jestExpect(yTabAfter).toBeLessThan(yTabBefore);
jestExpect(yTextAfter).toEqual(yTextBefore);

await device.pressBack();
});

it('both props false — tab bar stays at bottom when keyboard opens', async () => {
await element(by.id('tab-bar-respects-ime-insets-switch')).tap();
await expect(element(by.id('safe-area-bottom-edge-switch'))).toHaveLabel(
'safeAreaViewBottomEdgeEnabled: false',
);
await expect(
element(by.id('tab-bar-respects-ime-insets-switch')),
).toHaveLabel('tabBarRespectsIMEInsets: false');

const yTabBefore = (await getTabBarItemAttrs()).frame.y;
const yTextBefore = (await getTextAttrs()).frame.y;
jestExpect(yTextBefore).toBeGreaterThan(yTabBefore);

await element(by.id('ime-insets-text-input')).tap();

const yTabAfter = (await getTabBarItemAttrs()).frame.y;
const yTextAfter = (await getTextAttrs()).frame.y;

jestExpect(yTabAfter).toEqual(yTabBefore);
jestExpect(yTextAfter).toEqual(yTextBefore);

await device.pressBack();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function ConfigScreen() {
onValueChange={function (value: boolean): void {
setSafeAreaViewBottomEdgeEnabled(value);
}}
testID="safe-area-bottom-edge-switch"
/>
</View>
<View style={styles.section}>
Expand All @@ -49,17 +50,19 @@ function ConfigScreen() {
onValueChange={function (value: boolean): void {
updateHostConfig({ android: { tabBarRespectsIMEInsets: value } });
}}
testID="tab-bar-respects-ime-insets-switch"
/>
</View>
<View style={styles.section}>
<Text style={styles.heading}>TextInput</Text>
<TextInput
placeholder="Focus TextInput to show IME..."
style={styles.textInput}
testID="ime-insets-text-input"
/>
</View>
<View style={styles.end}>
<Text>TabsScreen bottom</Text>
<Text testID="tabs-screen-bottom-text">TabsScreen bottom</Text>
</View>
</View>
);
Expand All @@ -72,6 +75,7 @@ const ROUTE_CONFIGS: TabRouteConfig[] = [
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Config',
tabBarItemTestID: 'ime-insets-config-tab-item',
safeAreaConfiguration: {
edges: {
bottom: true,
Expand All @@ -85,6 +89,7 @@ const ROUTE_CONFIGS: TabRouteConfig[] = [
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Tab2',
tabBarItemTestID: 'ime-insets-tab2-tab-item',
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ export const scenarioDescription: ScenarioDescription = {
details:
'Tests prop that determines whether BottomNavigationView respects IME insets.',
platforms: ['android'],
e2eCoverage: 'tbd',
e2eCoverage: 'full',
smokeTest: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ the layout content relative to the tab bar to prevent keyboard overlapping.

## E2E test

TBD: Planned, but will be implemented separately.
Full: All manual steps are covered by an E2E test based on changes to the tab bar
and text frame Y-positions.

## Prerequisites

Expand Down
Loading