Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions FabricExample/e2e/e2e-utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { device, expect, element, by } from 'detox';
import { AndroidElementAttributes, IosElementAttributes } from 'detox/detox';
Comment on lines 1 to +2
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think that we can really do anything about it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I was already trying to get rid of it and it didn't work so I kept it in this form.


export const describeIfiOS =
device.getPlatform() === 'ios' ? describe : describe.skip;

export const describeIfAndroid =
device.getPlatform() === 'android' ? describe : describe.skip;
Comment thread
kligarski marked this conversation as resolved.

async function scrollUntilVisible(id: string, scrollViewId: string) {
await waitFor(element(by.id(id)))
.toBeVisible()
Expand Down Expand Up @@ -62,3 +66,27 @@ export async function selectSingleFeatureTestsScreen(
);
await element(by.id(`${screenKey}`)).tap();
}
type ElementAttributes = IosElementAttributes | AndroidElementAttributes;

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

if ('elements' in attrs) {
throw new Error(
`Multiple elements (${attrs.elements.length}) found for label: "${testLabel}". `
);
}

return attrs as ElementAttributes;
}
Comment thread
LKuchno marked this conversation as resolved.

export async function forceTapByLabeliOS(testLabel: string) {
Comment thread
LKuchno marked this conversation as resolved.
const elementAttributes = await getElementAttributes(testLabel);
const { x, y, width, height } = elementAttributes.frame;
await device.tap({
x: x + width / 2,
y: y + height / 2,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { device, expect, element, by } from 'detox';
import {
selectSingleFeatureTestsScreen,
forceTapByLabeliOS,
} from '../../e2e-utils';

async function forceSelectTabByLabel(label: string) {
Comment thread
LKuchno marked this conversation as resolved.
if (device.getPlatform() === 'ios') {
await forceTapByLabeliOS(label);
} else {
await element(by.label(label)).tap();
}
}

describe('Tabs specialEffects — scrollToTop', () => {
beforeAll(async () => {
await device.reloadReactNative();
await selectSingleFeatureTestsScreen(
'Tabs',
'test-tabs-special-effects-scroll-to-top',
);
Comment on lines +19 to +25
});

it('should display tab bar and Tab1 scrollable list on load', async () => {
await expect(element(by.id('tab1-scrollview'))).toBeVisible();
await expect(element(by.id('tab1-item-1'))).toBeVisible();
if (device.getPlatform() === 'ios') {
await expect(element(by.type('UITabBar'))).toBeVisible();
} else {
await expect(element(by.id('tab1-tab-item'))).toBeVisible();
await expect(element(by.id('tab2-tab-item'))).toBeVisible();
await expect(element(by.id('tab3-tab-item'))).toBeVisible();
}
});

it('Tab1 (scrollToTop: true) — re-tapping active tab scrolls list back to top', async () => {
await element(by.id('tab1-scrollview')).scroll(300, 'down', NaN, 0.85);
await expect(element(by.id('tab1-item-1'))).not.toBeVisible();

await forceSelectTabByLabel('tab1-tab-item-label');

await waitFor(element(by.id('tab1-item-1')))
.toBeVisible()
.withTimeout(3000);
});

it('Tab2 (scrollToTop: false) — re-tapping active tab preserves scroll position', async () => {
await element(by.id('tab2-tab-item')).tap();
await expect(element(by.id('tab2-item-1'))).toBeVisible();

await element(by.id('tab2-scrollview')).scroll(300, 'down', NaN, 0.85);
await expect(element(by.id('tab2-item-1'))).not.toBeVisible();

await forceSelectTabByLabel('tab2-tab-item-label');

await expect(element(by.id('tab2-item-1'))).not.toBeVisible();
});

it('Tab3 (no specialEffects) — re-tapping active tab scrolls list back to top', async () => {
await element(by.id('tab3-tab-item')).tap();
await expect(element(by.id('tab3-item-1'))).toBeVisible();

await element(by.id('tab3-scrollview')).scroll(300, 'down', NaN, 0.85);
await expect(element(by.id('tab3-item-1'))).not.toBeVisible();

await forceSelectTabByLabel('tab3-tab-item-label');

await waitFor(element(by.id('tab3-item-1')))
.toBeVisible()
.withTimeout(3000);
});

it('Tab1 (scrollToTop: true) — switching away and back preserves scroll position', async () => {
await forceSelectTabByLabel('tab1-tab-item-label');
await expect(element(by.id('tab1-item-1'))).toBeVisible();

await element(by.id('tab1-scrollview')).scroll(300, 'down', NaN, 0.85);
await expect(element(by.id('tab1-item-1'))).not.toBeVisible();

await forceSelectTabByLabel('tab3-tab-item-label');
await expect(element(by.id('tab3-item-1'))).toBeVisible();

await forceSelectTabByLabel('tab1-tab-item-label');

await expect(element(by.id('tab1-item-1'))).not.toBeVisible();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ import {
} from '@apps/shared/gamma/containers/tabs';

const scenarioDescription: ScenarioDescription = {
name: 'Tabs scrollToTop special effect',
name: 'Tabs special effect scroll to top',
key: 'test-tabs-special-effects-scroll-to-top',
details:
'Test settings of scrollToTop specialEffect.',
'Test settings of specialEffect scrollToTop.',
platforms: ['ios', 'android'],
};

export function ScrollScreen() {
interface ScrollScreenProps {
tabName: string;
}

export function ScrollScreen({ tabName }: ScrollScreenProps) {
return (
<ScrollView>
<ScrollView testID={`${tabName}-scrollview`}>
<Text style={styles.hint}>Scroll Screen — scroll down or re-tap the tab.</Text>
{Array.from({ length: 50 }, (_, i) => (
<Text key={i} style={styles.item}>
<Text key={i} testID={`${tabName}-item-${i + 1}`} style={styles.item}>
Item {i + 1}
</Text>
))}
Expand All @@ -32,10 +36,12 @@ export function ScrollScreen() {
const TAB_CONFIGS: TabRouteConfig[] = [
{
name: 'Tab1',
Component: ScrollScreen,
Component: () => <ScrollScreen tabName="tab1" />,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Tab1',
tabBarItemTestID: 'tab1-tab-item',
tabBarItemAccessibilityLabel: 'tab1-tab-item-label',
specialEffects: {
repeatedTabSelection: {
scrollToTop: true,
Expand All @@ -45,10 +51,12 @@ const TAB_CONFIGS: TabRouteConfig[] = [
},
{
name: 'Tab2',
Component: ScrollScreen,
Component: () => <ScrollScreen tabName="tab2" />,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Tab2',
tabBarItemTestID: 'tab2-tab-item',
tabBarItemAccessibilityLabel: 'tab2-tab-item-label',
specialEffects: {
repeatedTabSelection: {
scrollToTop: false
Expand All @@ -58,10 +66,12 @@ const TAB_CONFIGS: TabRouteConfig[] = [
},
{
name: 'Tab3',
Component: ScrollScreen,
Component: () => <ScrollScreen tabName="tab3" />,
options: {
...DEFAULT_TAB_ROUTE_OPTIONS,
title: 'Tab3',
tabBarItemTestID: 'tab3-tab-item',
tabBarItemAccessibilityLabel: 'tab3-tab-item-label',
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ that there is no scroll-to-top behavior when it is disabled or absent.

## E2E test

Other: ongoing research.
Yes: Covers all manual scenario steps.

## Prerequisites

Expand All @@ -28,7 +28,7 @@ list of 50 items.

### scrollToTop: true

1. Launch the app and navigate to the screen **Tabs specialEffects**.
1. Launch the app and navigate to the screen **Tabs special effect scroll to top**.

- [ ] Expected: Three tabs (Tab1, Tab2, Tab3) are visible in the tab bar.
Tab1 is active and displays a scrollable list of items.
Expand Down
Loading