Skip to content

Commit

Permalink
refactor: add unit test and adjust icon example screen (callstack#4135)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewalczak authored Oct 16, 2023
1 parent 8c933fd commit 41ee87b
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 10 deletions.
23 changes: 16 additions & 7 deletions example/src/Examples/IconExample.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { StyleSheet, View, Image } from 'react-native';

import { Icon, List, MD2Colors } from 'react-native-paper';
import { Icon, List } from 'react-native-paper';

import ScreenWrapper from '../ScreenWrapper';

const AssetIcon = ({ size, testID }: { size: number; testID: string }) => (
<Image
accessibilityIgnoresInvertColors
source={require('../../assets/images/paper-icon.png')}
style={{ width: size, height: size }}
testID={testID}
/>
);

const IconExample = () => {
return (
<ScreenWrapper>
<List.Section title="Default color">
<List.Section title="Default icon (MaterialCommunityIcon)">
<View style={styles.row}>
<Icon source="camera" size={24} />
</View>
</List.Section>
<List.Section title="Custom color">
<List.Section title="Image icon">
<View style={styles.row}>
<Icon source="camera" color={MD2Colors.green500} size={24} />
<Icon source={{ uri: 'https://picsum.photos/700' }} size={48} />
</View>
</List.Section>
<List.Section title="Custom Size">
<List.Section title="Render function icon">
<View style={styles.row}>
<Icon source="heart" color={MD2Colors.pink300} size={50} />
<Icon source={AssetIcon} size={48} />
</View>
</List.Section>
</ScreenWrapper>
Expand Down
10 changes: 8 additions & 2 deletions src/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ export type Props = IconProps & {
*/
source: any;
/**
*
* Color of the icon.
*/
color?: string;
/**
* TestID used for testing purposes
*/
testID?: string;
/**
* @optional
*/
Expand Down Expand Up @@ -102,6 +105,7 @@ const Icon = ({
color,
size,
theme: themeOverrides,
testID,
...rest
}: Props) => {
const theme = useInternalTheme(themeOverrides);
Expand All @@ -125,6 +129,7 @@ const Icon = ({
return (
<Image
{...rest}
testID={testID}
source={s}
style={[
{
Expand All @@ -150,12 +155,13 @@ const Icon = ({
color: iconColor,
size,
direction,
testID,
});
}}
</SettingsConsumer>
);
} else if (typeof s === 'function') {
return s({ color: iconColor, size, direction });
return s({ color: iconColor, size, direction, testID });
}

return null;
Expand Down
3 changes: 3 additions & 0 deletions src/components/MaterialCommunityIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type IconProps = {
size: number;
direction: 'rtl' | 'ltr';
allowFontScaling?: boolean;
testID?: string;
};

type AccessibilityProps =
Expand Down Expand Up @@ -89,6 +90,7 @@ const defaultIcon = ({
size,
direction,
allowFontScaling,
testID,
}: IconProps) => (
<MaterialCommunityIcons
allowFontScaling={allowFontScaling}
Expand All @@ -104,6 +106,7 @@ const defaultIcon = ({
]}
pointerEvents="none"
selectable={false}
testID={testID}
{...accessibilityProps}
/>
);
Expand Down
51 changes: 51 additions & 0 deletions src/components/__tests__/Icon.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { Image } from 'react-native';

import { render } from '@testing-library/react-native';

import Icon from '../Icon';

const ICON_SIZE = 24;

describe('Icon Component', () => {
it('renders correctly with image source', () => {
const source = { uri: 'https://picsum.photos/700' };
const { getByTestId } = render(
<Icon source={source} size={ICON_SIZE} testID="image-icon" />
);
const imageIcon = getByTestId('image-icon');

expect(imageIcon).toBeOnTheScreen();
expect(imageIcon).toHaveStyle({ width: ICON_SIZE, height: ICON_SIZE });
});

it('renders correctly with string source', () => {
const source = 'camera';
const { getByTestId } = render(
<Icon source={source} size={ICON_SIZE} testID="camera-icon" />
);
const icon = getByTestId('camera-icon');

expect(icon).toBeOnTheScreen();
expect(icon).toHaveStyle({ fontSize: ICON_SIZE, lineHeight: ICON_SIZE });
});

it('renders correctly with function source', () => {
const source = ({ size, testID }: { size: number; testID: string }) => (
<Image
accessibilityIgnoresInvertColors
source={{ uri: 'https://picsum.photos/700' }}
style={{ width: size, height: size }}
testID={testID}
/>
);
const { getByTestId } = render(
<Icon source={source} size={ICON_SIZE} testID="function-icon" />
);

const functionIcon = getByTestId('function-icon');

expect(functionIcon).toHaveStyle({ width: ICON_SIZE, height: ICON_SIZE });
expect(functionIcon).toBeOnTheScreen();
});
});
8 changes: 7 additions & 1 deletion src/core/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import MaterialCommunityIcon, {
} from '../components/MaterialCommunityIcon';

export type Settings = {
icon?: ({ name, color, size, direction }: IconProps) => React.ReactNode;
icon?: ({
name,
color,
size,
direction,
testID,
}: IconProps) => React.ReactNode;
rippleEffectEnabled?: boolean;
};

Expand Down

0 comments on commit 41ee87b

Please sign in to comment.