From 27d0e70079e57dacdd2a6f8071272bd8e34a97fa Mon Sep 17 00:00:00 2001
From: Anton Dosov <anton.dosov@elastic.co>
Date: Thu, 5 Aug 2021 17:46:01 +0200
Subject: [PATCH 1/3] wip

---
 .../bytes/__snapshots__/bytes.test.tsx.snap   |   1 +
 .../__snapshots__/duration.test.tsx.snap      |   6 +
 .../editors/duration/duration.tsx             |   2 +
 .../number/__snapshots__/number.test.tsx.snap |   1 +
 .../editors/number/number.tsx                 |   1 +
 .../__snapshots__/percent.test.tsx.snap       |   1 +
 .../__snapshots__/truncate.test.tsx.snap      |   1 +
 .../editors/truncate/truncate.tsx             |   1 +
 test/common/services/index.ts                 |   2 +
 test/common/services/index_patterns.ts        |  32 ++
 .../apps/management/_field_formatter.js       |  53 ---
 .../apps/management/_field_formatter.ts       | 366 ++++++++++++++++++
 12 files changed, 414 insertions(+), 53 deletions(-)
 create mode 100644 test/common/services/index_patterns.ts
 delete mode 100644 test/functional/apps/management/_field_formatter.js
 create mode 100644 test/functional/apps/management/_field_formatter.ts

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"
   >
     <EuiFieldText
+      data-test-subj="numberEditorFormatPattern"
       isInvalid={false}
       onChange={[Function]}
       placeholder="0,0.[000]b"
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap
index d000af4453cd1..85e0177964a29 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap
@@ -19,6 +19,7 @@ exports[`DurationFormatEditor should not render show suffix on dynamic output 1`
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorInputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
@@ -49,6 +50,7 @@ exports[`DurationFormatEditor should not render show suffix on dynamic output 1`
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorOutputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
@@ -198,6 +200,7 @@ exports[`DurationFormatEditor should render human readable output normally 1`] =
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorInputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
@@ -228,6 +231,7 @@ exports[`DurationFormatEditor should render human readable output normally 1`] =
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorOutputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
@@ -310,6 +314,7 @@ exports[`DurationFormatEditor should render non-human readable output normally 1
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorInputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
@@ -340,6 +345,7 @@ exports[`DurationFormatEditor should render non-human readable output normally 1
     labelType="label"
   >
     <EuiSelect
+      data-test-subj="durationEditorOutputFormat"
       isInvalid={false}
       onChange={[Function]}
       options={
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/duration.tsx b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/duration.tsx
index 89bac89a95b76..24582e853d38f 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/duration.tsx
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/duration/duration.tsx
@@ -103,6 +103,7 @@ export class DurationFormatEditor extends DefaultFormatEditor<
           error={hasDecimalError ? null : error}
         >
           <EuiSelect
+            data-test-subj={'durationEditorInputFormat'}
             value={formatParams.inputFormat}
             options={format.type.inputFormats.map((fmt: InputFormat) => {
               return {
@@ -126,6 +127,7 @@ export class DurationFormatEditor extends DefaultFormatEditor<
           isInvalid={!!error}
         >
           <EuiSelect
+            data-test-subj={'durationEditorOutputFormat'}
             value={formatParams.outputFormat}
             options={format.type.outputFormats.map((fmt: OutputFormat) => {
               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"
   >
     <EuiFieldText
+      data-test-subj="numberEditorFormatPattern"
       isInvalid={false}
       onChange={[Function]}
       placeholder="0,0.[000]"
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/number.tsx b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/number.tsx
index 83110a4e42574..9bb1b57f0a701 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/number.tsx
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/number/number.tsx
@@ -66,6 +66,7 @@ export class NumberFormatEditor extends DefaultFormatEditor<NumberFormatEditorPa
           error={error}
         >
           <EuiFieldText
+            data-test-subj={'numberEditorFormatPattern'}
             value={formatParams.pattern}
             placeholder={defaultPattern}
             onChange={(e) => {
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"
   >
     <EuiFieldText
+      data-test-subj="numberEditorFormatPattern"
       isInvalid={false}
       onChange={[Function]}
       placeholder="0,0.[000]%"
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap
index f982632bba523..cc6eddbf0dc8c 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap
@@ -19,6 +19,7 @@ exports[`TruncateFormatEditor should render normally 1`] = `
     labelType="label"
   >
     <EuiFieldNumber
+      data-test-subj="truncateEditorLength"
       defaultValue={5}
       isInvalid={false}
       min={1}
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/truncate.tsx b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/truncate.tsx
index 8d4a227270718..ef4365cc576e2 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/truncate.tsx
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/truncate/truncate.tsx
@@ -48,6 +48,7 @@ export class TruncateFormatEditor extends DefaultFormatEditor<TruncateFormatEdit
           <EuiFieldNumber
             defaultValue={formatParams.fieldLength}
             min={1}
+            data-test-subj={'truncateEditorLength'}
             onChange={(e) => {
               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..eb1d5da4a9496
--- /dev/null
+++ b/test/common/services/index_patterns.ts
@@ -0,0 +1,32 @@
+/*
+ * 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';
+
+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 }
+  ) {
+    const response = await this.kibanaServer.request({
+      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..7b6ce17279eca
--- /dev/null
+++ b/test/functional/apps/management/_field_formatter.ts
@@ -0,0 +1,366 @@
+/*
+ * 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/data/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',
+          },
+          {
+            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');
+            },
+          },
+          {
+            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',
+          },
+        ]);
+      });
+
+      describe('Number format', () => {
+        testFormatEditors([
+          {
+            fieldType: ES_FIELD_TYPES.LONG,
+            fieldValue: 324,
+            applyFormatterType: FIELD_FORMAT_IDS.NUMBER,
+            expectFormattedValue: '324',
+          },
+          {
+            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}}'
+              );
+            },
+          },
+          {
+            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');
+            },
+          },
+        ]);
+      });
+
+      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');
+            },
+          },
+          {
+            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',
+          },
+          {
+            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('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,
+            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');
+            },
+          },
+        ]);
+      });
+    });
+  });
+
+  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<string, { type: ES_FIELD_TYPES }>),
+          },
+        },
+      });
+
+      const docResult = await es.index({
+        index: indexTitle,
+        body: specs.reduce((properties, spec, index) => {
+          properties[`${index}`] = spec.fieldValue;
+          return properties;
+        }, {} as Record<string, FieldFormatEditorSpecDescriptor['fieldValue']>),
+        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);
+      });
+
+      specs.forEach((spec, index) => {
+        const fieldName = `${index}`;
+        it(`edit field format of "${fieldName}" field to "${spec.applyFormatterType}"`, async () => {
+          await PageObjects.settings.filterField(fieldName);
+          await PageObjects.settings.openControlsByName(fieldName);
+          await PageObjects.settings.toggleRow('formatRow');
+          await PageObjects.settings.setFieldFormat(spec.applyFormatterType);
+          if (spec.beforeSave) {
+            await spec.beforeSave(await testSubjects.find('formatRow'));
+          }
+          await PageObjects.settings.controlChangeSave();
+          await toasts.dismissToast(); // dismiss "saved" toast, otherwise it could overlap save button for a next test
+        });
+      });
+    });
+
+    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);
+        });
+      });
+    });
+  }
+}
+
+/**
+ * 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;
+  /**
+   * 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<void>;
+
+  /**
+   * An expected formatted value rendered by Discover app,
+   * Use this for final assertion
+   */
+  expectFormattedValue: string;
+}

From 8727715b3fb3a4df5353d17fe510861a3554c667 Mon Sep 17 00:00:00 2001
From: Anton Dosov <anton.dosov@elastic.co>
Date: Mon, 9 Aug 2021 11:47:47 +0200
Subject: [PATCH 2/3] fix typescript

---
 test/common/services/index_patterns.ts              | 7 +++++--
 test/functional/apps/management/_field_formatter.ts | 4 ++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/test/common/services/index_patterns.ts b/test/common/services/index_patterns.ts
index eb1d5da4a9496..5b6d20990b6d1 100644
--- a/test/common/services/index_patterns.ts
+++ b/test/common/services/index_patterns.ts
@@ -7,6 +7,7 @@
  */
 
 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');
@@ -17,8 +18,10 @@ export class IndexPatternsService extends FtrService {
   async create(
     indexPattern: { title: string },
     { override = false }: { override: boolean } = { override: false }
-  ) {
-    const response = await this.kibanaServer.request({
+  ): Promise<IndexPatternSpec> {
+    const response = await this.kibanaServer.request<{
+      index_pattern: IndexPatternSpec;
+    }>({
       path: '/api/index_patterns/index_pattern',
       method: 'POST',
       body: {
diff --git a/test/functional/apps/management/_field_formatter.ts b/test/functional/apps/management/_field_formatter.ts
index 7b6ce17279eca..cf06eff671ce3 100644
--- a/test/functional/apps/management/_field_formatter.ts
+++ b/test/functional/apps/management/_field_formatter.ts
@@ -8,7 +8,7 @@
 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/data/common';
+import { FIELD_FORMAT_IDS } from '../../../../src/plugins/field_formats/common';
 import { WebElementWrapper } from '../../services/lib/web_element_wrapper';
 
 export default function ({ getService, getPageObjects }: FtrProviderContext) {
@@ -290,7 +290,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
         { title: indexTitle },
         { override: true }
       );
-      indexPatternId = indexPatternResult.id;
+      indexPatternId = indexPatternResult.id!;
     });
 
     describe('edit formats', () => {

From 44f02d70bf47f994465c1dc56e95d6c086a9e07a Mon Sep 17 00:00:00 2001
From: Anton Dosov <anton.dosov@elastic.co>
Date: Mon, 9 Aug 2021 18:00:34 +0200
Subject: [PATCH 3/3] wip

---
 .../color/__snapshots__/color.test.tsx.snap   |   6 +
 .../editors/color/color.tsx                   |  12 +-
 .../__snapshots__/static_lookup.test.tsx.snap |   6 +
 .../editors/static_lookup/static_lookup.tsx   |  11 +-
 .../apps/management/_field_formatter.ts       | 225 +++++++++++++++++-
 5 files changed, 248 insertions(+), 12 deletions(-)

diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/__snapshots__/color.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/__snapshots__/color.test.tsx.snap
index c33bb57bfeac8..7406e5ae9bb2d 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/__snapshots__/color.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/__snapshots__/color.test.tsx.snap
@@ -45,6 +45,7 @@ exports[`ColorFormatEditor should render multiple colors 1`] = `
             Object {
               "available": [Function],
               "color": "danger",
+              "data-test-subj": "colorEditorRemoveColor",
               "description": "Delete color format",
               "icon": "trash",
               "name": "Delete",
@@ -83,6 +84,7 @@ exports[`ColorFormatEditor should render multiple colors 1`] = `
     size="m"
   />
   <EuiButton
+    data-test-subj="colorEditorAddColor"
     iconType="plusInCircle"
     onClick={[Function]}
     size="s"
@@ -144,6 +146,7 @@ exports[`ColorFormatEditor should render other type normally (range field) 1`] =
             Object {
               "available": [Function],
               "color": "danger",
+              "data-test-subj": "colorEditorRemoveColor",
               "description": "Delete color format",
               "icon": "trash",
               "name": "Delete",
@@ -175,6 +178,7 @@ exports[`ColorFormatEditor should render other type normally (range field) 1`] =
     size="m"
   />
   <EuiButton
+    data-test-subj="colorEditorAddColor"
     iconType="plusInCircle"
     onClick={[Function]}
     size="s"
@@ -236,6 +240,7 @@ exports[`ColorFormatEditor should render string type normally (regex field) 1`]
             Object {
               "available": [Function],
               "color": "danger",
+              "data-test-subj": "colorEditorRemoveColor",
               "description": "Delete color format",
               "icon": "trash",
               "name": "Delete",
@@ -267,6 +272,7 @@ exports[`ColorFormatEditor should render string type normally (regex field) 1`]
     size="m"
   />
   <EuiButton
+    data-test-subj="colorEditorAddColor"
     iconType="plusInCircle"
     onClick={[Function]}
     size="s"
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/color.tsx b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/color.tsx
index 67290212c04dd..9944c031198ef 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/color.tsx
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/color/color.tsx
@@ -96,6 +96,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
               return (
                 <EuiFieldText
                   value={value}
+                  data-test-subj={`colorEditorKeyPattern ${item.index}`}
                   onChange={(e) => {
                     this.onColorChange(
                       {
@@ -120,6 +121,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
               return (
                 <EuiFieldText
                   value={value}
+                  data-test-subj={`colorEditorKeyRange ${item.index}`}
                   onChange={(e) => {
                     this.onColorChange(
                       {
@@ -144,6 +146,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
           return (
             <EuiColorPicker
               color={color}
+              data-test-subj={`colorEditorColorPicker ${item.index}`}
               onChange={(newColor) => {
                 this.onColorChange(
                   {
@@ -168,6 +171,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
           return (
             <EuiColorPicker
               color={color}
+              data-test-subj={`colorEditorBackgroundPicker ${item.index}`}
               onChange={(newColor) => {
                 this.onColorChange(
                   {
@@ -220,6 +224,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
             icon: 'trash',
             color: 'danger',
             available: () => items.length > 1,
+            'data-test-subj': 'colorEditorRemoveColor',
           },
         ],
       },
@@ -229,7 +234,12 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
       <Fragment>
         <EuiBasicTable items={items} columns={columns} />
         <EuiSpacer size="m" />
-        <EuiButton iconType="plusInCircle" size="s" onClick={this.addColor}>
+        <EuiButton
+          iconType="plusInCircle"
+          size="s"
+          onClick={this.addColor}
+          data-test-subj={'colorEditorAddColor'}
+        >
           <FormattedMessage
             id="indexPatternFieldEditor.color.addColorButton"
             defaultMessage="Add color"
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/__snapshots__/static_lookup.test.tsx.snap b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/__snapshots__/static_lookup.test.tsx.snap
index c5697cb699eb7..664912789b0e3 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/__snapshots__/static_lookup.test.tsx.snap
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/__snapshots__/static_lookup.test.tsx.snap
@@ -28,6 +28,7 @@ exports[`StaticLookupFormatEditor should render multiple lookup entries and unkn
             Object {
               "available": [Function],
               "color": "danger",
+              "data-test-subj": "staticLookupEditorRemoveEntry",
               "description": "Delete entry",
               "icon": "trash",
               "name": "Delete",
@@ -67,6 +68,7 @@ exports[`StaticLookupFormatEditor should render multiple lookup entries and unkn
     size="m"
   />
   <EuiButton
+    data-test-subj="staticLookupEditorAddEntry"
     iconType="plusInCircle"
     onClick={[Function]}
     size="s"
@@ -96,6 +98,7 @@ exports[`StaticLookupFormatEditor should render multiple lookup entries and unkn
     labelType="label"
   >
     <EuiFieldText
+      data-test-subj="staticLookupEditorUnknownValue"
       onChange={[Function]}
       placeholder="Leave blank to keep value as-is"
       value="test value"
@@ -135,6 +138,7 @@ exports[`StaticLookupFormatEditor should render normally 1`] = `
             Object {
               "available": [Function],
               "color": "danger",
+              "data-test-subj": "staticLookupEditorRemoveEntry",
               "description": "Delete entry",
               "icon": "trash",
               "name": "Delete",
@@ -168,6 +172,7 @@ exports[`StaticLookupFormatEditor should render normally 1`] = `
     size="m"
   />
   <EuiButton
+    data-test-subj="staticLookupEditorAddEntry"
     iconType="plusInCircle"
     onClick={[Function]}
     size="s"
@@ -197,6 +202,7 @@ exports[`StaticLookupFormatEditor should render normally 1`] = `
     labelType="label"
   >
     <EuiFieldText
+      data-test-subj="staticLookupEditorUnknownValue"
       onChange={[Function]}
       placeholder="Leave blank to keep value as-is"
       value=""
diff --git a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/static_lookup.tsx b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/static_lookup.tsx
index 485660fbb2bd4..ab0653d141fce 100644
--- a/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/static_lookup.tsx
+++ b/src/plugins/index_pattern_field_editor/public/components/field_format_editor/editors/static_lookup/static_lookup.tsx
@@ -81,6 +81,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor<StaticLookupFo
           return (
             <EuiFieldText
               value={value || ''}
+              data-test-subj={`staticLookupEditorKey ${item.index}`}
               onChange={(e) => {
                 this.onLookupChange(
                   {
@@ -105,6 +106,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor<StaticLookupFo
           return (
             <EuiFieldText
               value={value || ''}
+              data-test-subj={`staticLookupEditorValue ${item.index}`}
               onChange={(e) => {
                 this.onLookupChange(
                   {
@@ -136,6 +138,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor<StaticLookupFo
             type: 'icon',
             icon: 'trash',
             color: 'danger',
+            'data-test-subj': 'staticLookupEditorRemoveEntry',
             available: () => items.length > 1,
           },
         ],
@@ -147,7 +150,12 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor<StaticLookupFo
       <Fragment>
         <EuiBasicTable items={items} columns={columns} style={{ maxWidth: '400px' }} />
         <EuiSpacer size="m" />
-        <EuiButton iconType="plusInCircle" size="s" onClick={this.addLookup}>
+        <EuiButton
+          iconType="plusInCircle"
+          size="s"
+          onClick={this.addLookup}
+          data-test-subj={'staticLookupEditorAddEntry'}
+        >
           <FormattedMessage
             id="indexPatternFieldEditor.staticLookup.addEntryButton"
             defaultMessage="Add entry"
@@ -164,6 +172,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor<StaticLookupFo
         >
           <EuiFieldText
             value={formatParams.unknownKeyValue || ''}
+            data-test-subj={'staticLookupEditorUnknownValue'}
             placeholder={i18n.translate(
               'indexPatternFieldEditor.staticLookup.leaveBlankPlaceholder',
               {
diff --git a/test/functional/apps/management/_field_formatter.ts b/test/functional/apps/management/_field_formatter.ts
index cf06eff671ce3..60c1bbe7b3d1d 100644
--- a/test/functional/apps/management/_field_formatter.ts
+++ b/test/functional/apps/management/_field_formatter.ts
@@ -71,6 +71,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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,
@@ -89,6 +99,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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,
@@ -140,6 +159,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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,
+            ],
           },
         ]);
       });
@@ -151,6 +182,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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,
@@ -177,6 +220,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
                 '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,
@@ -190,6 +238,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
               );
               await testSubjects.setValue('urlEditorLabelTemplate', 'url label');
             },
+            expect: async (renderedValueContainer) => {
+              expect(
+                await (await renderedValueContainer.findByTagName('a')).getAttribute('href')
+              ).to.be('https://elastic.co/?value=100');
+            },
           },
         ]);
       });
@@ -204,12 +257,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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,
@@ -220,6 +289,64 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
         ]);
       });
 
+      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([
           {
@@ -235,6 +362,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
             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%');
@@ -249,11 +388,33 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
               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;
@@ -300,19 +461,49 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
         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}"`, async () => {
-          await PageObjects.settings.filterField(fieldName);
-          await PageObjects.settings.openControlsByName(fieldName);
-          await PageObjects.settings.toggleRow('formatRow');
-          await PageObjects.settings.setFieldFormat(spec.applyFormatterType);
-          if (spec.beforeSave) {
-            await spec.beforeSave(await testSubjects.find('formatRow'));
+        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'));
+            }
           }
-          await PageObjects.settings.controlChangeSave();
-          await toasts.dismissToast(); // dismiss "saved" toast, otherwise it could overlap save button for a next test
-        });
+        );
       });
     });
 
@@ -329,6 +520,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
           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);
+          }
         });
       });
     });
@@ -351,6 +545,12 @@ interface FieldFormatEditorSpecDescriptor {
    * 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
@@ -363,4 +563,9 @@ interface FieldFormatEditorSpecDescriptor {
    * Use this for final assertion
    */
   expectFormattedValue: string;
+
+  /**
+   * Run additional assertions on rendered element
+   */
+  expect?: (renderedValueContainer: WebElementWrapper) => Promise<void>;
 }