diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md index b168602b64927..e139b326b7500 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md @@ -7,5 +7,5 @@ Signature: ```typescript -QueryStringInput: React.FC> +QueryStringInput: React.FC> ``` diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 340a378b946ec..c8110dbfd0041 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -51,7 +51,6 @@ import { ErrorToastOptions } from 'src/core/public/notifications'; import { EuiButtonEmptyProps } from '@elastic/eui'; import { EuiComboBoxProps } from '@elastic/eui'; import { EuiConfirmModalProps } from '@elastic/eui'; -import { EuiFieldText } from '@elastic/eui'; import { EuiGlobalToastListToast } from '@elastic/eui'; import { ExclusiveUnion } from '@elastic/eui'; import { ExistsParams } from 'elasticsearch'; @@ -1482,7 +1481,7 @@ export interface QueryState { // Warning: (ae-missing-release-tag) "QueryStringInput" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const QueryStringInput: React.FC>; +export const QueryStringInput: React.FC>; // @public (undocumented) export type QuerySuggestion = QuerySuggestionBasic | QuerySuggestionField; diff --git a/src/plugins/data/public/ui/query_string_input/_query_bar.scss b/src/plugins/data/public/ui/query_string_input/_query_bar.scss index f95fe748dfdae..007be9da63e49 100644 --- a/src/plugins/data/public/ui/query_string_input/_query_bar.scss +++ b/src/plugins/data/public/ui/query_string_input/_query_bar.scss @@ -1,3 +1,41 @@ +.kbnQueryBar__wrap { + max-width: 100%; + z-index: $euiZContentMenu; +} + +// Uses the append style, but no bordering +.kqlQueryBar__languageSwitcherButton { + border-right: none !important; +} + +.kbnQueryBar__textarea { + z-index: $euiZContentMenu; + resize: none !important; // When in the group, it will autosize + height: $euiSizeXXL; + // Unlike most inputs within layout control groups, the text area still needs a border. + // These adjusts help it sit above the control groups shadow to line up correctly. + padding-top: $euiSizeS + 3px !important; + transform: translateY(-2px); + padding: $euiSizeS - 1px; + + &:not(:focus) { + @include euiYScrollWithShadows; + white-space: nowrap; + overflow-y: hidden; + overflow-x: hidden; + border: none; + box-shadow: none; + } + + // When focused, let it scroll + &:focus { + overflow-x: auto; + overflow-y: auto; + width: calc(100% + 1px); // To overtake the group's fake border + white-space: normal; + } +} + @include euiBreakpoint('xs', 's') { .kbnQueryBar--withDatePicker { > :first-child { @@ -16,5 +54,11 @@ // sass-lint:disable-block no-important flex-grow: 0 !important; flex-basis: auto !important; + margin-right: -$euiSizeXS !important; + + &.kbnQueryBar__datePickerWrapper-isHidden { + width: 0; + overflow: hidden; + } } } diff --git a/src/plugins/data/public/ui/query_string_input/language_switcher.tsx b/src/plugins/data/public/ui/query_string_input/language_switcher.tsx index a4c93d0044c9a..4d51b173f6743 100644 --- a/src/plugins/data/public/ui/query_string_input/language_switcher.tsx +++ b/src/plugins/data/public/ui/query_string_input/language_switcher.tsx @@ -60,7 +60,7 @@ export function QueryLanguageSwitcher(props: Props) { setIsPopoverOpen(!isPopoverOpen)} - className="euiFormControlLayout__append" + className="euiFormControlLayout__append kqlQueryBar__languageSwitcherButton" data-test-subj={'switchQueryLanguageButton'} > {props.language === 'lucene' ? luceneLabel : kqlLabel} diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx index 4b0dc579c39ce..86bf30ba0e374 100644 --- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx @@ -69,6 +69,7 @@ interface Props { export function QueryBarTopRow(props: Props) { const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); + const [isQueryInputFocused, setIsQueryInputFocused] = useState(false); const kibana = useKibana(); const { uiSettings, notifications, storage, appName, docLinks } = kibana.services; @@ -107,6 +108,10 @@ export function QueryBarTopRow(props: Props) { }); } + function onChangeQueryInputFocus(isFocused: boolean) { + setIsQueryInputFocused(isFocused); + } + function onTimeChange({ start, end, @@ -182,6 +187,7 @@ export function QueryBarTopRow(props: Props) { query={props.query!} screenTitle={props.screenTitle} onChange={onQueryChange} + onChangeQueryInputFocus={onChangeQueryInputFocus} onSubmit={onInputSubmit} persistedLog={persistedLog} dataTestSubj={props.dataTestSubj} @@ -268,8 +274,12 @@ export function QueryBarTopRow(props: Props) { }; }); + const wrapperClasses = classNames('kbnQueryBar__datePickerWrapper', { + 'kbnQueryBar__datePickerWrapper-isHidden': isQueryInputFocused, + }); + return ( - + ); diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx index 755716aee8f48..0397c34d0c2b8 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx @@ -23,7 +23,7 @@ import { mockPersistedLogFactory, } from './query_string_input.test.mocks'; -import { EuiFieldText } from '@elastic/eui'; +import { EuiTextArea } from '@elastic/eui'; import React from 'react'; import { QueryLanguageSwitcher } from './language_switcher'; import { QueryStringInput, QueryStringInputUI } from './query_string_input'; @@ -102,7 +102,7 @@ describe('QueryStringInput', () => { indexPatterns: [stubIndexPatternWithFields], }) ); - expect(component.find(EuiFieldText).props().value).toBe(kqlQuery.query); + expect(component.find(EuiTextArea).props().value).toBe(kqlQuery.query); expect(component.find(QueryLanguageSwitcher).prop('language')).toBe(kqlQuery.language); }); @@ -117,7 +117,7 @@ describe('QueryStringInput', () => { expect(component.find(QueryLanguageSwitcher).prop('language')).toBe(luceneQuery.language); }); - it('Should disable autoFocus on EuiFieldText when disableAutoFocus prop is true', () => { + it('Should disable autoFocus on EuiTextArea when disableAutoFocus prop is true', () => { const component = mount( wrapQueryStringInputInContext({ query: kqlQuery, @@ -126,7 +126,7 @@ describe('QueryStringInput', () => { disableAutoFocus: true, }) ); - expect(component.find(EuiFieldText).prop('autoFocus')).toBeFalsy(); + expect(component.find(EuiTextArea).prop('autoFocus')).toBeFalsy(); }); it('Should create a unique PersistedLog based on the appName and query language', () => { @@ -179,7 +179,7 @@ describe('QueryStringInput', () => { const instance = component.find('QueryStringInputUI').instance() as QueryStringInputUI; const input = instance.inputRef; - const inputWrapper = component.find(EuiFieldText).find('input'); + const inputWrapper = component.find(EuiTextArea).find('textarea'); inputWrapper.simulate('keyDown', { target: input, keyCode: 13, key: 'Enter', metaKey: true }); expect(mockCallback).toHaveBeenCalledTimes(1); @@ -199,7 +199,7 @@ describe('QueryStringInput', () => { const instance = component.find('QueryStringInputUI').instance() as QueryStringInputUI; const input = instance.inputRef; - const inputWrapper = component.find(EuiFieldText).find('input'); + const inputWrapper = component.find(EuiTextArea).find('textarea'); inputWrapper.simulate('keyDown', { target: input, keyCode: 13, key: 'Enter', metaKey: true }); expect(mockPersistedLog.add).toHaveBeenCalledWith('response:200'); diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index c746449f14c26..6f72aa829d8f3 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -22,13 +22,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { - EuiFieldText, + EuiTextArea, EuiOutsideClickDetector, PopoverAnchorPosition, EuiFlexGroup, EuiFlexItem, EuiButton, EuiLink, + htmlIdGenerator, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -49,13 +50,14 @@ interface Props { query: Query; disableAutoFocus?: boolean; screenTitle?: string; - prepend?: React.ComponentProps['prepend']; + prepend?: any; persistedLog?: PersistedLog; bubbleSubmitEvent?: boolean; placeholder?: string; languageSwitcherPopoverAnchorPosition?: PopoverAnchorPosition; onBlur?: () => void; onChange?: (query: Query) => void; + onChangeQueryInputFocus?: (isFocused: boolean) => void; onSubmit?: (query: Query) => void; dataTestSubj?: string; } @@ -93,7 +95,7 @@ export class QueryStringInputUI extends Component { indexPatterns: [], }; - public inputRef: HTMLInputElement | null = null; + public inputRef: HTMLTextAreaElement | null = null; private persistedLog: PersistedLog | undefined; private abortController?: AbortController; @@ -223,27 +225,32 @@ export class QueryStringInputUI extends Component { this.onChange({ query: value, language: this.props.query.language }); }; - private onInputChange = (event: React.ChangeEvent) => { + private onInputChange = (event: React.ChangeEvent) => { this.onQueryStringChange(event.target.value); + if (event.target.value === '') { + this.handleRemoveHeight(); + } else { + this.handleAutoHeight(); + } }; - private onClickInput = (event: React.MouseEvent) => { - if (event.target instanceof HTMLInputElement) { + private onClickInput = (event: React.MouseEvent) => { + if (event.target instanceof HTMLTextAreaElement) { this.onQueryStringChange(event.target.value); } }; - private onKeyUp = (event: React.KeyboardEvent) => { + private onKeyUp = (event: React.KeyboardEvent) => { if ([KEY_CODES.LEFT, KEY_CODES.RIGHT, KEY_CODES.HOME, KEY_CODES.END].includes(event.keyCode)) { this.setState({ isSuggestionsVisible: true }); - if (event.target instanceof HTMLInputElement) { + if (event.target instanceof HTMLTextAreaElement) { this.onQueryStringChange(event.target.value); } } }; - private onKeyDown = (event: React.KeyboardEvent) => { - if (event.target instanceof HTMLInputElement) { + private onKeyDown = (event: React.KeyboardEvent) => { + if (event.target instanceof HTMLTextAreaElement) { const { isSuggestionsVisible, index } = this.state; const preventDefault = event.preventDefault.bind(event); const { target, key, metaKey } = event; @@ -258,16 +265,19 @@ export class QueryStringInputUI extends Component { switch (event.keyCode) { case KEY_CODES.DOWN: - event.preventDefault(); if (isSuggestionsVisible && index !== null) { + event.preventDefault(); this.incrementIndex(index); - } else { + // Note to engineers. `isSuggestionVisible` does not mean the suggestions are visible. + // This should likely be fixed, it's more that suggestions can be shown. + } else if ((isSuggestionsVisible && index == null) || this.getQueryString() === '') { + event.preventDefault(); this.setState({ isSuggestionsVisible: true, index: 0 }); } break; case KEY_CODES.UP: - event.preventDefault(); if (isSuggestionsVisible && index !== null) { + event.preventDefault(); this.decrementIndex(index); } break; @@ -439,6 +449,17 @@ export class QueryStringInputUI extends Component { if (this.state.isSuggestionsVisible) { this.setState({ isSuggestionsVisible: false, index: null }); } + this.handleBlurHeight(); + if (this.props.onChangeQueryInputFocus) { + this.props.onChangeQueryInputFocus(false); + } + }; + + private onInputBlur = () => { + this.handleBlurHeight(); + if (this.props.onChangeQueryInputFocus) { + this.props.onChangeQueryInputFocus(false); + } }; private onClickSuggestion = (suggestion: QuerySuggestion) => { @@ -460,6 +481,8 @@ export class QueryStringInputUI extends Component { this.setState({ index }); }; + textareaId = htmlIdGenerator()(); + public componentDidMount() { const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { @@ -468,6 +491,8 @@ export class QueryStringInputUI extends Component { this.initPersistedLog(); this.fetchIndexPatterns().then(this.updateSuggestions); + + window.addEventListener('resize', this.handleAutoHeight); } public componentDidUpdate(prevProps: Props) { @@ -485,15 +510,18 @@ export class QueryStringInputUI extends Component { } if (this.state.selectionStart !== null && this.state.selectionEnd !== null) { - if (this.inputRef) { - // For some reason the type guard above does not make the compiler happy - // @ts-ignore + if (this.inputRef != null) { this.inputRef.setSelectionRange(this.state.selectionStart, this.state.selectionEnd); } this.setState({ selectionStart: null, selectionEnd: null, }); + if (document.activeElement !== null && document.activeElement.id === this.textareaId) { + this.handleAutoHeight(); + } else { + this.handleRemoveHeight(); + } } } @@ -501,8 +529,37 @@ export class QueryStringInputUI extends Component { if (this.abortController) this.abortController.abort(); this.updateSuggestions.cancel(); this.componentIsUnmounting = true; + window.removeEventListener('resize', this.handleAutoHeight); } + handleAutoHeight = () => { + if (this.inputRef !== null && document.activeElement === this.inputRef) { + this.inputRef.style.setProperty('height', `${this.inputRef.scrollHeight}px`, 'important'); + } + }; + + handleRemoveHeight = () => { + if (this.inputRef !== null) { + this.inputRef.style.removeProperty('height'); + } + }; + + handleBlurHeight = () => { + if (this.inputRef !== null) { + this.handleRemoveHeight(); + this.inputRef.scrollTop = 0; + } + }; + + handleOnFocus = () => { + if (this.props.onChangeQueryInputFocus) { + this.props.onChangeQueryInputFocus(true); + } + requestAnimationFrame(() => { + this.handleAutoHeight(); + }); + }; + public render() { const isSuggestionsVisible = this.state.isSuggestionsVisible && { 'aria-controls': 'kbnTypeahead__items', @@ -511,20 +568,24 @@ export class QueryStringInputUI extends Component { const ariaCombobox = { ...isSuggestionsVisible, role: 'combobox' }; return ( - -
-
-
- + {this.props.prepend} + +
+
+ { onKeyUp={this.onKeyUp} onChange={this.onInputChange} onClick={this.onClickInput} - onBlur={this.props.onBlur} + onBlur={this.onInputBlur} + onFocus={this.handleOnFocus} + className="kbnQueryBar__textarea" fullWidth - autoFocus={!this.props.disableAutoFocus} - inputRef={(node) => { + rows={1} + id={this.textareaId} + autoFocus={ + this.props.onChangeQueryInputFocus ? false : !this.props.disableAutoFocus + } + inputRef={(node: any) => { if (node) { this.inputRef = node; } @@ -550,7 +617,6 @@ export class QueryStringInputUI extends Component { defaultMessage: 'Start typing to search and filter the {pageType} page', values: { pageType: this.services.appName }, })} - type="text" aria-autocomplete="list" aria-controls={this.state.isSuggestionsVisible ? 'kbnTypeahead__items' : undefined} aria-activedescendant={ @@ -559,29 +625,29 @@ export class QueryStringInputUI extends Component { : undefined } role="textbox" - prepend={this.props.prepend} - append={ - - } data-test-subj={this.props.dataTestSubj || 'queryInput'} - /> + > + {this.getQueryString()} +
-
- -
- + +
+ + + +
); } } diff --git a/src/plugins/data/public/ui/typeahead/_suggestion.scss b/src/plugins/data/public/ui/typeahead/_suggestion.scss index 3a215ceddcd00..81c05f1a8a78c 100644 --- a/src/plugins/data/public/ui/typeahead/_suggestion.scss +++ b/src/plugins/data/public/ui/typeahead/_suggestion.scss @@ -16,7 +16,7 @@ $kbnTypeaheadTypes: ( color: $euiTextColor; background-color: $euiColorEmptyShade; position: absolute; - top: -1px; + top: -2px; z-index: $euiZContentMenu; width: 100%; border-bottom-left-radius: $euiBorderRadius; @@ -56,7 +56,6 @@ $kbnTypeaheadTypes: ( .kbnTypeahead__item.active { background-color: $euiColorLightestShade; - .kbnSuggestionItem__callout { background: $euiColorEmptyShade; } @@ -130,7 +129,6 @@ $kbnTypeaheadTypes: ( align-items: center; } - .kbnSuggestionItem__text { flex-grow: 0; /* 2 */ flex-basis: auto; /* 2 */ @@ -142,16 +140,15 @@ $kbnTypeaheadTypes: ( color: $euiTextColor; } - .kbnSuggestionItem__description { color: $euiColorDarkShade; overflow: hidden; text-overflow: ellipsis; margin-left: $euiSizeXL; - + &:empty { flex-grow: 0; - margin-left:0; + margin-left: 0; } } diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index 906f0b83e99e7..949a01ff7873a 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -218,6 +218,8 @@ export default function ({ getService, getPageObjects }) { await PageObjects.common.navigateToApp('discover'); await PageObjects.header.awaitKibanaChrome(); await queryBar.setQuery(''); + // To remove focus of the of the search bar so date/time picker can show + await PageObjects.discover.selectIndexPattern(defaultSettings.defaultIndex); await PageObjects.timePicker.setDefaultAbsoluteRange(); log.debug( diff --git a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts index efd9ece8aec56..9438c28f05fef 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts @@ -99,6 +99,6 @@ describe('Cases', () => { cy.get(TIMELINE_TITLE).should('have.attr', 'value', case1.timeline.title); cy.get(TIMELINE_DESCRIPTION).should('have.attr', 'value', case1.timeline.description); - cy.get(TIMELINE_QUERY).should('have.attr', 'value', case1.timeline.query); + cy.get(TIMELINE_QUERY).invoke('text').should('eq', case1.timeline.query); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts b/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts index 0c3424576e4cf..6b3fc9e751ea4 100644 --- a/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts @@ -27,74 +27,67 @@ import { describe('ml conditional links', () => { it('sets the KQL from a single IP with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkSingleIpKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(process.name: "conhost.exe" or process.name: "sc.exe")' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); }); it('sets the KQL from a multiple IPs with a null for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkMultipleIpNullKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2"))' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should( + 'eq', + '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2"))' + ); }); it('sets the KQL from a multiple IPs with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkMultipleIpKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2")) and ((process.name: "conhost.exe" or process.name: "sc.exe"))' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should( + 'eq', + '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2")) and ((process.name: "conhost.exe" or process.name: "sc.exe"))' + ); }); it('sets the KQL from a $ip$ with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(process.name: "conhost.exe" or process.name: "sc.exe")' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); }); it('sets the KQL from a single host name with a value for query', () => { loginAndWaitForPageWithoutDateRange(mlHostSingleHostKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(process.name: "conhost.exe" or process.name: "sc.exe")' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); }); it('sets the KQL from a multiple host names with null for query', () => { loginAndWaitForPageWithoutDateRange(mlHostMultiHostNullKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(host.name: "siem-windows" or host.name: "siem-suricata")' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should('eq', '(host.name: "siem-windows" or host.name: "siem-suricata")'); }); it('sets the KQL from a multiple host names with a value for query', () => { loginAndWaitForPageWithoutDateRange(mlHostMultiHostKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(host.name: "siem-windows" or host.name: "siem-suricata") and ((process.name: "conhost.exe" or process.name: "sc.exe"))' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should( + 'eq', + '(host.name: "siem-windows" or host.name: "siem-suricata") and ((process.name: "conhost.exe" or process.name: "sc.exe"))' + ); }); it('sets the KQL from a undefined/null host name but with a value for query', () => { loginAndWaitForPageWithoutDateRange(mlHostVariableHostKqlQuery); - cy.get(KQL_INPUT).should( - 'have.attr', - 'value', - '(process.name: "conhost.exe" or process.name: "sc.exe")' - ); + cy.get(KQL_INPUT) + .invoke('text') + .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); }); it('redirects from a single IP with a null for the query', () => { diff --git a/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts b/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts index a3a927cbea7d4..81af9ece9ed45 100644 --- a/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts @@ -154,12 +154,12 @@ describe('url state', () => { it('sets kql on network page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlNetworkNetwork); - cy.get(KQL_INPUT).should('have.attr', 'value', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); }); it('sets kql on hosts page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlHostsHosts); - cy.get(KQL_INPUT).should('have.attr', 'value', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); }); it('sets the url state when kql is set', () => { @@ -230,8 +230,7 @@ describe('url state', () => { it('Do not clears kql when navigating to a new page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlHostsHosts); navigateFromHeaderTo(NETWORK); - - cy.get(KQL_INPUT).should('have.attr', 'value', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); }); it.skip('sets and reads the url state for timeline by id', () => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts index eca5885e7b3d9..88ae582b58891 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts @@ -82,7 +82,7 @@ export const fillAboutRuleAndContinue = (rule: CustomRule | MachineLearningRule) export const fillDefineCustomRuleAndContinue = (rule: CustomRule) => { cy.get(CUSTOM_QUERY_INPUT).type(rule.customQuery); - cy.get(CUSTOM_QUERY_INPUT).should('have.attr', 'value', rule.customQuery); + cy.get(CUSTOM_QUERY_INPUT).invoke('text').should('eq', rule.customQuery); cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); cy.get(CUSTOM_QUERY_INPUT).should('not.exist'); @@ -91,7 +91,7 @@ export const fillDefineCustomRuleAndContinue = (rule: CustomRule) => { export const fillDefineCustomRuleWithImportedQueryAndContinue = (rule: CustomRule) => { cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click(); cy.get(TIMELINE(rule.timelineId)).click(); - cy.get(CUSTOM_QUERY_INPUT).should('have.attr', 'value', rule.customQuery); + cy.get(CUSTOM_QUERY_INPUT).invoke('text').should('eq', rule.customQuery); cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); cy.get(CUSTOM_QUERY_INPUT).should('not.exist'); diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index 9e17433090c2b..761fd2c1e6a0b 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -58,7 +58,7 @@ export const createNewTimeline = () => { }; export const executeTimelineKQL = (query: string) => { - cy.get(`${SEARCH_OR_FILTER_CONTAINER} input`).type(`${query} {enter}`); + cy.get(`${SEARCH_OR_FILTER_CONTAINER} textarea`).type(`${query} {enter}`); }; export const expandFirstTimelineEventDetails = () => { diff --git a/x-pack/plugins/security_solution/public/common/components/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/query_bar/index.test.tsx index a3cab1cfabd71..aac83ce650d86 100644 --- a/x-pack/plugins/security_solution/public/common/components/query_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/query_bar/index.test.tsx @@ -214,15 +214,18 @@ describe('QueryBar ', () => { /> ); - const queryInput = wrapper.find(QueryBar).find('input[data-test-subj="queryInput"]'); + let queryInput = wrapper.find(QueryBar).find('textarea[data-test-subj="queryInput"]'); queryInput.simulate('change', { target: { value: 'host.name:*' } }); - expect(queryInput.html()).toContain('value="host.name:*"'); + wrapper.update(); + queryInput = wrapper.find(QueryBar).find('textarea[data-test-subj="queryInput"]'); + expect(queryInput.props().children).toBe('host.name:*'); wrapper.setProps({ filterQueryDraft: null }); wrapper.update(); + queryInput = wrapper.find(QueryBar).find('textarea[data-test-subj="queryInput"]'); - expect(queryInput.html()).toContain('value=""'); + expect(queryInput.props().children).toBe(''); }); }); @@ -258,7 +261,7 @@ describe('QueryBar ', () => { const onSubmitQueryRef = searchBarProps.onQuerySubmit; const onSavedQueryRef = searchBarProps.onSavedQueryUpdated; - const queryInput = wrapper.find(QueryBar).find('input[data-test-subj="queryInput"]'); + const queryInput = wrapper.find(QueryBar).find('textarea[data-test-subj="queryInput"]'); queryInput.simulate('change', { target: { value: 'hello: world' } }); wrapper.update();