From 1385fe35fb7fab7acb731620e085dfcdd81d52bd Mon Sep 17 00:00:00 2001 From: lkuchno Date: Thu, 16 Apr 2026 09:26:58 +0200 Subject: [PATCH 01/21] chore(test): e2e test-tabs-tab-bar-layout-direction first draft --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 141 ++++++++++++++++++ .../index.tsx | 14 +- 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts new file mode 100644 index 0000000000..8315ef2c1a --- /dev/null +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -0,0 +1,141 @@ +import { expect as jestExpect } from '@jest/globals'; +import { device, expect, element, by } from 'detox'; +import { selectSingleFeatureTestsScreen } from '../../e2e-utils'; +import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox'; + +type ElementAttributes = IosElementAttributes | AndroidElementAttributes; + +async function getElementAttributes(testLabel: string): Promise { + const attrs = await element(by.label(testLabel)).getAttributes(); + return attrs as ElementAttributes; +} + +// describe('Tab Bar Layout Direction - system settings: LTR', () => { +// beforeAll(async () => { +// await device.reloadReactNative(); +// await selectSingleFeatureTestsScreen('Tabs', 'test-tabs-tab-bar-layout-direction'); +// }); + +// it('Tab Bar Layout Direction screen should be displayed with default options.', async () => { +// await expect(element(by.id('tab-bar-layout-direction-picker'))).toBeVisible(); +// 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); +// await expect(element(by.id('is-rtl-information'))).toHaveText('I18nManager.isRTL == false'); +// }); + +// //inherit +// it('Tab Bar Layout Direction: inherit, tab bar follow system settings - ltr order - Tab1 first from left.', async () => { +// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); + +// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); +// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); +// jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); +// }); + +// //rtl +// it('Tab Bar Layout Direction: rtl, overridesystem settings - tab bar displayed in rtl order - Tab2 first from left.', async () => { +// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); +// await element(by.text('rtl')).tap(); +// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); +// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: rtl'); + +// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); +// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); +// jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); +// }); + +// //ltr +// it('Tab Bar Layout Direction: ltr, tab bar displayed in ltr order - Tab1 first from left.', async () => { +// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); +// await element(by.text('ltr')).tap(); +// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); +// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: ltr'); + +// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); +// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); +// jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); +// }); +// }); + +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 { + const { execSync } = require('child_process'); + execSync(`adb shell settings put global development_settings_enabled 1`); + execSync(`adb shell settings put global debug.force_rtl 1`); + await device.launchApp({ newInstance: true }); + } + + 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 { + const { execSync } = require('child_process'); + execSync(`adb shell settings put global debug.force_rtl 0`); + await device.launchApp({ newInstance: true }); + } + }); + + it('Tab Bar Layout Direction screen should be displayed with default options.', async () => { + await expect(element(by.id('tab-bar-layout-direction-picker'))).toBeVisible(); + 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); + await expect(element(by.id('is-rtl-information'))).toHaveText('I18nManager.isRTL == true'); + }); + + //inherit + it('Tab Bar Layout Direction: inherit, tab bar follow system settings - ltr order - Tab1 first from left.', async () => { + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + }); + + // //rtl + // it('Tab Bar Layout Direction: rtl, overridesystem settings - tab bar displayed in rtl order - Tab2 first from left.', async () => { + // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); + // await element(by.text('rtl')).tap(); + // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); + // await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: rtl'); + + // const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + // const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + // jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + // }); + + // //ltr + // it('Tab Bar Layout Direction: ltr, tab bar displayed in ltr order - Tab1 first from left.', async () => { + // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); + // await element(by.text('ltr')).tap(); + // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); + // await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: ltr'); + + // const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + // const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + // jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + // }); +}); diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/index.tsx b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/index.tsx index 1ce0578250..e9d5f18f15 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/index.tsx +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/index.tsx @@ -43,7 +43,8 @@ function ConfigScreen() { }, [reactAllowRtl]); return ( - + There are 3 sources of layout direction: system, React Native and our @@ -64,7 +65,7 @@ function ConfigScreen() { React Native's isRTL - + {'I18nManager.isRTL == ' + (I18nManager.isRTL ? 'true' : 'false')} @@ -81,6 +82,7 @@ function ConfigScreen() { onValueChange={function (value: boolean): void { setReactForceRtl(value); }} + testID='react-force-rtl-picker' /> @@ -96,6 +98,7 @@ function ConfigScreen() { onValueChange={function (value: boolean): void { setReactAllowRtl(value); }} + testID='react-allow-rtl-picker' /> @@ -106,6 +109,7 @@ function ConfigScreen() { value={hostConfig.direction ?? 'inherit'} onValueChange={value => updateHostConfig({ direction: value })} items={['inherit', 'ltr', 'rtl']} + testID='tab-bar-layout-direction-picker' /> @@ -114,11 +118,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, @@ -132,6 +137,7 @@ const ROUTE_CONFIGS: TabRouteConfig[] = [ options: { ...DEFAULT_TAB_ROUTE_OPTIONS, title: 'Tab2', + tabBarItemAccessibilityLabel: 'tab-bar-item-2-label', }, }, ]; From 4bdd79b576f8d3135aa6a0e4fdc4fb0712d2c5f2 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 11:51:40 +0200 Subject: [PATCH 02/21] chore(test): e2e test implementation, scenario update with e2e infromations. --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 310 ++++++++++-------- .../scenario.md | 76 ++--- 2 files changed, 215 insertions(+), 171 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 8315ef2c1a..d2331487fc 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -1,141 +1,191 @@ import { expect as jestExpect } from '@jest/globals'; import { device, expect, element, by } from 'detox'; -import { selectSingleFeatureTestsScreen } from '../../e2e-utils'; +import { describeIfiOS, selectSingleFeatureTestsScreen } from '../../e2e-utils'; import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox'; type ElementAttributes = IosElementAttributes | AndroidElementAttributes; -async function getElementAttributes(testLabel: string): Promise { - const attrs = await element(by.label(testLabel)).getAttributes(); - return attrs as ElementAttributes; +async function getElementAttributes( + testLabel: string, +): Promise { + const attrs = await element(by.label(testLabel)).getAttributes(); + return attrs as ElementAttributes; } -// describe('Tab Bar Layout Direction - system settings: LTR', () => { -// beforeAll(async () => { -// await device.reloadReactNative(); -// await selectSingleFeatureTestsScreen('Tabs', 'test-tabs-tab-bar-layout-direction'); -// }); - -// it('Tab Bar Layout Direction screen should be displayed with default options.', async () => { -// await expect(element(by.id('tab-bar-layout-direction-picker'))).toBeVisible(); -// 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); -// await expect(element(by.id('is-rtl-information'))).toHaveText('I18nManager.isRTL == false'); -// }); - -// //inherit -// it('Tab Bar Layout Direction: inherit, tab bar follow system settings - ltr order - Tab1 first from left.', async () => { -// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); - -// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); -// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); -// jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); -// }); - -// //rtl -// it('Tab Bar Layout Direction: rtl, overridesystem settings - tab bar displayed in rtl order - Tab2 first from left.', async () => { -// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); -// await element(by.text('rtl')).tap(); -// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); -// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: rtl'); - -// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); -// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); -// jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); -// }); - -// //ltr -// it('Tab Bar Layout Direction: ltr, tab bar displayed in ltr order - Tab1 first from left.', async () => { -// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); -// await element(by.text('ltr')).tap(); -// await (element(by.id('tab-bar-layout-direction-picker'))).tap(); -// await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: ltr'); - -// const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); -// const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); -// jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); -// }); -// }); +describe('Tab Bar Layout Direction - system settings: LTR', () => { + beforeAll(async () => { + await device.reloadReactNative(); + await selectSingleFeatureTestsScreen( + 'Tabs', + 'test-tabs-tab-bar-layout-direction', + ); + }); + + it('Tab Bar Layout Direction screen should be displayed with default options. Tab bar follow lts order: Tab1 first from left.', async () => { + await expect( + element(by.id('tab-bar-layout-direction-picker')), + ).toBeVisible(); + 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: inherit', + ); + await expect(element(by.id('is-rtl-information'))).toHaveText( + 'I18nManager.isRTL == false', + ); + }); + + //inherit + it('Tab Bar Layout Direction: inherit. Tab bar follow system settings - ltr order: Tab1 first from left.', async () => { + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: inherit', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + }); + + //rtl + it('Tab Bar Layout Direction: rtl, overridesystem settings. Tab bar displayed in rtl order: Tab2 first from left.', async () => { + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await element(by.text('rtl')).tap(); + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: rtl', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + }); + + //ltr + it('Tab Bar Layout Direction: ltr. Tab bar displayed in ltr order: Tab1 first from left.', async () => { + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await element(by.text('ltr')).tap(); + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: ltr', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + }); +}); 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 { - const { execSync } = require('child_process'); - execSync(`adb shell settings put global development_settings_enabled 1`); - execSync(`adb shell settings put global debug.force_rtl 1`); - await device.launchApp({ newInstance: true }); - } - - 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 { - const { execSync } = require('child_process'); - execSync(`adb shell settings put global debug.force_rtl 0`); - await device.launchApp({ newInstance: true }); - } - }); - - it('Tab Bar Layout Direction screen should be displayed with default options.', async () => { - await expect(element(by.id('tab-bar-layout-direction-picker'))).toBeVisible(); - 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); - await expect(element(by.id('is-rtl-information'))).toHaveText('I18nManager.isRTL == true'); - }); - - //inherit - it('Tab Bar Layout Direction: inherit, tab bar follow system settings - ltr order - Tab1 first from left.', async () => { - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: inherit'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); - }); - - // //rtl - // it('Tab Bar Layout Direction: rtl, overridesystem settings - tab bar displayed in rtl order - Tab2 first from left.', async () => { - // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); - // await element(by.text('rtl')).tap(); - // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); - // await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: rtl'); - - // const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - // const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - // jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); - // }); - - // //ltr - // it('Tab Bar Layout Direction: ltr, tab bar displayed in ltr order - Tab1 first from left.', async () => { - // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); - // await element(by.text('ltr')).tap(); - // await (element(by.id('tab-bar-layout-direction-picker'))).tap(); - // await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel('direction: ltr'); - - // const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - // const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - // jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); - // }); + 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-allow-rtl-picker')).tap(); + await device.reloadReactNative(); + } + }); + + it('Tab Bar Layout Direction screen should be displayed with default options. Tab bar follow system settings - rtl order: Tab2 first from left.', async () => { + await expect( + element(by.id('tab-bar-layout-direction-picker')), + ).toBeVisible(); + 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 expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: inherit', + ); + await expect(element(by.id('is-rtl-information'))).toHaveText( + 'I18nManager.isRTL == true', + ); + }); + + //inherit + it('Tab Bar Layout Direction: inherit. Tab bar follow system settings - rtl order: Tab2 first from left.', async () => { + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: inherit', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + }); + + //rtl + it('Tab Bar Layout Direction: rtl. Tab bar displayed in rtl order: Tab2 first from left.', async () => { + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await element(by.text('rtl')).tap(); + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: rtl', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + }); + + //ltr + it('Tab Bar Layout Direction: ltr, override system settings. Tab bar displayed in ltr order: Tab1 first from left.', async () => { + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await element(by.text('ltr')).tap(); + await element(by.id('tab-bar-layout-direction-picker')).tap(); + await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( + 'direction: ltr', + ); + + const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); + const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); + jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + }); }); diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 759bc7c144..f7b62d49c0 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -1,83 +1,77 @@ # Test Scenario: direction -**E2E test:** ongoing research +## Details + +**Description:** + +**OS test creation version:** iOS: 18.6 and 26.2, Android: 16.0 (Baklava) + +## E2E test + +Yes: covers all manual scenario steps. + +Implementation Details: + +- iOS: The system RTL direction is set by configuring I18NIsRTL to YES during the app launch sequence. +- Android: RTL direction must be triggered using the forceRTL toggle located within the Layout Direction screen. ## Prerequisites -- iOS device or simulator -with at least one RTL language localization configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system language set to Arabic/Hebrew -- Android emulator -Android emulator with supportRtl enabled in app manifest +- iOS device or simulato with at least one RTL language localization configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system language set to Arabic/Hebrew, +- Android emulator with supportRtl enabled in app manifest. -Note: +## Note -- App restart is required after changing forceRTL / allowRTL - Assumption: system and RN settings are working correctly. Here only react-native-screens prop is tested. ## Steps ### Baseline -1. Launch the app and navigate to the scenario +1. Launch the app and navigate to the scenario. -- [ ] Expected: Config and Tab2 are shown in LTR order (Config on left, Tab2 to its right). All controls default to forceRTL=false, allowRTL=true, TabsHost direction = inherit +- [ ] Expected: Tab1 and Tab2 are shown in LTR order. Tab1 displayed as the leftmost item and Tab2 as second. All controls default to forceRTL=false, allowRTL=true, TabsHost direction = inherit. --- ### TabsHost inherit — follows RN/system -2. Ensure system/RN is LTR (I18nManager.isRTL == false), set TabsHost direction = inherit +2. Ensure system/RN is LTR (I18nManager.isRTL == false), set TabsHost direction = inherit. -- [ ] Expected: Tab bar displays in LTR order (Config on left, Tab2 to its right) +- [ ] Expected: Tab bar displays in LTR order. Tab1 is displayed as the the leftmost item and Tab2 as second. -3. Set system/RN to RTL (I18nManager.isRTL == true), keep TabsHost direction = inherit +3. Set system/RN to RTL (I18nManager.isRTL == true), keep TabsHost direction = inherit. -- [ ] Expected: Tab bar displays in RTL order — (Config on right, Tab2 to its left) +- [ ] Expected: Tab bar displays in RTL order. Tab2 displayed as the leftmost item and Tab1 as second. --- ### TabsHost ltr -4. Set system/RN to RTL, set TabsHost direction = ltr +4. Set system/RN to RTL, set TabsHost direction = ltr. -- [ ] Expected: Tab bar displays in LTR order — TabsHost overrides RTL from RN/system +- [ ] Expected: Tab bar displays in LTR order — TabsHost overrides RTL from RN/system. Tab1 is displayed as the the leftmost item. -5. Set system/RN to LTR, keep TabsHost direction = ltr +5. Set system/RN to LTR, keep TabsHost direction = ltr. -- [ ] Expected: Tab bar stays LTR +- [ ] Expected: Tab bar remains in LTR order. Tab1 is displayed as the the leftmost item. -6. Cycle through inherit → rtl → ltr → rtl → inherit +6. Cycle through inherit → rtl → ltr → rtl → inherit. -- [ ] Expected: Tab bar direction updates immediately with each change, no crash or layout freeze +- [ ] Expected: Tab bar direction updates immediately with each change; no crashes or layout freezes occur. --- ### TabsHost rtl -7. Set system/RN to LTR, set TabsHost direction = rtl - -- [ ] Expected: Tab bar displays in RTL order — TabsHost overrides LTR from RN/system - -8. Set system/RN to RTL, keep TabsHost direction = rtl - -- [ ] Expected: Tab bar stays RTL - -9. Cycle through inherit → ltr → rtl → ltr → inherit - -- [ ] Expected: Tab bar direction updates immediately with each change, no crash or layout freeze - ---- - -### Precedence chain verification - -10. System = RTL, forceRTL=false, allowRTL=false, TabsHost = inherit +7. Set system/RN to LTR, set TabsHost direction = rtl. -- [ ] Expected: Tab bar is LTR (allowRTL=false blocks system RTL) +- [ ] Expected: Tab bar displays in RTL order — TabsHost overrides LTR from RN/system. Tab2 displayed as the leftmost item. -11. System = LTR, forceRTL=true (restart), TabsHost = inherit +8. Set system/RN to RTL, keep TabsHost direction = rtl. -- [ ] Expected: Tab bar is RTL (forceRTL overrides system) +- [ ] Expected: Tab bar remains RTL. Tab2 displayed as the leftmost item. -12. System = LTR, forceRTL=true (restart), TabsHost = ltr +9. Cycle through inherit → ltr → rtl → ltr → inherit. -- [ ] Expected: Tab bar is LTR (TabsHost wins over forceRTL) +- [ ] Expected: Tab bar direction updates immediately with each change, no crash or layout freeze occur. From a8b947054502d24f68a341bdc5b22f71ba99b485 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 12:04:13 +0200 Subject: [PATCH 03/21] test titiles changed --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index d2331487fc..946e38ae0a 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -21,7 +21,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { ); }); - it('Tab Bar Layout Direction screen should be displayed with default options. Tab bar follow lts order: Tab1 first from left.', async () => { + it('displays default options and renders Tab1 at the visually leftmost position (LTR)', async () => { await expect( element(by.id('tab-bar-layout-direction-picker')), ).toBeVisible(); @@ -43,7 +43,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { }); //inherit - it('Tab Bar Layout Direction: inherit. Tab bar follow system settings - ltr order: Tab1 first from left.', async () => { + it('follows system LTR settings when direction is set to inherit', async () => { await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -54,7 +54,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { }); //rtl - it('Tab Bar Layout Direction: rtl, overridesystem settings. Tab bar displayed in rtl order: Tab2 first from left.', async () => { + it('overrides system LTR settings and renders the tab bar in RTL order', async () => { await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -68,7 +68,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { }); //ltr - it('Tab Bar Layout Direction: ltr. Tab bar displayed in ltr order: Tab1 first from left.', async () => { + it('remains in LTR order when direction is explicitly set to ltr', async () => { await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -129,7 +129,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { } }); - it('Tab Bar Layout Direction screen should be displayed with default options. Tab bar follow system settings - rtl order: Tab2 first from left.', async () => { + it('displays default options and renders Tab2 at the visually leftmost position (RTL)', async () => { await expect( element(by.id('tab-bar-layout-direction-picker')), ).toBeVisible(); @@ -151,7 +151,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); //inherit - it('Tab Bar Layout Direction: inherit. Tab bar follow system settings - rtl order: Tab2 first from left.', async () => { + it('follows system RTL settings when direction is set to inherit', async () => { await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -162,7 +162,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); //rtl - it('Tab Bar Layout Direction: rtl. Tab bar displayed in rtl order: Tab2 first from left.', async () => { + it('remains in RTL order when direction is explicitly set to rtl', async () => { await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -176,7 +176,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); //ltr - it('Tab Bar Layout Direction: ltr, override system settings. Tab bar displayed in ltr order: Tab1 first from left.', async () => { + it('overrides system RTL settings and renders the tab bar in LTR order', async () => { await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); From b8a16ba0b55cbbfc2ec28884545902a6c2f4ea11 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 12:17:03 +0200 Subject: [PATCH 04/21] scenario description --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index f7b62d49c0..25570dc8a4 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -2,7 +2,7 @@ ## Details -**Description:** +**Description:** This test scenario validates the layout directionality of the TabBar component across iOS and Android. It specifically verifies that the component correctly handles Right-to-Left (RTL) and Left-to-Right (LTR) rendering by testing the precedence between system-level settings, React Native's I18nManager, and the explicit direction prop from react-native-screens. **OS test creation version:** iOS: 18.6 and 26.2, Android: 16.0 (Baklava) From b6e0eb33cb97983841a91063e8278dfcb7c955e2 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 14:22:19 +0200 Subject: [PATCH 05/21] note section added to sceanrio --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 25570dc8a4..5a9d4643e4 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -22,7 +22,7 @@ Implementation Details: ## Note -- Assumption: system and RN settings are working correctly. Here only react-native-screens prop is tested. +Assumption: System and RN settings are working correctly. Here only react-native-screens prop is tested. ## Steps From 9efb89ac94a65ed5c4f6d0ffba4fee75e512c287 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 15:20:42 +0200 Subject: [PATCH 06/21] small change in scenario for consistency --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 5a9d4643e4..279398e261 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -8,7 +8,7 @@ ## E2E test -Yes: covers all manual scenario steps. +Yes: Covers all manual scenario steps. Implementation Details: From f8a844325ae48d9cf76c8ae4258f7b60d2beb810 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Fri, 17 Apr 2026 16:03:39 +0200 Subject: [PATCH 07/21] adding info about rtl language coverage - manual only- priority --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 279398e261..6d3bf51b1b 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -8,13 +8,15 @@ ## E2E test -Yes: Covers all manual scenario steps. +Yes: Covers all manual scenario steps for LTR/RTL configured via React Native. Implementation Details: - iOS: The system RTL direction is set by configuring I18NIsRTL to YES during the app launch sequence. - Android: RTL direction must be triggered using the forceRTL toggle located within the Layout Direction screen. +Scenarios where RTL is enabled at the device level by setting a system-wide RTL language are NOT covered by e2e tests. + ## Prerequisites - iOS device or simulato with at least one RTL language localization configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system language set to Arabic/Hebrew, @@ -22,7 +24,8 @@ Implementation Details: ## Note -Assumption: System and RN settings are working correctly. Here only react-native-screens prop is tested. +- Assumption: System and RN settings are working correctly. Here only react-native-screens prop is tested. +- Each of the below steps must be executed twice:once with a system-wide RTL language enabled at the device level and once with the RTL direction set via React Native. The device-level test is particularly critical, as the React Native configuration is already covered by E2E tests. ## Steps From d5c3c1d21e7abed25ee45821e75f4fcc443876fa Mon Sep 17 00:00:00 2001 From: lkuchno Date: Wed, 22 Apr 2026 11:27:54 +0200 Subject: [PATCH 08/21] adding scroll to direction picker to fix problem in android test --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 946e38ae0a..aa040331b7 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -22,9 +22,6 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { }); it('displays default options and renders Tab1 at the visually leftmost position (LTR)', async () => { - await expect( - element(by.id('tab-bar-layout-direction-picker')), - ).toBeVisible(); await expect( element(by.id('tab-bar-layout-direction-scrollview')), ).toBeVisible(); @@ -34,6 +31,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -55,6 +56,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //rtl it('overrides system LTR settings and renders the tab bar in RTL order', async () => { + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -69,6 +74,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //ltr it('remains in LTR order when direction is explicitly set to ltr', async () => { + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -130,9 +139,6 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); it('displays default options and renders Tab2 at the visually leftmost position (RTL)', async () => { - await expect( - element(by.id('tab-bar-layout-direction-picker')), - ).toBeVisible(); await expect( element(by.id('tab-bar-layout-direction-scrollview')), ).toBeVisible(); @@ -142,6 +148,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -163,6 +173,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //rtl it('remains in RTL order when direction is explicitly set to rtl', async () => { + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); @@ -177,6 +191,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //ltr it('overrides system RTL settings and renders the tab bar in LTR order', async () => { + await waitFor(element(by.id('tab-bar-layout-direction-picker'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); From 42b7c6bdbf2aff884df06f38e1c51003c1e514ef Mon Sep 17 00:00:00 2001 From: lkuchno Date: Wed, 22 Apr 2026 12:13:18 +0200 Subject: [PATCH 09/21] four more scrools added to make sure that element is visible and fix problem on android --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index aa040331b7..129e6631c7 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -61,6 +61,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { .whileElement(by.id('tab-bar-layout-direction-scrollview')) .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); + await waitFor(element(by.text('rtl'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -79,6 +83,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { .whileElement(by.id('tab-bar-layout-direction-scrollview')) .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); + await waitFor(element(by.text('ltr'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -178,6 +186,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { .whileElement(by.id('tab-bar-layout-direction-scrollview')) .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); + await waitFor(element(by.text('rtl'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -196,6 +208,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { .whileElement(by.id('tab-bar-layout-direction-scrollview')) .scroll(100, 'down'); await element(by.id('tab-bar-layout-direction-picker')).tap(); + await waitFor(element(by.text('ltr'))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( From f539f504ce69202004b262ae1f06270ff70ca667 Mon Sep 17 00:00:00 2001 From: lkuchno Date: Wed, 22 Apr 2026 13:43:59 +0200 Subject: [PATCH 10/21] adding scrollTo function to e2e test --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 129e6631c7..c8d3f19305 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -1,6 +1,6 @@ import { expect as jestExpect } from '@jest/globals'; import { device, expect, element, by } from 'detox'; -import { describeIfiOS, selectSingleFeatureTestsScreen } from '../../e2e-utils'; +import { selectSingleFeatureTestsScreen } from '../../e2e-utils'; import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox'; type ElementAttributes = IosElementAttributes | AndroidElementAttributes; @@ -12,6 +12,13 @@ async function getElementAttributes( return attrs as ElementAttributes; } +async function scrollTo(id: string) { + await waitFor(element(by.id(id))) + .toBeVisible() + .whileElement(by.id('tab-bar-layout-direction-scrollview')) + .scroll(100, 'down'); +} + describe('Tab Bar Layout Direction - system settings: LTR', () => { beforeAll(async () => { await device.reloadReactNative(); @@ -31,10 +38,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -56,10 +60,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //rtl it('overrides system LTR settings and renders the tab bar in RTL order', async () => { - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await waitFor(element(by.text('rtl'))) .toBeVisible() @@ -78,15 +79,9 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //ltr it('remains in LTR order when direction is explicitly set to ltr', async () => { - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await waitFor(element(by.text('ltr'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('ltr'); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -156,10 +151,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -181,15 +173,9 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //rtl it('remains in RTL order when direction is explicitly set to rtl', async () => { - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await waitFor(element(by.text('rtl'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('rtl'); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -203,10 +189,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //ltr it('overrides system RTL settings and renders the tab bar in LTR order', async () => { - await waitFor(element(by.id('tab-bar-layout-direction-picker'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo('tab-bar-layout-direction-picker'); await element(by.id('tab-bar-layout-direction-picker')).tap(); await waitFor(element(by.text('ltr'))) .toBeVisible() From 72b322e1ceac3bd9575f822753a8e23d656061db Mon Sep 17 00:00:00 2001 From: lkuchno Date: Wed, 22 Apr 2026 13:45:31 +0200 Subject: [PATCH 11/21] adding scrollTo function to e2e test --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index c8d3f19305..4be2392907 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -12,8 +12,13 @@ async function getElementAttributes( return attrs as ElementAttributes; } -async function scrollTo(id: string) { - await waitFor(element(by.id(id))) +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'); @@ -38,7 +43,7 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -60,12 +65,10 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //rtl it('overrides system LTR settings and renders the tab bar in RTL order', async () => { - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await waitFor(element(by.text('rtl'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo({ text: 'rtl' }); + await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -79,9 +82,9 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { //ltr it('remains in LTR order when direction is explicitly set to ltr', async () => { - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo('ltr'); + await scrollTo({ text: 'ltr' }); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -151,7 +154,7 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { await expect(element(by.id('react-allow-rtl-picker'))).toHaveLabel( 'allowRTL: true', ); - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( 'direction: inherit', ); @@ -173,9 +176,9 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //rtl it('remains in RTL order when direction is explicitly set to rtl', async () => { - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo('rtl'); + await scrollTo({ text: 'rtl' }); await element(by.text('rtl')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( @@ -189,12 +192,9 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { //ltr it('overrides system RTL settings and renders the tab bar in LTR order', async () => { - await scrollTo('tab-bar-layout-direction-picker'); + await scrollTo({ id: 'tab-bar-layout-direction-picker' }); await element(by.id('tab-bar-layout-direction-picker')).tap(); - await waitFor(element(by.text('ltr'))) - .toBeVisible() - .whileElement(by.id('tab-bar-layout-direction-scrollview')) - .scroll(100, 'down'); + await scrollTo({ text: 'ltr' }); await element(by.text('ltr')).tap(); await element(by.id('tab-bar-layout-direction-picker')).tap(); await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( From 59cded8b2e724b3fa942926e6dcc405053cebfda Mon Sep 17 00:00:00 2001 From: lkuchno Date: Mon, 27 Apr 2026 08:48:28 +0200 Subject: [PATCH 12/21] formatting scenarios --- .../scenario.md | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 6d3bf51b1b..cbc8ab9636 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -2,7 +2,12 @@ ## Details -**Description:** This test scenario validates the layout directionality of the TabBar component across iOS and Android. It specifically verifies that the component correctly handles Right-to-Left (RTL) and Left-to-Right (LTR) rendering by testing the precedence between system-level settings, React Native's I18nManager, and the explicit direction prop from react-native-screens. +**Description:** This test scenario validates the layout directionality of +the TabBar component across iOS and Android. It specifically verifies that +the component correctly handles Right-to-Left (RTL) and Left-to-Right (LTR) +rendering by testing the precedence between system-level settings, React +Native's I18nManager, and the explicit direction prop from +react-native-screens. **OS test creation version:** iOS: 18.6 and 26.2, Android: 16.0 (Baklava) @@ -12,20 +17,29 @@ Yes: Covers all manual scenario steps for LTR/RTL configured via React Native. Implementation Details: -- iOS: The system RTL direction is set by configuring I18NIsRTL to YES during the app launch sequence. -- Android: RTL direction must be triggered using the forceRTL toggle located within the Layout Direction screen. +- iOS: The system RTL direction is set by configuring I18NIsRTL to YES + during the app launch sequence. +- Android: RTL direction must be triggered using the forceRTL toggle located + within the Layout Direction screen. -Scenarios where RTL is enabled at the device level by setting a system-wide RTL language are NOT covered by e2e tests. +Scenarios where RTL is enabled at the device level by setting a system-wide +RTL language are NOT covered by e2e tests. ## Prerequisites -- iOS device or simulato with at least one RTL language localization configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system language set to Arabic/Hebrew, +- iOS device or simulato with at least one RTL language localization + configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system + language set to Arabic/Hebrew, - Android emulator with supportRtl enabled in app manifest. ## Note -- Assumption: System and RN settings are working correctly. Here only react-native-screens prop is tested. -- Each of the below steps must be executed twice:once with a system-wide RTL language enabled at the device level and once with the RTL direction set via React Native. The device-level test is particularly critical, as the React Native configuration is already covered by E2E tests. +- Assumption: System and RN settings are working correctly. Here only + react-native-screens prop is tested. +- Each of the below steps must be executed twice:once with a system-wide RTL + language enabled at the device level and once with the RTL direction set + via React Native. The device-level test is particularly critical, as the + React Native configuration is already covered by E2E tests. ## Steps @@ -33,19 +47,25 @@ Scenarios where RTL is enabled at the device level by setting a system-wide RTL 1. Launch the app and navigate to the scenario. -- [ ] Expected: Tab1 and Tab2 are shown in LTR order. Tab1 displayed as the leftmost item and Tab2 as second. All controls default to forceRTL=false, allowRTL=true, TabsHost direction = inherit. +- [ ] Expected: Tab1 and Tab2 are shown in LTR order. Tab1 displayed as the + leftmost item and Tab2 as second. All controls default to + forceRTL=false, allowRTL=true, TabsHost direction = inherit. --- ### TabsHost inherit — follows RN/system -2. Ensure system/RN is LTR (I18nManager.isRTL == false), set TabsHost direction = inherit. +2. Ensure system/RN is LTR (I18nManager.isRTL == false), set TabsHost + direction = inherit. -- [ ] Expected: Tab bar displays in LTR order. Tab1 is displayed as the the leftmost item and Tab2 as second. +- [ ] Expected: Tab bar displays in LTR order. Tab1 is displayed as the the + leftmost item and Tab2 as second. -3. Set system/RN to RTL (I18nManager.isRTL == true), keep TabsHost direction = inherit. +3. Set system/RN to RTL (I18nManager.isRTL == true), keep TabsHost + direction = inherit. -- [ ] Expected: Tab bar displays in RTL order. Tab2 displayed as the leftmost item and Tab1 as second. +- [ ] Expected: Tab bar displays in RTL order. Tab2 displayed as the + leftmost item and Tab1 as second. --- @@ -53,15 +73,18 @@ Scenarios where RTL is enabled at the device level by setting a system-wide RTL 4. Set system/RN to RTL, set TabsHost direction = ltr. -- [ ] Expected: Tab bar displays in LTR order — TabsHost overrides RTL from RN/system. Tab1 is displayed as the the leftmost item. +- [ ] Expected: Tab bar displays in LTR order — TabsHost overrides RTL from + RN/system. Tab1 is displayed as the the leftmost item. 5. Set system/RN to LTR, keep TabsHost direction = ltr. -- [ ] Expected: Tab bar remains in LTR order. Tab1 is displayed as the the leftmost item. +- [ ] Expected: Tab bar remains in LTR order. Tab1 is displayed as the the + leftmost item. 6. Cycle through inherit → rtl → ltr → rtl → inherit. -- [ ] Expected: Tab bar direction updates immediately with each change; no crashes or layout freezes occur. +- [ ] Expected: Tab bar direction updates immediately with each change; no + crashes or layout freezes occur. --- @@ -69,7 +92,8 @@ Scenarios where RTL is enabled at the device level by setting a system-wide RTL 7. Set system/RN to LTR, set TabsHost direction = rtl. -- [ ] Expected: Tab bar displays in RTL order — TabsHost overrides LTR from RN/system. Tab2 displayed as the leftmost item. +- [ ] Expected: Tab bar displays in RTL order — TabsHost overrides LTR from + RN/system. Tab2 displayed as the leftmost item. 8. Set system/RN to RTL, keep TabsHost direction = rtl. @@ -77,4 +101,5 @@ Scenarios where RTL is enabled at the device level by setting a system-wide RTL 9. Cycle through inherit → ltr → rtl → ltr → inherit. -- [ ] Expected: Tab bar direction updates immediately with each change, no crash or layout freeze occur. +- [ ] Expected: Tab bar direction updates immediately with each change, no + crash or layout freeze occur. From 784141f1f707ddae5bf64c558ae8259100b01b4a Mon Sep 17 00:00:00 2001 From: lkuchno Date: Mon, 27 Apr 2026 09:38:15 +0200 Subject: [PATCH 13/21] refactor e2e tests to be independent --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 68 ++++++------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 4be2392907..31c88a0a49 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -24,8 +24,19 @@ async function scrollTo(selector: { id: string } | { text: string }) { .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}`, + ); +} + describe('Tab Bar Layout Direction - system settings: LTR', () => { - beforeAll(async () => { + beforeEach(async () => { await device.reloadReactNative(); await selectSingleFeatureTestsScreen( 'Tabs', @@ -52,44 +63,24 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { ); }); - //inherit it('follows system LTR settings when direction is set to inherit', async () => { - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: inherit', - ); + await selectDirection('inherit'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); }); - //rtl it('overrides system LTR settings and renders the tab bar in RTL order', async () => { - await scrollTo({ id: 'tab-bar-layout-direction-picker' }); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo({ text: 'rtl' }); - - await element(by.text('rtl')).tap(); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: rtl', - ); + await selectDirection('rtl'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); }); - //ltr it('remains in LTR order when direction is explicitly set to ltr', async () => { - await scrollTo({ id: 'tab-bar-layout-direction-picker' }); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo({ text: 'ltr' }); - await element(by.text('ltr')).tap(); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: ltr', - ); + await selectDirection('ltr'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); @@ -145,6 +136,8 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); it('displays default options and renders Tab2 at the visually leftmost position (RTL)', async () => { + await selectDirection('inherit'); + await expect( element(by.id('tab-bar-layout-direction-scrollview')), ).toBeVisible(); @@ -163,43 +156,26 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { ); }); - //inherit it('follows system RTL settings when direction is set to inherit', async () => { - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: inherit', - ); + await selectDirection('inherit'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); }); - //rtl it('remains in RTL order when direction is explicitly set to rtl', async () => { - await scrollTo({ id: 'tab-bar-layout-direction-picker' }); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo({ text: 'rtl' }); - await element(by.text('rtl')).tap(); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: rtl', - ); + await selectDirection('inherit'); + await selectDirection('rtl'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); }); - //ltr it('overrides system RTL settings and renders the tab bar in LTR order', async () => { - await scrollTo({ id: 'tab-bar-layout-direction-picker' }); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await scrollTo({ text: 'ltr' }); - await element(by.text('ltr')).tap(); - await element(by.id('tab-bar-layout-direction-picker')).tap(); - await expect(element(by.id('tab-bar-layout-direction-picker'))).toHaveLabel( - 'direction: ltr', - ); + await selectDirection('inherit'); + await selectDirection('ltr'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); From fedc6b3128c1b25296dc9e489a088fe74ba058ad Mon Sep 17 00:00:00 2001 From: lkuchno <45803783+LKuchno@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:23:34 +0200 Subject: [PATCH 14/21] Grammar changes Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index cbc8ab9636..8d1508e4b2 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -102,4 +102,4 @@ RTL language are NOT covered by e2e tests. 9. Cycle through inherit → ltr → rtl → ltr → inherit. - [ ] Expected: Tab bar direction updates immediately with each change, no - crash or layout freeze occur. + crashes or layout freezes occur. From 3f9e7a5285d2ff5b9a0dad3119de7fac5cf650f9 Mon Sep 17 00:00:00 2001 From: lkuchno <45803783+LKuchno@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:24:20 +0200 Subject: [PATCH 15/21] Update FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tabs/test-tabs-tab-bar-layout-direction.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 31c88a0a49..9feb8af036 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -1,7 +1,7 @@ import { expect as jestExpect } from '@jest/globals'; import { device, expect, element, by } from 'detox'; +import type { AndroidElementAttributes, IosElementAttributes } from 'detox'; import { selectSingleFeatureTestsScreen } from '../../e2e-utils'; -import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox'; type ElementAttributes = IosElementAttributes | AndroidElementAttributes; From 6882b34b15a9491fe577f51fa686fe2097ccae7d Mon Sep 17 00:00:00 2001 From: lkuchno <45803783+LKuchno@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:24:33 +0200 Subject: [PATCH 16/21] Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 8d1508e4b2..c9ab150be0 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -27,7 +27,7 @@ RTL language are NOT covered by e2e tests. ## Prerequisites -- iOS device or simulato with at least one RTL language localization +- iOS device or simulator with at least one RTL language localization configured in Xcode (e.g. empty ar.lproj/InfoPlist.strings), or system language set to Arabic/Hebrew, - Android emulator with supportRtl enabled in app manifest. From 69ec8bfba2223e43979004fe1046ee3d72f27006 Mon Sep 17 00:00:00 2001 From: lkuchno <45803783+LKuchno@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:24:53 +0200 Subject: [PATCH 17/21] Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index c9ab150be0..0487cce3a6 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -36,7 +36,7 @@ RTL language are NOT covered by e2e tests. - Assumption: System and RN settings are working correctly. Here only react-native-screens prop is tested. -- Each of the below steps must be executed twice:once with a system-wide RTL +- Each of the below steps must be executed twice: once with a system-wide RTL language enabled at the device level and once with the RTL direction set via React Native. The device-level test is particularly critical, as the React Native configuration is already covered by E2E tests. From 3d1990843dd76fd09d32f6b380edb5070c4d33d0 Mon Sep 17 00:00:00 2001 From: lkuchno <45803783+LKuchno@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:25:09 +0200 Subject: [PATCH 18/21] Update apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index 0487cce3a6..f6490cde43 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -58,7 +58,7 @@ RTL language are NOT covered by e2e tests. 2. Ensure system/RN is LTR (I18nManager.isRTL == false), set TabsHost direction = inherit. -- [ ] Expected: Tab bar displays in LTR order. Tab1 is displayed as the the +- [ ] Expected: Tab bar displays in LTR order. Tab1 is displayed as the leftmost item and Tab2 as second. 3. Set system/RN to RTL (I18nManager.isRTL == true), keep TabsHost From 6e6f2cf63a9ece541814214d764d1eb0ab4a69cd Mon Sep 17 00:00:00 2001 From: lkuchno Date: Mon, 27 Apr 2026 13:11:40 +0200 Subject: [PATCH 19/21] separate test to make it independent, adding cycle changes check test --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 51 +++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 9feb8af036..5c040c139c 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -1,6 +1,6 @@ import { expect as jestExpect } from '@jest/globals'; import { device, expect, element, by } from 'detox'; -import type { AndroidElementAttributes, IosElementAttributes } from 'detox'; +import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox'; import { selectSingleFeatureTestsScreen } from '../../e2e-utils'; type ElementAttributes = IosElementAttributes | AndroidElementAttributes; @@ -34,6 +34,15 @@ async function selectDirection(direction: 'inherit' | 'rtl' | 'ltr') { `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 () => { @@ -86,6 +95,22 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); }); + + 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', () => { @@ -130,7 +155,10 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { 'Tabs', 'test-tabs-tab-bar-layout-direction', ); - await element(by.id('react-allow-rtl-picker')).tap(); + 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(); } }); @@ -165,7 +193,6 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); it('remains in RTL order when direction is explicitly set to rtl', async () => { - await selectDirection('inherit'); await selectDirection('rtl'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); @@ -174,11 +201,27 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); it('overrides system RTL settings and renders the tab bar in LTR order', async () => { - await selectDirection('inherit'); await selectDirection('ltr'); const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); }); + + 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); + }); }); From edfa1d690900cf191ba888563f3ae39c56a75a4b Mon Sep 17 00:00:00 2001 From: lkuchno Date: Mon, 27 Apr 2026 13:13:22 +0200 Subject: [PATCH 20/21] removing duplicated the --- .../tabs/test-tabs-tab-bar-layout-direction/scenario.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md index f6490cde43..ea3ed76746 100644 --- a/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md +++ b/apps/src/tests/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction/scenario.md @@ -74,9 +74,9 @@ RTL language are NOT covered by e2e tests. 4. Set system/RN to RTL, set TabsHost direction = ltr. - [ ] Expected: Tab bar displays in LTR order — TabsHost overrides RTL from - RN/system. Tab1 is displayed as the the leftmost item. + RN/system. Tab1 is displayed as the leftmost item. -5. Set system/RN to LTR, keep TabsHost direction = ltr. +1. Set system/RN to LTR, keep TabsHost direction = ltr. - [ ] Expected: Tab bar remains in LTR order. Tab1 is displayed as the the leftmost item. From 4c8a6706ab198edb7c0190d11092576fdd30164c Mon Sep 17 00:00:00 2001 From: lkuchno Date: Mon, 27 Apr 2026 13:55:19 +0200 Subject: [PATCH 21/21] applying new function to all tests --- .../test-tabs-tab-bar-layout-direction.e2e.ts | 35 +++++-------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts index 5c040c139c..7c6fde9e5f 100644 --- a/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts +++ b/FabricExample/e2e/single-feature-tests/tabs/test-tabs-tab-bar-layout-direction.e2e.ts @@ -70,35 +70,28 @@ describe('Tab Bar Layout Direction - system settings: LTR', () => { 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'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + await expectTab1ToBeLeftOfTab2(true); }); it('overrides system LTR settings and renders the tab bar in RTL order', async () => { await selectDirection('rtl'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + await expectTab1ToBeLeftOfTab2(false); }); it('remains in LTR order when direction is explicitly set to ltr', async () => { await selectDirection('ltr'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + 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); @@ -164,8 +157,6 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { }); it('displays default options and renders Tab2 at the visually leftmost position (RTL)', async () => { - await selectDirection('inherit'); - await expect( element(by.id('tab-bar-layout-direction-scrollview')), ).toBeVisible(); @@ -182,30 +173,22 @@ describe('Tab Bar Layout Direction - system settings: RTL', () => { 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'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + await expectTab1ToBeLeftOfTab2(false); }); it('remains in RTL order when direction is explicitly set to rtl', async () => { await selectDirection('rtl'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab1attrs.frame.x).toBeGreaterThan(tab2attrs.frame.x); + await expectTab1ToBeLeftOfTab2(false); }); it('overrides system RTL settings and renders the tab bar in LTR order', async () => { await selectDirection('ltr'); - - const tab1attrs = await getElementAttributes('tab-bar-item-1-label'); - const tab2attrs = await getElementAttributes('tab-bar-item-2-label'); - jestExpect(tab2attrs.frame.x).toBeGreaterThan(tab1attrs.frame.x); + await expectTab1ToBeLeftOfTab2(true); }); it('cycle through inherit → ltr → rtl → ltr → inherit renders the tab bar in correct order', async () => {