Skip to content

Commit

Permalink
test(scrollview): add test for custom scroll view
Browse files Browse the repository at this point in the history
  • Loading branch information
pierpo committed Aug 1, 2024
1 parent 0b904fc commit 078ec59
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Props = {
contentContainerStyle?: ViewStyle;
scrollDuration?: number;
onScroll?: (event: { nativeEvent: { contentOffset: { y: number; x: number } } }) => void;
testID?: string;
};

export const AnyScrollView = React.forwardRef<CustomScrollViewRef, Props>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { View } from 'react-native';
import { RenderResult, act, fireEvent, render, screen } from '@testing-library/react-native';
import { ReactTestInstance } from 'react-test-renderer';
import '../../tests/helpers/configureTestRemoteControl';
import { SpatialNavigationScrollView } from '../ScrollView';
import { SpatialNavigationView } from '../../View';
import { TestButton } from '../../tests/TestButton';
import { SpatialNavigationRoot } from '../../Root';
import testRemoteControlManager from '../../tests/helpers/testRemoteControlManager';
import { DefaultFocus } from '../../../context/DefaultFocusContext';

const MOCKED_BUTTON_HEIGHT = 100;

export const setComponentLayoutSize = (
component: ReactTestInstance,
size: { width: number; height: number; x: number; y: number },
) => {
fireEvent(component, 'layout', {
nativeEvent: { layout: { width: size.width, height: size.height, x: size.x, y: size.y } },
});
};

export const expectButtonToHaveFocus = (component: RenderResult, text: string) => {
const element = component.getByRole('button', { name: text });
expect(element).toBeSelected();
};

const TestPage = () => {
return (
<SpatialNavigationRoot>
<DefaultFocus>
<SpatialNavigationScrollView testID="scrollview" useCssScroll>
<SpatialNavigationView direction="vertical">
<TestButton title="1" />
<TestButton title="2" />
<TestButton title="3" />
<TestButton title="4" />
<TestButton title="5" />
<TestButton title="6" />
<TestButton title="7" />
<TestButton title="8" />
</SpatialNavigationView>
</SpatialNavigationScrollView>
</DefaultFocus>
</SpatialNavigationRoot>
);
};

jest.spyOn(View.prototype, 'measureLayout').mockImplementation(function (node, callback) {
// @ts-expect-error it's weird but that's fine, it's our only way to get the button's context
const buttonLabel = this?.props?.accessibilityLabel;
const buttonNumber = parseInt(buttonLabel, 10) - 1;

callback(0, buttonNumber * MOCKED_BUTTON_HEIGHT, 0, 0);
});

const expectViewToHaveScroll = (element: ReactTestInstance, scrollValue: number) =>
expect(element).toHaveStyle({ transform: [{ translateY: scrollValue }] });

describe('CustomScrollView', () => {
const scrollViewTestId = 'scrollview';
const innerScrollViewTestId = scrollViewTestId + '-content';

it('scrolls properly upon focus and stops when overflowing', async () => {
const MOCK_SCREEN_SIZE = 300;
const MOCK_TOTAL_CONTENT_SIZE = 800;

const component = render(<TestPage />);
act(() => jest.runAllTimers());

const scrollViewRoot = component.getByTestId(scrollViewTestId);
setComponentLayoutSize(scrollViewRoot, { width: 0, height: MOCK_SCREEN_SIZE, x: 0, y: 0 });
const scrollViewInner = component.getByTestId(innerScrollViewTestId);
setComponentLayoutSize(scrollViewInner, {
width: 0,
height: MOCK_TOTAL_CONTENT_SIZE,
x: 0,
y: 0,
});

testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -100);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -200);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -300);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -400);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -500);
testRemoteControlManager.handleDown();

// Once the view is going to over-scroll, it should stop scrolling
expectViewToHaveScroll(scrollViewInner, -500);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -500);
testRemoteControlManager.handleDown();
expectViewToHaveScroll(scrollViewInner, -500);
testRemoteControlManager.handleDown();

expect(screen).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CustomScrollView scrolls properly upon focus and stops when overflowing 1`] = `
<View
onLayout={[Function]}
style={
[
{
"flex": 1,
"flexDirection": "column",
"overflow": "hidden",
},
undefined,
]
}
testID="scrollview"
>
<View
collapsable={false}
onLayout={[Function]}
style={
{
"transform": [
{
"translateY": -500,
},
],
}
}
testID="scrollview-content"
>
<View
style={
[
undefined,
{
"display": "flex",
"flexDirection": "column",
},
]
}
>
<View
accessibilityHint="1"
accessibilityLabel="1"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
1
</Text>
</View>
<View
accessibilityHint="2"
accessibilityLabel="2"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
2
</Text>
</View>
<View
accessibilityHint="3"
accessibilityLabel="3"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
3
</Text>
</View>
<View
accessibilityHint="4"
accessibilityLabel="4"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
4
</Text>
</View>
<View
accessibilityHint="5"
accessibilityLabel="5"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
5
</Text>
</View>
<View
accessibilityHint="6"
accessibilityLabel="6"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
6
</Text>
</View>
<View
accessibilityHint="7"
accessibilityLabel="7"
accessibilityRole="button"
accessibilityState={
{
"selected": false,
}
}
accessible={true}
isFocused={false}
style={
[
{
"backgroundColor": "transparent",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
7
</Text>
</View>
<View
accessibilityHint="8"
accessibilityLabel="8"
accessibilityRole="button"
accessibilityState={
{
"selected": true,
}
}
accessible={true}
isFocused={true}
style={
[
{
"backgroundColor": "red",
"borderRadius": 100,
"padding": 6,
},
undefined,
]
}
>
<Text>
8
</Text>
</View>
</View>
</View>
</View>
`;
Loading

0 comments on commit 078ec59

Please sign in to comment.