diff --git a/docs/demo/field-names.md b/docs/demo/field-names.md new file mode 100644 index 00000000..5d2046a4 --- /dev/null +++ b/docs/demo/field-names.md @@ -0,0 +1,3 @@ +## FieldNames + + diff --git a/examples/debug.tsx b/examples/debug.tsx index cea95c85..fc5086dc 100644 --- a/examples/debug.tsx +++ b/examples/debug.tsx @@ -1,54 +1,18 @@ /* eslint-disable react/no-array-index-key */ import React from 'react'; -import TreeSelect, { TreeNode } from '../src'; +import TreeSelect from '../src'; import '../assets/index.less'; -class Demo extends React.Component { - state = { - value: undefined, - }; +export default () => { + const [treeData, setTreeData] = React.useState([]); - onChange = value => { - console.log(value); - this.setState({ value }); - }; + React.useEffect(() => { + setTimeout(() => { + console.clear(); + setTreeData([{ value: 'light', title: 'bamboo' }]); + }, 1000); + }, []); - render() { - return ( - { - let current = entity; - const nodes = []; - - while (current) { - nodes.unshift(current.data.title); - current = current.parent; - } - - return nodes.join('>'); - }} - > - - - - - - - sss} key="random3" /> - - - - ); - } -} - -export default Demo; + return ; +}; diff --git a/examples/fieldNames.tsx b/examples/fieldNames.tsx new file mode 100644 index 00000000..be636993 --- /dev/null +++ b/examples/fieldNames.tsx @@ -0,0 +1,33 @@ +import '../assets/index.less'; +import React from 'react'; +import 'rc-dialog/assets/index.css'; +import TreeSelect from '../src'; + +export default () => { + return ( + + ); +}; diff --git a/package.json b/package.json index 81f932ae..938f8e88 100644 --- a/package.json +++ b/package.json @@ -68,8 +68,8 @@ "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", - "rc-select": "^12.0.0", - "rc-tree": "^4.0.0", + "rc-select": "~13.0.0-alpha.1", + "rc-tree": "~5.0.0", "rc-util": "^5.0.5" } } diff --git a/src/OptionList.tsx b/src/OptionList.tsx index 32045830..1c4bef11 100644 --- a/src/OptionList.tsx +++ b/src/OptionList.tsx @@ -105,7 +105,7 @@ const OptionList: React.RefForwardingComponent< // ========================== Values ========================== const valueKeys = React.useMemo( () => - checkedKeys.map((val) => { + checkedKeys.map(val => { const entity = getEntityByValue(val); return entity ? entity.key : null; }), @@ -153,7 +153,7 @@ const OptionList: React.RefForwardingComponent< React.useEffect(() => { if (searchValue) { - setSearchExpandedKeys(flattenOptions.map((o) => o.key)); + setSearchExpandedKeys(flattenOptions.map(o => o.key)); } }, [searchValue]); @@ -167,7 +167,7 @@ const OptionList: React.RefForwardingComponent< }; // ========================== Events ========================== - const onListMouseDown: React.MouseEventHandler = (event) => { + const onListMouseDown: React.MouseEventHandler = event => { event.preventDefault(); }; @@ -190,7 +190,7 @@ const OptionList: React.RefForwardingComponent< React.useImperativeHandle(ref, () => ({ scrollTo: treeRef.current?.scrollTo, - onKeyDown: (event) => { + onKeyDown: event => { const { which } = event; switch (which) { // >>> Arrow keys @@ -203,7 +203,7 @@ const OptionList: React.RefForwardingComponent< // >>> Select item case KeyCode.ENTER: { - const { selectable, value } = activeEntity?.data || {}; + const { selectable, value } = activeEntity?.data.node || {}; if (selectable !== false) { onInternalSelect(null, { node: { key: activeKey }, @@ -281,8 +281,9 @@ const OptionList: React.RefForwardingComponent< ); }; -const RefOptionList = - React.forwardRef>(OptionList); +const RefOptionList = React.forwardRef>( + OptionList, +); RefOptionList.displayName = 'OptionList'; export default RefOptionList; diff --git a/src/generate.tsx b/src/generate.tsx index 08bafa69..d5036408 100644 --- a/src/generate.tsx +++ b/src/generate.tsx @@ -6,6 +6,7 @@ import { getLabeledValue } from 'rc-select/lib/utils/valueUtil'; import { convertDataToEntities } from 'rc-tree/lib/utils/treeUtil'; import { conductCheck } from 'rc-tree/lib/utils/conductUtil'; import type { IconType } from 'rc-tree/lib/interface'; +import omit from 'rc-util/lib/omit'; import type { FilterFunc } from 'rc-select/lib/interface/generator'; import { INTERNAL_PROPS_MARK } from 'rc-select/lib/interface/generator'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; @@ -22,6 +23,7 @@ import type { LegacyDataNode, SelectSource, FlattenDataNode, + FieldNames, } from './interface'; import { flattenOptions, @@ -32,6 +34,7 @@ import { removeValue, getRawValueLabeled, toArray, + fillFieldNames, } from './utils/valueUtil'; import warningProps from './utils/warningPropsUtil'; import { SelectContext } from './Context'; @@ -43,8 +46,8 @@ import { formatStrategyKeys, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './utils/s import { fillAdditionalInfo } from './utils/legacyUtil'; import useSelectValues from './hooks/useSelectValues'; -const OMIT_PROPS = [ - 'expandedKeys', +const OMIT_PROPS: (keyof TreeSelectProps)[] = [ + 'expandedKeys' as any, 'treeData', 'treeCheckable', 'showCheckedStrategy', @@ -63,6 +66,7 @@ const OMIT_PROPS = [ 'treeMotion', 'onTreeExpand', 'onTreeLoad', + 'labelRender', 'loadData', 'treeDataSimpleMode', 'treeNodeLabelProp', @@ -81,6 +85,7 @@ export interface TreeSelectProps | 'optionLabelProp' | 'tokenSeparators' | 'filterOption' + | 'fieldNames' > { multiple?: boolean; showArrow?: boolean; @@ -99,6 +104,7 @@ export interface TreeSelectProps maxTagPlaceholder?: (omittedValues: LabelValueType[]) => React.ReactNode; + fieldNames?: FieldNames; loadData?: (dataNode: LegacyDataNode) => Promise; treeNodeFilterProp?: string; treeNodeLabelProp?: string; @@ -155,13 +161,7 @@ export default function generate(config: { filterOptions, isValueDisabled, findValueOption, - omitDOMProps: (props: object) => { - const cloneProps = { ...props }; - OMIT_PROPS.forEach(prop => { - delete cloneProps[prop]; - }); - return cloneProps; - }, + omitDOMProps: (props: TreeSelectProps) => omit(props, OMIT_PROPS), }); RefSelect.displayName = 'Select'; @@ -171,6 +171,7 @@ export default function generate(config: { // ================================================================================= const RefTreeSelect = React.forwardRef((props, ref) => { const { + fieldNames, multiple, treeCheckable, treeCheckStrictly, @@ -207,17 +208,25 @@ export default function generate(config: { const mergedLabelInValue = treeCheckStrictly || labelInValue; // ======================= Tree Data ======================= + // FieldNames + const mergedFieldNames = fillFieldNames(fieldNames, true); + // Legacy both support `label` or `title` if not set. // We have to fallback to function to handle this const getTreeNodeTitle = (node: DataNode): React.ReactNode => { if (!treeData) { return node.title; } + + if (mergedFieldNames?.label) { + return node[mergedFieldNames.label]; + } + return node.label || node.title; }; const getTreeNodeLabelProp = (entity: FlattenDataNode): React.ReactNode => { - const node = entity.data; + const { node } = entity.data; if (labelRender) { return labelRender(entity); @@ -233,6 +242,7 @@ export default function generate(config: { const mergedTreeData = useTreeData(treeData, children, { getLabelProp: getTreeNodeTitle, simpleMode: treeDataSimpleMode, + fieldNames: mergedFieldNames, }); const flattedOptions = useMemo(() => flattenOptions(mergedTreeData), [mergedTreeData]); @@ -404,7 +414,7 @@ export default function generate(config: { ? null : eventValues.map(val => { const entity = getEntityByValue(val); - return entity ? getTreeNodeLabelProp(entity) : null; + return entity ? entity.data.title : null; }), additionalInfo, ); diff --git a/src/hooks/useKeyValueMapping.ts b/src/hooks/useKeyValueMapping.ts index ea067e44..4882cd30 100644 --- a/src/hooks/useKeyValueMapping.ts +++ b/src/hooks/useKeyValueMapping.ts @@ -8,16 +8,15 @@ export function isDisabled(dataNode: FlattenDataNode, skipType: SkipType): boole return true; } - const { disabled, disableCheckbox } = dataNode.data; + const { disabled, disableCheckbox } = dataNode.data.node; switch (skipType) { - case 'select': - return disabled; case 'checkbox': return disabled || disableCheckbox; - } - return false; + default: + return disabled; + } } export default function useKeyValueMapping( diff --git a/src/hooks/useTreeData.ts b/src/hooks/useTreeData.ts index 9e132add..b935df07 100644 --- a/src/hooks/useTreeData.ts +++ b/src/hooks/useTreeData.ts @@ -1,6 +1,12 @@ import * as React from 'react'; import warning from 'rc-util/lib/warning'; -import type { DataNode, InnerDataNode, SimpleModeConfig, RawValueType } from '../interface'; +import type { + DataNode, + InternalDataEntity, + SimpleModeConfig, + RawValueType, + FieldNames, +} from '../interface'; import { convertChildrenToData } from '../utils/legacyUtil'; const MAX_WARNING_TIMES = 10; @@ -13,7 +19,7 @@ function parseSimpleTreeData( const rootNodeList = []; // Fill in the map - const nodeList = treeData.map((node) => { + const nodeList = treeData.map(node => { const clone = { ...node }; const key = clone[id]; keyNodes[key] = clone; @@ -22,7 +28,7 @@ function parseSimpleTreeData( }); // Connect tree - nodeList.forEach((node) => { + nodeList.forEach(node => { const parentKey = node[pId]; const parent = keyNodes[parentKey]; @@ -47,21 +53,28 @@ function parseSimpleTreeData( function formatTreeData( treeData: DataNode[], getLabelProp: (node: DataNode) => React.ReactNode, -): InnerDataNode[] { + fieldNames: FieldNames, +): InternalDataEntity[] { let warningTimes = 0; const valueSet = new Set(); + // Field names + const { value: fieldValue, children: fieldChildren } = fieldNames; + function dig(dataNodes: DataNode[]) { - return (dataNodes || []).map((node) => { - const { key, value, children, ...rest } = node; + return (dataNodes || []).map(node => { + const { key, disableCheckbox, disabled } = node; - const mergedValue = 'value' in node ? value : key; + const value = node[fieldValue]; + const mergedValue = fieldValue in node ? value : key; - const dataNode: InnerDataNode = { - ...rest, + const dataNode: InternalDataEntity = { + disableCheckbox, + disabled, key: key !== null && key !== undefined ? key : mergedValue, value: mergedValue, title: getLabelProp(node), + node, }; // Check `key` & `value` and warning user @@ -84,8 +97,8 @@ function formatTreeData( valueSet.add(value); } - if ('children' in node) { - dataNode.children = dig(children); + if (fieldChildren in node) { + dataNode.children = dig(node[fieldChildren]); } return dataNode; @@ -105,15 +118,17 @@ export default function useTreeData( { getLabelProp, simpleMode, + fieldNames, }: { getLabelProp: (node: DataNode) => React.ReactNode; simpleMode: boolean | SimpleModeConfig; + fieldNames: FieldNames; }, -): InnerDataNode[] { +): InternalDataEntity[] { const cacheRef = React.useRef<{ treeData?: DataNode[]; children?: React.ReactNode; - formatTreeData?: InnerDataNode[]; + formatTreeData?: InternalDataEntity[]; }>({}); if (treeData) { @@ -130,6 +145,7 @@ export default function useTreeData( }) : treeData, getLabelProp, + fieldNames, ); cacheRef.current.treeData = treeData; @@ -137,7 +153,7 @@ export default function useTreeData( cacheRef.current.formatTreeData = cacheRef.current.children === children ? cacheRef.current.formatTreeData - : formatTreeData(convertChildrenToData(children), getLabelProp); + : formatTreeData(convertChildrenToData(children), getLabelProp, fieldNames); } return cacheRef.current.formatTreeData; diff --git a/src/interface.ts b/src/interface.ts index 8c614a0a..9f491eda 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -30,11 +30,16 @@ export interface DataNode { [prop: string]: any; } -export interface InnerDataNode extends DataNode { +export interface InternalDataEntity { key: Key; value: RawValueType; - label?: React.ReactNode; - children?: InnerDataNode[]; + title?: React.ReactNode; + disableCheckbox?: boolean; + disabled?: boolean; + children?: InternalDataEntity[]; + + /** Origin DataNode */ + node: DataNode; } export interface LegacyDataNode extends DataNode { @@ -47,8 +52,9 @@ export interface TreeDataNode extends DataNode { } export interface FlattenDataNode { - data: DataNode; + data: InternalDataEntity; key: Key; + value: RawValueType; level: number; parent?: FlattenDataNode; } @@ -81,3 +87,9 @@ export interface ChangeEventExtra { /** @deprecated This prop not work as react node anymore. */ allCheckedNodes: LegacyCheckedNode[]; } + +export interface FieldNames { + value?: string; + label?: string; + children?: string; +} diff --git a/src/utils/legacyUtil.tsx b/src/utils/legacyUtil.tsx index 4a32d3d2..878c53c2 100644 --- a/src/utils/legacyUtil.tsx +++ b/src/utils/legacyUtil.tsx @@ -5,7 +5,7 @@ import type { DataNode, LegacyDataNode, ChangeEventExtra, - InnerDataNode, + InternalDataEntity, RawValueType, LegacyCheckedNode, } from '../interface'; @@ -36,7 +36,7 @@ export function convertChildrenToData(nodes: React.ReactNode): DataNode[] { return data; }) - .filter((data) => data); + .filter(data => data); } export function fillLegacyProps(dataNode: DataNode): LegacyDataNode { @@ -66,20 +66,20 @@ export function fillAdditionalInfo( extra: ChangeEventExtra, triggerValue: RawValueType, checkedValues: RawValueType[], - treeData: InnerDataNode[], + treeData: InternalDataEntity[], showPosition: boolean, ) { let triggerNode: React.ReactNode = null; let nodeList: LegacyCheckedNode[] = null; function generateMap() { - function dig(list: InnerDataNode[], level = '0', parentIncluded = false) { + function dig(list: InternalDataEntity[], level = '0', parentIncluded = false) { return list .map((dataNode, index) => { const pos = `${level}-${index}`; const included = checkedValues.includes(dataNode.value); const children = dig(dataNode.children || [], pos, included); - const node = {children.map((child) => child.node)}; + const node = {children.map(child => child.node)}; // Link with trigger node if (triggerValue === dataNode.value) { @@ -101,7 +101,7 @@ export function fillAdditionalInfo( } return null; }) - .filter((node) => node); + .filter(node => node); } if (!nodeList) { diff --git a/src/utils/valueUtil.ts b/src/utils/valueUtil.ts index 6e6f54b3..b973301e 100644 --- a/src/utils/valueUtil.ts +++ b/src/utils/valueUtil.ts @@ -9,6 +9,8 @@ import type { DefaultValueType, LabelValueType, LegacyDataNode, + FieldNames, + InternalDataEntity, } from '../interface'; import { fillLegacyProps } from './legacyUtil'; import type { SkipType } from '../hooks/useKeyValueMapping'; @@ -22,12 +24,34 @@ export function toArray(value: T | T[]): T[] { return value !== undefined ? [value] : []; } +/** + * Fill `fieldNames` with default field names. + * + * @param fieldNames passed props + * @param skipTitle Skip if no need fill `title`. This is useful since we have 2 name as same title level + * @returns + */ +export function fillFieldNames(fieldNames?: FieldNames, skipTitle: boolean = false) { + const { label, value, children } = fieldNames || {}; + + const filledNames: FieldNames = { + value: value || 'value', + children: children || 'children', + }; + + if (!skipTitle || label) { + filledNames.label = label || 'label'; + } + + return filledNames; +} + export function findValueOption(values: RawValueType[], options: CompatibleDataNode[]): DataNode[] { const optionMap: Map = new Map(); options.forEach(flattenItem => { - const { data } = flattenItem; - optionMap.set(data.value, data); + const { data, value } = flattenItem; + optionMap.set(value, data.node); }); return values.map(val => fillLegacyProps(optionMap.get(val))); @@ -46,8 +70,9 @@ export function isCheckDisabled(node: DataNode) { return node.disabled || node.disableCheckbox || node.checkable === false; } -interface TreeDataNode { +interface TreeDataNode extends InternalDataEntity { key: Key; + children?: TreeDataNode[]; } function getLevel({ parent }: FlattenNode): number { @@ -65,13 +90,15 @@ function getLevel({ parent }: FlattenNode): number { /** * Before reuse `rc-tree` logic, we need to add key since TreeSelect use `value` instead of `key`. */ -export function flattenOptions(options: DataNode[]): FlattenDataNode[] { +export function flattenOptions(options: any): FlattenDataNode[] { + const typedOptions = options as InternalDataEntity[]; + // Add missing key - function fillKey(list: DataNode[]): TreeDataNode[] { + function fillKey(list: InternalDataEntity[]): TreeDataNode[] { return (list || []).map(node => { const { value, key, children } = node; - const clone = { + const clone: TreeDataNode = { ...node, key: 'key' in node ? key : value, }; @@ -84,19 +111,22 @@ export function flattenOptions(options: DataNode[]): FlattenDataNode[] { }); } - const flattenList = flattenTreeData(fillKey(options), true); + const flattenList = flattenTreeData(fillKey(typedOptions), true, null); const cacheMap = new Map(); const flattenDateNodeList: (FlattenDataNode & { parentKey?: React.Key })[] = flattenList.map( - node => { - const { data } = node; - const { key } = data; + option => { + const { data, key, value } = option as any as Omit & { + value: RawValueType; + data: InternalDataEntity; + }; const flattenNode = { key, + value, data, - level: getLevel(node), - parentKey: node.parent?.data.key, + level: getLevel(option), + parentKey: option.parent?.data.key, }; cacheMap.set(key, flattenNode); diff --git a/tests/Select.checkable.spec.js b/tests/Select.checkable.spec.js index fad39e94..727e44ec 100644 --- a/tests/Select.checkable.spec.js +++ b/tests/Select.checkable.spec.js @@ -1,4 +1,4 @@ -/* eslint-disable no-undef, react/no-multi-comp */ +/* eslint-disable no-undef, react/no-multi-comp, max-classes-per-file */ import React from 'react'; import { mount } from 'enzyme'; import TreeSelect, { SHOW_PARENT, SHOW_ALL, TreeNode } from '../src'; @@ -231,12 +231,7 @@ describe('TreeSelect.checkable', () => { wrapper.search('foo'); wrapper.clearAll(); expect(wrapper.getSelection()).toHaveLength(0); - expect( - wrapper - .find('input') - .first() - .props().value, - ).toBe(''); + expect(wrapper.find('input').first().props().value).toBe(''); }); describe('uncheck', () => { @@ -277,7 +272,10 @@ describe('TreeSelect.checkable', () => { }); wrapper.clearSelection(1); expect(onChange).toHaveBeenCalledWith( - [{ label: '0', value: '0' }, { label: '0-0-0', value: '0-0-0' }], + [ + { label: '0', value: '0' }, + { label: '0-0-0', value: '0-0-0' }, + ], null, expect.anything(), ); @@ -616,15 +614,15 @@ describe('TreeSelect.checkable', () => { value={[{ value: 'half', halfChecked: true }]} open onChange={onChange} - treeData={[{ value: 'half', title: 'Half Check' }, { value: 'full', title: 'Full Check' }]} + treeData={[ + { value: 'half', title: 'Half Check' }, + { value: 'full', title: 'Full Check' }, + ]} />, ); function getTreeNode(index) { - return wrapper - .find('.rc-tree-select-tree-treenode') - .not('[aria-hidden]') - .at(index); + return wrapper.find('.rc-tree-select-tree-treenode').not('[aria-hidden]').at(index); } expect( @@ -651,4 +649,39 @@ describe('TreeSelect.checkable', () => { expect.anything(), ); }); + + it('disableCheckbox', () => { + const onChange = jest.fn(); + const wrapper = mount( + , + ); + + wrapper.selectNode(0); + expect(onChange).toHaveBeenCalledWith(['parent', 'sub1'], expect.anything(), expect.anything()); + + onChange.mockReset(); + wrapper.selectNode(2); + wrapper.selectNode(3); + expect(onChange).not.toHaveBeenCalled(); + + wrapper.selectNode(1); + expect(onChange).toHaveBeenCalledWith([], expect.anything(), expect.anything()); + }); }); diff --git a/tests/Select.fieldNames.spec.tsx b/tests/Select.fieldNames.spec.tsx new file mode 100644 index 00000000..4af433c7 --- /dev/null +++ b/tests/Select.fieldNames.spec.tsx @@ -0,0 +1,89 @@ +/* eslint-disable no-undef, react/no-multi-comp, no-console */ +import React from 'react'; +import { mount } from 'enzyme'; +import type { TreeSelectProps } from '../src'; +import TreeSelect from '../src'; + +describe('TreeSelect.FieldNames', () => { + function mountTreeSelect(props?: TreeSelectProps) { + return mount( + , + ); + } + + it('render correctly', () => { + const onChange = jest.fn(); + const wrapper = mountTreeSelect({ onChange, open: true }); + wrapper.selectNode(1); + + expect(onChange).toHaveBeenCalledWith('sub_1', ['Sub 1'], expect.anything()); + }); + + it('labelInValue', () => { + const onChange = jest.fn(); + const wrapper = mountTreeSelect({ onChange, open: true, labelInValue: true }); + wrapper.selectNode(2); + + expect(onChange).toHaveBeenCalledWith( + { label: 'Sub 2', value: 'sub_2' }, + null, + expect.anything(), + ); + }); + + it('multiple', () => { + const onChange = jest.fn(); + const wrapper = mountTreeSelect({ onChange, open: true, multiple: true }); + + wrapper.selectNode(1); + + onChange.mockReset(); + wrapper.selectNode(2); + + expect(onChange).toHaveBeenCalledWith( + ['sub_1', 'sub_2'], + ['Sub 1', 'Sub 2'], + expect.anything(), + ); + }); + + it('onSelect', () => { + const onSelect = jest.fn(); + const wrapper = mountTreeSelect({ onSelect, open: true }); + + wrapper.selectNode(0); + + expect(onSelect).toHaveBeenCalledWith('parent', { + myChildren: [ + { myLabel: 'Sub 1', myValue: 'sub_1' }, + { myLabel: 'Sub 2', myValue: 'sub_2' }, + ], + myLabel: 'Parent', + myValue: 'parent', + }); + }); +}); diff --git a/tests/Select.internal.spec.tsx b/tests/Select.internal.spec.tsx index 8bb3ba29..5180eff3 100644 --- a/tests/Select.internal.spec.tsx +++ b/tests/Select.internal.spec.tsx @@ -21,7 +21,7 @@ describe('TreeSelect.InternalAPI', () => { const nodes = []; while (current) { - nodes.unshift(current.data.label); + nodes.unshift(current.data.node.label); current = current.parent; } diff --git a/tests/Select.multiple.spec.js b/tests/Select.multiple.spec.js index d273a1d8..2fb38350 100644 --- a/tests/Select.multiple.spec.js +++ b/tests/Select.multiple.spec.js @@ -12,9 +12,7 @@ describe('TreeSelect.multiple', () => { { key: '0', value: '0', title: 'label0' }, { key: '1', value: '1', title: 'label1' }, ]; - const createSelect = props => ( - - ); + const createSelect = props => ; it('select multiple nodes', () => { const wrapper = mount(createSelect({ open: true })); @@ -33,10 +31,7 @@ describe('TreeSelect.multiple', () => { it('remove by backspace key', () => { const wrapper = mount(createSelect({ defaultValue: ['0', '1'] })); - wrapper - .find('input') - .first() - .simulate('keyDown', { which: KeyCode.BACKSPACE }); + wrapper.find('input').first().simulate('keyDown', { which: KeyCode.BACKSPACE }); expect(wrapper.getSelection()).toHaveLength(1); expect(wrapper.getSelection(0).text()).toBe('label0'); }); @@ -63,15 +58,9 @@ describe('TreeSelect.multiple', () => { } } const wrapper = mount(); - wrapper - .find('input') - .first() - .simulate('keyDown', { which: KeyCode.BACKSPACE }); + wrapper.find('input').first().simulate('keyDown', { which: KeyCode.BACKSPACE }); wrapper.selectNode(1); - wrapper - .find('input') - .first() - .simulate('keyDown', { which: KeyCode.BACKSPACE }); + wrapper.find('input').first().simulate('keyDown', { which: KeyCode.BACKSPACE }); expect(wrapper.getSelection()).toHaveLength(1); expect(wrapper.getSelection(0).text()).toBe('label0'); }); @@ -96,10 +85,12 @@ describe('TreeSelect.multiple', () => { wrapper.clearSelection(1); + expect(handleChange.mock.calls[0][2].allCheckedNodes[0].props).toBeTruthy(); + expect(handleChange).toHaveBeenCalledWith( ['0'], ['label0'], - expect.objectContaining({ + expect.anything({ allCheckedNodes: [ expect.objectContaining({ props: expect.objectContaining(children[0].props), @@ -120,21 +111,11 @@ describe('TreeSelect.multiple', () => { wrapper.search('0'); wrapper.selectNode(0); - expect( - wrapper - .find('input') - .first() - .props().value, - ).toBe(''); + expect(wrapper.find('input').first().props().value).toBe(''); wrapper.search('0'); wrapper.selectNode(0); - expect( - wrapper - .find('input') - .first() - .props().value, - ).toBe(''); + expect(wrapper.find('input').first().props().value).toBe(''); }); it('do not open tree when close button click', () => { @@ -238,19 +219,11 @@ describe('TreeSelect.multiple', () => { ); wrapper.selectNode(0); - expect(onChange).toHaveBeenCalledWith( - [4, 0], - expect.anything(), - expect.anything(), - ); + expect(onChange).toHaveBeenCalledWith([4, 0], expect.anything(), expect.anything()); onChange.mockReset(); wrapper.selectNode(1); - expect(onChange).toHaveBeenCalledWith( - [4, 0, 2, 3], - expect.anything(), - expect.anything(), - ); + expect(onChange).toHaveBeenCalledWith([4, 0, 2, 3], expect.anything(), expect.anything()); }); // https://github.com/ant-design/ant-design/issues/12315 @@ -271,11 +244,7 @@ describe('TreeSelect.multiple', () => { wrapper.search('sss'); wrapper.selectNode(2); - expect(onChange).toHaveBeenCalledWith( - ['leaf1', 'sss'], - expect.anything(), - expect.anything(), - ); + expect(onChange).toHaveBeenCalledWith(['leaf1', 'sss'], expect.anything(), expect.anything()); }); it('do not crash when value has empty string', () => { diff --git a/tests/Select.props.spec.js b/tests/Select.props.spec.js index d5ac5517..724cfc14 100644 --- a/tests/Select.props.spec.js +++ b/tests/Select.props.spec.js @@ -239,12 +239,9 @@ describe('TreeSelect.props', () => { dropdownStyle: style, }), ); - expect( - wrapper - .find('.test-dropdownClassName') - .first() - .props().style, - ).toEqual(expect.objectContaining(style)); + expect(wrapper.find('.test-dropdownClassName').first().props().style).toEqual( + expect.objectContaining(style), + ); }); it('notFoundContent', () => { @@ -449,12 +446,7 @@ describe('TreeSelect.props', () => { it('getPopupContainer', () => { const getPopupContainer = trigger => trigger.parentNode; const wrapper = mount(createOpenSelect({ getPopupContainer })); - expect( - wrapper - .find('Trigger') - .first() - .props().getPopupContainer, - ).toBe(getPopupContainer); + expect(wrapper.find('Trigger').first().props().getPopupContainer).toBe(getPopupContainer); }); it('set value not in the Tree', () => { diff --git a/tests/__snapshots__/Select.checkable.spec.js.snap b/tests/__snapshots__/Select.checkable.spec.js.snap index cb461788..470162d7 100644 --- a/tests/__snapshots__/Select.checkable.spec.js.snap +++ b/tests/__snapshots__/Select.checkable.spec.js.snap @@ -17,6 +17,7 @@ exports[`TreeSelect.checkable uncheck remove by selector not treeCheckStrictly 1 >
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
{ - it('isValueDisabled', () => { - const options = [{ data: { value: 'disabled', disabled: true } }, { data: { value: 'pass' } }]; - expect(isValueDisabled('disabled', options)).toBeTruthy(); - expect(isValueDisabled('pass', options)).toBeFalsy(); - expect(isValueDisabled('not-exist', options)).toBeFalsy(); - }); - - it('isDisabled', () => { - expect(isDisabled({ data: { disabled: true } }, 'select')).toBeTruthy(); - expect(isDisabled({ data: { disableCheckbox: true } }, 'select')).toBeFalsy(); - expect(isDisabled({ data: { disabled: true } }, 'checkbox')).toBeTruthy(); - expect(isDisabled({ data: { disableCheckbox: true } }, 'checkbox')).toBeTruthy(); - expect(isDisabled({ data: { disabled: true } }, null)).toBeFalsy(); - }); -});