From 93acfb4d43ddfdf29a8261de19e9ee8083c99105 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 26 May 2021 11:36:06 +0200 Subject: [PATCH 1/6] [Ingest pipelines] add support for ip type in convert processor (#100531) * add ip option type to convert processor * remove duped option * small CR changes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../__jest__/processors/convert.test.tsx | 123 ++++++++++++++++++ .../__jest__/processors/processor.helpers.tsx | 1 + .../processor_form/processors/convert.tsx | 7 + 3 files changed, 131 insertions(+) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx new file mode 100644 index 00000000000000..5a58a7b595c90d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/convert.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setup, SetupResult, getProcessorValue } from './processor.helpers'; + +// Default parameter values automatically added to the `convert processor` when saved +const defaultConvertParameters = { + if: undefined, + tag: undefined, + description: undefined, + target_field: undefined, + ignore_missing: undefined, + ignore_failure: undefined, +}; + +const CONVERT_TYPE = 'convert'; + +describe('Processor: Convert', () => { + let onUpdate: jest.Mock; + let testBed: SetupResult; + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + beforeEach(async () => { + onUpdate = jest.fn(); + + await act(async () => { + testBed = await setup({ + value: { + processors: [], + }, + onFlyoutOpen: jest.fn(), + onUpdate, + }); + }); + + testBed.component.update(); + + // Open flyout to add new processor + testBed.actions.addProcessor(); + // Add type (the other fields are not visible until a type is selected) + await testBed.actions.addProcessorType(CONVERT_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the processor type defined + await saveNewProcessor(); + + // Expect form error as "field" and "type" are required parameters + expect(form.getErrorsMessages()).toEqual([ + 'A field value is required.', + 'A type value is required.', + ]); + }); + + test('saves with default parameter values', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Add "field" value (required) + form.setInputValue('fieldNameField.input', 'field_1'); + // Add "type" value (required) + form.setSelectValue('typeSelectorField', 'ip'); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, CONVERT_TYPE); + expect(processors[0][CONVERT_TYPE]).toEqual({ + ...defaultConvertParameters, + field: 'field_1', + type: 'ip', + }); + }); + + test('allows optional parameters to be set', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Add "field" value (required) + form.setInputValue('fieldNameField.input', 'field_1'); + // Add "type" value (required) + form.setSelectValue('typeSelectorField', 'ip'); + + // Set optional parameteres + form.setInputValue('targetField.input', 'target_field'); + form.toggleEuiSwitch('ignoreMissingSwitch.input'); + form.toggleEuiSwitch('ignoreFailureSwitch.input'); + + // Save the field with new changes + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, CONVERT_TYPE); + expect(processors[0][CONVERT_TYPE]).toEqual({ + ...defaultConvertParameters, + type: 'ip', + field: 'field_1', + target_field: 'target_field', + ignore_failure: true, + ignore_missing: true, + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx index 193e94c7aeb9e6..d69ceb385ddd71 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx @@ -143,6 +143,7 @@ type TestSubject = | 'messageField.input' | 'mockCodeEditor' | 'tagField.input' + | 'typeSelectorField' | 'ignoreMissingSwitch.input' | 'ignoreFailureSwitch.input' | 'ifField.textarea' diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/convert.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/convert.tsx index 46aee71fdee427..af671dce295599 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/convert.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/convert.tsx @@ -58,6 +58,7 @@ export const Convert: FunctionComponent = () => { { { defaultMessage: 'Boolean' } ), }, + { + value: 'ip', + text: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.ipOption', { + defaultMessage: 'IP', + }), + }, { value: 'auto', text: i18n.translate( From 5d5cc55b3a946faf735f18aa0165bd7d4deffaf2 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 26 May 2021 06:47:28 -0400 Subject: [PATCH 2/6] Fix spaces test flakyness (#100605) --- .../spaces/public/nav_control/nav_control_popover.tsx | 5 +---- x-pack/test/functional/apps/spaces/enter_space.ts | 3 +-- x-pack/test/functional/apps/spaces/spaces_selection.ts | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx index 392219d480e671..6f743b3a308e25 100644 --- a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx +++ b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx @@ -71,9 +71,6 @@ export class NavControlPopover extends Component { public render() { const button = this.getActiveSpaceButton(); - if (!button) { - return null; - } let element: React.ReactNode; if (!this.state.loading && this.state.spaces.length < 2) { @@ -102,7 +99,7 @@ export class NavControlPopover extends Component { return ( { await esArchiver.load('spaces/enter_space'); diff --git a/x-pack/test/functional/apps/spaces/spaces_selection.ts b/x-pack/test/functional/apps/spaces/spaces_selection.ts index f3d3665bf9f613..99efdf29eecb97 100644 --- a/x-pack/test/functional/apps/spaces/spaces_selection.ts +++ b/x-pack/test/functional/apps/spaces/spaces_selection.ts @@ -22,8 +22,7 @@ export default function spaceSelectorFunctionalTests({ 'spaceSelector', ]); - // FLAKY: https://github.com/elastic/kibana/issues/99581 - describe.skip('Spaces', function () { + describe('Spaces', function () { this.tags('includeFirefox'); describe('Space Selector', () => { before(async () => { From 2d6ee26223aa49d108423a7cc948df75cfa5e412 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 03:48:41 -0700 Subject: [PATCH 3/6] [ftr] migrate "testSubjects" to FtrService class (#100512) Co-authored-by: spalger --- test/functional/services/common/index.ts | 2 +- .../services/common/test_subjects.ts | 560 +++++++++--------- test/functional/services/index.ts | 4 +- 3 files changed, 284 insertions(+), 282 deletions(-) diff --git a/test/functional/services/common/index.ts b/test/functional/services/common/index.ts index e491b964c8ff60..a928b3ddf93788 100644 --- a/test/functional/services/common/index.ts +++ b/test/functional/services/common/index.ts @@ -11,4 +11,4 @@ export { FailureDebuggingProvider } from './failure_debugging'; export { FindProvider } from './find'; export { ScreenshotsProvider } from './screenshots'; export { SnapshotsProvider } from './snapshots'; -export { TestSubjectsProvider, TestSubjects } from './test_subjects'; +export { TestSubjects } from './test_subjects'; diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index d0050859cbb32a..ae04fe5d2b9390 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -8,9 +8,8 @@ import testSubjSelector from '@kbn/test-subj-selector'; import { map as mapAsync } from 'bluebird'; -import { ProvidedType } from '@kbn/test'; import { WebElementWrapper } from '../lib/web_element_wrapper'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; interface ExistsOptions { timeout?: number; @@ -22,326 +21,329 @@ interface SetValueOptions { typeCharByChar?: boolean; } -export type TestSubjects = ProvidedType; -export function TestSubjectsProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const find = getService('find'); - const config = getService('config'); - - const FIND_TIME = config.get('timeouts.find'); - const TRY_TIME = config.get('timeouts.try'); - const WAIT_FOR_EXISTS_TIME = config.get('timeouts.waitForExists'); - - class TestSubjects { - public async exists(selector: string, options: ExistsOptions = {}): Promise { - const { timeout = WAIT_FOR_EXISTS_TIME, allowHidden = false } = options; - - log.debug(`TestSubjects.exists(${selector})`); - return await (allowHidden - ? find.existsByCssSelector(testSubjSelector(selector), timeout) - : find.existsByDisplayedByCssSelector(testSubjSelector(selector), timeout)); - } - - public async existOrFail( - selector: string, - existsOptions?: ExistsOptions - ): Promise { - if (!(await this.exists(selector, { timeout: TRY_TIME, ...existsOptions }))) { - throw new Error(`expected testSubject(${selector}) to exist`); - } - } +export class TestSubjects extends FtrService { + public readonly log = this.ctx.getService('log'); + public readonly retry = this.ctx.getService('retry'); + public readonly findService = this.ctx.getService('find'); + public readonly config = this.ctx.getService('config'); - public async missingOrFail( - selector: string, - options: ExistsOptions = {} - ): Promise { - const { timeout = WAIT_FOR_EXISTS_TIME, allowHidden = false } = options; + public readonly FIND_TIME = this.config.get('timeouts.find'); + public readonly TRY_TIME = this.config.get('timeouts.try'); + public readonly WAIT_FOR_EXISTS_TIME = this.config.get('timeouts.waitForExists'); - log.debug(`TestSubjects.missingOrFail(${selector})`); - return await (allowHidden - ? this.waitForHidden(selector, timeout) - : find.waitForDeletedByCssSelector(testSubjSelector(selector), timeout)); - } + public async exists(selector: string, options: ExistsOptions = {}): Promise { + const { timeout = this.WAIT_FOR_EXISTS_TIME, allowHidden = false } = options; - async stringExistsInCodeBlockOrFail(codeBlockSelector: string, stringToFind: string) { - await retry.try(async () => { - const responseCodeBlock = await this.find(codeBlockSelector); - const spans = await find.allDescendantDisplayedByTagName('span', responseCodeBlock); - const foundInSpans = await Promise.all( - spans.map(async (span) => { - const text = await span.getVisibleText(); - if (text === stringToFind) { - log.debug(`"${text}" matched "${stringToFind}"!`); - return true; - } else { - log.debug(`"${text}" did not match "${stringToFind}"`); - } - }) - ); - if (!foundInSpans.find((foundInSpan) => foundInSpan)) { - throw new Error(`"${stringToFind}" was not found. Trying again...`); - } - }); - } + this.log.debug(`TestSubjects.exists(${selector})`); + return await (allowHidden + ? this.findService.existsByCssSelector(testSubjSelector(selector), timeout) + : this.findService.existsByDisplayedByCssSelector(testSubjSelector(selector), timeout)); + } - public async append(selector: string, text: string): Promise { - log.debug(`TestSubjects.append(${selector}, ${text})`); - const input = await this.find(selector); - await input.click(); - await input.type(text); + public async existOrFail(selector: string, existsOptions?: ExistsOptions): Promise { + if (!(await this.exists(selector, { timeout: this.TRY_TIME, ...existsOptions }))) { + throw new Error(`expected testSubject(${selector}) to exist`); } + } - public async clickWhenNotDisabled( - selector: string, - { timeout = FIND_TIME }: { timeout?: number } = {} - ): Promise { - log.debug(`TestSubjects.clickWhenNotDisabled(${selector})`); - await find.clickByCssSelectorWhenNotDisabled(testSubjSelector(selector), { timeout }); - } + public async missingOrFail(selector: string, options: ExistsOptions = {}): Promise { + const { timeout = this.WAIT_FOR_EXISTS_TIME, allowHidden = false } = options; - public async click( - selector: string, - timeout: number = FIND_TIME, - topOffset?: number - ): Promise { - log.debug(`TestSubjects.click(${selector})`); - await find.clickByCssSelector(testSubjSelector(selector), timeout, topOffset); - } + this.log.debug(`TestSubjects.missingOrFail(${selector})`); + return await (allowHidden + ? this.waitForHidden(selector, timeout) + : this.findService.waitForDeletedByCssSelector(testSubjSelector(selector), timeout)); + } - public async doubleClick(selector: string, timeout: number = FIND_TIME): Promise { - log.debug(`TestSubjects.doubleClick(${selector})`); - const element = await this.find(selector, timeout); - await element.moveMouseTo(); - await element.doubleClick(); - } + async stringExistsInCodeBlockOrFail(codeBlockSelector: string, stringToFind: string) { + await this.retry.try(async () => { + const responseCodeBlock = await this.find(codeBlockSelector); + const spans = await this.findService.allDescendantDisplayedByTagName( + 'span', + responseCodeBlock + ); + const foundInSpans = await Promise.all( + spans.map(async (span) => { + const text = await span.getVisibleText(); + if (text === stringToFind) { + this.log.debug(`"${text}" matched "${stringToFind}"!`); + return true; + } else { + this.log.debug(`"${text}" did not match "${stringToFind}"`); + } + }) + ); + if (!foundInSpans.find((foundInSpan) => foundInSpan)) { + throw new Error(`"${stringToFind}" was not found. Trying again...`); + } + }); + } - async descendantExists(selector: string, parentElement: WebElementWrapper): Promise { - log.debug(`TestSubjects.descendantExists(${selector})`); - return await find.descendantExistsByCssSelector(testSubjSelector(selector), parentElement); - } + public async append(selector: string, text: string): Promise { + this.log.debug(`TestSubjects.append(${selector}, ${text})`); + const input = await this.find(selector); + await input.click(); + await input.type(text); + } - public async findDescendant( - selector: string, - parentElement: WebElementWrapper - ): Promise { - log.debug(`TestSubjects.findDescendant(${selector})`); - return await find.descendantDisplayedByCssSelector(testSubjSelector(selector), parentElement); - } + public async clickWhenNotDisabled( + selector: string, + { timeout = this.FIND_TIME }: { timeout?: number } = {} + ): Promise { + this.log.debug(`TestSubjects.clickWhenNotDisabled(${selector})`); + await this.findService.clickByCssSelectorWhenNotDisabled(testSubjSelector(selector), { + timeout, + }); + } - public async findAllDescendant( - selector: string, - parentElement: WebElementWrapper - ): Promise { - log.debug(`TestSubjects.findAllDescendant(${selector})`); - return await find.allDescendantDisplayedByCssSelector( - testSubjSelector(selector), - parentElement - ); - } + public async click( + selector: string, + timeout: number = this.FIND_TIME, + topOffset?: number + ): Promise { + this.log.debug(`TestSubjects.click(${selector})`); + await this.findService.clickByCssSelector(testSubjSelector(selector), timeout, topOffset); + } - public async find(selector: string, timeout: number = FIND_TIME): Promise { - log.debug(`TestSubjects.find(${selector})`); - return await find.byCssSelector(testSubjSelector(selector), timeout); - } + public async doubleClick(selector: string, timeout: number = this.FIND_TIME): Promise { + this.log.debug(`TestSubjects.doubleClick(${selector})`); + const element = await this.find(selector, timeout); + await element.moveMouseTo(); + await element.doubleClick(); + } - public async findAll(selector: string, timeout?: number): Promise { - return await retry.try(async () => { - log.debug(`TestSubjects.findAll(${selector})`); - const all = await find.allByCssSelector(testSubjSelector(selector), timeout); - return await find.filterElementIsDisplayed(all); - }); - } + async descendantExists(selector: string, parentElement: WebElementWrapper): Promise { + this.log.debug(`TestSubjects.descendantExists(${selector})`); + return await this.findService.descendantExistsByCssSelector( + testSubjSelector(selector), + parentElement + ); + } - public async getAttributeAll(selector: string, attribute: string): Promise { - log.debug(`TestSubjects.getAttributeAll(${selector}, ${attribute})`); - return await this._mapAll(selector, async (element: WebElementWrapper) => { - return await element.getAttribute(attribute); - }); - } + public async findDescendant( + selector: string, + parentElement: WebElementWrapper + ): Promise { + this.log.debug(`TestSubjects.findDescendant(${selector})`); + return await this.findService.descendantDisplayedByCssSelector( + testSubjSelector(selector), + parentElement + ); + } - public async getAttribute( - selector: string, - attribute: string, - options?: - | number - | { - findTimeout?: number; - tryTimeout?: number; - } - ): Promise { - const findTimeout = - (typeof options === 'number' ? options : options?.findTimeout) ?? - config.get('timeouts.find'); + public async findAllDescendant( + selector: string, + parentElement: WebElementWrapper + ): Promise { + this.log.debug(`TestSubjects.findAllDescendant(${selector})`); + return await this.findService.allDescendantDisplayedByCssSelector( + testSubjSelector(selector), + parentElement + ); + } - const tryTimeout = - (typeof options !== 'number' ? options?.tryTimeout : undefined) ?? - config.get('timeouts.try'); + public async find( + selector: string, + timeout: number = this.FIND_TIME + ): Promise { + this.log.debug(`TestSubjects.find(${selector})`); + return await this.findService.byCssSelector(testSubjSelector(selector), timeout); + } - log.debug( - `TestSubjects.getAttribute(${selector}, ${attribute}, tryTimeout=${tryTimeout}, findTimeout=${findTimeout})` - ); + public async findAll(selector: string, timeout?: number): Promise { + return await this.retry.try(async () => { + this.log.debug(`TestSubjects.findAll(${selector})`); + const all = await this.findService.allByCssSelector(testSubjSelector(selector), timeout); + return await this.findService.filterElementIsDisplayed(all); + }); + } - return await retry.tryForTime(tryTimeout, async () => { - const element = await this.find(selector, findTimeout); - return await element.getAttribute(attribute); - }); - } + public async getAttributeAll(selector: string, attribute: string): Promise { + this.log.debug(`TestSubjects.getAttributeAll(${selector}, ${attribute})`); + return await this._mapAll(selector, async (element: WebElementWrapper) => { + return await element.getAttribute(attribute); + }); + } - public async setValue( - selector: string, - text: string, - options: SetValueOptions = {}, - topOffset?: number - ): Promise { - return await retry.try(async () => { - const { clearWithKeyboard = false, typeCharByChar = false } = options; - log.debug(`TestSubjects.setValue(${selector}, ${text})`); - await this.click(selector, undefined, topOffset); - // in case the input element is actually a child of the testSubject, we - // call clearValue() and type() on the element that is focused after - // clicking on the testSubject - const input = await find.activeElement(); - if (clearWithKeyboard === true) { - await input.clearValueWithKeyboard(); - } else { - await input.clearValue(); + public async getAttribute( + selector: string, + attribute: string, + options?: + | number + | { + findTimeout?: number; + tryTimeout?: number; } - await input.type(text, { charByChar: typeCharByChar }); - }); - } + ): Promise { + const findTimeout = + (typeof options === 'number' ? options : options?.findTimeout) ?? + this.config.get('timeouts.find'); + + const tryTimeout = + (typeof options !== 'number' ? options?.tryTimeout : undefined) ?? + this.config.get('timeouts.try'); + + this.log.debug( + `TestSubjects.getAttribute(${selector}, ${attribute}, tryTimeout=${tryTimeout}, findTimeout=${findTimeout})` + ); + + return await this.retry.tryForTime(tryTimeout, async () => { + const element = await this.find(selector, findTimeout); + return await element.getAttribute(attribute); + }); + } - public async selectValue(selector: string, value: string): Promise { - await find.selectValue(`[data-test-subj="${selector}"]`, value); - } + public async setValue( + selector: string, + text: string, + options: SetValueOptions = {}, + topOffset?: number + ): Promise { + return await this.retry.try(async () => { + const { clearWithKeyboard = false, typeCharByChar = false } = options; + this.log.debug(`TestSubjects.setValue(${selector}, ${text})`); + await this.click(selector, undefined, topOffset); + // in case the input element is actually a child of the testSubject, we + // call clearValue() and type() on the element that is focused after + // clicking on the testSubject + const input = await this.findService.activeElement(); + if (clearWithKeyboard === true) { + await input.clearValueWithKeyboard(); + } else { + await input.clearValue(); + } + await input.type(text, { charByChar: typeCharByChar }); + }); + } - public async isEnabled(selector: string): Promise { - log.debug(`TestSubjects.isEnabled(${selector})`); - const element = await this.find(selector); - return await element.isEnabled(); - } + public async selectValue(selector: string, value: string): Promise { + await this.findService.selectValue(`[data-test-subj="${selector}"]`, value); + } - public async isDisplayed(selector: string): Promise { - log.debug(`TestSubjects.isDisplayed(${selector})`); - const element = await this.find(selector); - return await element.isDisplayed(); - } + public async isEnabled(selector: string): Promise { + this.log.debug(`TestSubjects.isEnabled(${selector})`); + const element = await this.find(selector); + return await element.isEnabled(); + } - public async isSelected(selector: string): Promise { - log.debug(`TestSubjects.isSelected(${selector})`); - const element = await this.find(selector); + public async isDisplayed(selector: string): Promise { + this.log.debug(`TestSubjects.isDisplayed(${selector})`); + const element = await this.find(selector); + return await element.isDisplayed(); + } + + public async isSelected(selector: string): Promise { + this.log.debug(`TestSubjects.isSelected(${selector})`); + const element = await this.find(selector); + return await element.isSelected(); + } + + public async isSelectedAll(selectorAll: string): Promise { + this.log.debug(`TestSubjects.isSelectedAll(${selectorAll})`); + return await this._mapAll(selectorAll, async (element: WebElementWrapper) => { return await element.isSelected(); - } + }); + } - public async isSelectedAll(selectorAll: string): Promise { - log.debug(`TestSubjects.isSelectedAll(${selectorAll})`); - return await this._mapAll(selectorAll, async (element: WebElementWrapper) => { - return await element.isSelected(); - }); - } + public async getVisibleText(selector: string): Promise { + this.log.debug(`TestSubjects.getVisibleText(${selector})`); + const element = await this.find(selector); + return await element.getVisibleText(); + } - public async getVisibleText(selector: string): Promise { - log.debug(`TestSubjects.getVisibleText(${selector})`); - const element = await this.find(selector); + async getVisibleTextAll(selectorAll: string): Promise { + this.log.debug(`TestSubjects.getVisibleTextAll(${selectorAll})`); + return await this._mapAll(selectorAll, async (element: WebElementWrapper) => { return await element.getVisibleText(); - } + }); + } - async getVisibleTextAll(selectorAll: string): Promise { - log.debug(`TestSubjects.getVisibleTextAll(${selectorAll})`); - return await this._mapAll(selectorAll, async (element: WebElementWrapper) => { - return await element.getVisibleText(); - }); - } + public async moveMouseTo(selector: string): Promise { + // Wrapped in a retry because even though the find should do a stale element check of it's own, we seem to + // have run into a case where the element becomes stale after the find succeeds, throwing an error during the + // moveMouseTo function. + await this.retry.try(async () => { + this.log.debug(`TestSubjects.moveMouseTo(${selector})`); + const element = await this.find(selector); + await element.moveMouseTo(); + }); + } - public async moveMouseTo(selector: string): Promise { - // Wrapped in a retry because even though the find should do a stale element check of it's own, we seem to - // have run into a case where the element becomes stale after the find succeeds, throwing an error during the - // moveMouseTo function. - await retry.try(async () => { - log.debug(`TestSubjects.moveMouseTo(${selector})`); - const element = await this.find(selector); - await element.moveMouseTo(); - }); - } + private async _mapAll( + selectorAll: string, + mapFn: (element: WebElementWrapper, index?: number, arrayLength?: number) => Promise + ): Promise { + return await this.retry.try(async () => { + const elements = await this.findAll(selectorAll); + return await mapAsync(elements, mapFn); + }); + } - private async _mapAll( - selectorAll: string, - mapFn: (element: WebElementWrapper, index?: number, arrayLength?: number) => Promise - ): Promise { - return await retry.try(async () => { - const elements = await this.findAll(selectorAll); - return await mapAsync(elements, mapFn); - }); + public async waitForDeleted(selectorOrElement: string | WebElementWrapper): Promise { + if (typeof selectorOrElement === 'string') { + await this.findService.waitForDeletedByCssSelector(testSubjSelector(selectorOrElement)); + } else { + await this.findService.waitForElementStale(selectorOrElement); } + } - public async waitForDeleted(selectorOrElement: string | WebElementWrapper): Promise { - if (typeof selectorOrElement === 'string') { - await find.waitForDeletedByCssSelector(testSubjSelector(selectorOrElement)); - } else { - await find.waitForElementStale(selectorOrElement); - } - } + public async waitForAttributeToChange( + selector: string, + attribute: string, + value: string + ): Promise { + await this.findService.waitForAttributeToChange(testSubjSelector(selector), attribute, value); + } - public async waitForAttributeToChange( - selector: string, - attribute: string, - value: string - ): Promise { - await find.waitForAttributeToChange(testSubjSelector(selector), attribute, value); - } + public async waitForHidden(selector: string, timeout?: number): Promise { + this.log.debug(`TestSubjects.waitForHidden(${selector})`); + const element = await this.find(selector); + await this.findService.waitForElementHidden(element, timeout); + } - public async waitForHidden(selector: string, timeout?: number): Promise { - log.debug(`TestSubjects.waitForHidden(${selector})`); + public async waitForEnabled(selector: string, timeout: number = this.TRY_TIME): Promise { + await this.retry.tryForTime(timeout, async () => { const element = await this.find(selector); - await find.waitForElementHidden(element, timeout); - } - - public async waitForEnabled(selector: string, timeout: number = TRY_TIME): Promise { - await retry.tryForTime(timeout, async () => { - const element = await this.find(selector); - return (await element.isDisplayed()) && (await element.isEnabled()); - }); - } + return (await element.isDisplayed()) && (await element.isEnabled()); + }); + } - public getCssSelector(selector: string): string { - return testSubjSelector(selector); - } + public getCssSelector(selector: string): string { + return testSubjSelector(selector); + } - public async scrollIntoView(selector: string) { - const element = await this.find(selector); - await element.scrollIntoViewIfNecessary(); - } + public async scrollIntoView(selector: string) { + const element = await this.find(selector); + await element.scrollIntoViewIfNecessary(); + } - // isChecked always returns false when run on an euiSwitch, because they use the aria-checked attribute - public async isChecked(selector: string) { - const checkbox = await this.find(selector); - return await checkbox.isSelected(); - } + // isChecked always returns false when run on an euiSwitch, because they use the aria-checked attribute + public async isChecked(selector: string) { + const checkbox = await this.find(selector); + return await checkbox.isSelected(); + } - public async setCheckbox(selector: string, state: 'check' | 'uncheck') { - const isChecked = await this.isChecked(selector); - const states = { check: true, uncheck: false }; - if (isChecked !== states[state]) { - log.debug(`updating checkbox ${selector} from ${isChecked} to ${states[state]}`); - await this.click(selector); - } + public async setCheckbox(selector: string, state: 'check' | 'uncheck') { + const isChecked = await this.isChecked(selector); + const states = { check: true, uncheck: false }; + if (isChecked !== states[state]) { + this.log.debug(`updating checkbox ${selector} from ${isChecked} to ${states[state]}`); + await this.click(selector); } + } - public async isEuiSwitchChecked(selector: string) { - const euiSwitch = await this.find(selector); - const isChecked = await euiSwitch.getAttribute('aria-checked'); - return isChecked === 'true'; - } + public async isEuiSwitchChecked(selector: string) { + const euiSwitch = await this.find(selector); + const isChecked = await euiSwitch.getAttribute('aria-checked'); + return isChecked === 'true'; + } - public async setEuiSwitch(selector: string, state: 'check' | 'uncheck') { - const isChecked = await this.isEuiSwitchChecked(selector); - const states = { check: true, uncheck: false }; - if (isChecked !== states[state]) { - log.debug(`updating checkbox ${selector} from ${isChecked} to ${states[state]}`); - await this.click(selector); - } + public async setEuiSwitch(selector: string, state: 'check' | 'uncheck') { + const isChecked = await this.isEuiSwitchChecked(selector); + const states = { check: true, uncheck: false }; + if (isChecked !== states[state]) { + this.log.debug(`updating checkbox ${selector} from ${isChecked} to ${states[state]}`); + await this.click(selector); } } - - return new TestSubjects(); } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 43f891ee4644fe..fc90fcdb2d52e4 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -15,7 +15,7 @@ import { FindProvider, ScreenshotsProvider, SnapshotsProvider, - TestSubjectsProvider, + TestSubjects, } from './common'; import { ComboBoxProvider } from './combo_box'; import { @@ -56,7 +56,7 @@ export const services = { filterBar: FilterBarService, queryBar: QueryBarProvider, find: FindProvider, - testSubjects: TestSubjectsProvider, + testSubjects: TestSubjects, docTable: DocTableService, screenshots: ScreenshotsProvider, snapshots: SnapshotsProvider, From 6d48a50c2a4ecff9188e4d2c9f7d426ba4398294 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 05:18:13 -0700 Subject: [PATCH 4/6] [ftr] migrate "globalNav" service to FtrService class (#100604) Co-authored-by: spalger --- test/functional/services/global_nav.ts | 71 +++++++++++++------------- test/functional/services/index.ts | 4 +- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/test/functional/services/global_nav.ts b/test/functional/services/global_nav.ts index ec404bcb068e94..4ce8ed6cb79dde 100644 --- a/test/functional/services/global_nav.ts +++ b/test/functional/services/global_nav.ts @@ -7,50 +7,49 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function GlobalNavProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); +export class GlobalNavService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); - class GlobalNav { - public async moveMouseToLogo(): Promise { - await testSubjects.moveMouseTo('headerGlobalNav > logo'); - } - - public async clickLogo(): Promise { - return await testSubjects.click('headerGlobalNav > logo'); - } + public async moveMouseToLogo(): Promise { + await this.testSubjects.moveMouseTo('headerGlobalNav > logo'); + } - public async clickNewsfeed(): Promise { - return await testSubjects.click('headerGlobalNav > newsfeed'); - } + public async clickLogo(): Promise { + return await this.testSubjects.click('headerGlobalNav > logo'); + } - public async exists(): Promise { - return await testSubjects.exists('headerGlobalNav'); - } + public async clickNewsfeed(): Promise { + return await this.testSubjects.click('headerGlobalNav > newsfeed'); + } - public async getFirstBreadcrumb(): Promise { - return await testSubjects.getVisibleText( - 'headerGlobalNav > breadcrumbs > ~breadcrumb & ~first' - ); - } + public async exists(): Promise { + return await this.testSubjects.exists('headerGlobalNav'); + } - public async getLastBreadcrumb(): Promise { - return await testSubjects.getVisibleText( - 'headerGlobalNav > breadcrumbs > ~breadcrumb & ~last' - ); - } + public async getFirstBreadcrumb(): Promise { + return await this.testSubjects.getVisibleText( + 'headerGlobalNav > breadcrumbs > ~breadcrumb & ~first' + ); + } - public async badgeExistsOrFail(expectedLabel: string): Promise { - await testSubjects.existOrFail('headerBadge'); - const actualLabel = await testSubjects.getAttribute('headerBadge', 'data-test-badge-label'); - expect(actualLabel.toUpperCase()).to.equal(expectedLabel.toUpperCase()); - } + public async getLastBreadcrumb(): Promise { + return await this.testSubjects.getVisibleText( + 'headerGlobalNav > breadcrumbs > ~breadcrumb & ~last' + ); + } - public async badgeMissingOrFail(): Promise { - await testSubjects.missingOrFail('headerBadge'); - } + public async badgeExistsOrFail(expectedLabel: string): Promise { + await this.testSubjects.existOrFail('headerBadge'); + const actualLabel = await this.testSubjects.getAttribute( + 'headerBadge', + 'data-test-badge-label' + ); + expect(actualLabel.toUpperCase()).to.equal(expectedLabel.toUpperCase()); } - return new GlobalNav(); + public async badgeMissingOrFail(): Promise { + await this.testSubjects.missingOrFail('headerBadge'); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index fc90fcdb2d52e4..b1443244d2c5a7 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -29,7 +29,7 @@ import { DocTableService } from './doc_table'; import { EmbeddingProvider } from './embedding'; import { FilterBarService } from './filter_bar'; import { FlyoutProvider } from './flyout'; -import { GlobalNavProvider } from './global_nav'; +import { GlobalNavService } from './global_nav'; import { InspectorProvider } from './inspector'; import { FieldEditorService } from './field_editor'; import { ManagementMenuProvider } from './management'; @@ -78,7 +78,7 @@ export const services = { fieldEditor: FieldEditorService, vegaDebugInspector: VegaDebugInspectorViewProvider, appsMenu: AppsMenuProvider, - globalNav: GlobalNavProvider, + globalNav: GlobalNavService, toasts: ToastsProvider, savedQueryManagementComponent: SavedQueryManagementComponentProvider, elasticChart: ElasticChartProvider, From 638ab8247bef2f3a41e7f4b8e87c174224d02a25 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Wed, 26 May 2021 16:02:28 +0300 Subject: [PATCH 5/6] [Gauge] Fixes wrong translations on ranges less than symbol (#100535) --- x-pack/plugins/translations/translations/ja-JP.json | 2 +- x-pack/plugins/translations/translations/zh-CN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 417c8360d0df37..66941a8fb591dc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4215,7 +4215,7 @@ "visDefaultEditor.controls.ranges.fromLabel": "開始:", "visDefaultEditor.controls.ranges.greaterThanOrEqualPrepend": "≧", "visDefaultEditor.controls.ranges.greaterThanOrEqualTooltip": "よりも大きいまたは等しい", - "visDefaultEditor.controls.ranges.lessThanPrepend": "<", + "visDefaultEditor.controls.ranges.lessThanPrepend": "<", "visDefaultEditor.controls.ranges.lessThanTooltip": "より小さい", "visDefaultEditor.controls.ranges.removeRangeButtonAriaLabel": "{from}から{to}の範囲を削除", "visDefaultEditor.controls.ranges.toLabel": "終了:", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8f0694e02ad91b..306ac0bf744e2d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4241,7 +4241,7 @@ "visDefaultEditor.controls.ranges.fromLabel": "自", "visDefaultEditor.controls.ranges.greaterThanOrEqualPrepend": "≥", "visDefaultEditor.controls.ranges.greaterThanOrEqualTooltip": "大于或等于", - "visDefaultEditor.controls.ranges.lessThanPrepend": "<", + "visDefaultEditor.controls.ranges.lessThanPrepend": "<", "visDefaultEditor.controls.ranges.lessThanTooltip": "小于", "visDefaultEditor.controls.ranges.removeRangeButtonAriaLabel": "移除范围 {from} 至 {to}", "visDefaultEditor.controls.ranges.toLabel": "至", From e7bc8831c2f096da931ea8451406dc65ae3272c3 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 26 May 2021 15:17:03 +0200 Subject: [PATCH 6/6] improve default time ranges (#100536) --- src/plugins/data/server/ui_settings.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index ed3510c5776e0d..e0d475e7124fd2 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -605,35 +605,35 @@ export function getUiSettings(): Record> { }), }, { - from: 'now-24h', + from: 'now-24h/h', to: 'now', display: i18n.translate('data.advancedSettings.timepicker.last24Hours', { defaultMessage: 'Last 24 hours', }), }, { - from: 'now-7d', + from: 'now-7d/d', to: 'now', display: i18n.translate('data.advancedSettings.timepicker.last7Days', { defaultMessage: 'Last 7 days', }), }, { - from: 'now-30d', + from: 'now-30d/d', to: 'now', display: i18n.translate('data.advancedSettings.timepicker.last30Days', { defaultMessage: 'Last 30 days', }), }, { - from: 'now-90d', + from: 'now-90d/d', to: 'now', display: i18n.translate('data.advancedSettings.timepicker.last90Days', { defaultMessage: 'Last 90 days', }), }, { - from: 'now-1y', + from: 'now-1y/d', to: 'now', display: i18n.translate('data.advancedSettings.timepicker.last1Year', { defaultMessage: 'Last 1 year',