[change] modernize Picker

Rewrite Picker to use function components and hooks.
Rewrite the tests to replace enzyme with testing-library.
This commit is contained in:
Nicolas Gallagher
2020-02-04 16:05:41 -08:00
parent fdf53df301
commit 8d37fde5ee
4 changed files with 75 additions and 68 deletions
+4 -7
View File
@@ -10,7 +10,6 @@
import type { ColorValue } from '../../types';
import React from 'react';
import createElement from '../createElement';
type Props = {
@@ -20,10 +19,8 @@ type Props = {
value?: number | string
};
export default class PickerItem extends React.Component<Props> {
render() {
const { color, label, testID, value } = this.props;
const style = { color };
return createElement('option', { style, testID, value }, label);
}
export default function PickerItem(props: Props) {
const { color, label, testID, value } = props;
const style = { color };
return createElement('option', { style, testID, value }, label);
}
@@ -9,14 +9,9 @@ exports[`components/Picker prop "children" items 1`] = `
`;
exports[`components/Picker prop "children" renders items 1`] = `
Array [
<PickerItem
label="label-1"
value="value-1"
/>,
<PickerItem
label="label-2"
value="value-2"
/>,
]
<option
value="value-1"
>
label-1
</option>
`;
@@ -1,9 +1,13 @@
/* eslint-env jasmine, jest */
import React from 'react';
import { shallow } from 'enzyme';
import { render } from '@testing-library/react';
import Picker from '..';
function findSelect(container) {
return container.querySelector('select');
}
describe('components/Picker', () => {
describe('prop "children"', () => {
test('renders items', () => {
@@ -13,14 +17,14 @@ describe('components/Picker', () => {
<Picker.Item label="label-2" value="value-2" />
</Picker>
);
const component = shallow(picker);
expect(component.children()).toMatchSnapshot();
const { container } = render(picker);
expect(container.firstChild.firstChild).toMatchSnapshot();
});
test('items', () => {
const pickerItem = <Picker.Item label="label-1" value="value-1" />;
const component = shallow(pickerItem);
expect(component).toMatchSnapshot();
const { container } = render(pickerItem);
expect(container.firstChild).toMatchSnapshot();
});
});
@@ -32,8 +36,8 @@ describe('components/Picker', () => {
<Picker.Item label="label-2" value="value-2" />
</Picker>
);
const component = shallow(picker);
expect(component.find('select').prop('disabled')).toBe(true);
const { container } = render(picker);
expect(findSelect(container).disabled).toBe(true);
});
});
@@ -46,11 +50,14 @@ describe('components/Picker', () => {
<Picker.Item label="label-2" value="value-2" />
</Picker>
);
const component = shallow(picker);
component.find('select').simulate('change', {
target: { selectedIndex: '1', value: 'value-2' }
});
expect(onValueChange).toHaveBeenCalledWith('value-2', '1');
const { container } = render(picker);
const select = findSelect(container);
// mock change event
select.selectedIndex = '1';
select.value = 'value-2';
select.dispatchEvent(new window.Event('change', { bubbles: true }));
expect(onValueChange).toHaveBeenCalledWith('value-2', 1);
});
});
@@ -62,8 +69,8 @@ describe('components/Picker', () => {
<Picker.Item label="label-2" value="value-2" />
</Picker>
);
const component = shallow(picker);
expect(component.find('select').prop('value')).toBe('value-2');
const { container } = render(picker);
expect(findSelect(container).value).toBe('value-2');
});
test('selects the correct item (number)', () => {
@@ -73,8 +80,8 @@ describe('components/Picker', () => {
<Picker.Item label="label-2" value={22} />
</Picker>
);
const component = shallow(picker);
expect(component.find('select').prop('value')).toBe(22);
const { container } = render(picker);
expect(findSelect(container).value).toBe('22');
});
});
});
+43 -35
View File
@@ -10,11 +10,12 @@
import type { ViewProps } from '../View';
import applyNativeMethods from '../../modules/applyNativeMethods';
import { Component } from 'react';
import createElement from '../createElement';
import setAndForwardRef from '../../modules/setAndForwardRef';
import usePlatformMethods from '../../hooks/usePlatformMethods';
import PickerItem from './PickerItem';
import StyleSheet, { type StyleObj } from '../StyleSheet';
import { forwardRef, useRef } from 'react';
type PickerProps = {
...ViewProps,
@@ -29,44 +30,51 @@ type PickerProps = {
prompt?: string
};
class Picker extends Component<PickerProps> {
static Item = PickerItem;
const Picker = forwardRef<PickerProps, *>((props, ref) => {
const {
children,
enabled,
onValueChange,
selectedValue,
style,
testID,
/* eslint-disable */
itemStyle,
mode,
prompt,
/* eslint-enable */
...other
} = props;
render() {
const {
children,
enabled,
selectedValue,
style,
testID,
/* eslint-disable */
itemStyle,
mode,
prompt,
onValueChange,
/* eslint-enable */
...otherProps
} = this.props;
const hostRef = useRef(null);
const setRef = setAndForwardRef({
getForwardedRef: () => ref,
setLocalRef: c => {
hostRef.current = c;
}
});
usePlatformMethods(hostRef, ref, null, style);
return createElement('select', {
children,
disabled: enabled === false ? true : undefined,
onChange: this._handleChange,
style: [styles.initial, style],
testID,
value: selectedValue,
...otherProps
});
}
_handleChange = (e: Object) => {
const { onValueChange } = this.props;
function handleChange(e: Object) {
const { selectedIndex, value } = e.target;
if (onValueChange) {
onValueChange(value, selectedIndex);
}
};
}
}
return createElement('select', {
children,
disabled: enabled === false ? true : undefined,
onChange: handleChange,
ref: setRef,
style: [styles.initial, style],
testID,
value: selectedValue,
...other
});
});
Picker.Item = PickerItem;
const styles = StyleSheet.create({
initial: {
@@ -76,4 +84,4 @@ const styles = StyleSheet.create({
}
});
export default applyNativeMethods(Picker);
export default Picker;