Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1385fe3
chore(test): e2e test-tabs-tab-bar-layout-direction first draft
LKuchno Apr 16, 2026
f9faaa7
Merge branch 'main' of github.com:software-mansion/react-native-scree…
LKuchno Apr 16, 2026
4bdd79b
chore(test): e2e test implementation, scenario update with e2e infrom…
LKuchno Apr 17, 2026
8172e35
Merge branch 'main' of github.com:software-mansion/react-native-scree…
LKuchno Apr 17, 2026
a8b9470
test titiles changed
LKuchno Apr 17, 2026
b8a16ba
scenario description
LKuchno Apr 17, 2026
b6e0eb3
note section added to sceanrio
LKuchno Apr 17, 2026
9efb89a
small change in scenario for consistency
LKuchno Apr 17, 2026
f8a8443
adding info about rtl language coverage - manual only- priority
LKuchno Apr 17, 2026
dcf633d
Merge branch 'main' of github.com:software-mansion/react-native-scree…
LKuchno Apr 22, 2026
d5c3c1d
adding scroll to direction picker to fix problem in android test
LKuchno Apr 22, 2026
42b7c6b
four more scrools added to make sure that element is visible and fix …
LKuchno Apr 22, 2026
f539f50
adding scrollTo function to e2e test
LKuchno Apr 22, 2026
72b322e
adding scrollTo function to e2e test
LKuchno Apr 22, 2026
59cded8
formatting scenarios
LKuchno Apr 27, 2026
784141f
refactor e2e tests to be independent
LKuchno Apr 27, 2026
fedc6b3
Grammar changes Update apps/src/tests/single-feature-tests/tabs/test-…
LKuchno Apr 27, 2026
3f9e7a5
Update FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-…
LKuchno Apr 27, 2026
6882b34
Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-lay…
LKuchno Apr 27, 2026
69ec8bf
Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-lay…
LKuchno Apr 27, 2026
3d19908
Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-lay…
LKuchno Apr 27, 2026
6e6f2cf
separate test to make it independent, adding cycle changes check test
LKuchno Apr 27, 2026
edfa1d6
removing duplicated the
LKuchno Apr 27, 2026
4c8a670
applying new function to all tests
LKuchno Apr 27, 2026
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,210 @@
import { expect as jestExpect } from '@jest/globals';
import { device, expect, element, by } from 'detox';
import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox';
import { selectSingleFeatureTestsScreen } from '../../e2e-utils';

type ElementAttributes = IosElementAttributes | AndroidElementAttributes;

async function getElementAttributes(
testLabel: string,
): Promise<ElementAttributes> {
const attrs = await element(by.label(testLabel)).getAttributes();
return attrs as ElementAttributes;
}

async function scrollTo(selector: { id: string } | { text: string }) {
const el =
'text' in selector
? element(by.text(selector.text))
: element(by.id(selector.id));

await waitFor(el)
.toBeVisible()
.whileElement(by.id('tab-bar-layout-direction-scrollview'))
.scroll(100, 'down');
}

async function selectDirection(direction: 'inherit' | 'rtl' | 'ltr') {
await scrollTo({ id: 'tab-bar-layout-direction-picker' });
await element(by.id('tab-bar-layout-direction-picker')).tap();
await scrollTo({ text: direction });
await element(by.text(direction)).tap();
await element(by.id('tab-bar-layout-direction-picker')).tap();
await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel(
`direction: ${direction}`,
);
}
const expectTab1ToBeLeftOfTab2 = async (shouldBeLeft: boolean) => {
const t1 = await getElementAttributes('tab-bar-item-1-label');
const t2 = await getElementAttributes('tab-bar-item-2-label');
if (shouldBeLeft) {
jestExpect(t2.frame.x).toBeGreaterThan(t1.frame.x);
} else {
jestExpect(t1.frame.x).toBeGreaterThan(t2.frame.x);
}
};

describe('Tab Bar Layout Direction - system settings: LTR', () => {
beforeEach(async () => {
await device.reloadReactNative();
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-tab-bar-layout-direction',
);
});

it('displays default options and renders Tab1 at the visually leftmost position (LTR)', async () => {
await expect(
element(by.id('tab-bar-layout-direction-scrollview')),
).toBeVisible();
await expect(element(by.id('react-force-rtl-picker'))).toHaveLabel(
'forceRTL: false',
);
await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel(
'allowRTL: true',
);
await scrollTo({ id: 'tab-bar-layout-direction-picker' });
await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel(
'direction: inherit',
);
await expect(element(by.id('is-rtl-information'))).toHaveText(
'I18nManager.isRTL == false',
);
await expectTab1ToBeLeftOfTab2(true);
});

it('follows system LTR settings when direction is set to inherit', async () => {
await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(true);
});

it('overrides system LTR settings and renders the tab bar in RTL order', async () => {
await selectDirection('rtl');
await expectTab1ToBeLeftOfTab2(false);
});

it('remains in LTR order when direction is explicitly set to ltr', async () => {
await selectDirection('ltr');
await expectTab1ToBeLeftOfTab2(true);
});

it('cycle through inherit → rtl → ltr → rtl → inherit renders the tab bar in correct order', async () => {
await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(true);

await selectDirection('rtl');
await expectTab1ToBeLeftOfTab2(false);

await selectDirection('ltr');
await expectTab1ToBeLeftOfTab2(true);

await selectDirection('rtl');
await expectTab1ToBeLeftOfTab2(false);

await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(true);
});
});

describe('Tab Bar Layout Direction - system settings: RTL', () => {
beforeAll(async () => {
if (device.getPlatform() === 'ios') {
await device.launchApp({
newInstance: true,
launchArgs: {
AppleTextDirection: 'YES',
NSForceRightToLeftWritingDirection: 'YES',
I18NIsRTL: 'YES',
},
});
} else {
await device.launchApp({ newInstance: true });
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-tab-bar-layout-direction',
);
await element(by.id('react-force-rtl-picker')).tap();
await device.reloadReactNative();
}
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-tab-bar-layout-direction',
);
});

afterAll(async () => {
if (device.getPlatform() === 'ios') {
await device.launchApp({
newInstance: true,
launchArgs: {
AppleTextDirection: 'NO',
NSForceRightToLeftWritingDirection: 'NO',
I18NIsRTL: 'NO',
},
});
} else {
await device.launchApp({ newInstance: true });
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-tab-bar-layout-direction',
);
await element(by.id('react-force-rtl-picker')).multiTap(2);
await expect(element(by.id('react-force-rtl-picker'))).toHaveLabel(
'forceRTL: false',
);
await device.reloadReactNative();
}
});

it('displays default options and renders Tab2 at the visually leftmost position (RTL)', async () => {
await expect(
element(by.id('tab-bar-layout-direction-scrollview')),
).toBeVisible();
await expect(element(by.id('react-force-rtl-picker'))).toHaveLabel(
'forceRTL: false',
);
await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel(
'allowRTL: true',
);
await scrollTo({ id: 'tab-bar-layout-direction-picker' });
await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel(
'direction: inherit',
);
await expect(element(by.id('is-rtl-information'))).toHaveText(
'I18nManager.isRTL == true',
);
await expectTab1ToBeLeftOfTab2(false);
});

it('follows system RTL settings when direction is set to inherit', async () => {
await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(false);
});

it('remains in RTL order when direction is explicitly set to rtl', async () => {
await selectDirection('rtl');
await expectTab1ToBeLeftOfTab2(false);
});

it('overrides system RTL settings and renders the tab bar in LTR order', async () => {
await selectDirection('ltr');
await expectTab1ToBeLeftOfTab2(true);
});

it('cycle through inherit → ltr → rtl → ltr → inherit renders the tab bar in correct order', async () => {
await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(false);

await selectDirection('ltr');
await expectTab1ToBeLeftOfTab2(true);

await selectDirection('rtl');
await expectTab1ToBeLeftOfTab2(false);

await selectDirection('ltr');
await expectTab1ToBeLeftOfTab2(true);

await selectDirection('inherit');
await expectTab1ToBeLeftOfTab2(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ function ConfigScreen() {
}, [reactAllowRtl]);

return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<ScrollView style={styles.container} contentContainerStyle={styles.content}
testID='tab-bar-layout-direction-scrollview'>
<View style={styles.section}>
<Text>
There are 3 sources of layout direction: system, React Native and our
Expand All @@ -62,7 +63,7 @@ function ConfigScreen() {

<View style={styles.section}>
<Text style={styles.heading}>React Native's isRTL</Text>
<Text style={styles.rtlInfo}>
<Text style={styles.rtlInfo} testID='is-rtl-information'>
{'I18nManager.isRTL == ' + (I18nManager.isRTL ? 'true' : 'false')}
</Text>
</View>
Expand All @@ -79,6 +80,7 @@ function ConfigScreen() {
onValueChange={function (value: boolean): void {
setReactForceRtl(value);
}}
testID='react-force-rtl-picker'
/>
</View>

Expand All @@ -94,6 +96,7 @@ function ConfigScreen() {
onValueChange={function (value: boolean): void {
setReactAllowRtl(value);
}}
testID='react-allow-rtl-picker'
/>
</View>

Expand All @@ -104,6 +107,7 @@ function ConfigScreen() {
value={hostConfig.direction ?? 'inherit'}
onValueChange={value => updateHostConfig({ direction: value })}
items={['inherit', 'ltr', 'rtl']}
testID='tab-bar-layout-direction-picker'
/>
</View>
</ScrollView>
Expand All @@ -112,11 +116,12 @@ function ConfigScreen() {

const ROUTE_CONFIGS: TabRouteConfig[] = [
{
name: 'Config',
name: 'Tab1',
Component: ConfigScreen,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Config',
title: 'Tab1',
tabBarItemAccessibilityLabel: 'tab-bar-item-1-label',
safeAreaConfiguration: {
edges: {
bottom: true,
Expand All @@ -130,6 +135,7 @@ const ROUTE_CONFIGS: TabRouteConfig[] = [
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Tab2',
tabBarItemAccessibilityLabel: 'tab-bar-item-2-label',
},
},
];
Expand Down
Loading
Loading