diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts
index 66021b531919a..ab42a035a3d90 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts
@@ -4,18 +4,44 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { setup as homeSetup } from './home.helpers';
-import { setup as templateCreateSetup } from './template_create.helpers';
-import { setup as templateCloneSetup } from './template_clone.helpers';
-import { setup as templateEditSetup } from './template_edit.helpers';
-
export { nextTick, getRandomString, findTestSubject, TestBed } from '../../../../../test_utils';
-export { setupEnvironment } from './setup_environment';
+export { setupEnvironment, WithAppDependencies, services } from './setup_environment';
-export const pageHelpers = {
- home: { setup: homeSetup },
- templateCreate: { setup: templateCreateSetup },
- templateClone: { setup: templateCloneSetup },
- templateEdit: { setup: templateEditSetup },
-};
+export type TestSubjects =
+ | 'aliasesTab'
+ | 'appTitle'
+ | 'cell'
+ | 'closeDetailsButton'
+ | 'createTemplateButton'
+ | 'deleteSystemTemplateCallOut'
+ | 'deleteTemplateButton'
+ | 'deleteTemplatesConfirmation'
+ | 'documentationLink'
+ | 'emptyPrompt'
+ | 'manageTemplateButton'
+ | 'mappingsTab'
+ | 'noAliasesCallout'
+ | 'noMappingsCallout'
+ | 'noSettingsCallout'
+ | 'indicesList'
+ | 'indicesTab'
+ | 'indexTableIncludeHiddenIndicesToggle'
+ | 'indexTableIndexNameLink'
+ | 'reloadButton'
+ | 'reloadIndicesButton'
+ | 'row'
+ | 'sectionError'
+ | 'sectionLoading'
+ | 'settingsTab'
+ | 'summaryTab'
+ | 'summaryTitle'
+ | 'systemTemplatesSwitch'
+ | 'templateDetails'
+ | 'templateDetails.manageTemplateButton'
+ | 'templateDetails.sectionLoading'
+ | 'templateDetails.tab'
+ | 'templateDetails.title'
+ | 'templateList'
+ | 'templateTable'
+ | 'templatesTab';
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx
index 1eaf7efd17395..0a49191fdb149 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx
+++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx
@@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
/* eslint-disable @kbn/eslint/no-restricted-paths */
import React from 'react';
import axios from 'axios';
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home.test.ts
deleted file mode 100644
index f5af11330a6d8..0000000000000
--- a/x-pack/plugins/index_management/__jest__/client_integration/home.test.ts
+++ /dev/null
@@ -1,587 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { act } from 'react-dom/test-utils';
-import * as fixtures from '../../test/fixtures';
-import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers';
-import { IdxMgmtHomeTestBed } from './helpers/home.helpers';
-import { API_BASE_PATH } from '../../common/constants';
-
-const { setup } = pageHelpers.home;
-
-const removeWhiteSpaceOnArrayValues = (array: any[]) =>
- array.map((value) => {
- if (!value.trim) {
- return value;
- }
- return value.trim();
- });
-
-jest.mock('ui/new_platform');
-
-describe('', () => {
- const { server, httpRequestsMockHelpers } = setupEnvironment();
- let testBed: IdxMgmtHomeTestBed;
-
- afterAll(() => {
- server.restore();
- });
-
- describe('on component mount', () => {
- beforeEach(async () => {
- httpRequestsMockHelpers.setLoadIndicesResponse([]);
-
- testBed = await setup();
-
- await act(async () => {
- const { component } = testBed;
-
- await nextTick();
- component.update();
- });
- });
-
- test('sets the hash query param base on include hidden indices toggle', () => {
- const { actions } = testBed;
- expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
- expect(window.location.hash.includes('includeHidden=true')).toBe(true);
- actions.clickIncludeHiddenIndicesToggle();
- expect(window.location.hash.includes('includeHidden=true')).toBe(false);
- // Note: this test modifies the shared location.hash state, we put it back the way it was
- actions.clickIncludeHiddenIndicesToggle();
- expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
- expect(window.location.hash.includes('includeHidden=true')).toBe(true);
- });
-
- test('should set the correct app title', () => {
- const { exists, find } = testBed;
- expect(exists('appTitle')).toBe(true);
- expect(find('appTitle').text()).toEqual('Index Management');
- });
-
- test('should have a link to the documentation', () => {
- const { exists, find } = testBed;
- expect(exists('documentationLink')).toBe(true);
- expect(find('documentationLink').text()).toBe('Index Management docs');
- });
-
- describe('tabs', () => {
- test('should have 2 tabs', () => {
- const { find } = testBed;
- const templatesTab = find('templatesTab');
- const indicesTab = find('indicesTab');
-
- expect(indicesTab.length).toBe(1);
- expect(indicesTab.text()).toEqual('Indices');
- expect(templatesTab.length).toBe(1);
- expect(templatesTab.text()).toEqual('Index Templates');
- });
-
- test('should navigate to Index Templates tab', async () => {
- const { exists, actions, component } = testBed;
-
- expect(exists('indicesList')).toBe(true);
- expect(exists('templateList')).toBe(false);
-
- httpRequestsMockHelpers.setLoadTemplatesResponse([]);
-
- actions.selectHomeTab('templatesTab');
-
- await act(async () => {
- await nextTick();
- component.update();
- });
-
- expect(exists('indicesList')).toBe(false);
- expect(exists('templateList')).toBe(true);
- });
- });
-
- describe('index templates', () => {
- describe('when there are no index templates', () => {
- beforeEach(async () => {
- const { actions, component } = testBed;
-
- httpRequestsMockHelpers.setLoadTemplatesResponse([]);
-
- actions.selectHomeTab('templatesTab');
-
- await act(async () => {
- await nextTick();
- component.update();
- });
- });
-
- test('should display an empty prompt', async () => {
- const { exists } = testBed;
-
- expect(exists('sectionLoading')).toBe(false);
- expect(exists('emptyPrompt')).toBe(true);
- });
- });
-
- describe('when there are index templates', () => {
- const template1 = fixtures.getTemplate({
- name: `a${getRandomString()}`,
- indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
- template: {
- settings: {
- index: {
- number_of_shards: '1',
- lifecycle: {
- name: 'my_ilm_policy',
- },
- },
- },
- },
- });
- const template2 = fixtures.getTemplate({
- name: `b${getRandomString()}`,
- indexPatterns: ['template2Pattern1*'],
- });
- const template3 = fixtures.getTemplate({
- name: `.c${getRandomString()}`, // mock system template
- indexPatterns: ['template3Pattern1*', 'template3Pattern2', 'template3Pattern3'],
- });
-
- const templates = [template1, template2, template3];
-
- beforeEach(async () => {
- const { actions, component } = testBed;
-
- httpRequestsMockHelpers.setLoadTemplatesResponse(templates);
-
- actions.selectHomeTab('templatesTab');
-
- await act(async () => {
- await nextTick();
- component.update();
- });
- });
-
- test('should list them in the table', async () => {
- const { table } = testBed;
-
- const { tableCellsValues } = table.getMetaData('templateTable');
-
- tableCellsValues.forEach((row, i) => {
- const template = templates[i];
- const { name, indexPatterns, order, ilmPolicy } = template;
-
- const ilmPolicyName = ilmPolicy && ilmPolicy.name ? ilmPolicy.name : '';
- const orderFormatted = order ? order.toString() : order;
-
- expect(removeWhiteSpaceOnArrayValues(row)).toEqual([
- '',
- name,
- indexPatterns.join(', '),
- ilmPolicyName,
- orderFormatted,
- '',
- '',
- '',
- '',
- ]);
- });
- });
-
- test('should have a button to reload the index templates', async () => {
- const { component, exists, actions } = testBed;
- const totalRequests = server.requests.length;
-
- expect(exists('reloadButton')).toBe(true);
-
- await act(async () => {
- actions.clickReloadButton();
- await nextTick();
- component.update();
- });
-
- expect(server.requests.length).toBe(totalRequests + 1);
- expect(server.requests[server.requests.length - 1].url).toBe(
- `${API_BASE_PATH}/templates`
- );
- });
-
- test('should have a button to create a new template', () => {
- const { exists } = testBed;
- expect(exists('createTemplateButton')).toBe(true);
- });
-
- test('should have a switch to view system templates', async () => {
- const { table, exists, component, form } = testBed;
- const { rows } = table.getMetaData('templateTable');
-
- expect(rows.length).toEqual(
- templates.filter((template) => !template.name.startsWith('.')).length
- );
-
- expect(exists('systemTemplatesSwitch')).toBe(true);
-
- await act(async () => {
- form.toggleEuiSwitch('systemTemplatesSwitch');
- await nextTick();
- component.update();
- });
-
- const { rows: updatedRows } = table.getMetaData('templateTable');
- expect(updatedRows.length).toEqual(templates.length);
- });
-
- test('each row should have a link to the template details panel', async () => {
- const { find, exists, actions } = testBed;
-
- await actions.clickTemplateAt(0);
-
- expect(exists('templateList')).toBe(true);
- expect(exists('templateDetails')).toBe(true);
- expect(find('templateDetails.title').text()).toBe(template1.name);
- });
-
- test('template actions column should have an option to delete', () => {
- const { actions, findAction } = testBed;
- const { name: templateName } = template1;
-
- actions.clickActionMenu(templateName);
-
- const deleteAction = findAction('delete');
-
- expect(deleteAction.text()).toEqual('Delete');
- });
-
- test('template actions column should have an option to clone', () => {
- const { actions, findAction } = testBed;
- const { name: templateName } = template1;
-
- actions.clickActionMenu(templateName);
-
- const cloneAction = findAction('clone');
-
- expect(cloneAction.text()).toEqual('Clone');
- });
-
- test('template actions column should have an option to edit', () => {
- const { actions, findAction } = testBed;
- const { name: templateName } = template1;
-
- actions.clickActionMenu(templateName);
-
- const editAction = findAction('edit');
-
- expect(editAction.text()).toEqual('Edit');
- });
-
- describe('delete index template', () => {
- test('should show a confirmation when clicking the delete template button', async () => {
- const { actions } = testBed;
- const { name: templateName } = template1;
-
- await actions.clickTemplateAction(templateName, 'delete');
-
- // We need to read the document "body" as the modal is added there and not inside
- // the component DOM tree.
- expect(
- document.body.querySelector('[data-test-subj="deleteTemplatesConfirmation"]')
- ).not.toBe(null);
-
- expect(
- document.body.querySelector('[data-test-subj="deleteTemplatesConfirmation"]')!
- .textContent
- ).toContain('Delete template');
- });
-
- test('should show a warning message when attempting to delete a system template', async () => {
- const { component, form, actions } = testBed;
-
- await act(async () => {
- form.toggleEuiSwitch('systemTemplatesSwitch');
- await nextTick();
- component.update();
- });
-
- const { name: systemTemplateName } = template3;
- await actions.clickTemplateAction(systemTemplateName, 'delete');
-
- expect(
- document.body.querySelector('[data-test-subj="deleteSystemTemplateCallOut"]')
- ).not.toBe(null);
- });
-
- test('should send the correct HTTP request to delete an index template', async () => {
- const { component, actions, table } = testBed;
- const { rows } = table.getMetaData('templateTable');
-
- const templateId = rows[0].columns[2].value;
-
- const {
- name: templateName,
- _kbnMeta: { formatVersion },
- } = template1;
- await actions.clickTemplateAction(templateName, 'delete');
-
- const modal = document.body.querySelector(
- '[data-test-subj="deleteTemplatesConfirmation"]'
- );
- const confirmButton: HTMLButtonElement | null = modal!.querySelector(
- '[data-test-subj="confirmModalConfirmButton"]'
- );
-
- httpRequestsMockHelpers.setDeleteTemplateResponse({
- results: {
- successes: [templateId],
- errors: [],
- },
- });
-
- await act(async () => {
- confirmButton!.click();
- await nextTick();
- component.update();
- });
-
- const latestRequest = server.requests[server.requests.length - 1];
-
- expect(latestRequest.method).toBe('POST');
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/delete-templates`);
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({
- templates: [{ name: template1.name, formatVersion }],
- });
- });
- });
-
- describe('detail panel', () => {
- beforeEach(async () => {
- const template = fixtures.getTemplate({
- name: `a${getRandomString()}`,
- indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
- });
-
- httpRequestsMockHelpers.setLoadTemplateResponse(template);
- });
-
- test('should show details when clicking on a template', async () => {
- const { exists, actions } = testBed;
-
- expect(exists('templateDetails')).toBe(false);
-
- await actions.clickTemplateAt(0);
-
- expect(exists('templateDetails')).toBe(true);
- });
-
- describe('on mount', () => {
- beforeEach(async () => {
- const { actions } = testBed;
-
- await actions.clickTemplateAt(0);
- });
-
- test('should set the correct title', async () => {
- const { find } = testBed;
- const { name } = template1;
-
- expect(find('templateDetails.title').text()).toEqual(name);
- });
-
- it('should have a close button and be able to close flyout', async () => {
- const { actions, component, exists } = testBed;
-
- expect(exists('closeDetailsButton')).toBe(true);
- expect(exists('summaryTab')).toBe(true);
-
- actions.clickCloseDetailsButton();
-
- await act(async () => {
- await nextTick();
- component.update();
- });
-
- expect(exists('summaryTab')).toBe(false);
- });
-
- it('should have a manage button', async () => {
- const { actions, exists } = testBed;
-
- await actions.clickTemplateAt(0);
-
- expect(exists('templateDetails.manageTemplateButton')).toBe(true);
- });
- });
-
- describe('tabs', () => {
- test('should have 4 tabs', async () => {
- const template = fixtures.getTemplate({
- name: `a${getRandomString()}`,
- indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
- template: {
- settings: {
- index: {
- number_of_shards: '1',
- },
- },
- mappings: {
- _source: {
- enabled: false,
- },
- properties: {
- created_at: {
- type: 'date',
- format: 'EEE MMM dd HH:mm:ss Z yyyy',
- },
- },
- },
- aliases: {
- alias1: {},
- },
- },
- });
-
- const { find, actions, exists } = testBed;
-
- httpRequestsMockHelpers.setLoadTemplateResponse(template);
-
- await actions.clickTemplateAt(0);
-
- expect(find('templateDetails.tab').length).toBe(4);
- expect(find('templateDetails.tab').map((t) => t.text())).toEqual([
- 'Summary',
- 'Settings',
- 'Mappings',
- 'Aliases',
- ]);
-
- // Summary tab should be initial active tab
- expect(exists('summaryTab')).toBe(true);
-
- // Navigate and verify all tabs
- actions.selectDetailsTab('settings');
- expect(exists('summaryTab')).toBe(false);
- expect(exists('settingsTab')).toBe(true);
-
- actions.selectDetailsTab('aliases');
- expect(exists('summaryTab')).toBe(false);
- expect(exists('settingsTab')).toBe(false);
- expect(exists('aliasesTab')).toBe(true);
-
- actions.selectDetailsTab('mappings');
- expect(exists('summaryTab')).toBe(false);
- expect(exists('settingsTab')).toBe(false);
- expect(exists('aliasesTab')).toBe(false);
- expect(exists('mappingsTab')).toBe(true);
- });
-
- test('should show an info callout if data is not present', async () => {
- const templateWithNoOptionalFields = fixtures.getTemplate({
- name: `a${getRandomString()}`,
- indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
- });
-
- const { actions, find, exists, component } = testBed;
-
- httpRequestsMockHelpers.setLoadTemplateResponse(templateWithNoOptionalFields);
-
- await actions.clickTemplateAt(0);
-
- await act(async () => {
- await nextTick();
- component.update();
- });
-
- expect(find('templateDetails.tab').length).toBe(4);
- expect(exists('summaryTab')).toBe(true);
-
- // Navigate and verify callout message per tab
- actions.selectDetailsTab('settings');
- expect(exists('noSettingsCallout')).toBe(true);
-
- actions.selectDetailsTab('mappings');
- expect(exists('noMappingsCallout')).toBe(true);
-
- actions.selectDetailsTab('aliases');
- expect(exists('noAliasesCallout')).toBe(true);
- });
- });
-
- describe('error handling', () => {
- it('should render an error message if error fetching template details', async () => {
- const { actions, exists } = testBed;
- const error = {
- status: 404,
- error: 'Not found',
- message: 'Template not found',
- };
-
- httpRequestsMockHelpers.setLoadTemplateResponse(undefined, { body: error });
-
- await actions.clickTemplateAt(0);
-
- expect(exists('sectionError')).toBe(true);
- // Manage button should not render if error
- expect(exists('templateDetails.manageTemplateButton')).toBe(false);
- });
- });
- });
- });
- });
- });
-
- describe('index detail panel with % character in index name', () => {
- const indexName = 'test%';
- beforeEach(async () => {
- const index = {
- health: 'green',
- status: 'open',
- primary: 1,
- replica: 1,
- documents: 10000,
- documents_deleted: 100,
- size: '156kb',
- primary_size: '156kb',
- name: indexName,
- };
- httpRequestsMockHelpers.setLoadIndicesResponse([index]);
-
- testBed = await setup();
- const { component, find } = testBed;
-
- component.update();
-
- find('indexTableIndexNameLink').at(0).simulate('click');
- });
-
- test('should encode indexName when loading settings in detail panel', async () => {
- const { actions } = testBed;
- await actions.selectIndexDetailsTab('settings');
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`);
- });
-
- test('should encode indexName when loading mappings in detail panel', async () => {
- const { actions } = testBed;
- await actions.selectIndexDetailsTab('mappings');
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/mapping/${encodeURIComponent(indexName)}`);
- });
-
- test('should encode indexName when loading stats in detail panel', async () => {
- const { actions } = testBed;
- await actions.selectIndexDetailsTab('stats');
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/stats/${encodeURIComponent(indexName)}`);
- });
-
- test('should encode indexName when editing settings in detail panel', async () => {
- const { actions } = testBed;
- await actions.selectIndexDetailsTab('edit_settings');
-
- const latestRequest = server.requests[server.requests.length - 1];
- expect(latestRequest.url).toBe(`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`);
- });
- });
-});
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts
new file mode 100644
index 0000000000000..c58109364890a
--- /dev/null
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { registerTestBed, TestBed, TestBedConfig } from '../../../../../test_utils';
+import { IndexManagementHome } from '../../../public/application/sections/home'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { indexManagementStore } from '../../../public/application/store'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { WithAppDependencies, services, TestSubjects } from '../helpers';
+
+const testBedConfig: TestBedConfig = {
+ store: () => indexManagementStore(services as any),
+ memoryRouter: {
+ initialEntries: [`/indices?includeHidden=true`],
+ componentRoutePath: `/:section(indices|templates)`,
+ },
+ doMountAsync: true,
+};
+
+const initTestBed = registerTestBed(WithAppDependencies(IndexManagementHome), testBedConfig);
+
+export interface HomeTestBed extends TestBed {
+ actions: {
+ selectHomeTab: (tab: 'indicesTab' | 'templatesTab') => void;
+ };
+}
+
+export const setup = async (): Promise => {
+ const testBed = await initTestBed();
+
+ /**
+ * User Actions
+ */
+
+ const selectHomeTab = (tab: 'indicesTab' | 'templatesTab') => {
+ testBed.find(tab).simulate('click');
+ };
+
+ return {
+ ...testBed,
+ actions: {
+ selectHomeTab,
+ },
+ };
+};
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts
new file mode 100644
index 0000000000000..d195ce46c2f54
--- /dev/null
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts
@@ -0,0 +1,79 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { act } from 'react-dom/test-utils';
+
+import { setupEnvironment, nextTick } from '../helpers';
+
+import { HomeTestBed, setup } from './home.helpers';
+
+describe('', () => {
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+ let testBed: HomeTestBed;
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ describe('on component mount', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadIndicesResponse([]);
+
+ testBed = await setup();
+
+ await act(async () => {
+ const { component } = testBed;
+
+ await nextTick();
+ component.update();
+ });
+ });
+
+ test('should set the correct app title', () => {
+ const { exists, find } = testBed;
+ expect(exists('appTitle')).toBe(true);
+ expect(find('appTitle').text()).toEqual('Index Management');
+ });
+
+ test('should have a link to the documentation', () => {
+ const { exists, find } = testBed;
+ expect(exists('documentationLink')).toBe(true);
+ expect(find('documentationLink').text()).toBe('Index Management docs');
+ });
+
+ describe('tabs', () => {
+ test('should have 2 tabs', () => {
+ const { find } = testBed;
+ const templatesTab = find('templatesTab');
+ const indicesTab = find('indicesTab');
+
+ expect(indicesTab.length).toBe(1);
+ expect(indicesTab.text()).toEqual('Indices');
+ expect(templatesTab.length).toBe(1);
+ expect(templatesTab.text()).toEqual('Index Templates');
+ });
+
+ test('should navigate to Index Templates tab', async () => {
+ const { exists, actions, component } = testBed;
+
+ expect(exists('indicesList')).toBe(true);
+ expect(exists('templateList')).toBe(false);
+
+ httpRequestsMockHelpers.setLoadTemplatesResponse([]);
+
+ actions.selectHomeTab('templatesTab');
+
+ await act(async () => {
+ await nextTick();
+ component.update();
+ });
+
+ expect(exists('indicesList')).toBe(false);
+ expect(exists('templateList')).toBe(true);
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.helpers.ts
similarity index 61%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.helpers.ts
index 36d8e1d343b5e..0c4cca4dbcc7e 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.helpers.ts
@@ -6,6 +6,7 @@
import { ReactWrapper } from 'enzyme';
import { act } from 'react-dom/test-utils';
+
import {
registerTestBed,
TestBed,
@@ -13,10 +14,12 @@ import {
findTestSubject,
nextTick,
} from '../../../../../test_utils';
+// NOTE: We have to use the Home component instead of the TemplateList component because we depend
+// upon react router to provide the name of the template to load in the detail panel.
import { IndexManagementHome } from '../../../public/application/sections/home'; // eslint-disable-line @kbn/eslint/no-restricted-paths
import { indexManagementStore } from '../../../public/application/store'; // eslint-disable-line @kbn/eslint/no-restricted-paths
import { TemplateDeserialized } from '../../../common';
-import { WithAppDependencies, services } from './setup_environment';
+import { WithAppDependencies, services, TestSubjects } from '../helpers';
const testBedConfig: TestBedConfig = {
store: () => indexManagementStore(services as any),
@@ -29,12 +32,11 @@ const testBedConfig: TestBedConfig = {
const initTestBed = registerTestBed(WithAppDependencies(IndexManagementHome), testBedConfig);
-export interface IdxMgmtHomeTestBed extends TestBed {
+export interface IndexTemplatesTabTestBed extends TestBed {
findAction: (action: 'edit' | 'clone' | 'delete') => ReactWrapper;
actions: {
- selectHomeTab: (tab: 'indicesTab' | 'templatesTab') => void;
+ goToTemplatesList: () => void;
selectDetailsTab: (tab: 'summary' | 'settings' | 'mappings' | 'aliases') => void;
- selectIndexDetailsTab: (tab: 'settings' | 'mappings' | 'stats' | 'edit_settings') => void;
clickReloadButton: () => void;
clickTemplateAction: (
name: TemplateDeserialized['name'],
@@ -43,12 +45,10 @@ export interface IdxMgmtHomeTestBed extends TestBed {
clickTemplateAt: (index: number) => void;
clickCloseDetailsButton: () => void;
clickActionMenu: (name: TemplateDeserialized['name']) => void;
- getIncludeHiddenIndicesToggleStatus: () => boolean;
- clickIncludeHiddenIndicesToggle: () => void;
};
}
-export const setup = async (): Promise => {
+export const setup = async (): Promise => {
const testBed = await initTestBed();
/**
@@ -65,8 +65,8 @@ export const setup = async (): Promise => {
* User Actions
*/
- const selectHomeTab = (tab: 'indicesTab' | 'templatesTab') => {
- testBed.find(tab).simulate('click');
+ const goToTemplatesList = () => {
+ testBed.find('templatesTab').simulate('click');
};
const selectDetailsTab = (tab: 'summary' | 'settings' | 'mappings' | 'aliases') => {
@@ -119,82 +119,17 @@ export const setup = async (): Promise => {
find('closeDetailsButton').simulate('click');
};
- const clickIncludeHiddenIndicesToggle = () => {
- const { find } = testBed;
- find('indexTableIncludeHiddenIndicesToggle').simulate('click');
- };
-
- const getIncludeHiddenIndicesToggleStatus = () => {
- const { find } = testBed;
- const props = find('indexTableIncludeHiddenIndicesToggle').props();
- return Boolean(props['aria-checked']);
- };
-
- const selectIndexDetailsTab = async (
- tab: 'settings' | 'mappings' | 'stats' | 'edit_settings'
- ) => {
- const indexDetailsTabs = ['settings', 'mappings', 'stats', 'edit_settings'];
- const { find, component } = testBed;
- await act(async () => {
- find('detailPanelTab').at(indexDetailsTabs.indexOf(tab)).simulate('click');
- });
- component.update();
- };
-
return {
...testBed,
findAction,
actions: {
- selectHomeTab,
+ goToTemplatesList,
selectDetailsTab,
- selectIndexDetailsTab,
clickReloadButton,
clickTemplateAction,
clickTemplateAt,
clickCloseDetailsButton,
clickActionMenu,
- getIncludeHiddenIndicesToggleStatus,
- clickIncludeHiddenIndicesToggle,
},
};
};
-
-type IdxMgmtTestSubjects = TestSubjects;
-
-export type TestSubjects =
- | 'aliasesTab'
- | 'appTitle'
- | 'cell'
- | 'closeDetailsButton'
- | 'createTemplateButton'
- | 'deleteSystemTemplateCallOut'
- | 'deleteTemplateButton'
- | 'deleteTemplatesConfirmation'
- | 'documentationLink'
- | 'emptyPrompt'
- | 'manageTemplateButton'
- | 'mappingsTab'
- | 'noAliasesCallout'
- | 'noMappingsCallout'
- | 'noSettingsCallout'
- | 'indicesList'
- | 'indicesTab'
- | 'indexTableIncludeHiddenIndicesToggle'
- | 'indexTableIndexNameLink'
- | 'reloadButton'
- | 'reloadIndicesButton'
- | 'row'
- | 'sectionError'
- | 'sectionLoading'
- | 'settingsTab'
- | 'summaryTab'
- | 'summaryTitle'
- | 'systemTemplatesSwitch'
- | 'templateDetails'
- | 'templateDetails.manageTemplateButton'
- | 'templateDetails.sectionLoading'
- | 'templateDetails.tab'
- | 'templateDetails.title'
- | 'templateList'
- | 'templateTable'
- | 'templatesTab';
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts
new file mode 100644
index 0000000000000..c9a279e90d0e0
--- /dev/null
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/index_templates_tab.test.ts
@@ -0,0 +1,463 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { act } from 'react-dom/test-utils';
+
+import * as fixtures from '../../../test/fixtures';
+import { API_BASE_PATH } from '../../../common/constants';
+import { setupEnvironment, nextTick, getRandomString } from '../helpers';
+
+import { IndexTemplatesTabTestBed, setup } from './index_templates_tab.helpers';
+
+const removeWhiteSpaceOnArrayValues = (array: any[]) =>
+ array.map((value) => {
+ if (!value.trim) {
+ return value;
+ }
+ return value.trim();
+ });
+
+describe('Index Templates tab', () => {
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+ let testBed: IndexTemplatesTabTestBed;
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadIndicesResponse([]);
+
+ testBed = await setup();
+
+ await act(async () => {
+ const { component } = testBed;
+
+ await nextTick();
+ component.update();
+ });
+ });
+
+ describe('when there are no index templates', () => {
+ beforeEach(async () => {
+ const { actions, component } = testBed;
+
+ httpRequestsMockHelpers.setLoadTemplatesResponse([]);
+
+ actions.goToTemplatesList();
+
+ await act(async () => {
+ await nextTick();
+ component.update();
+ });
+ });
+
+ test('should display an empty prompt', async () => {
+ const { exists } = testBed;
+
+ expect(exists('sectionLoading')).toBe(false);
+ expect(exists('emptyPrompt')).toBe(true);
+ });
+ });
+
+ describe('when there are index templates', () => {
+ const template1 = fixtures.getTemplate({
+ name: `a${getRandomString()}`,
+ indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
+ template: {
+ settings: {
+ index: {
+ number_of_shards: '1',
+ lifecycle: {
+ name: 'my_ilm_policy',
+ },
+ },
+ },
+ },
+ });
+ const template2 = fixtures.getTemplate({
+ name: `b${getRandomString()}`,
+ indexPatterns: ['template2Pattern1*'],
+ });
+ const template3 = fixtures.getTemplate({
+ name: `.c${getRandomString()}`, // mock system template
+ indexPatterns: ['template3Pattern1*', 'template3Pattern2', 'template3Pattern3'],
+ });
+
+ const templates = [template1, template2, template3];
+
+ beforeEach(async () => {
+ const { actions, component } = testBed;
+
+ httpRequestsMockHelpers.setLoadTemplatesResponse(templates);
+
+ actions.goToTemplatesList();
+
+ await act(async () => {
+ await nextTick();
+ component.update();
+ });
+ });
+
+ test('should list them in the table', async () => {
+ const { table } = testBed;
+
+ const { tableCellsValues } = table.getMetaData('templateTable');
+
+ tableCellsValues.forEach((row, i) => {
+ const template = templates[i];
+ const { name, indexPatterns, order, ilmPolicy } = template;
+
+ const ilmPolicyName = ilmPolicy && ilmPolicy.name ? ilmPolicy.name : '';
+ const orderFormatted = order ? order.toString() : order;
+
+ expect(removeWhiteSpaceOnArrayValues(row)).toEqual([
+ '',
+ name,
+ indexPatterns.join(', '),
+ ilmPolicyName,
+ orderFormatted,
+ '',
+ '',
+ '',
+ '',
+ ]);
+ });
+ });
+
+ test('should have a button to reload the index templates', async () => {
+ const { component, exists, actions } = testBed;
+ const totalRequests = server.requests.length;
+
+ expect(exists('reloadButton')).toBe(true);
+
+ await act(async () => {
+ actions.clickReloadButton();
+ await nextTick();
+ component.update();
+ });
+
+ expect(server.requests.length).toBe(totalRequests + 1);
+ expect(server.requests[server.requests.length - 1].url).toBe(`${API_BASE_PATH}/templates`);
+ });
+
+ test('should have a button to create a new template', () => {
+ const { exists } = testBed;
+ expect(exists('createTemplateButton')).toBe(true);
+ });
+
+ test('should have a switch to view system templates', async () => {
+ const { table, exists, component, form } = testBed;
+ const { rows } = table.getMetaData('templateTable');
+
+ expect(rows.length).toEqual(
+ templates.filter((template) => !template.name.startsWith('.')).length
+ );
+
+ expect(exists('systemTemplatesSwitch')).toBe(true);
+
+ await act(async () => {
+ form.toggleEuiSwitch('systemTemplatesSwitch');
+ await nextTick();
+ component.update();
+ });
+
+ const { rows: updatedRows } = table.getMetaData('templateTable');
+ expect(updatedRows.length).toEqual(templates.length);
+ });
+
+ test('each row should have a link to the template details panel', async () => {
+ const { find, exists, actions } = testBed;
+
+ await actions.clickTemplateAt(0);
+
+ expect(exists('templateList')).toBe(true);
+ expect(exists('templateDetails')).toBe(true);
+ expect(find('templateDetails.title').text()).toBe(template1.name);
+ });
+
+ test('template actions column should have an option to delete', () => {
+ const { actions, findAction } = testBed;
+ const { name: templateName } = template1;
+
+ actions.clickActionMenu(templateName);
+
+ const deleteAction = findAction('delete');
+
+ expect(deleteAction.text()).toEqual('Delete');
+ });
+
+ test('template actions column should have an option to clone', () => {
+ const { actions, findAction } = testBed;
+ const { name: templateName } = template1;
+
+ actions.clickActionMenu(templateName);
+
+ const cloneAction = findAction('clone');
+
+ expect(cloneAction.text()).toEqual('Clone');
+ });
+
+ test('template actions column should have an option to edit', () => {
+ const { actions, findAction } = testBed;
+ const { name: templateName } = template1;
+
+ actions.clickActionMenu(templateName);
+
+ const editAction = findAction('edit');
+
+ expect(editAction.text()).toEqual('Edit');
+ });
+
+ describe('delete index template', () => {
+ test('should show a confirmation when clicking the delete template button', async () => {
+ const { actions } = testBed;
+ const { name: templateName } = template1;
+
+ await actions.clickTemplateAction(templateName, 'delete');
+
+ // We need to read the document "body" as the modal is added there and not inside
+ // the component DOM tree.
+ expect(
+ document.body.querySelector('[data-test-subj="deleteTemplatesConfirmation"]')
+ ).not.toBe(null);
+
+ expect(
+ document.body.querySelector('[data-test-subj="deleteTemplatesConfirmation"]')!.textContent
+ ).toContain('Delete template');
+ });
+
+ test('should show a warning message when attempting to delete a system template', async () => {
+ const { component, form, actions } = testBed;
+
+ await act(async () => {
+ form.toggleEuiSwitch('systemTemplatesSwitch');
+ await nextTick();
+ component.update();
+ });
+
+ const { name: systemTemplateName } = template3;
+ await actions.clickTemplateAction(systemTemplateName, 'delete');
+
+ expect(
+ document.body.querySelector('[data-test-subj="deleteSystemTemplateCallOut"]')
+ ).not.toBe(null);
+ });
+
+ test('should send the correct HTTP request to delete an index template', async () => {
+ const { component, actions, table } = testBed;
+ const { rows } = table.getMetaData('templateTable');
+
+ const templateId = rows[0].columns[2].value;
+
+ const {
+ name: templateName,
+ _kbnMeta: { formatVersion },
+ } = template1;
+ await actions.clickTemplateAction(templateName, 'delete');
+
+ const modal = document.body.querySelector('[data-test-subj="deleteTemplatesConfirmation"]');
+ const confirmButton: HTMLButtonElement | null = modal!.querySelector(
+ '[data-test-subj="confirmModalConfirmButton"]'
+ );
+
+ httpRequestsMockHelpers.setDeleteTemplateResponse({
+ results: {
+ successes: [templateId],
+ errors: [],
+ },
+ });
+
+ await act(async () => {
+ confirmButton!.click();
+ await nextTick();
+ component.update();
+ });
+
+ const latestRequest = server.requests[server.requests.length - 1];
+
+ expect(latestRequest.method).toBe('POST');
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/delete-templates`);
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({
+ templates: [{ name: template1.name, formatVersion }],
+ });
+ });
+ });
+
+ describe('detail panel', () => {
+ beforeEach(async () => {
+ const template = fixtures.getTemplate({
+ name: `a${getRandomString()}`,
+ indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
+ });
+
+ httpRequestsMockHelpers.setLoadTemplateResponse(template);
+ });
+
+ test('should show details when clicking on a template', async () => {
+ const { exists, actions } = testBed;
+
+ expect(exists('templateDetails')).toBe(false);
+
+ await actions.clickTemplateAt(0);
+
+ expect(exists('templateDetails')).toBe(true);
+ });
+
+ describe('on mount', () => {
+ beforeEach(async () => {
+ const { actions } = testBed;
+
+ await actions.clickTemplateAt(0);
+ });
+
+ test('should set the correct title', async () => {
+ const { find } = testBed;
+ const { name } = template1;
+
+ expect(find('templateDetails.title').text()).toEqual(name);
+ });
+
+ it('should have a close button and be able to close flyout', async () => {
+ const { actions, component, exists } = testBed;
+
+ expect(exists('closeDetailsButton')).toBe(true);
+ expect(exists('summaryTab')).toBe(true);
+
+ actions.clickCloseDetailsButton();
+
+ await act(async () => {
+ await nextTick();
+ component.update();
+ });
+
+ expect(exists('summaryTab')).toBe(false);
+ });
+
+ it('should have a manage button', async () => {
+ const { actions, exists } = testBed;
+
+ await actions.clickTemplateAt(0);
+
+ expect(exists('templateDetails.manageTemplateButton')).toBe(true);
+ });
+ });
+
+ describe('tabs', () => {
+ test('should have 4 tabs', async () => {
+ const template = fixtures.getTemplate({
+ name: `a${getRandomString()}`,
+ indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
+ template: {
+ settings: {
+ index: {
+ number_of_shards: '1',
+ },
+ },
+ mappings: {
+ _source: {
+ enabled: false,
+ },
+ properties: {
+ created_at: {
+ type: 'date',
+ format: 'EEE MMM dd HH:mm:ss Z yyyy',
+ },
+ },
+ },
+ aliases: {
+ alias1: {},
+ },
+ },
+ });
+
+ const { find, actions, exists } = testBed;
+
+ httpRequestsMockHelpers.setLoadTemplateResponse(template);
+
+ await actions.clickTemplateAt(0);
+
+ expect(find('templateDetails.tab').length).toBe(4);
+ expect(find('templateDetails.tab').map((t) => t.text())).toEqual([
+ 'Summary',
+ 'Settings',
+ 'Mappings',
+ 'Aliases',
+ ]);
+
+ // Summary tab should be initial active tab
+ expect(exists('summaryTab')).toBe(true);
+
+ // Navigate and verify all tabs
+ actions.selectDetailsTab('settings');
+ expect(exists('summaryTab')).toBe(false);
+ expect(exists('settingsTab')).toBe(true);
+
+ actions.selectDetailsTab('aliases');
+ expect(exists('summaryTab')).toBe(false);
+ expect(exists('settingsTab')).toBe(false);
+ expect(exists('aliasesTab')).toBe(true);
+
+ actions.selectDetailsTab('mappings');
+ expect(exists('summaryTab')).toBe(false);
+ expect(exists('settingsTab')).toBe(false);
+ expect(exists('aliasesTab')).toBe(false);
+ expect(exists('mappingsTab')).toBe(true);
+ });
+
+ test('should show an info callout if data is not present', async () => {
+ const templateWithNoOptionalFields = fixtures.getTemplate({
+ name: `a${getRandomString()}`,
+ indexPatterns: ['template1Pattern1*', 'template1Pattern2'],
+ });
+
+ const { actions, find, exists, component } = testBed;
+
+ httpRequestsMockHelpers.setLoadTemplateResponse(templateWithNoOptionalFields);
+
+ await actions.clickTemplateAt(0);
+
+ await act(async () => {
+ await nextTick();
+ component.update();
+ });
+
+ expect(find('templateDetails.tab').length).toBe(4);
+ expect(exists('summaryTab')).toBe(true);
+
+ // Navigate and verify callout message per tab
+ actions.selectDetailsTab('settings');
+ expect(exists('noSettingsCallout')).toBe(true);
+
+ actions.selectDetailsTab('mappings');
+ expect(exists('noMappingsCallout')).toBe(true);
+
+ actions.selectDetailsTab('aliases');
+ expect(exists('noAliasesCallout')).toBe(true);
+ });
+ });
+
+ describe('error handling', () => {
+ it('should render an error message if error fetching template details', async () => {
+ const { actions, exists } = testBed;
+ const error = {
+ status: 404,
+ error: 'Not found',
+ message: 'Template not found',
+ };
+
+ httpRequestsMockHelpers.setLoadTemplateResponse(undefined, { body: error });
+
+ await actions.clickTemplateAt(0);
+
+ expect(exists('sectionError')).toBe(true);
+ // Manage button should not render if error
+ expect(exists('templateDetails.manageTemplateButton')).toBe(false);
+ });
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts
new file mode 100644
index 0000000000000..07f3391782a54
--- /dev/null
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts
@@ -0,0 +1,70 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { act } from 'react-dom/test-utils';
+
+import { registerTestBed, TestBed, TestBedConfig } from '../../../../../test_utils';
+import { IndexList } from '../../../public/application/sections/home/index_list'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { indexManagementStore } from '../../../public/application/store'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { WithAppDependencies, services, TestSubjects } from '../helpers';
+
+const testBedConfig: TestBedConfig = {
+ store: () => indexManagementStore(services as any),
+ memoryRouter: {
+ initialEntries: [`/indices?includeHidden=true`],
+ componentRoutePath: `/:section(indices|templates)`,
+ },
+ doMountAsync: true,
+};
+
+const initTestBed = registerTestBed(WithAppDependencies(IndexList), testBedConfig);
+
+export interface IndicesTestBed extends TestBed {
+ actions: {
+ selectIndexDetailsTab: (tab: 'settings' | 'mappings' | 'stats' | 'edit_settings') => void;
+ getIncludeHiddenIndicesToggleStatus: () => boolean;
+ clickIncludeHiddenIndicesToggle: () => void;
+ };
+}
+
+export const setup = async (): Promise => {
+ const testBed = await initTestBed();
+
+ /**
+ * User Actions
+ */
+
+ const clickIncludeHiddenIndicesToggle = () => {
+ const { find } = testBed;
+ find('indexTableIncludeHiddenIndicesToggle').simulate('click');
+ };
+
+ const getIncludeHiddenIndicesToggleStatus = () => {
+ const { find } = testBed;
+ const props = find('indexTableIncludeHiddenIndicesToggle').props();
+ return Boolean(props['aria-checked']);
+ };
+
+ const selectIndexDetailsTab = async (
+ tab: 'settings' | 'mappings' | 'stats' | 'edit_settings'
+ ) => {
+ const indexDetailsTabs = ['settings', 'mappings', 'stats', 'edit_settings'];
+ const { find, component } = testBed;
+ await act(async () => {
+ find('detailPanelTab').at(indexDetailsTabs.indexOf(tab)).simulate('click');
+ });
+ component.update();
+ };
+
+ return {
+ ...testBed,
+ actions: {
+ selectIndexDetailsTab,
+ getIncludeHiddenIndicesToggleStatus,
+ clickIncludeHiddenIndicesToggle,
+ },
+ };
+};
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts
new file mode 100644
index 0000000000000..e5db5d547f1ab
--- /dev/null
+++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts
@@ -0,0 +1,105 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { act } from 'react-dom/test-utils';
+
+import { API_BASE_PATH } from '../../../common/constants';
+import { setupEnvironment, nextTick } from '../helpers';
+
+import { IndicesTestBed, setup } from './indices_tab.helpers';
+
+describe('', () => {
+ const { server, httpRequestsMockHelpers } = setupEnvironment();
+ let testBed: IndicesTestBed;
+
+ afterAll(() => {
+ server.restore();
+ });
+
+ describe('on component mount', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadIndicesResponse([]);
+
+ testBed = await setup();
+
+ await act(async () => {
+ const { component } = testBed;
+
+ await nextTick();
+ component.update();
+ });
+ });
+
+ test('sets the hash query param base on include hidden indices toggle', () => {
+ const { actions } = testBed;
+ expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
+ expect(window.location.hash.includes('includeHidden=true')).toBe(true);
+ actions.clickIncludeHiddenIndicesToggle();
+ expect(window.location.hash.includes('includeHidden=true')).toBe(false);
+ // Note: this test modifies the shared location.hash state, we put it back the way it was
+ actions.clickIncludeHiddenIndicesToggle();
+ expect(actions.getIncludeHiddenIndicesToggleStatus()).toBe(true);
+ expect(window.location.hash.includes('includeHidden=true')).toBe(true);
+ });
+ });
+
+ describe('index detail panel with % character in index name', () => {
+ const indexName = 'test%';
+ beforeEach(async () => {
+ const index = {
+ health: 'green',
+ status: 'open',
+ primary: 1,
+ replica: 1,
+ documents: 10000,
+ documents_deleted: 100,
+ size: '156kb',
+ primary_size: '156kb',
+ name: indexName,
+ };
+ httpRequestsMockHelpers.setLoadIndicesResponse([index]);
+
+ testBed = await setup();
+ const { component, find } = testBed;
+
+ component.update();
+
+ find('indexTableIndexNameLink').at(0).simulate('click');
+ });
+
+ test('should encode indexName when loading settings in detail panel', async () => {
+ const { actions } = testBed;
+ await actions.selectIndexDetailsTab('settings');
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`);
+ });
+
+ test('should encode indexName when loading mappings in detail panel', async () => {
+ const { actions } = testBed;
+ await actions.selectIndexDetailsTab('mappings');
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/mapping/${encodeURIComponent(indexName)}`);
+ });
+
+ test('should encode indexName when loading stats in detail panel', async () => {
+ const { actions } = testBed;
+ await actions.selectIndexDetailsTab('stats');
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/stats/${encodeURIComponent(indexName)}`);
+ });
+
+ test('should encode indexName when editing settings in detail panel', async () => {
+ const { actions } = testBed;
+ await actions.selectIndexDetailsTab('edit_settings');
+
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(latestRequest.url).toBe(`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`);
+ });
+ });
+});
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/constants.ts
similarity index 100%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/constants.ts
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.helpers.ts
similarity index 76%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.helpers.ts
index 36498b99ba143..1a58cfa8fb55e 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.helpers.ts
@@ -5,16 +5,16 @@
*/
import { registerTestBed, TestBedConfig } from '../../../../../test_utils';
-import { BASE_PATH } from '../../../common/constants';
import { TemplateClone } from '../../../public/application/sections/template_clone'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { WithAppDependencies } from '../helpers';
+
import { formSetup } from './template_form.helpers';
import { TEMPLATE_NAME } from './constants';
-import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
- initialEntries: [`${BASE_PATH}clone_template/${TEMPLATE_NAME}`],
- componentRoutePath: `${BASE_PATH}clone_template/:name`,
+ initialEntries: [`/clone_template/${TEMPLATE_NAME}`],
+ componentRoutePath: `/clone_template/:name`,
},
doMountAsync: true,
};
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx
similarity index 88%
rename from x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx
index fa9d13d1ddd07..e0db9cd58ee23 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_clone.test.tsx
@@ -3,21 +3,16 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
import React from 'react';
import { act } from 'react-dom/test-utils';
-import { setupEnvironment, pageHelpers, nextTick } from './helpers';
-import { TemplateFormTestBed } from './helpers/template_form.helpers';
-import { getTemplate } from '../../test/fixtures';
-import {
- TEMPLATE_NAME,
- INDEX_PATTERNS as DEFAULT_INDEX_PATTERNS,
- MAPPINGS,
-} from './helpers/constants';
-
-const { setup } = pageHelpers.templateClone;
+import { getTemplate } from '../../../test/fixtures';
+import { setupEnvironment, nextTick } from '../helpers';
-jest.mock('ui/new_platform');
+import { TEMPLATE_NAME, INDEX_PATTERNS as DEFAULT_INDEX_PATTERNS, MAPPINGS } from './constants';
+import { setup } from './template_clone.helpers';
+import { TemplateFormTestBed } from './template_form.helpers';
jest.mock('@elastic/eui', () => ({
...jest.requireActual('@elastic/eui'),
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.helpers.ts
similarity index 77%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.helpers.ts
index 14a44968a93c3..ab0a7b8567607 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.helpers.ts
@@ -5,15 +5,15 @@
*/
import { registerTestBed, TestBedConfig } from '../../../../../test_utils';
-import { BASE_PATH } from '../../../common/constants';
import { TemplateCreate } from '../../../public/application/sections/template_create'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { WithAppDependencies } from '../helpers';
+
import { formSetup, TestSubjects } from './template_form.helpers';
-import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
- initialEntries: [`${BASE_PATH}create_template`],
- componentRoutePath: `${BASE_PATH}create_template`,
+ initialEntries: [`/create_template`],
+ componentRoutePath: `/create_template`,
},
doMountAsync: true,
};
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx
similarity index 97%
rename from x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx
index 8f464987418c0..95545b6c66f54 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx
@@ -3,23 +3,22 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
import React from 'react';
import { act } from 'react-dom/test-utils';
-import { DEFAULT_INDEX_TEMPLATE_VERSION_FORMAT } from '../../common';
-import { setupEnvironment, pageHelpers, nextTick } from './helpers';
-import { TemplateFormTestBed } from './helpers/template_form.helpers';
+import { DEFAULT_INDEX_TEMPLATE_VERSION_FORMAT } from '../../../common';
+import { setupEnvironment, nextTick } from '../helpers';
+
import {
TEMPLATE_NAME,
SETTINGS,
MAPPINGS,
ALIASES,
INDEX_PATTERNS as DEFAULT_INDEX_PATTERNS,
-} from './helpers/constants';
-
-const { setup } = pageHelpers.templateCreate;
-
-jest.mock('ui/new_platform');
+} from './constants';
+import { setup } from './template_create.helpers';
+import { TemplateFormTestBed } from './template_form.helpers';
jest.mock('@elastic/eui', () => ({
...jest.requireActual('@elastic/eui'),
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.helpers.ts
similarity index 77%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.helpers.ts
index af5fa8b79ecad..29ecd84e585ce 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.helpers.ts
@@ -5,16 +5,16 @@
*/
import { registerTestBed, TestBedConfig } from '../../../../../test_utils';
-import { BASE_PATH } from '../../../common/constants';
import { TemplateEdit } from '../../../public/application/sections/template_edit'; // eslint-disable-line @kbn/eslint/no-restricted-paths
+import { WithAppDependencies } from '../helpers';
+
import { formSetup, TestSubjects } from './template_form.helpers';
import { TEMPLATE_NAME } from './constants';
-import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
- initialEntries: [`${BASE_PATH}edit_template/${TEMPLATE_NAME}`],
- componentRoutePath: `${BASE_PATH}edit_template/:name`,
+ initialEntries: [`/edit_template/${TEMPLATE_NAME}`],
+ componentRoutePath: `/edit_template/:name`,
},
doMountAsync: true,
};
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx
similarity index 95%
rename from x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx
index 0ed369e9b13f7..6e935a5263301 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx
@@ -3,13 +3,16 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
import React from 'react';
import { act } from 'react-dom/test-utils';
-import { setupEnvironment, pageHelpers, nextTick } from './helpers';
-import { TemplateFormTestBed } from './helpers/template_form.helpers';
-import * as fixtures from '../../test/fixtures';
-import { TEMPLATE_NAME, SETTINGS, ALIASES, MAPPINGS as DEFAULT_MAPPING } from './helpers/constants';
+import * as fixtures from '../../../test/fixtures';
+import { setupEnvironment, nextTick } from '../helpers';
+
+import { TEMPLATE_NAME, SETTINGS, ALIASES, MAPPINGS as DEFAULT_MAPPING } from './constants';
+import { setup } from './template_edit.helpers';
+import { TemplateFormTestBed } from './template_form.helpers';
const UPDATED_INDEX_PATTERN = ['updatedIndexPattern'];
const UPDATED_MAPPING_TEXT_FIELD_NAME = 'updated_text_datatype';
@@ -22,10 +25,6 @@ const MAPPING = {
},
};
-const { setup } = pageHelpers.templateEdit;
-
-jest.mock('ui/new_platform');
-
jest.mock('@elastic/eui', () => ({
...jest.requireActual('@elastic/eui'),
// Mocking EuiComboBox, as it utilizes "react-virtualized" for rendering search suggestions,
diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts
similarity index 99%
rename from x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts
rename to x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts
index 21713428c4316..fdf837a914cf1 100644
--- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts
+++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts
@@ -3,9 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+
import { TestBed, SetupFunc, UnwrapPromise } from '../../../../../test_utils';
import { TemplateDeserialized } from '../../../common';
-import { nextTick } from './index';
+import { nextTick } from '../helpers';
interface MappingField {
name: string;
diff --git a/x-pack/plugins/index_management/__jest__/components/index_table.test.js b/x-pack/plugins/index_management/__jest__/components/index_table.test.js
index ffd3cbb83c2ce..8e8c2632a2372 100644
--- a/x-pack/plugins/index_management/__jest__/components/index_table.test.js
+++ b/x-pack/plugins/index_management/__jest__/components/index_table.test.js
@@ -37,8 +37,6 @@ import { findTestSubject } from '@elastic/eui/lib/test';
/* eslint-disable @kbn/eslint/no-restricted-paths */
import { notificationServiceMock } from '../../../../../src/core/public/notifications/notifications_service.mock';
-jest.mock('ui/new_platform');
-
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
let server = null;
diff --git a/x-pack/plugins/index_management/__mocks__/ace.js b/x-pack/plugins/index_management/__mocks__/ace.js
deleted file mode 100644
index 40ce7026eee11..0000000000000
--- a/x-pack/plugins/index_management/__mocks__/ace.js
+++ /dev/null
@@ -1,45 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export default {
- edit: () => {
- return {
- navigateFileEnd() {},
- destroy() {},
- acequire() {
- return {
- setCompleters() {},
- };
- },
- setValue() {},
- setOptions() {},
- setTheme() {},
- setFontSize() {},
- setShowPrintMargin() {},
- getSession() {
- return {
- setUseWrapMode() {},
- setMode() {},
- setValue() {},
- on() {},
- };
- },
- renderer: {
- setShowGutter() {},
- setScrollMargin() {},
- },
- setBehavioursEnabled() {},
- };
- },
- acequire() {
- return {
- setCompleters() {},
- };
- },
- setCompleters() {
- return [{}];
- },
-};
diff --git a/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js b/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js
deleted file mode 100644
index 0da03ba9b98ba..0000000000000
--- a/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js
+++ /dev/null
@@ -1,7 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export const settingsDocumentationLink = 'https://stuff.com/docs';
diff --git a/x-pack/plugins/index_management/__mocks__/ui/notify.js b/x-pack/plugins/index_management/__mocks__/ui/notify.js
deleted file mode 100644
index 3d64a99232bc3..0000000000000
--- a/x-pack/plugins/index_management/__mocks__/ui/notify.js
+++ /dev/null
@@ -1,15 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export const toastNotifications = {
- addInfo: () => {},
- addSuccess: () => {},
- addDanger: () => {},
- addWarning: () => {},
- addError: () => {},
-};
-
-export function fatalError() {}
diff --git a/x-pack/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap b/x-pack/plugins/index_management/public/application/lib/__snapshots__/flatten_object.test.js.snap
similarity index 100%
rename from x-pack/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap
rename to x-pack/plugins/index_management/public/application/lib/__snapshots__/flatten_object.test.js.snap
diff --git a/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js b/x-pack/plugins/index_management/public/application/lib/flatten_object.test.js
similarity index 90%
rename from x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js
rename to x-pack/plugins/index_management/public/application/lib/flatten_object.test.js
index 0d6d5ee796627..222d172d1ff86 100644
--- a/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js
+++ b/x-pack/plugins/index_management/public/application/lib/flatten_object.test.js
@@ -4,7 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { flattenObject } from '../../public/application/lib/flatten_object';
+import { flattenObject } from './flatten_object';
+
describe('flatten_object', () => {
test('it flattens an object', () => {
const obj = {
@@ -17,6 +18,7 @@ describe('flatten_object', () => {
};
expect(flattenObject(obj)).toMatchSnapshot();
});
+
test('it flattens an object that contains an array in a field', () => {
const obj = {
foo: {
diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts b/x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts
index a6d4bfee29d55..cc0e145909e62 100644
--- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts
+++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export * from './index_list';
+export { IndexList } from './index_list';