Refactor index management client integration tests for scalability (#67917)

This commit is contained in:
CJ Cenizal 2020-06-03 16:49:38 -07:00 committed by GitHub
parent a40076b658
commit 573409b9f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 850 additions and 785 deletions

View file

@ -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';

View file

@ -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';

View file

@ -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('<IndexManagementHome />', () => {
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)}`);
});
});
});

View file

@ -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<TestSubjects> {
actions: {
selectHomeTab: (tab: 'indicesTab' | 'templatesTab') => void;
};
}
export const setup = async (): Promise<HomeTestBed> => {
const testBed = await initTestBed();
/**
* User Actions
*/
const selectHomeTab = (tab: 'indicesTab' | 'templatesTab') => {
testBed.find(tab).simulate('click');
};
return {
...testBed,
actions: {
selectHomeTab,
},
};
};

View file

@ -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('<IndexManagementHome />', () => {
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);
});
});
});
});

View file

@ -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<IdxMgmtTestSubjects> {
export interface IndexTemplatesTabTestBed extends TestBed<TestSubjects> {
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<IdxMgmtTestSubjects> {
clickTemplateAt: (index: number) => void;
clickCloseDetailsButton: () => void;
clickActionMenu: (name: TemplateDeserialized['name']) => void;
getIncludeHiddenIndicesToggleStatus: () => boolean;
clickIncludeHiddenIndicesToggle: () => void;
};
}
export const setup = async (): Promise<IdxMgmtHomeTestBed> => {
export const setup = async (): Promise<IndexTemplatesTabTestBed> => {
const testBed = await initTestBed();
/**
@ -65,8 +65,8 @@ export const setup = async (): Promise<IdxMgmtHomeTestBed> => {
* 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<IdxMgmtHomeTestBed> => {
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';

View file

@ -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);
});
});
});
});
});

View file

@ -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<TestSubjects> {
actions: {
selectIndexDetailsTab: (tab: 'settings' | 'mappings' | 'stats' | 'edit_settings') => void;
getIncludeHiddenIndicesToggleStatus: () => boolean;
clickIncludeHiddenIndicesToggle: () => void;
};
}
export const setup = async (): Promise<IndicesTestBed> => {
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,
},
};
};

View file

@ -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('<IndexManagementHome />', () => {
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)}`);
});
});
});

View file

@ -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,
};

View file

@ -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';
import { getTemplate } from '../../../test/fixtures';
import { setupEnvironment, nextTick } from '../helpers';
const { setup } = pageHelpers.templateClone;
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'),

View file

@ -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,
};

View file

@ -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'),

View file

@ -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,
};

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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 [{}];
},
};

View file

@ -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';

View file

@ -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() {}

View file

@ -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: {

View file

@ -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';