diff options
author | Mathieu Suen <mathieu.suen@sonarsource.com> | 2022-10-18 14:36:44 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-10-21 20:03:17 +0000 |
commit | 483c51b8401fd096553bf64d946651e5024fd3eb (patch) | |
tree | aca117466e3bfa8577a6b5056db5da4abda26b13 /server | |
parent | d75de0570fc03c35f71569021454aa1d1f326d62 (diff) | |
download | sonarqube-483c51b8401fd096553bf64d946651e5024fd3eb.tar.gz sonarqube-483c51b8401fd096553bf64d946651e5024fd3eb.zip |
SONAR-17453 Fixed order when changing selection in nulti select ui
Diffstat (limited to 'server')
6 files changed, 179 insertions, 625 deletions
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx index ff01303af80..efffa6b4851 100644 --- a/server/sonar-web/src/main/js/components/common/MultiSelect.tsx +++ b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx @@ -18,20 +18,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import classNames from 'classnames'; -import { difference } from 'lodash'; +import { isEmpty, remove, xor } from 'lodash'; import * as React from 'react'; import SearchBox from '../../components/controls/SearchBox'; -import { isShortcut } from '../../helpers/keyboardEventHelpers'; -import { KeyboardKeys } from '../../helpers/keycodes'; import { translateWithParameters } from '../../helpers/l10n'; -import MultiSelectOption from './MultiSelectOption'; +import MultiSelectOption, { Element } from './MultiSelectOption'; export interface MultiSelectProps { allowNewElements?: boolean; allowSelection?: boolean; legend: string; elements: string[]; - // eslint-disable-next-line react/no-unused-prop-types filterSelected?: (query: string, selectedElements: string[]) => string[]; footerNode?: React.ReactNode; listSize?: number; @@ -45,11 +42,9 @@ export interface MultiSelectProps { } interface State { - activeIdx: number; loading: boolean; query: string; - selectedElements: string[]; - unselectedElements: string[]; + elements: Element[]; } interface DefaultProps { @@ -63,8 +58,6 @@ interface DefaultProps { type PropsWithDefault = MultiSelectProps & DefaultProps; export default class MultiSelect extends React.PureComponent<PropsWithDefault, State> { - container?: HTMLDivElement | null; - searchInput?: HTMLInputElement | null; mounted = false; static defaultProps: DefaultProps = { @@ -78,51 +71,79 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S constructor(props: PropsWithDefault) { super(props); this.state = { - activeIdx: 0, - loading: true, + loading: false, query: '', - selectedElements: [], - unselectedElements: [] + elements: [] }; } componentDidMount() { this.mounted = true; this.onSearchQuery(''); - this.updateSelectedElements(this.props as PropsWithDefault); - this.updateUnselectedElements(this.props as PropsWithDefault); - if (this.container) { - this.container.addEventListener('keydown', this.handleKeyboard, true); - } + this.computeElements(); } - componentDidUpdate(prevProps: PropsWithDefault) { + componentDidUpdate(prevProps: PropsWithDefault, prevState: State) { if ( - prevProps.elements !== this.props.elements || - prevProps.selectedElements !== this.props.selectedElements + !isEmpty( + xor( + [...prevProps.selectedElements, ...prevProps.elements], + [...this.props.selectedElements, ...this.props.elements] + ) + ) ) { - this.updateSelectedElements(this.props); - this.updateUnselectedElements(this.props); - - const totalElements = this.getAllElements(this.props, this.state).length; - if (this.state.activeIdx >= totalElements) { - this.setState({ activeIdx: totalElements - 1 }); - } + this.computeElements(); } - if (this.searchInput) { - this.searchInput.focus(); + if (prevState.query !== this.state.query) { + this.setState(({ query, elements }, props) => { + const newElements = [...elements]; + this.appendCreateElelement(newElements, query, props); + return { elements: newElements }; + }); } } componentWillUnmount() { this.mounted = false; - if (this.container) { - this.container.removeEventListener('keydown', this.handleKeyboard, true); + } + + computeElements() { + this.setState(({ query }, props) => { + const newStateElement: Element[] = [ + ...this.props + .filterSelected(query, this.props.selectedElements) + .map(e => ({ value: e, selected: true })), + ...this.props.elements.map(e => ({ + value: e, + selected: false + })) + ]; + + this.appendCreateElelement(newStateElement, query, props); + return { elements: newStateElement }; + }); + } + + appendCreateElelement(elements: Element[], query: string, props: PropsWithDefault) { + const { allowNewElements = true } = props; + if (this.isNewElement(query, props) && allowNewElements) { + const create = elements.find(e => e.custom); + if (create) { + create.value = query; + } else { + elements.push({ value: query, selected: false, custom: true }); + } + } else if (!this.isNewElement(query, props) && allowNewElements) { + remove(elements, e => e.custom); } } handleSelectChange = (selected: boolean, item: string) => { + this.setState(({ elements }) => { + const newElements = elements.map(e => (e.value === item ? { value: e.value, selected } : e)); + return { elements: newElements }; + }); if (selected) { this.onSelectItem(item); } else { @@ -134,42 +155,16 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S this.onSearchQuery((this.props as PropsWithDefault).validateSearchInput(value)); }; - handleElementHover = (element: string) => { - this.setState((prevState, props) => { - return { activeIdx: this.getAllElements(props, prevState).indexOf(element) }; - }); - }; - - handleKeyboard = (event: KeyboardEvent) => { - if (isShortcut(event)) { - return true; - } - switch (event.key) { - case KeyboardKeys.DownArrow: - event.stopPropagation(); - event.preventDefault(); - this.setState(this.selectNextElement); - break; - case KeyboardKeys.UpArrow: - event.stopPropagation(); - event.preventDefault(); - this.setState(this.selectPreviousElement); - break; - case KeyboardKeys.LeftArrow: - case KeyboardKeys.RightArrow: - event.stopPropagation(); - break; - case KeyboardKeys.Enter: - if (this.state.activeIdx >= 0) { - this.toggleSelect(this.getAllElements(this.props, this.state)[this.state.activeIdx]); - } - break; - } - }; - onSearchQuery = (query: string) => { - this.setState({ activeIdx: 0, loading: true, query }); + const { allowNewElements = true } = this.props; + this.props.onSearch(query).then(this.stopLoading, this.stopLoading); + if (allowNewElements) { + this.setState({ + loading: true, + query + }); + } }; onSelectItem = (item: string) => { @@ -182,67 +177,7 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S onUnselectItem = (item: string) => this.props.onUnselect(item); isNewElement = (elem: string, { selectedElements, elements }: PropsWithDefault) => - elem.length > 0 && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1; - - updateSelectedElements = (props: PropsWithDefault) => { - this.setState((state: State) => { - if (state.query) { - return { - selectedElements: props.filterSelected(state.query, props.selectedElements) - }; - } else { - return { selectedElements: [...props.selectedElements] }; - } - }); - }; - - updateUnselectedElements = (props: PropsWithDefault) => { - this.setState((state: State) => { - if (props.listSize === 0) { - return { unselectedElements: difference(props.elements, props.selectedElements) }; - } else if (props.listSize < state.selectedElements.length) { - return { unselectedElements: [] }; - } else { - return { - unselectedElements: difference(props.elements, props.selectedElements).slice( - 0, - props.listSize - state.selectedElements.length - ) - }; - } - }); - }; - - getAllElements = (props: PropsWithDefault, state: State) => { - if (this.isNewElement(state.query, props)) { - return [...state.selectedElements, ...state.unselectedElements, state.query]; - } else { - return [...state.selectedElements, ...state.unselectedElements]; - } - }; - - setElementActive = (idx: number) => this.setState({ activeIdx: idx }); - - selectNextElement = (state: State, props: PropsWithDefault) => { - const { activeIdx } = state; - const allElements = this.getAllElements(props, state); - if (activeIdx < 0 || activeIdx >= allElements.length - 1) { - return { activeIdx: 0 }; - } else { - return { activeIdx: activeIdx + 1 }; - } - }; - - selectPreviousElement = (state: State, props: PropsWithDefault) => { - const { activeIdx } = state; - const allElements = this.getAllElements(props, state); - if (activeIdx <= 0) { - const lastIdx = allElements.length - 1; - return { activeIdx: lastIdx }; - } else { - return { activeIdx: activeIdx - 1 }; - } - }; + !isEmpty(elem) && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1; stopLoading = () => { if (this.mounted) { @@ -250,20 +185,10 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S } }; - toggleSelect = (item: string) => { - if (this.props.selectedElements.indexOf(item) === -1) { - this.onSelectItem(item); - } else { - this.onUnselectItem(item); - } - }; - render() { - const { legend, allowSelection = true, allowNewElements = true, footerNode = '' } = this.props; + const { legend, allowSelection = true, footerNode = '' } = this.props; const { renderLabel } = this.props as PropsWithDefault; - const { query, activeIdx, selectedElements, unselectedElements } = this.state; - const activeElement = this.getAllElements(this.props, this.state)[activeIdx]; - const showNewElement = allowNewElements && this.isNewElement(query, this.props); + const { query, elements } = this.state; const infiniteList = this.props.listSize === 0; const listClasses = classNames('menu', { 'menu-vertically-limited': infiniteList, @@ -273,7 +198,7 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S }); return ( - <div className="multi-select" ref={div => (this.container = div)}> + <div className="multi-select"> <div className="menu-search"> <SearchBox autoFocus={true} @@ -286,42 +211,16 @@ export default class MultiSelect extends React.PureComponent<PropsWithDefault, S </div> <fieldset aria-label={legend}> <ul className={listClasses}> - {selectedElements.length > 0 && - selectedElements.map(element => ( - <MultiSelectOption - active={activeElement === element} - element={element} - key={element} - onHover={this.handleElementHover} - onSelectChange={this.handleSelectChange} - renderLabel={renderLabel} - selected={true} - /> - ))} - {unselectedElements.length > 0 && - unselectedElements.map(element => ( - <MultiSelectOption - active={activeElement === element} - disabled={!allowSelection} - element={element} - key={element} - onHover={this.handleElementHover} - onSelectChange={this.handleSelectChange} - renderLabel={renderLabel} - /> - ))} - {showNewElement && ( + {elements.map(e => ( <MultiSelectOption - active={activeElement === query} - custom={true} - element={query} - key={query} - onHover={this.handleElementHover} + element={e} + disabled={!allowSelection && !e.selected} + key={e.value} onSelectChange={this.handleSelectChange} renderLabel={renderLabel} /> - )} - {!showNewElement && selectedElements.length < 1 && unselectedElements.length < 1 && ( + ))} + {isEmpty(elements) && ( <li className="spacer-left">{translateWithParameters('no_results_for_x', query)}</li> )} </ul> diff --git a/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx index f3da85c78e8..70063767fd3 100644 --- a/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx +++ b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx @@ -22,32 +22,38 @@ import * as React from 'react'; import Checkbox from '../../components/controls/Checkbox'; import { translate } from '../../helpers/l10n'; -export interface MultiSelectOptionProps { - active?: boolean; +export interface Element { + value: string; + selected: boolean; custom?: boolean; +} + +export interface MultiSelectOptionProps { disabled?: boolean; - element: string; - onHover: (element: string) => void; + element: Element; onSelectChange: (selected: boolean, element: string) => void; renderLabel: (element: string) => React.ReactNode; - selected?: boolean; } export default function MultiSelectOption(props: MultiSelectOptionProps) { - const { active, custom, disabled, element, selected } = props; - const onHover = () => props.onHover(element); + const { disabled, element } = props; + const [active, setActive] = React.useState(false); const className = classNames({ active, disabled }); - const label = props.renderLabel(element); + const label = props.renderLabel(element.value); return ( - <li onFocus={onHover} onMouseOver={onHover}> + <li + onFocus={() => setActive(true)} + onBlur={() => setActive(false)} + onMouseLeave={() => setActive(false)} + onMouseOver={() => setActive(true)}> <Checkbox - checked={Boolean(selected)} + checked={element.selected} className={className} disabled={disabled} - id={element} + id={element.value} onCheck={props.onSelectChange}> - {custom ? ( + {element.custom ? ( <span aria-label={`${translate('create_new_element')}: ${label}`} className="little-spacer-left"> diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx index a2e5c946cbd..bc8fd239ee0 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx +++ b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx @@ -17,92 +17,105 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { mount, shallow } from 'enzyme'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import { KeyboardKeys } from '../../../helpers/keycodes'; -import { mockEvent } from '../../../helpers/testUtils'; -import MultiSelect, { MultiSelectProps } from '../MultiSelect'; +import { byRole, byText } from 'testing-library-selector'; +import MultiSelect from '../MultiSelect'; -const props = { - selectedElements: ['bar'], - elements: [], - onSearch: () => Promise.resolve(), - onSelect: () => {}, - onUnselect: () => {}, - renderLabel: (element: string) => element, - placeholder: '' +const ui = { + checkbox: (name: string) => byRole('checkbox', { name }), + search: byRole('searchbox', { name: 'search_verb' }), + noResult: byText('no_results_for_x.notfound') }; -const elements = ['foo', 'bar', 'baz']; +it('should handle selection', async () => { + const user = userEvent.setup(); + const rerender = renderMultiSelect(); + expect(ui.checkbox('az').get()).toBeChecked(); + await user.click(ui.checkbox('az').get()); + expect(ui.checkbox('az').get()).not.toBeChecked(); -it('should render multiselect with selected elements', () => { - const multiselect = shallowRender(); - // Will not only the selected element - expect(multiselect).toMatchSnapshot(); + await user.type(ui.search.get(), 'create'); + await user.click(ui.checkbox('create_new_element: create').get()); + expect(ui.checkbox('create').get()).toBeChecked(); - multiselect.setProps({ elements }); - expect(multiselect).toMatchSnapshot(); - multiselect.setState({ activeIdx: 2 }); - expect(multiselect).toMatchSnapshot(); - multiselect.setState({ query: 'test' }); - expect(multiselect).toMatchSnapshot(); + // Custom label + rerender({ renderLabel: label => `prefxed-${label}` }); + expect(ui.checkbox('prefxed-create').get()).toBeChecked(); }); -it('should render with the focus inside the search input', () => { - /* - * Need to attach to document body to have it set to `document.activeElement` - * See: https://github.com/jsdom/jsdom/issues/2723#issuecomment-580163361 - */ - const container = document.createElement('div'); - document.body.appendChild(container); - const multiselect = mount(<MultiSelect legend="multi select" {...props} />, { - attachTo: container - }); - - expect(multiselect.find('input').getDOMNode()).toBe(document.activeElement); - - multiselect.unmount(); -}); - -it.each([ - [KeyboardKeys.DownArrow, 1, 1], - [KeyboardKeys.UpArrow, 1, 1], - [KeyboardKeys.LeftArrow, 1, 0] -])('should handle keyboard event: %s', (key, stopPropagationCalls, preventDefaultCalls) => { - const wrapper = shallowRender(); - - const stopPropagation = jest.fn(); - const preventDefault = jest.fn(); - const event = mockEvent({ preventDefault, stopPropagation, key }); - - wrapper.instance().handleKeyboard(event); - - expect(stopPropagation).toBeCalledTimes(stopPropagationCalls); - expect(preventDefault).toBeCalledTimes(preventDefaultCalls); +it('should handle disable selection', () => { + renderMultiSelect({ allowSelection: false }); + expect(ui.checkbox('az').get()).toBeChecked(); + expect(ui.checkbox('cx').get()).toHaveAttribute('aria-disabled', 'true'); }); -it('should handle keyboard event: enter', () => { - const wrapper = shallowRender(); - - wrapper.instance().toggleSelect = jest.fn(); - - wrapper.instance().handleKeyboard(mockEvent({ key: KeyboardKeys.Enter })); - - expect(wrapper.instance().toggleSelect).toBeCalled(); +it('should handle search', async () => { + const user = userEvent.setup(); + const rerender = renderMultiSelect(); + expect(ui.checkbox('cx').get()).toBeInTheDocument(); + await user.type(ui.search.get(), 'az'); + expect(ui.checkbox('cx').query()).not.toBeInTheDocument(); + expect(ui.checkbox('az').get()).toBeInTheDocument(); + expect(ui.checkbox('az-new').get()).toBeInTheDocument(); + + await user.clear(ui.search.get()); + await user.type(ui.search.get(), 'notfound'); + expect(ui.checkbox('create_new_element: notfound').get()).toBeInTheDocument(); + + rerender({ allowNewElements: false }); + await user.clear(ui.search.get()); + await user.type(ui.search.get(), 'notfound'); + expect(ui.noResult.get()).toBeInTheDocument(); }); -function shallowRender(overrides: Partial<MultiSelectProps> = {}) { - return shallow<MultiSelect>( - <MultiSelect - selectedElements={['bar']} - elements={[]} - legend="multi select" - onSearch={() => Promise.resolve()} - onSelect={jest.fn()} - onUnselect={jest.fn()} - renderLabel={(element: string) => element} - placeholder="" - {...overrides} - /> - ); +function renderMultiSelect(override?: Partial<MultiSelect['props']>) { + const initial = ['cx', 'dw', 'ev', 'fu', 'gt', 'hs']; + const initialSelected = ['az', 'by']; + + function Parent(props?: Partial<MultiSelect['props']>) { + const [elements, setElements] = React.useState(initial); + const [selected, setSelected] = React.useState(['az', 'by']); + const onSearch = (query: string) => { + if (query === 'notfound') { + setElements([]); + setSelected([]); + } else if (query === '') { + setElements(initial); + setSelected(initialSelected); + } else { + setElements([...elements.filter(e => e.indexOf(query) !== -1), `${query}-new`]); + setSelected(selected.filter(e => e.indexOf(query) !== -1)); + } + return Promise.resolve(); + }; + + const onSelect = (element: string) => { + setSelected([...selected, element]); + setElements(elements.filter(e => e !== element)); + }; + + const onUnselect = (element: string) => { + setElements([...elements, element]); + setSelected(selected.filter(e => e !== element)); + }; + return ( + <MultiSelect + selectedElements={selected} + elements={elements} + legend="multi select" + onSearch={onSearch} + onSelect={onSelect} + onUnselect={onUnselect} + placeholder="" + {...props} + /> + ); + } + + const { rerender } = render(<Parent {...override} />); + return function(reoverride?: Partial<MultiSelect['props']>) { + rerender(<Parent {...override} {...reoverride} />); + }; } diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx deleted file mode 100644 index 28e09b68c5b..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import MultiSelectOption, { MultiSelectOptionProps } from '../MultiSelectOption'; - -it('should render standard element', () => { - expect(shallowRender()).toMatchSnapshot('default element'); - expect(shallowRender({ selected: true })).toMatchSnapshot('selected element'); - expect(shallowRender({ custom: true })).toMatchSnapshot('custom element'); - expect(shallowRender({ active: true, selected: true })).toMatchSnapshot('active element'); - expect(shallowRender({ disabled: true })).toMatchSnapshot('disabled element'); -}); - -function shallowRender(props: Partial<MultiSelectOptionProps> = {}) { - return shallow( - <MultiSelectOption - element="mytag" - onHover={jest.fn()} - onSelectChange={jest.fn()} - renderLabel={(element: string) => element} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap deleted file mode 100644 index 2ec8d126534..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap +++ /dev/null @@ -1,208 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render multiselect with selected elements 1`] = ` -<div - className="multi-select" -> - <div - className="menu-search" - > - <SearchBox - autoFocus={true} - className="little-spacer-top" - loading={true} - onChange={[Function]} - placeholder="" - value="" - /> - </div> - <fieldset - aria-label="multi select" - > - <ul - className="menu menu-vertically-limited spacer-top with-top-separator" - > - <MultiSelectOption - active={true} - element="bar" - key="bar" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - selected={true} - /> - </ul> - </fieldset> -</div> -`; - -exports[`should render multiselect with selected elements 2`] = ` -<div - className="multi-select" -> - <div - className="menu-search" - > - <SearchBox - autoFocus={true} - className="little-spacer-top" - loading={true} - onChange={[Function]} - placeholder="" - value="" - /> - </div> - <fieldset - aria-label="multi select" - > - <ul - className="menu menu-vertically-limited spacer-top with-top-separator" - > - <MultiSelectOption - active={true} - element="bar" - key="bar" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - selected={true} - /> - <MultiSelectOption - active={false} - disabled={false} - element="foo" - key="foo" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - <MultiSelectOption - active={false} - disabled={false} - element="baz" - key="baz" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - </ul> - </fieldset> -</div> -`; - -exports[`should render multiselect with selected elements 3`] = ` -<div - className="multi-select" -> - <div - className="menu-search" - > - <SearchBox - autoFocus={true} - className="little-spacer-top" - loading={true} - onChange={[Function]} - placeholder="" - value="" - /> - </div> - <fieldset - aria-label="multi select" - > - <ul - className="menu menu-vertically-limited spacer-top with-top-separator" - > - <MultiSelectOption - active={false} - element="bar" - key="bar" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - selected={true} - /> - <MultiSelectOption - active={false} - disabled={false} - element="foo" - key="foo" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - <MultiSelectOption - active={true} - disabled={false} - element="baz" - key="baz" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - </ul> - </fieldset> -</div> -`; - -exports[`should render multiselect with selected elements 4`] = ` -<div - className="multi-select" -> - <div - className="menu-search" - > - <SearchBox - autoFocus={true} - className="little-spacer-top" - loading={true} - onChange={[Function]} - placeholder="" - value="test" - /> - </div> - <fieldset - aria-label="multi select" - > - <ul - className="menu menu-vertically-limited spacer-top with-top-separator" - > - <MultiSelectOption - active={false} - element="bar" - key="bar" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - selected={true} - /> - <MultiSelectOption - active={false} - disabled={false} - element="foo" - key="foo" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - <MultiSelectOption - active={true} - disabled={false} - element="baz" - key="baz" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - <MultiSelectOption - active={false} - custom={true} - element="test" - key="test" - onHover={[Function]} - onSelectChange={[Function]} - renderLabel={[Function]} - /> - </ul> - </fieldset> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap deleted file mode 100644 index ee6ce1bf244..00000000000 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap +++ /dev/null @@ -1,114 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render standard element: active element 1`] = ` -<li - onFocus={[Function]} - onMouseOver={[Function]} -> - <Checkbox - checked={true} - className="active" - id="mytag" - onCheck={[MockFunction]} - thirdState={false} - > - <span - className="little-spacer-left" - > - mytag - </span> - </Checkbox> -</li> -`; - -exports[`should render standard element: custom element 1`] = ` -<li - onFocus={[Function]} - onMouseOver={[Function]} -> - <Checkbox - checked={false} - className="" - id="mytag" - onCheck={[MockFunction]} - thirdState={false} - > - <span - aria-label="create_new_element: mytag" - className="little-spacer-left" - > - <span - aria-hidden={true} - className="little-spacer-right" - > - + - </span> - mytag - </span> - </Checkbox> -</li> -`; - -exports[`should render standard element: default element 1`] = ` -<li - onFocus={[Function]} - onMouseOver={[Function]} -> - <Checkbox - checked={false} - className="" - id="mytag" - onCheck={[MockFunction]} - thirdState={false} - > - <span - className="little-spacer-left" - > - mytag - </span> - </Checkbox> -</li> -`; - -exports[`should render standard element: disabled element 1`] = ` -<li - onFocus={[Function]} - onMouseOver={[Function]} -> - <Checkbox - checked={false} - className="disabled" - disabled={true} - id="mytag" - onCheck={[MockFunction]} - thirdState={false} - > - <span - className="little-spacer-left" - > - mytag - </span> - </Checkbox> -</li> -`; - -exports[`should render standard element: selected element 1`] = ` -<li - onFocus={[Function]} - onMouseOver={[Function]} -> - <Checkbox - checked={true} - className="" - id="mytag" - onCheck={[MockFunction]} - thirdState={false} - > - <span - className="little-spacer-left" - > - mytag - </span> - </Checkbox> -</li> -`; |