mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-18 12:49:24 +00:00
[change] modernize CheckBox
Rewrite CheckBox to use function components and hooks. Rewrite the tests to replace enzyme with testing-library.
This commit is contained in:
@@ -2,59 +2,62 @@
|
||||
|
||||
import CheckBox from '../';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
const checkboxSelector = 'input[type="checkbox"]';
|
||||
function findCheckbox(container) {
|
||||
return container.firstChild.querySelector('input');
|
||||
}
|
||||
|
||||
describe('CheckBox', () => {
|
||||
describe('disabled', () => {
|
||||
test('when "false" a default checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(undefined);
|
||||
const { container } = render(<CheckBox />);
|
||||
expect(findCheckbox(container).disabled).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a disabled checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox disabled />);
|
||||
expect(component.find(checkboxSelector).prop('disabled')).toBe(true);
|
||||
const { container } = render(<CheckBox disabled />);
|
||||
expect(findCheckbox(container).disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onChange', () => {
|
||||
test('is called with the event object', () => {
|
||||
const onChange = jest.fn();
|
||||
const component = shallow(<CheckBox onChange={onChange} value={false} />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: true } } });
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
nativeEvent: { target: { checked: true }, value: true }
|
||||
});
|
||||
const { container } = render(<CheckBox onChange={onChange} value={false} />);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onValueChange', () => {
|
||||
test('when value is "false" it receives "true"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<CheckBox onValueChange={onValueChange} value={false} />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: true } } });
|
||||
const { container } = render(<CheckBox onValueChange={onValueChange} value={false} />);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onValueChange).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
test('when value is "true" it receives "false"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const component = shallow(<CheckBox onValueChange={onValueChange} value />);
|
||||
component.find('input').simulate('change', { nativeEvent: { target: { checked: false } } });
|
||||
const { container } = render(<CheckBox onValueChange={onValueChange} value />);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onValueChange).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value', () => {
|
||||
test('when "false" an unchecked checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox value={false} />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(false);
|
||||
const { container } = render(<CheckBox value={false} />);
|
||||
expect(findCheckbox(container).checked).toBe(false);
|
||||
});
|
||||
|
||||
test('when "true" a checked checkbox is rendered', () => {
|
||||
const component = shallow(<CheckBox value />);
|
||||
expect(component.find(checkboxSelector).prop('checked')).toBe(true);
|
||||
const { container } = render(<CheckBox value />);
|
||||
expect(findCheckbox(container).checked).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+52
-63
@@ -10,12 +10,11 @@
|
||||
|
||||
import type { ViewProps } from '../View';
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import createElement from '../createElement';
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import UIManager from '../UIManager';
|
||||
import View from '../View';
|
||||
import React from 'react';
|
||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||
|
||||
type CheckBoxProps = {
|
||||
...ViewProps,
|
||||
@@ -26,74 +25,64 @@ type CheckBoxProps = {
|
||||
value?: boolean
|
||||
};
|
||||
|
||||
class CheckBox extends React.Component<CheckBoxProps> {
|
||||
_checkboxElement: HTMLInputElement;
|
||||
const CheckBox = forwardRef<CheckBoxProps, *>((props, ref) => {
|
||||
const { color, disabled, onChange, onValueChange, style, value, ...other } = props;
|
||||
|
||||
static displayName = 'CheckBox';
|
||||
const checkboxRef = useRef(null);
|
||||
|
||||
blur() {
|
||||
UIManager.blur(this._checkboxElement);
|
||||
}
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => {
|
||||
return {
|
||||
blur() {
|
||||
UIManager.blur(checkboxRef.current);
|
||||
},
|
||||
focus() {
|
||||
UIManager.focus(checkboxRef.current);
|
||||
}
|
||||
};
|
||||
},
|
||||
[checkboxRef]
|
||||
);
|
||||
|
||||
focus() {
|
||||
UIManager.focus(this._checkboxElement);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
color,
|
||||
disabled,
|
||||
/* eslint-disable */
|
||||
onChange,
|
||||
onValueChange,
|
||||
/* eslint-enable */
|
||||
style,
|
||||
value,
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
const fakeControl = (
|
||||
<View
|
||||
style={[
|
||||
styles.fakeControl,
|
||||
value && styles.fakeControlChecked,
|
||||
// custom color
|
||||
value && color && { backgroundColor: color, borderColor: color },
|
||||
disabled && styles.fakeControlDisabled,
|
||||
value && disabled && styles.fakeControlCheckedAndDisabled
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const nativeControl = createElement('input', {
|
||||
checked: value,
|
||||
disabled: disabled,
|
||||
onChange: this._handleChange,
|
||||
ref: this._setCheckboxRef,
|
||||
style: [styles.nativeControl, styles.cursorInherit],
|
||||
type: 'checkbox'
|
||||
});
|
||||
|
||||
return (
|
||||
<View {...other} style={[styles.root, style, disabled && styles.cursorDefault]}>
|
||||
{fakeControl}
|
||||
{nativeControl}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleChange = (event: Object) => {
|
||||
const { onChange, onValueChange } = this.props;
|
||||
function handleChange(event: Object) {
|
||||
const value = event.nativeEvent.target.checked;
|
||||
event.nativeEvent.value = value;
|
||||
onChange && onChange(event);
|
||||
onValueChange && onValueChange(value);
|
||||
};
|
||||
}
|
||||
|
||||
_setCheckboxRef = element => {
|
||||
this._checkboxElement = element;
|
||||
};
|
||||
}
|
||||
const fakeControl = (
|
||||
<View
|
||||
style={[
|
||||
styles.fakeControl,
|
||||
value && styles.fakeControlChecked,
|
||||
// custom color
|
||||
value && color && { backgroundColor: color, borderColor: color },
|
||||
disabled && styles.fakeControlDisabled,
|
||||
value && disabled && styles.fakeControlCheckedAndDisabled
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const nativeControl = createElement('input', {
|
||||
checked: value,
|
||||
disabled: disabled,
|
||||
onChange: handleChange,
|
||||
ref: checkboxRef,
|
||||
style: [styles.nativeControl, styles.cursorInherit],
|
||||
type: 'checkbox'
|
||||
});
|
||||
|
||||
return (
|
||||
<View {...other} ref={ref} style={[styles.root, style, disabled && styles.cursorDefault]}>
|
||||
{fakeControl}
|
||||
{nativeControl}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
CheckBox.displayName = 'CheckBox';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
@@ -143,4 +132,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
export default applyNativeMethods(CheckBox);
|
||||
export default CheckBox;
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ const Switch = forwardRef<SwitchProps, *>((props, ref) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<View {...other} style={rootStyle}>
|
||||
<View {...other} ref={ref} style={rootStyle}>
|
||||
<View style={trackStyle} />
|
||||
<View ref={thumbRef} style={thumbStyle} />
|
||||
{nativeControl}
|
||||
|
||||
Reference in New Issue
Block a user