Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Add optional onItemClick callback to ComboBox.",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "keco@microsoft.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2908,6 +2908,7 @@ interface IComboBoxProps extends ISelectableDroppableTextProps<IComboBox> {
onChange?: (event: React.FormEvent<IComboBox>, option?: IComboBoxOption, index?: number, value?: string) => void;
// @deprecated
onChanged?: (option?: IComboBoxOption, index?: number, value?: string, submitPendingValueEvent?: any) => void;
onItemClick?: (event: React.FormEvent<IComboBox>, option?: IComboBoxOption, index?: number) => void;
onMenuDismissed?: () => void;
onMenuOpen?: () => void;
onPendingValueChanged?: (option?: IComboBoxOption, index?: number, value?: string) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ const DEFAULT_OPTIONS3: IComboBoxOption[] = [
{ key: '3', text: 'Bar' }
];

let wrapper: ReactWrapper<any, any>;

describe('ComboBox', () => {
afterEach(() => {
if (wrapper && wrapper.length) {
wrapper.unmount();
}
});

it('Renders ComboBox correctly', () => {
const createNodeMock = (el: React.ReactElement<{}>) => {
return {
Expand Down Expand Up @@ -49,7 +57,7 @@ describe('ComboBox', () => {
});

it('Can flip between enabled and disabled.', () => {
let wrapper = mount(<ComboBox disabled={false} label="testgroup" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox disabled={false} label="testgroup" options={DEFAULT_OPTIONS} />);

expectMissing(wrapper, '.ms-ComboBox.is-disabled');
expectOne(wrapper, '[data-is-interactable=true]');
Expand All @@ -61,21 +69,21 @@ describe('ComboBox', () => {
});

it('Renders no selected item in default case', () => {
const wrapper = mount(<ComboBox label="testgroup" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox label="testgroup" options={DEFAULT_OPTIONS} />);

expect(wrapper.find('input[role="combobox"]').text()).toEqual('');
});

it('Renders a selected item in uncontrolled case', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS} />);
const comboBoxRoot = wrapper.find('.ms-ComboBox');
const inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any> = comboBoxRoot.find('input');

expect(inputElement.props().value).toEqual('1');
});

it('Renders a selected item in controlled case', () => {
const wrapper = mount(<ComboBox label="testgroup" selectedKey="1" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox label="testgroup" selectedKey="1" options={DEFAULT_OPTIONS} />);
const comboBoxRoot = wrapper.find('.ms-ComboBox');
const inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any> = comboBoxRoot.find('input');

Expand All @@ -84,7 +92,7 @@ describe('ComboBox', () => {

it('Renders a selected item with zero key', () => {
const options: IComboBoxOption[] = [{ key: 0, text: 'zero' }, { key: 1, text: 'one' }];
const wrapper = mount(<ComboBox selectedKey={0} options={options} label="testgroup" />);
wrapper = mount(<ComboBox selectedKey={0} options={options} label="testgroup" />);
const comboBoxRoot = wrapper.find('.ms-ComboBox');
const inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any> = comboBoxRoot.find('input');
expect(inputElement.props().value).toEqual('zero');
Expand All @@ -101,7 +109,7 @@ describe('ComboBox', () => {
comboBoxComponent = ref;
};

const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" options={DEFAULT_OPTIONS} allowFreeform={true} onChange={returnUndefined} componentRef={setRef} />
);
comboBoxRoot = wrapper.find('.ms-ComboBox');
Expand All @@ -119,7 +127,7 @@ describe('ComboBox', () => {
comboBoxComponent = ref;
};

const wrapper = mount(<ComboBox label="testgroup" options={DEFAULT_OPTIONS} allowFreeform={true} componentRef={setRef} />);
wrapper = mount(<ComboBox label="testgroup" options={DEFAULT_OPTIONS} allowFreeform={true} componentRef={setRef} />);
comboBoxRoot = wrapper.find('.ms-ComboBox');
inputElement = comboBoxRoot.find('input');
inputElement.simulate('input', { target: { value: 'f' } });
Expand All @@ -130,23 +138,23 @@ describe('ComboBox', () => {
});

it('Renders a default value with options', () => {
const wrapper = mount(<ComboBox label="testgroup" text="1" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox label="testgroup" text="1" options={DEFAULT_OPTIONS} />);
const comboBoxRoot = wrapper.find('.ms-ComboBox');
const inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any> = comboBoxRoot.find('input');

expect(inputElement.props().value).toEqual('1');
});

it('Renders a default value with no options', () => {
const wrapper = mount(<ComboBox label="testgroup" options={[]} text="1" />);
wrapper = mount(<ComboBox label="testgroup" options={[]} text="1" />);
const comboBoxRoot = wrapper.find('.ms-ComboBox');
const inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any> = comboBoxRoot.find('input');

expect(inputElement.props().value).toEqual('1');
});

it('Can change items in uncontrolled case', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS} />);

// Manually assign `offsetParent` and `scrollIntoView` since it doesn't exist without DOM
const el = document.createElement('div') as Element;
Expand All @@ -166,7 +174,7 @@ describe('ComboBox', () => {
});

it('Can insert text in uncontrolled case with autoComplete and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={true} />
);

Expand All @@ -176,7 +184,7 @@ describe('ComboBox', () => {
});

it('Can insert text in uncontrolled case with autoComplete on and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={false} />
);

Expand All @@ -186,7 +194,7 @@ describe('ComboBox', () => {
});

it('Can insert text in uncontrolled case with autoComplete off and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={true} />
);
wrapper.find('input').simulate('input', { target: { value: 'f' } });
Expand All @@ -195,7 +203,7 @@ describe('ComboBox', () => {
});

it('Can insert text in uncontrolled case with autoComplete and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={false} />
);
wrapper.find('input').simulate('keydown', { which: 'f' });
Expand All @@ -204,7 +212,7 @@ describe('ComboBox', () => {
});

it('Can insert an empty string in uncontrolled case with autoComplete and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={true} />
);
(wrapper.find('input').instance() as any).value = '';
Expand All @@ -215,7 +223,7 @@ describe('ComboBox', () => {
});

it('Cannot insert an empty string in uncontrolled case with autoComplete on and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={false} />
);

Expand All @@ -227,7 +235,7 @@ describe('ComboBox', () => {
});

it('Can insert an empty string in uncontrolled case with autoComplete off and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={true} />
);
(wrapper.find('input').instance() as any).value = '';
Expand All @@ -238,7 +246,7 @@ describe('ComboBox', () => {
});

it('Cannot insert an empty string in uncontrolled case with autoComplete and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={false} />
);
(wrapper.find('input').instance() as any).value = '';
Expand All @@ -251,7 +259,7 @@ describe('ComboBox', () => {
// jeremy

it('Can insert an empty string after removing a pending value in uncontrolled case with autoComplete and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={true} />
);

Expand All @@ -265,7 +273,7 @@ describe('ComboBox', () => {
});

it('Cannot insert an empty string after removing a pending value in uncontrolled case with autoComplete on and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="on" allowFreeform={false} />
);

Expand All @@ -279,7 +287,7 @@ describe('ComboBox', () => {
});

it('Can insert an empty string after removing a pending value in uncontrolled case with autoComplete off and allowFreeform on', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={true} />
);

Expand All @@ -293,7 +301,7 @@ describe('ComboBox', () => {
});

it('Cannot insert an empty string after removing a pending value in uncontrolled case with autoComplete and allowFreeform off', () => {
const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} autoComplete="off" allowFreeform={false} />
);
(wrapper.find('input').instance() as any).value = 'f';
Expand All @@ -306,57 +314,57 @@ describe('ComboBox', () => {
});

it('Can change selected option with keyboard', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.down });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('Foo');
});

it('Can change selected option with keyboard, looping from top to bottom', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.up });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('Bar');
});

it('Can change selected option with keyboard, looping from bottom to top', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="3" options={DEFAULT_OPTIONS2} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="3" options={DEFAULT_OPTIONS2} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.down });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('One');
});

it('Can change selected option with keyboard, looping from top to bottom', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS3} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS3} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.up });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('Bar');
});

it('Cannot insert text while disabled', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.a });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('One');
});

it('Cannot change selected option with keyboard while disabled', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.down });
wrapper.update();
expect(wrapper.find('input').props().value).toEqual('One');
});

it('Cannot expand the menu when clicking on the input while disabled', () => {
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper.find('input').simulate('click');
expect(wrapper.find('.is-opened').length).toEqual(0);
});

it('Cannot expand the menu when clicking on the button while disabled', () => {
let comboBoxRoot;
let buttonElement;
const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} disabled={true} />);
comboBoxRoot = wrapper.find('.ms-ComboBox');
buttonElement = comboBoxRoot.find('button');
buttonElement.simulate('click');
Expand All @@ -368,7 +376,7 @@ describe('ComboBox', () => {
let buttonElement;
const returnUndefined = jest.fn();

const wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} onMenuOpen={returnUndefined} />);
wrapper = mount(<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} onMenuOpen={returnUndefined} />);
comboBoxRoot = wrapper.find('.ms-ComboBox');
buttonElement = comboBoxRoot.find('button');
buttonElement.simulate('click');
Expand All @@ -380,7 +388,7 @@ describe('ComboBox', () => {
let inputElement;
const returnUndefined = jest.fn();

const wrapper = mount(
wrapper = mount(
<ComboBox label="testgroup" defaultSelectedKey="1" options={DEFAULT_OPTIONS2} onMenuOpen={returnUndefined} allowFreeform={true} />
);
comboBoxRoot = wrapper.find('.ms-ComboBox');
Expand All @@ -405,7 +413,7 @@ describe('ComboBox', () => {
indexSeen.push(index);
}
};
const wrapper = mount(
wrapper = mount(
<ComboBox
label="testgroup"
options={DEFAULT_OPTIONS}
Expand All @@ -431,7 +439,7 @@ describe('ComboBox', () => {

let comboBoxRoot;
let inputElement: ReactWrapper<React.InputHTMLAttributes<any>, any>;
const wrapper = mount(
wrapper = mount(
<ComboBox
label="testgroup"
options={[initialOption]}
Expand Down Expand Up @@ -473,7 +481,7 @@ describe('ComboBox', () => {

it('Can clear text in controlled case with autoComplete off and allowFreeform on', () => {
let updatedText;
const wrapper = mount(
wrapper = mount(
<ComboBox
label="testgroup"
options={DEFAULT_OPTIONS}
Expand All @@ -495,4 +503,15 @@ describe('ComboBox', () => {

expect(updatedText).toEqual('');
});

it('invokes optional onItemClick callback on option select', () => {
const onItemClickMock = jest.fn();
wrapper = mount(<ComboBox options={DEFAULT_OPTIONS} onItemClick={onItemClickMock} />);
wrapper.find('input').simulate('keydown', { which: KeyCodes.enter });
const buttons = document.querySelectorAll('.ms-ComboBox-option');

(buttons[0] as HTMLButtonElement).click();

expect(onItemClickMock).toHaveBeenCalledTimes(1);
});
});
Loading