Skip to content

Commit 992dcea

Browse files
authored
Merge pull request #474 from yaob421123/yb
test: perfect component test
2 parents 1df1684 + d2c572f commit 992dcea

File tree

9 files changed

+332
-94
lines changed

9 files changed

+332
-94
lines changed

packages/core/src/Button/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,15 @@ export default class ButtonView<T> extends React.Component<ButtonProps> {
132132
}
133133
return (
134134
<TouchableOpacity
135+
testID="RNE__Button__wrap"
135136
style={[styles.button, styles.content, buttonStyle, boxStyle, style]}
136137
disabled={disabled}
137138
{...restProps}
138139
>
139140
{loading && <ActivityIndicator size={16} color={textColor} style={styles.icon} />}
140141
{React.Children.toArray(children).map((child: any, idx) => {
141142
return (
142-
<Div key={idx} style={[sizeStyle, styles.label, textStyle, childStyle]}>
143+
<Div testID="RNE__Button__div" key={idx} style={[sizeStyle, styles.label, textStyle, childStyle]}>
143144
{child}
144145
</Div>
145146
);

packages/core/src/ButtonGroup/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default class ButtonGroup extends Component<ButtonGroupProps> {
5555
}
5656

5757
return (
58-
<Flex style={styles.default} {...flexProps} {...otherProps}>
58+
<Flex testID="RNE__ButtonGroup__wrap" style={styles.default} {...flexProps} {...otherProps}>
5959
{childs.map((child: React.ReactNode, idx: number) => {
6060
if (!React.isValidElement(child)) {
6161
return null;
@@ -80,7 +80,7 @@ export default class ButtonGroup extends Component<ButtonGroupProps> {
8080
childStyle.borderWidth = 0;
8181
}
8282
if (bordered && !gutter) {
83-
if (((idx > 0 && idx < (children as ButtonProps[]).length - 1)) || idx === 0) {
83+
if ((idx > 0 && idx < (children as ButtonProps[]).length - 1) || idx === 0) {
8484
childStyle.borderRightWidth = StyleSheet.hairlineWidth;
8585
}
8686
if (idx > 0 && idx < (children as ButtonProps[]).length) {

packages/core/src/Icon/index.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,34 @@ export interface IconsProps extends SvgProps {
1919
xml?: string;
2020
}
2121

22-
export default class Icons extends React.Component<IconsProps> {
23-
static displayName = 'uiwm.Icon';
24-
static defaultProps: IconsProps = {
25-
size: 26,
26-
};
27-
render() {
28-
const { name, size, fill = '#000000', stroke, xml, paths, color, ...otherProps } = this.props;
29-
if (xml) {
30-
return <SvgXml xml={xml} height={size} width={size} {...otherProps} />;
31-
}
32-
let pathData = paths;
33-
if (!pathData) {
34-
if (!name || !svgPaths[name]) {
35-
return null;
36-
}
37-
pathData = svgPaths[name] as string[];
22+
export default (props: IconsProps) => {
23+
const { size = 26, name, fill = '#000000', stroke, xml, paths, color, ...otherProps } = props;
24+
25+
if (xml) {
26+
return <SvgXml testID="RNE__Icon__svgXml" xml={xml} height={size} width={size} {...otherProps} />;
27+
}
28+
29+
let pathData = paths;
30+
if (!pathData) {
31+
if (!name || !svgPaths[name]) {
32+
return null;
3833
}
39-
return (
40-
<Svg fill={color || fill} stroke={stroke} height={size} width={size} viewBox="0 0 20 20" {...otherProps}>
41-
{pathData.map((d: string, i: number) => (
42-
<Path key={i} d={d} fillRule="evenodd" />
43-
))}
44-
</Svg>
45-
);
34+
pathData = svgPaths[name] as string[];
4635
}
47-
}
36+
37+
return (
38+
<Svg
39+
testID="RNE__Icon__svg"
40+
fill={color || fill}
41+
stroke={stroke}
42+
height={size}
43+
width={size}
44+
viewBox="0 0 20 20"
45+
{...otherProps}
46+
>
47+
{pathData.map((d: string, i: number) => (
48+
<Path key={i} d={d} fillRule="evenodd" />
49+
))}
50+
</Svg>
51+
);
52+
};

packages/core/src/Input/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,15 @@ const Input = (props: InputProps) => {
138138
},
139139
containerStyle,
140140
]}
141+
testID="RNE__Input__wrap"
141142
>
142-
<View style={[inputStyles.container, { flex: 1, borderColor: borderColor }, border ? inputStyles[border] : {}]}>
143+
<View
144+
style={[inputStyles.container, { flex: 1, borderColor: borderColor }, border ? inputStyles[border] : {}]}
145+
testID="RNE__Input__view"
146+
>
143147
{typeof extraStart === 'string' ? <Text style={{ color: '#888888', fontSize }}>{extraStart}</Text> : extraStart}
144148
<TextInput
149+
testID="RNE__Input__input"
145150
{...others}
146151
ref={inputRef}
147152
editable={!disabled}

test-ci/src/__tests__/button.tsx

Lines changed: 105 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,112 @@
1-
/**
2-
* @format
3-
*/
4-
51
import 'react-native';
62
import React from 'react';
73
import Button from '../lib/Button';
84
import { colors } from '../lib/utils';
9-
// Note: test renderer must be required after react-native.
10-
import TestRenderer from 'react-test-renderer';
11-
import { colorRgb } from '../utils';
12-
import { render, screen, fireEvent } from '@testing-library/react-native';
5+
import { ActivityIndicator } from 'react-native';
6+
import { render, fireEvent } from '@testing-library/react-native';
7+
import { keys, colorRgb, toObject } from '../utils';
8+
9+
const TYPES: keys = {
10+
primary: colors.blue,
11+
success: colors.green,
12+
warning: colors.yellow,
13+
danger: colors.red,
14+
light: colors.white,
15+
dark: colors.black,
16+
};
17+
18+
const SIZES: keys = { small: 3, default: 8, large: 10 };
1319

1420
describe('Button', () => {
15-
test('renders with color', () => {
16-
const testInstance = TestRenderer.create(
17-
<>
18-
<Button type="primary">主要按钮</Button>
19-
<Button type="success">成功按钮</Button>
20-
<Button color="#1EABCD">自定义颜色</Button>
21-
</>,
22-
) as any;
23-
expect(testInstance.toJSON()[0].props.style.backgroundColor).toBe(colorRgb(colors.blue));
24-
expect(testInstance.toJSON()[1].props.style.backgroundColor).toBe(colorRgb(colors.green));
25-
expect(testInstance.toJSON()[2].props.style.backgroundColor).toBe(colorRgb('#1EABCD'));
26-
});
27-
test('loading with ActivityIndicator', () => {
28-
const testInstance = TestRenderer.create(<Button loading>加载中按钮</Button>) as any;
29-
const testRoot = testInstance.root;
30-
31-
expect(testRoot.props.loading).toBeTruthy();
32-
expect(testInstance.toJSON().children[0].type).toBe('ActivityIndicator');
33-
});
34-
35-
// test('renders with onClick', () => {
36-
// const DefaultButton = () => {
37-
// const [loading, setLoading] = React.useState(true)
38-
// return (
39-
// <Button onPress={() => setLoading(false)} loading={loading}>
40-
// click loading
41-
// </Button>
42-
// )
43-
// }
44-
45-
// render(<DefaultButton />);
46-
47-
// const { getByText } = render(<DefaultButton />)
48-
49-
// const btn = getByText('click loading')
50-
51-
// })
21+
it('color', () => {
22+
const { getByTestId } = render(<Button color="#1EABCD">自定义颜色</Button>);
23+
const component = getByTestId('RNE__Button__wrap');
24+
expect(component.props.style.backgroundColor).toBe(colorRgb('#1EABCD'));
25+
});
26+
27+
it('disabled', () => {
28+
const { getByTestId } = render(<Button disabled>disabled</Button>);
29+
const component = getByTestId('RNE__Button__wrap');
30+
expect(component.props.accessibilityState.disabled).toBe(true);
31+
});
32+
33+
it('border', () => {
34+
const { getByTestId } = render(<Button bordered={false}>bordered</Button>);
35+
const component = getByTestId('RNE__Button__wrap');
36+
expect(component.props.style.borderWidth).toBe(0);
37+
});
38+
39+
it('loading', () => {
40+
const { UNSAFE_getByType } = render(<Button loading>loading</Button>);
41+
const icons = UNSAFE_getByType(ActivityIndicator);
42+
expect(icons.props.size).toBe(16);
43+
});
44+
45+
it('rounded', () => {
46+
const { getByTestId } = render(<Button rounded={20}>rounded</Button>);
47+
const component = getByTestId('RNE__Button__wrap');
48+
expect(component.props.style.borderRadius).toBe(20);
49+
});
50+
51+
it('textStyle', () => {
52+
const { getByTestId } = render(<Button textStyle={{ fontSize: 20 }}>textStyle</Button>);
53+
const component = getByTestId('RNE__Button__div');
54+
const styles = toObject(component.props.style);
55+
expect(styles.fontSize).toBe(20);
56+
});
57+
58+
it('type', () => {
59+
const { getByTestId } = render(<Button type="success">success</Button>);
60+
const component = getByTestId('RNE__Button__wrap');
61+
expect(component.props.style.backgroundColor).toBe(colorRgb(colors.green));
62+
});
63+
64+
describe.each`
65+
type
66+
${'primary'}
67+
${'success'}
68+
${'warning'}
69+
${'danger'}
70+
${'light'}
71+
${'dark'}
72+
`('$type', ({ type }) => {
73+
it(`should display type ${type} button`, () => {
74+
const { getByTestId } = render(<Button type={type}>{type}</Button>);
75+
const component = getByTestId('RNE__Button__wrap');
76+
expect(component.props.style.backgroundColor).toBe(colorRgb(TYPES[type]));
77+
});
78+
});
79+
80+
describe.each`
81+
size
82+
${'small'}
83+
${'default'}
84+
${'large'}
85+
`('$size', ({ size }) => {
86+
it(`should display size ${size} button`, () => {
87+
const { getByTestId } = render(<Button size={size}>{size}</Button>);
88+
const component = getByTestId('RNE__Button__wrap');
89+
expect(component.props.style.paddingHorizontal).toBe(SIZES[size]);
90+
});
91+
});
92+
93+
it('onPress events', () => {
94+
const fn = jest.fn();
95+
const { getByTestId } = render(<Button onPress={fn}>onPress</Button>);
96+
const component = getByTestId('RNE__Button__wrap');
97+
fireEvent(component, 'press');
98+
expect(fn).toHaveBeenCalled();
99+
});
100+
101+
it('onPress events if disabled', () => {
102+
const fn = jest.fn();
103+
const { getByTestId } = render(
104+
<Button disabled onPress={fn}>
105+
onPress
106+
</Button>,
107+
);
108+
const component = getByTestId('RNE__Button__wrap');
109+
fireEvent(component, 'press');
110+
expect(fn).not.toHaveBeenCalled();
111+
});
52112
});
Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,42 @@
1+
import 'react-native';
2+
import React from 'react';
13
import ButtonGroup from '../lib/ButtonGroup';
24
import Button from '../lib/Button';
3-
import renderer from 'react-test-renderer';
5+
import Flex from '../lib/Flex';
6+
import { render } from '@testing-library/react-native';
7+
import { toObject } from '../utils';
48

5-
it('ButtonGroup', () => {
6-
const component = renderer.create(
7-
<ButtonGroup size="small" color="#ffc107" type="warning" bordered={false} gutter={10}>
8-
<Button>警告</Button>
9-
<Button>警告</Button>
10-
<Button>主要</Button>
11-
<Button>警告</Button>
12-
</ButtonGroup>,
13-
);
14-
expect(component.root.props.size).toBe('small');
15-
expect(component.root.props.color).toBe('#ffc107');
16-
expect(component.root.props.type).toBe('warning');
17-
expect(component.root.props.bordered).toBe(false);
18-
expect(component.root.props.gutter).toBe(10);
9+
describe('ButtonGroup', () => {
10+
it('gutter', () => {
11+
const { UNSAFE_getByType } = render(
12+
<ButtonGroup gutter={20}>
13+
<Button>警告</Button>
14+
<Button>警告</Button>
15+
<Button>主要</Button>
16+
<Button>警告</Button>
17+
</ButtonGroup>,
18+
);
19+
const flex = UNSAFE_getByType(Flex);
20+
flex.props.children.map((item: any, index: number) => {
21+
const marginLeft = index === 0 ? undefined : 10;
22+
const styles = toObject(item.props.style);
23+
expect(styles.marginLeft).toBe(marginLeft);
24+
});
25+
});
26+
27+
it('inline', () => {
28+
const { UNSAFE_getByType } = render(
29+
<ButtonGroup inline>
30+
<Button>警告</Button>
31+
<Button>警告</Button>
32+
<Button>主要</Button>
33+
<Button>警告</Button>
34+
</ButtonGroup>,
35+
);
36+
const flex = UNSAFE_getByType(Flex);
37+
flex.props.children.map((item: any) => {
38+
const styles = toObject(item.props.style);
39+
expect(styles.flex).toBe(0);
40+
});
41+
});
1942
});

test-ci/src/__tests__/icon.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import 'react-native';
2+
import React from 'react';
3+
import Icon from '../lib/Icon';
4+
import { render, fireEvent } from '@testing-library/react-native';
5+
import svgPaths from '@uiw/icons/fonts/w-icon.json';
6+
7+
describe('Icon', () => {
8+
// it('name', () => {
9+
// const { getByTestId } = render(<Icon name='apple' />);
10+
// const component = getByTestId('RNE__Icon__svg');
11+
// const svg = component.props.children.props.children[0].props.d;
12+
// expect(svg).toBe(svgPaths['apple'][0]);
13+
// });
14+
15+
it('fill', () => {
16+
const { getByTestId } = render(<Icon name="apple" fill="#ff0000" />);
17+
const component = getByTestId('RNE__Icon__svg');
18+
expect(component.props.fill).toBe('#ff0000');
19+
});
20+
21+
it('stroke', () => {
22+
const { getByTestId } = render(<Icon name="apple" stroke="#ffff00" />);
23+
const component = getByTestId('RNE__Icon__svg');
24+
expect(component.props.stroke).toBe('#ffff00');
25+
});
26+
27+
it('xml', () => {
28+
const xml = `
29+
<svg width="20" height="20" viewBox="0 0 20 20">
30+
<path
31+
fill-rule="evenodd"
32+
fill="#000"
33+
d="M19 8h-1.26c-.19-.73-.48-1.42-.85-2.06l.94-.94a.996.996 0 0 0 0-1.41l-1.41-1.41a.996.996 0 0 0-1.41 0l-.94.94c-.65-.38-1.34-.67-2.07-.86V1c0-.55-.45-1-1-1H9c-.55 0-1 .45-1 1v1.26c-.76.2-1.47.5-2.13.89L5 2.28a.972.972 0 0 0-1.36 0L2.28 3.64c-.37.38-.37.98 0 1.36l.87.87c-.39.66-.69 1.37-.89 2.13H1c-.55 0-1 .45-1 1v2c0 .55.45 1 1 1h1.26c.19.73.48 1.42.85 2.06l-.94.94a.996.996 0 0 0 0 1.41l1.41 1.41c.39.39 1.02.39 1.41 0l.94-.94c.64.38 1.33.66 2.06.85V19c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-1.26c.76-.2 1.47-.5 2.13-.89l.88.87c.37.37.98.37 1.36 0l1.36-1.36c.37-.38.37-.98 0-1.36l-.87-.87c.4-.65.7-1.37.89-2.13H19c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zm-9 7c-2.76 0-5-2.24-5-5s2.24-5 5-5v10z"
34+
/>
35+
</svg>
36+
`;
37+
const { getByTestId } = render(<Icon xml={xml} />);
38+
const component = getByTestId('RNE__Icon__svgXml');
39+
expect(component.props.xml).toBe(xml);
40+
});
41+
42+
it('size', () => {
43+
const { getByTestId } = render(<Icon name="apple" size={21} />);
44+
const component = getByTestId('RNE__Icon__svg');
45+
expect(component.props.width).toBe(21);
46+
expect(component.props.height).toBe(21);
47+
});
48+
49+
it('width and height', () => {
50+
const { getByTestId } = render(<Icon name="apple" width={21} height={22} />);
51+
const component = getByTestId('RNE__Icon__svg');
52+
expect(component.props.width).toBe(21);
53+
expect(component.props.height).toBe(22);
54+
});
55+
56+
it('onPress', () => {
57+
const fn = jest.fn();
58+
const { getByTestId } = render(<Icon name="apple" onPress={fn} />);
59+
const component = getByTestId('RNE__Icon__svg');
60+
fireEvent(component, 'press');
61+
expect(fn).toHaveBeenCalled();
62+
});
63+
});

0 commit comments

Comments
 (0)