diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap
index 2ab8037639f85..2b71d1882b0cf 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap
@@ -43,6 +43,7 @@ exports[`BytesFormatEditor should render normally 1`] = `
labelType="label"
>
{
this.onColorChange(
{
@@ -120,6 +121,7 @@ export class ColorFormatEditor extends DefaultFormatEditor {
this.onColorChange(
{
@@ -144,6 +146,7 @@ export class ColorFormatEditor extends DefaultFormatEditor {
this.onColorChange(
{
@@ -168,6 +171,7 @@ export class ColorFormatEditor extends DefaultFormatEditor {
this.onColorChange(
{
@@ -220,6 +224,7 @@ export class ColorFormatEditor extends DefaultFormatEditor items.length > 1,
+ 'data-test-subj': 'colorEditorRemoveColor',
},
],
},
@@ -229,7 +234,12 @@ export class ColorFormatEditor extends DefaultFormatEditor
-
+
{
return {
@@ -126,6 +127,7 @@ export class DurationFormatEditor extends DefaultFormatEditor<
isInvalid={!!error}
>
{
return {
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/__snapshots__/number.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/__snapshots__/number.test.tsx.snap
index 4d42e3848d3cd..8b59c0da10167 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/__snapshots__/number.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/__snapshots__/number.test.tsx.snap
@@ -43,6 +43,7 @@ exports[`NumberFormatEditor should render normally 1`] = `
labelType="label"
>
{
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap
index fce51e8fa3871..7d8ab5e682a3e 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap
@@ -43,6 +43,7 @@ exports[`PercentFormatEditor should render normally 1`] = `
labelType="label"
>
{
this.onLookupChange(
{
@@ -105,6 +106,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor {
this.onLookupChange(
{
@@ -136,6 +138,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor items.length > 1,
},
],
@@ -147,7 +150,12 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor
-
+
{
if (e.target.checkValidity()) {
this.onChange({
diff --git a/test/common/services/index.ts b/test/common/services/index.ts
index 370d289093517..c04bd778468a9 100644
--- a/test/common/services/index.ts
+++ b/test/common/services/index.ts
@@ -15,6 +15,7 @@ import { RandomnessService } from './randomness';
import { SecurityServiceProvider } from './security';
import { EsDeleteAllIndicesProvider } from './es_delete_all_indices';
import { SavedObjectInfoService } from './saved_object_info';
+import { IndexPatternsService } from './index_patterns';
export const services = {
deployment: DeploymentService,
@@ -26,4 +27,5 @@ export const services = {
security: SecurityServiceProvider,
esDeleteAllIndices: EsDeleteAllIndicesProvider,
savedObjectInfo: SavedObjectInfoService,
+ indexPatterns: IndexPatternsService,
};
diff --git a/test/common/services/index_patterns.ts b/test/common/services/index_patterns.ts
new file mode 100644
index 0000000000000..5b6d20990b6d1
--- /dev/null
+++ b/test/common/services/index_patterns.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { FtrService } from '../ftr_provider_context';
+import { IndexPatternSpec } from '../../../src/plugins/data/common';
+
+export class IndexPatternsService extends FtrService {
+ private readonly kibanaServer = this.ctx.getService('kibanaServer');
+
+ /**
+ * Create a new index pattern
+ */
+ async create(
+ indexPattern: { title: string },
+ { override = false }: { override: boolean } = { override: false }
+ ): Promise {
+ const response = await this.kibanaServer.request<{
+ index_pattern: IndexPatternSpec;
+ }>({
+ path: '/api/index_patterns/index_pattern',
+ method: 'POST',
+ body: {
+ override,
+ index_pattern: indexPattern,
+ },
+ });
+
+ return response.data.index_pattern;
+ }
+}
diff --git a/test/functional/apps/management/_field_formatter.js b/test/functional/apps/management/_field_formatter.js
deleted file mode 100644
index 383b4faecc40c..0000000000000
--- a/test/functional/apps/management/_field_formatter.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-export default function ({ getService, getPageObjects }) {
- const esArchiver = getService('esArchiver');
- const kibanaServer = getService('kibanaServer');
- const browser = getService('browser');
- const PageObjects = getPageObjects(['settings']);
- const testSubjects = getService('testSubjects');
-
- describe('field formatter', function () {
- this.tags(['skipFirefox']);
-
- before(async function () {
- await browser.setWindowSize(1200, 800);
- await esArchiver.load('test/functional/fixtures/es_archiver/discover');
- await kibanaServer.uiSettings.replace({});
- await kibanaServer.uiSettings.update({});
- });
-
- after(async function afterAll() {
- await PageObjects.settings.navigateTo();
- await esArchiver.emptyKibanaIndex();
- });
-
- describe('set and change field formatter', function describeIndexTests() {
- // addresses https://github.com/elastic/kibana/issues/93349
- it('can change format more than once', async function () {
- await PageObjects.settings.navigateTo();
- await PageObjects.settings.clickKibanaIndexPatterns();
- await PageObjects.settings.clickIndexPatternLogstash();
- await PageObjects.settings.clickAddField();
- await PageObjects.settings.setFieldType('Long');
- const formatRow = await testSubjects.find('formatRow');
- const formatRowToggle = (
- await formatRow.findAllByCssSelector('[data-test-subj="toggle"]')
- )[0];
-
- await formatRowToggle.click();
- await PageObjects.settings.setFieldFormat('duration');
- await PageObjects.settings.setFieldFormat('bytes');
- await PageObjects.settings.setFieldFormat('duration');
- await testSubjects.click('euiFlyoutCloseButton');
- await PageObjects.settings.closeIndexPatternFieldEditor();
- });
- });
- });
-}
diff --git a/test/functional/apps/management/_field_formatter.ts b/test/functional/apps/management/_field_formatter.ts
new file mode 100644
index 0000000000000..60c1bbe7b3d1d
--- /dev/null
+++ b/test/functional/apps/management/_field_formatter.ts
@@ -0,0 +1,571 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+import { ES_FIELD_TYPES } from '@kbn/field-types';
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../ftr_provider_context';
+import { FIELD_FORMAT_IDS } from '../../../../src/plugins/field_formats/common';
+import { WebElementWrapper } from '../../services/lib/web_element_wrapper';
+
+export default function ({ getService, getPageObjects }: FtrProviderContext) {
+ const esArchiver = getService('esArchiver');
+ const kibanaServer = getService('kibanaServer');
+ const browser = getService('browser');
+ const PageObjects = getPageObjects(['settings', 'common']);
+ const testSubjects = getService('testSubjects');
+ const es = getService('es');
+ const indexPatterns = getService('indexPatterns');
+ const toasts = getService('toasts');
+
+ describe('field formatter', function () {
+ this.tags(['skipFirefox']);
+
+ before(async function () {
+ await browser.setWindowSize(1200, 800);
+ await esArchiver.load('test/functional/fixtures/es_archiver/discover');
+ await kibanaServer.uiSettings.replace({});
+ await kibanaServer.uiSettings.update({});
+ });
+
+ after(async function afterAll() {
+ await PageObjects.settings.navigateTo();
+ await esArchiver.emptyKibanaIndex();
+ });
+
+ describe('set and change field formatter', function describeIndexTests() {
+ // addresses https://github.com/elastic/kibana/issues/93349
+ it('can change format more than once', async function () {
+ await PageObjects.settings.navigateTo();
+ await PageObjects.settings.clickKibanaIndexPatterns();
+ await PageObjects.settings.clickIndexPatternLogstash();
+ await PageObjects.settings.clickAddField();
+ await PageObjects.settings.setFieldType('Long');
+ const formatRow = await testSubjects.find('formatRow');
+ const formatRowToggle = (
+ await formatRow.findAllByCssSelector('[data-test-subj="toggle"]')
+ )[0];
+
+ await formatRowToggle.click();
+ await PageObjects.settings.setFieldFormat('duration');
+ await PageObjects.settings.setFieldFormat('bytes');
+ await PageObjects.settings.setFieldFormat('duration');
+ await testSubjects.click('euiFlyoutCloseButton');
+ await PageObjects.settings.closeIndexPatternFieldEditor();
+ });
+ });
+
+ /**
+ * The purpose of these tests is to cover **editing experience** of different field formats editors,
+ * The logic of each converter is extensively covered by unit tests.
+ * TODO: these tests also could check field formats behaviour with different combinations of browser locale, timezone and ui settings
+ */
+ describe('field format editors', () => {
+ describe('String format', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.TEXT,
+ fieldValue: 'A regular text',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'A regular text',
+
+ // check available formats for ES_FIELD_TYPES.TEXT
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.COLOR,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.TRUNCATE,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ {
+ fieldType: ES_FIELD_TYPES.TEXT,
+ fieldValue: 'A regular text',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'a regular text',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'lower');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'a keyword',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'A KEYWORD',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'upper');
+ },
+ // check available formats for ES_FIELD_TYPES.KEYWORD
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.COLOR,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.TRUNCATE,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'a keyword',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'A Keyword',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'title');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'com.organizations.project.ClassName',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'c.o.p.ClassName',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'short');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'SGVsbG8gd29ybGQ=',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: 'Hello world',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'base64');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: '%EC%95%88%EB%85%95%20%ED%82%A4%EB%B0%94%EB%82%98',
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: '안녕 키바나',
+ beforeSave: async () => {
+ await testSubjects.selectValue('stringEditorTransform', 'urlparam');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: '123456789',
+ applyFormatterType: FIELD_FORMAT_IDS.TRUNCATE,
+ expectFormattedValue: '123...',
+ beforeSave: async () => {
+ await testSubjects.setValue('truncateEditorLength', '3');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.INTEGER,
+ fieldValue: 324,
+ applyFormatterType: FIELD_FORMAT_IDS.STRING,
+ expectFormattedValue: '324',
+ // check available formats for ES_FIELD_TYPES.INTEGER
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.BYTES,
+ FIELD_FORMAT_IDS.COLOR,
+ FIELD_FORMAT_IDS.DURATION,
+ FIELD_FORMAT_IDS.NUMBER,
+ FIELD_FORMAT_IDS.PERCENT,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ ]);
+ });
+
+ describe('Number format', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 324,
+ applyFormatterType: FIELD_FORMAT_IDS.NUMBER,
+ expectFormattedValue: '324',
+ // check available formats for ES_FIELD_TYPES.LONG
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.BYTES,
+ FIELD_FORMAT_IDS.COLOR,
+ FIELD_FORMAT_IDS.DURATION,
+ FIELD_FORMAT_IDS.NUMBER,
+ FIELD_FORMAT_IDS.PERCENT,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 324,
+ applyFormatterType: FIELD_FORMAT_IDS.NUMBER,
+ expectFormattedValue: '+324',
+ beforeSave: async () => {
+ await testSubjects.setValue('numberEditorFormatPattern', '+0,0');
+ },
+ },
+ ]);
+ });
+
+ describe('URL format', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 100,
+ applyFormatterType: FIELD_FORMAT_IDS.URL,
+ expectFormattedValue: 'https://elastic.co/?value=100',
+ beforeSave: async () => {
+ await testSubjects.setValue(
+ 'urlEditorUrlTemplate',
+ 'https://elastic.co/?value={{value}}'
+ );
+ },
+ expect: async (renderedValueContainer) => {
+ expect(
+ await (await renderedValueContainer.findByTagName('a')).getAttribute('href')
+ ).to.be('https://elastic.co/?value=100');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 100,
+ applyFormatterType: FIELD_FORMAT_IDS.URL,
+ expectFormattedValue: 'url label',
+ beforeSave: async () => {
+ await testSubjects.setValue(
+ 'urlEditorUrlTemplate',
+ 'https://elastic.co/?value={{value}}'
+ );
+ await testSubjects.setValue('urlEditorLabelTemplate', 'url label');
+ },
+ expect: async (renderedValueContainer) => {
+ expect(
+ await (await renderedValueContainer.findByTagName('a')).getAttribute('href')
+ ).to.be('https://elastic.co/?value=100');
+ },
+ },
+ ]);
+ });
+
+ describe('Date format', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.DATE,
+ fieldValue: '2021-08-05T15:05:37.151Z',
+ applyFormatterType: FIELD_FORMAT_IDS.DATE,
+ expectFormattedValue: 'Aug 5, 2021',
+ beforeSave: async () => {
+ await testSubjects.setValue('dateEditorPattern', 'MMM D, YYYY');
+ },
+ // check available formats for ES_FIELD_TYPES.DATE
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.DATE,
+ FIELD_FORMAT_IDS.DATE_NANOS,
+ FIELD_FORMAT_IDS.RELATIVE_DATE,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ {
+ fieldType: ES_FIELD_TYPES.DATE_NANOS,
+ fieldValue: '2015-01-01T12:10:30.123456789Z',
+ applyFormatterType: FIELD_FORMAT_IDS.DATE,
+ expectFormattedValue: 'Jan 1, 2015 @ 12:10:30.123',
+ // check available formats for ES_FIELD_TYPES.DATE_NANOS
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.DATE,
+ FIELD_FORMAT_IDS.DATE_NANOS,
+ FIELD_FORMAT_IDS.RELATIVE_DATE,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ },
+ {
+ fieldType: ES_FIELD_TYPES.DATE_NANOS,
+ fieldValue: '2015-01-01T12:10:30.123456789Z',
+ applyFormatterType: FIELD_FORMAT_IDS.DATE_NANOS,
+ expectFormattedValue: 'Jan 1, 2015 @ 12:10:30.123456789',
+ },
+ ]);
+ });
+
+ describe('Static lookup format', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'look me up',
+ applyFormatterType: FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ expectFormattedValue: 'looked up!',
+ beforeSave: async () => {
+ await testSubjects.click('staticLookupEditorAddEntry');
+ await testSubjects.setValue('~staticLookupEditorKey', 'look me up');
+ await testSubjects.setValue('~staticLookupEditorValue', 'looked up!');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.BOOLEAN,
+ fieldValue: 'true',
+ applyFormatterType: FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ // check available formats for ES_FIELD_TYPES.BOOLEAN
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ expectFormattedValue: 'yes',
+ beforeSave: async () => {
+ await testSubjects.click('staticLookupEditorAddEntry');
+ await testSubjects.setValue('~staticLookupEditorKey', 'true');
+ await testSubjects.setValue('~staticLookupEditorValue', 'yes');
+ await testSubjects.setValue('staticLookupEditorUnknownValue', 'no');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.BOOLEAN,
+ fieldValue: 'false',
+ applyFormatterType: FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ expectFormattedValue: 'no',
+ beforeSave: async () => {
+ await testSubjects.click('staticLookupEditorAddEntry');
+ await testSubjects.setValue('~staticLookupEditorKey', 'true');
+ await testSubjects.setValue('~staticLookupEditorValue', 'yes');
+ await testSubjects.setValue('staticLookupEditorUnknownValue', 'no');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.BOOLEAN,
+ fieldValue: 'false',
+ applyFormatterType: FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ expectFormattedValue: 'false',
+ beforeSave: async () => {
+ await testSubjects.click('staticLookupEditorAddEntry');
+ await testSubjects.setValue('~staticLookupEditorKey', 'true');
+ await testSubjects.setValue('~staticLookupEditorValue', 'yes');
+ },
+ },
+ ]);
+ });
+
+ describe('Other formats', () => {
+ testFormatEditors([
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 123292,
+ applyFormatterType: FIELD_FORMAT_IDS.DURATION,
+ expectFormattedValue: '2 minutes',
+ beforeSave: async () => {
+ await testSubjects.setValue('durationEditorInputFormat', 'milliseconds');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.DOUBLE,
+ fieldValue: 0.1,
+ applyFormatterType: FIELD_FORMAT_IDS.PERCENT,
+ // check available formats for ES_FIELD_TYPES.DOUBLE
+ expectFormatterTypes: [
+ FIELD_FORMAT_IDS.BOOLEAN,
+ FIELD_FORMAT_IDS.BYTES,
+ FIELD_FORMAT_IDS.COLOR,
+ FIELD_FORMAT_IDS.DURATION,
+ FIELD_FORMAT_IDS.NUMBER,
+ FIELD_FORMAT_IDS.PERCENT,
+ FIELD_FORMAT_IDS.STATIC_LOOKUP,
+ FIELD_FORMAT_IDS.STRING,
+ FIELD_FORMAT_IDS.URL,
+ ],
+ expectFormattedValue: '10.0%',
+ beforeSave: async () => {
+ await testSubjects.setValue('numberEditorFormatPattern', '0.0%');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.LONG,
+ fieldValue: 1990000000,
+ applyFormatterType: FIELD_FORMAT_IDS.BYTES,
+ expectFormattedValue: '2GB',
+ beforeSave: async () => {
+ await testSubjects.setValue('numberEditorFormatPattern', '0b');
+ },
+ },
+ {
+ fieldType: ES_FIELD_TYPES.KEYWORD,
+ fieldValue: 'red',
+ applyFormatterType: FIELD_FORMAT_IDS.COLOR,
+ expectFormattedValue: 'red',
+ beforeSave: async () => {
+ await testSubjects.click('colorEditorAddColor');
+ await testSubjects.setValue('~colorEditorKeyPattern', 'red');
+ await testSubjects.setValue('~colorEditorColorPicker', '#ffffff');
+ await testSubjects.setValue('~colorEditorBackgroundPicker', '#ff0000');
+ },
+ expect: async (renderedValueContainer) => {
+ const span = await renderedValueContainer.findByTagName('span');
+ expect(await span.getComputedStyle('color')).to.be('rgba(255, 255, 255, 1)');
+ expect(await span.getComputedStyle('background-color')).to.be('rgba(255, 0, 0, 1)');
+ },
+ },
+ ]);
+ });
+ });
+ });
+
+ /**
+ * Runs a field format editors tests covering data setup, editing a field and checking a resulting formatting in Discover app
+ * TODO: might be useful to reuse this util for runtime fields formats tests
+ * @param specs - {@link FieldFormatEditorSpecDescriptor}
+ */
+ function testFormatEditors(specs: FieldFormatEditorSpecDescriptor[]) {
+ const indexTitle = 'field_formats_management_functional_tests';
+ let indexPatternId: string;
+ let testDocumentId: string;
+
+ before(async () => {
+ if ((await es.indices.exists({ index: indexTitle })).body) {
+ await es.indices.delete({ index: indexTitle });
+ }
+
+ await es.indices.create({
+ index: indexTitle,
+ body: {
+ mappings: {
+ properties: specs.reduce((properties, spec, index) => {
+ properties[`${index}`] = { type: spec.fieldType };
+ return properties;
+ }, {} as Record),
+ },
+ },
+ });
+
+ const docResult = await es.index({
+ index: indexTitle,
+ body: specs.reduce((properties, spec, index) => {
+ properties[`${index}`] = spec.fieldValue;
+ return properties;
+ }, {} as Record),
+ refresh: 'wait_for',
+ });
+ testDocumentId = docResult.body._id;
+
+ const indexPatternResult = await indexPatterns.create(
+ { title: indexTitle },
+ { override: true }
+ );
+ indexPatternId = indexPatternResult.id!;
+ });
+
+ describe('edit formats', () => {
+ before(async () => {
+ await PageObjects.settings.navigateTo();
+ await PageObjects.settings.clickKibanaIndexPatterns();
+ await PageObjects.settings.clickIndexPatternByName(indexTitle);
+ });
+
+ afterEach(async () => {
+ try {
+ await PageObjects.settings.controlChangeSave();
+ } catch (e) {
+ // in case previous test failed in a state when save is disabled
+ await PageObjects.settings.controlChangeCancel();
+ }
+
+ await toasts.dismissAllToasts(); // dismiss "saved" toast, otherwise it could overlap save button for a next test
+ });
+
+ specs.forEach((spec, index) => {
+ const fieldName = `${index}`;
+ it(
+ `edit field format of "${fieldName}" field to "${spec.applyFormatterType}"` +
+ spec.expectFormatterTypes
+ ? `, and check available formats types`
+ : '',
+ async () => {
+ await PageObjects.settings.filterField(fieldName);
+ await PageObjects.settings.openControlsByName(fieldName);
+ await PageObjects.settings.toggleRow('formatRow');
+
+ if (spec.expectFormatterTypes) {
+ expect(
+ (
+ await Promise.all(
+ (
+ await (await testSubjects.find('editorSelectedFormatId')).findAllByTagName(
+ 'option'
+ )
+ ).map((option) => option.getAttribute('value'))
+ )
+ ).filter(Boolean)
+ ).to.eql(spec.expectFormatterTypes);
+ }
+
+ await PageObjects.settings.setFieldFormat(spec.applyFormatterType);
+ if (spec.beforeSave) {
+ await spec.beforeSave(await testSubjects.find('formatRow'));
+ }
+ }
+ );
+ });
+ });
+
+ describe('check formats', async () => {
+ before(async () => {
+ await PageObjects.common.navigateToApp('discover', {
+ hash: `/doc/${indexPatternId}/${indexTitle}?id=${testDocumentId}`,
+ });
+ await testSubjects.exists('doc-hit');
+ });
+
+ specs.forEach((spec, index) => {
+ it(`check field format of "${index}" field`, async () => {
+ const renderedValue = await testSubjects.find(`tableDocViewRow-${index}-value`);
+ const text = await renderedValue.getVisibleText();
+ expect(text).to.be(spec.expectFormattedValue);
+ if (spec.expect) {
+ await spec.expect(renderedValue);
+ }
+ });
+ });
+ });
+ }
+}
+
+/**
+ * Describes a field format editor test
+ */
+interface FieldFormatEditorSpecDescriptor {
+ /**
+ * Raw field value to put into document
+ */
+ fieldValue: string | number | boolean | null;
+ /**
+ * Explicitly specify a type for a {@link fieldValue}
+ */
+ fieldType: ES_FIELD_TYPES;
+ /**
+ * Type of a field formatter to apply
+ */
+ applyFormatterType: FIELD_FORMAT_IDS;
+
+ /**
+ * Optionally check available formats for {@link fieldType}
+ */
+ expectFormatterTypes?: FIELD_FORMAT_IDS[];
+
+ /**
+ * Function to execute before field format is applied.
+ * Use it set specific configuration params for applied field formatter
+ * @param formatRowContainer - field format editor container
+ */
+ beforeSave?: (formatRowContainer: WebElementWrapper) => Promise;
+
+ /**
+ * An expected formatted value rendered by Discover app,
+ * Use this for final assertion
+ */
+ expectFormattedValue: string;
+
+ /**
+ * Run additional assertions on rendered element
+ */
+ expect?: (renderedValueContainer: WebElementWrapper) => Promise;
+}