input.test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import Input, { Input as BaseInput } from '../index';
  2. import Icon from '../../icons/index';
  3. import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
  4. import GraphemeSplitter from 'grapheme-splitter';
  5. import { isString, isFunction } from 'lodash';
  6. import { InputGroup, InputNumber } from '../../index';
  7. function getValueLength(str) {
  8. if (isString(str)) {
  9. const splitter = new GraphemeSplitter();
  10. return splitter.countGraphemes(str);
  11. } else {
  12. return -1;
  13. }
  14. }
  15. describe('Input', () => {
  16. // it('call foundation destory when compoonent Unmount', () => {
  17. // });
  18. it('input should call onChange when value change', () => {
  19. let inputValue = 'semi';
  20. let event = { target: { value: inputValue } };
  21. let onChange = value => {
  22. console.log(value);
  23. };
  24. let spyOnChange = sinon.spy(onChange);
  25. const input = mount(<Input onChange={spyOnChange} />);
  26. input.find('input').simulate('change', event);
  27. expect(spyOnChange.calledOnce).toBe(true);
  28. expect(spyOnChange.calledWithMatch(inputValue)).toBe(true);
  29. });
  30. it('input with custom className & style', () => {
  31. const wrapper = mount(<Input className="test" style={{ color: 'red' }} />);
  32. expect(wrapper.hasClass('test')).toEqual(true);
  33. expect(wrapper.find('div.test')).toHaveStyle('color', 'red');
  34. });
  35. // TODO ,找不到focus的className
  36. // it('input autofocus', () => {
  37. // const wrapper = mount(<Input autofocus={true} />);
  38. // wrapper.setProps({ autofocus: true })
  39. // wrapper.update();
  40. // expect(wrapper.find(`.${BASE_CLASS_PREFIX}-input-wrapper-focus`)).toEqual(true);
  41. // });
  42. it('input different size', () => {
  43. const largeInput = mount(<Input size="large" />);
  44. const defaultInput = mount(<Input />);
  45. const smallInput = mount(<Input size="small" />);
  46. expect(largeInput.find(`.${BASE_CLASS_PREFIX}-input-large`)).toHaveLength(1);
  47. expect(smallInput.find(`.${BASE_CLASS_PREFIX}-input-small`)).toHaveLength(1);
  48. });
  49. it('input with placeholder', () => {
  50. let placeholderText = `semi placeholder`;
  51. const input = mount(<Input placeholder={placeholderText} />);
  52. let inputDom = input.find('input');
  53. expect(inputDom.props().placeholder).toEqual(placeholderText);
  54. });
  55. it('input with defaultValue', () => {
  56. let defaultValue = 'semi';
  57. const inputWithDefaultValue = mount(<Input defaultValue={defaultValue} />);
  58. const inputDom = inputWithDefaultValue.find('input');
  59. expect(inputDom.instance().value).toEqual(defaultValue);
  60. });
  61. it('input disabled when props.disabled', () => {
  62. const disabledInput = mount(<Input disabled />);
  63. expect(disabledInput.exists(`.${BASE_CLASS_PREFIX}-input-wrapper-disabled`)).toEqual(true);
  64. expect(disabledInput.find(`.${BASE_CLASS_PREFIX}-input-disabled`)).toHaveLength(1);
  65. });
  66. it('input different validateStatus', () => {
  67. const warningInput = mount(<Input validateStatus="warning" />);
  68. const errorInput = mount(<Input validateStatus="error" />);
  69. const normalInput = mount(<Input />);
  70. expect(warningInput.exists(`.${BASE_CLASS_PREFIX}-input-wrapper-warning`)).toEqual(true);
  71. expect(errorInput.exists(`.${BASE_CLASS_PREFIX}-input-wrapper-error`)).toEqual(true);
  72. expect(normalInput.exists(`.${BASE_CLASS_PREFIX}-input-wrapper-error`)).toEqual(false);
  73. expect(normalInput.exists(`.${BASE_CLASS_PREFIX}-input-wrapper-warning`)).toEqual(false);
  74. });
  75. // TODO,同上,focus时才会展示clearBtn,autoFocus似乎不起作用
  76. // it('input clearable', () => {
  77. // const clearableInput = mount(<Input clearable defaultValue='semi' autofocus/>);
  78. // expect(clearableInput.find('input').instance().value).toEqual('semi');
  79. // // clearableInput.find(`.${BASE_CLASS_PREFIX}-input-clearbtn`).simulate('click');
  80. // })
  81. it('input with prefix / suffix', () => {
  82. let suffix = <div className="suffix">suffix</div>;
  83. let prefix = <div className="prefix">prefix</div>;
  84. const withNodeSuffix = mount(<Input suffix={suffix} />);
  85. const withNodePrefix = mount(<Input prefix={prefix} />);
  86. expect(withNodeSuffix.contains(suffix)).toEqual(true);
  87. expect(withNodePrefix.contains(prefix)).toEqual(true);
  88. });
  89. it('input addonBefore / addonAfter', () => {
  90. let input = mount(<Input addonBefore="https://" addonAfter=".com" />);
  91. expect(input.find(`.${BASE_CLASS_PREFIX}-input-prepend`).getDOMNode().textContent).toEqual('https://');
  92. expect(input.find(`.${BASE_CLASS_PREFIX}-input-append`).getDOMNode().textContent).toEqual('.com');
  93. });
  94. it('input password', () => {
  95. const pwInput = mount(<Input type="password" />);
  96. expect(pwInput.find('input').instance().type).toEqual('password');
  97. });
  98. it('input password mode', () => {
  99. const inputMode = mount(<Input />);
  100. expect(inputMode.find('input').instance().type).toEqual('text');
  101. inputMode.setProps({ mode: 'password' }) ;
  102. expect(inputMode.find('input').instance().type).toEqual('password');
  103. inputMode.setProps({ mode: '' }) ;
  104. expect(inputMode.find('input').instance().type).toEqual('text');
  105. });
  106. it('input password click eyes icon', () => {
  107. const inputMode = mount(<Input mode='password' defaultValue="123456" autofocus/>);
  108. inputMode.simulate('mouseEnter', {}).find(`.${BASE_CLASS_PREFIX}-input-modebtn`).simulate('click');
  109. expect(inputMode.find('input').instance().type).toEqual('text');
  110. });
  111. it('input controlled mode', () => {
  112. let initValue = 'semi';
  113. let onChange = value => {
  114. console.log(value);
  115. };
  116. let spyOnChange = sinon.spy(onChange);
  117. const input = mount(<Input onChange={spyOnChange} value={initValue} />);
  118. const inputDom = input.find('input');
  119. expect(inputDom.instance().value).toEqual(initValue);
  120. let newInputValue = 'vita lemon';
  121. let event = { target: { value: newInputValue } };
  122. input.find('input').simulate('change', event);
  123. expect(spyOnChange.calledOnce).toBe(true);
  124. expect(spyOnChange.calledWithMatch(newInputValue)).toBe(true);
  125. input.setProps({ value: newInputValue });
  126. expect(inputDom.instance().value).toEqual(newInputValue);
  127. });
  128. // TODO InputGroup
  129. // TODO onClear 回调
  130. it('click prefix/suffix focus', () => {
  131. const spyFocus = sinon.spy(() => {});
  132. const inputNode = mount(<Input style={{ width: 200 }} onFocus={spyFocus} prefix="search" defaultValue="Semi Design" />);
  133. const inputNode2 = mount(<Input style={{ width: 200 }} onFocus={spyFocus} suffix="search" defaultValue="Semi Design" />);
  134. inputNode.find(`.${BASE_CLASS_PREFIX}-input-prefix`).simulate('click');
  135. expect(inputNode.find(BaseInput).state('isFocus')).toEqual(true);
  136. inputNode2.find(`.${BASE_CLASS_PREFIX}-input-suffix`).simulate('click');
  137. expect(inputNode2.find(BaseInput).state('isFocus')).toEqual(true);
  138. });
  139. it('test input GraphemeSplitter function', () => {
  140. const testCases = [
  141. ['💖', 1],
  142. ['字节跳动', 4],
  143. ['Semi 💖', 6],
  144. ['💖💖💖💖💖', 5],
  145. ['🤣', 1],
  146. ['1️⃣', 1],
  147. ['👨‍👨‍👦', 1],
  148. ];
  149. for (let item of testCases) {
  150. const [value, result] = item;
  151. expect(getValueLength(value)).toEqual(result);
  152. }
  153. });
  154. it('test getValueLength onChange', () => {
  155. let inputValue = '0123456789semi design';
  156. let event = { target: { value: inputValue } };
  157. let onChange = value => {
  158. console.log(value);
  159. };
  160. let spyOnChange = sinon.spy(onChange);
  161. const input = mount(<Input onChange={spyOnChange} maxLength={10} getValueLength={getValueLength} />);
  162. input.find('input').simulate('change', event);
  163. expect(spyOnChange.calledOnce).toBe(true);
  164. expect(spyOnChange.calledWithMatch(inputValue)).toBe(false);
  165. });
  166. it('test visibleLength controlled mode', () => {
  167. let value = '0123456789semi design';
  168. const input = mount(<Input value={value} maxLength={10} getValueLength={getValueLength} />);
  169. const inputDom = input.find('input');
  170. expect(inputDom.instance().value).toEqual(value);
  171. });
  172. it('test minLength + getValueLength', () => {
  173. let inputValue = '💖💖💖';
  174. let minLength = 4;
  175. let event = { target: { value: inputValue } };
  176. let onChange = value => {
  177. console.log(value);
  178. };
  179. let spyOnChange = sinon.spy(onChange);
  180. const input = mount(<Input onChange={spyOnChange} minLength={minLength} getValueLength={getValueLength} />);
  181. const inputDom = input.find('input');
  182. inputDom.simulate('change', event);
  183. expect(spyOnChange.calledOnce).toBe(true);
  184. expect(spyOnChange.calledWithMatch(inputValue)).toBe(true);
  185. expect(inputDom.instance().minLength).toEqual(inputValue.length + (minLength - getValueLength(inputValue)));
  186. });
  187. it('test truncateValue function', () => {
  188. function truncateValue(value, maxLength, getValueLength) {
  189. if (isFunction(getValueLength)) {
  190. let truncatedValue = '';
  191. for (let i = 1, len = value.length; i <= len; i++) {
  192. const currentValue = value.slice(0, i);
  193. if (getValueLength(currentValue) > maxLength) {
  194. return truncatedValue;
  195. } else {
  196. truncatedValue = currentValue;
  197. }
  198. }
  199. return truncatedValue;
  200. } else {
  201. return value.slice(0, maxLength);
  202. }
  203. }
  204. const testCases = [
  205. // 没有传递函数
  206. ['Semi Design', 4, null, 'Semi'],
  207. ['💖', 0, null, ''],
  208. ['🆗', 1, null, '\ud83c'],
  209. // 自定义valueLength
  210. ['Semi Design', 4, getValueLength, 'Semi'],
  211. ['💖💖💖💖💖💖💖💖💖💖👨‍👩‍👧‍👦', 10, getValueLength, '💖💖💖💖💖💖💖💖💖💖'],
  212. ['💖', 0, getValueLength, ''],
  213. ['🆗', 1, getValueLength, '🆗'],
  214. ];
  215. for (let [value, length, fc, result] of testCases) {
  216. expect(truncateValue(value, length, fc)).toBe(result);
  217. }
  218. })
  219. it('input group', () => {
  220. const groupFocus = sinon.spy(() => {
  221. console.log('group focus');
  222. });
  223. const groupBlur = sinon.spy(() => {
  224. console.log('group focus');
  225. });
  226. const inputFocus = sinon.spy(() => {
  227. console.log('input focus');
  228. });
  229. const inputBlur = sinon.spy(() => {
  230. console.log('input blur');
  231. });
  232. const inputGroup = mount(
  233. <InputGroup disabled={true} onFocus={groupFocus} onBlur={groupBlur}>
  234. <Input disabled={false} onFocus={inputFocus} onBlur={inputBlur} placeholder="Name" style={{ width: 100 }} />
  235. <InputNumber placeholder="Score" style={{ width: 140 }} />
  236. </InputGroup>
  237. );
  238. inputGroup.find('input').at(0).simulate('focus');
  239. expect(inputFocus.called).toBe(true);
  240. expect(groupFocus.called).toBe(true);
  241. inputGroup.find('input').at(0).simulate('blur');
  242. expect(inputBlur.called).toBe(true);
  243. expect(groupBlur.called).toBe(true);
  244. expect(inputGroup.find('input').at(0).instance().disabled).toBe(false);
  245. expect(inputGroup.find('input').at(1).instance().disabled).toBe(true);
  246. })
  247. });