-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[CCR] Client tests auto-follow pattern & follower index forms #34449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f0e0091
f48eed0
c173642
ff97e76
c671d99
8d180d1
255e729
5d4a1bd
7b7adb7
d7453da
3e8e381
433a507
b3be437
008b290
aeb5335
68dfa07
1edb053
7680894
fccb8da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| /* | ||
| * 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 sinon from 'sinon'; | ||
|
|
||
| import { initTestBed, registerHttpRequestMockHelpers, nextTick, findTestSubject, getRandomString } from './test_helpers'; | ||
| import { AutoFollowPatternAdd } from '../../public/app/sections/auto_follow_pattern_add'; | ||
| import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from '../../../../../src/legacy/ui/public/index_patterns'; | ||
| import routing from '../../public/app/services/routing'; | ||
|
|
||
| jest.mock('ui/chrome', () => ({ | ||
| addBasePath: (path) => path || 'api/cross_cluster_replication', | ||
| breadcrumbs: { set: () => {} }, | ||
| })); | ||
|
|
||
| jest.mock('ui/index_patterns', () => { | ||
| const { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } = | ||
| jest.requireActual('../../../../../src/legacy/ui/public/index_patterns/constants'); | ||
| const { validateIndexPattern, ILLEGAL_CHARACTERS, CONTAINS_SPACES } = | ||
| jest.requireActual('../../../../../src/legacy/ui/public/index_patterns/validate/validate_index_pattern'); | ||
| return { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE, validateIndexPattern, ILLEGAL_CHARACTERS, CONTAINS_SPACES }; | ||
| }); | ||
|
|
||
| const testBedOptions = { | ||
| memoryRouter: { | ||
| onRouter: (router) => routing.reactRouter = router | ||
| } | ||
| }; | ||
|
|
||
| describe('Create Auto-follow pattern', () => { | ||
| let server; | ||
| let find; | ||
| let exists; | ||
| let component; | ||
| let getUserActions; | ||
| let form; | ||
| let getFormErrorsMessages; | ||
| let clickSaveForm; | ||
| let setLoadRemoteClustersResponse; | ||
|
|
||
| beforeEach(() => { | ||
| server = sinon.fakeServer.create(); | ||
| server.respondImmediately = true; | ||
|
|
||
| // Register helpers to mock Http Requests | ||
| ({ | ||
| setLoadRemoteClustersResponse | ||
| } = registerHttpRequestMockHelpers(server)); | ||
|
|
||
| // Set "default" mock responses by not providing any arguments | ||
| setLoadRemoteClustersResponse(); | ||
|
|
||
| // Mock all HTTP Requests that have not been handled previously | ||
| server.respondWith([200, {}, '']); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same with this mocked response. I think we can remove it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nooooooooooo 😄 This is our safeguard against any not handled HTTP requests (that we don't care in our test but could break the CI at any point). |
||
| }); | ||
|
|
||
| describe('on component mount', () => { | ||
| beforeEach(() => { | ||
| ({ find, exists } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| }); | ||
|
|
||
| test('should display a "loading remote clusters" indicator', () => { | ||
| expect(exists('remoteClustersLoading')).toBe(true); | ||
| expect(find('remoteClustersLoading').text()).toBe('Loading remote clusters…'); | ||
| }); | ||
|
|
||
| test('should have a link to the documentation', () => { | ||
| expect(exists('autoFollowPatternDocsButton')).toBe(true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('when remote clusters are loaded', () => { | ||
| beforeEach(async () => { | ||
| ({ find, exists, component, getUserActions, getFormErrorsMessages } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
|
|
||
| ({ clickSaveForm } = getUserActions('autoFollowPatternForm')); | ||
|
|
||
| await nextTick(); // We need to wait next tick for the mock server response to comes in | ||
| component.update(); | ||
| }); | ||
|
|
||
| test('should display the Auto-follow pattern form', async () => { | ||
| expect(exists('ccrAutoFollowPatternForm')).toBe(true); | ||
| }); | ||
|
|
||
| test('should display errors and disable the save button when clicking "save" without filling the form', () => { | ||
| expect(exists('autoFollowPatternFormError')).toBe(false); | ||
| expect(find('ccrAutoFollowPatternFormSubmitButton').props().disabled).toBe(false); | ||
|
|
||
| clickSaveForm(); | ||
|
|
||
| expect(exists('autoFollowPatternFormError')).toBe(true); | ||
| expect(getFormErrorsMessages()).toEqual([ | ||
| 'Name is required.', | ||
| 'At least one leader index pattern is required.', | ||
| ]); | ||
| expect(find('ccrAutoFollowPatternFormSubmitButton').props().disabled).toBe(true); | ||
| }); | ||
| }); | ||
|
|
||
| describe('form validation', () => { | ||
| describe('auto-follow pattern name', () => { | ||
| beforeEach(async () => { | ||
| ({ component, form, getUserActions, getFormErrorsMessages } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| ({ clickSaveForm } = getUserActions('autoFollowPatternForm')); | ||
|
|
||
| await nextTick(); | ||
| component.update(); | ||
| }); | ||
|
|
||
| test('should not allow spaces', () => { | ||
| form.setInputValue('ccrAutoFollowPatternFormNameInput', 'with space'); | ||
| clickSaveForm(); | ||
| expect(getFormErrorsMessages()).toContain('Spaces are not allowed in the name.'); | ||
| }); | ||
|
|
||
| test('should not allow a "_" (underscore) as first character', () => { | ||
| form.setInputValue('ccrAutoFollowPatternFormNameInput', '_withUnderscore'); | ||
| clickSaveForm(); | ||
| expect(getFormErrorsMessages()).toContain(`Name can't begin with an underscore.`); | ||
| }); | ||
|
|
||
| test('should not allow a "," (comma)', () => { | ||
| form.setInputValue('ccrAutoFollowPatternFormNameInput', 'with,coma'); | ||
| clickSaveForm(); | ||
| expect(getFormErrorsMessages()).toContain(`Commas are not allowed in the name.`); | ||
| }); | ||
| }); | ||
|
|
||
| describe('remote clusters', () => { | ||
| describe('when no remote clusters were found', () => { | ||
| test('should indicate it and have a button to add one', async () => { | ||
| setLoadRemoteClustersResponse([]); | ||
|
|
||
| ({ find, component } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| await nextTick(); | ||
| component.update(); | ||
| const errorCallOut = find('remoteClusterFieldNoClusterFoundError'); | ||
|
|
||
| expect(errorCallOut.length).toBe(1); | ||
| expect(findTestSubject(errorCallOut, 'ccrRemoteClusterAddButton').length).toBe(1); | ||
| }); | ||
| }); | ||
|
|
||
| describe('when there was an error loading the remote clusters', () => { | ||
| test('should indicate no clusters found and have a button to add one', async () => { | ||
| setLoadRemoteClustersResponse(undefined, { body: 'Houston we got a problem' }); | ||
|
|
||
| ({ find, component } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| await nextTick(); | ||
| component.update(); | ||
| const errorCallOut = find('remoteClusterFieldNoClusterFoundError'); | ||
|
|
||
| expect(errorCallOut.length).toBe(1); | ||
| expect(findTestSubject(errorCallOut, 'ccrRemoteClusterAddButton').length).toBe(1); | ||
| }); | ||
| }); | ||
|
|
||
| describe('when none of the remote clusters is connected', () => { | ||
| const clusterName = 'new-york'; | ||
| const remoteClusters = [{ | ||
| name: clusterName, | ||
| seeds: ['localhost:9600'], | ||
| isConnected: false, | ||
| }]; | ||
|
|
||
| beforeEach(async () => { | ||
| setLoadRemoteClustersResponse(remoteClusters); | ||
|
|
||
| ({ find, exists, component } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| await nextTick(); | ||
| component.update(); | ||
| }); | ||
|
|
||
| test('should show a callout warning and have a button to edit the cluster', () => { | ||
| const errorCallOut = find('remoteClusterFieldCallOutError'); | ||
|
|
||
| expect(errorCallOut.length).toBe(1); | ||
| expect(errorCallOut.find('.euiCallOutHeader__title').text()).toBe(`Remote cluster '${clusterName}' is not connected`); | ||
| expect(findTestSubject(errorCallOut, 'ccrRemoteClusterEditButton').length).toBe(1); | ||
| }); | ||
|
|
||
| test('should have a button to add another remote cluster', () => { | ||
| expect(exists('ccrRemoteClusterInlineAddButton')).toBe(true); | ||
| }); | ||
|
|
||
| test('should indicate in the select option that the cluster is not connected', () => { | ||
| const selectOptions = find('ccrRemoteClusterSelect').find('option'); | ||
| expect(selectOptions.at(0).text()).toBe(`${clusterName} (not connected)`); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('index patterns', () => { | ||
| beforeEach(async () => { | ||
| ({ component, form, getUserActions, getFormErrorsMessages } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| ({ clickSaveForm } = getUserActions('autoFollowPatternForm')); | ||
|
|
||
| await nextTick(); | ||
| component.update(); | ||
| }); | ||
|
|
||
| test('should not allow spaces', () => { | ||
| expect(getFormErrorsMessages()).toEqual([]); | ||
|
|
||
| form.setIndexPatternValue('with space'); | ||
|
|
||
| expect(getFormErrorsMessages()).toContain('Spaces are not allowed in the index pattern.'); | ||
| }); | ||
|
|
||
| test('should not allow invalid characters', () => { | ||
| const expectInvalidChar = (char) => { | ||
| form.setIndexPatternValue(`with${char}space`); | ||
| expect(getFormErrorsMessages()).toContain(`Remove the character ${char} from the index pattern.`); | ||
| }; | ||
|
|
||
| return INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.reduce((promise, char) => { | ||
| return promise.then(() => expectInvalidChar(char)); | ||
| }, Promise.resolve()); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('generated indices preview', () => { | ||
| beforeEach(async () => { | ||
| ({ exists, find, component, form, getUserActions } = initTestBed(AutoFollowPatternAdd, undefined, testBedOptions)); | ||
| ({ clickSaveForm } = getUserActions('autoFollowPatternForm')); | ||
|
|
||
| await nextTick(); | ||
| component.update(); | ||
| }); | ||
|
|
||
| test('should display a preview of the possible indices generated by the auto-follow pattern', () => { | ||
| expect(exists('ccrAutoFollowPatternIndicesPreview')).toBe(false); | ||
|
|
||
| form.setIndexPatternValue('kibana-'); | ||
|
|
||
| expect(exists('ccrAutoFollowPatternIndicesPreview')).toBe(true); | ||
| }); | ||
|
|
||
| test('should display 3 indices example when providing a wildcard(*)', () => { | ||
| form.setIndexPatternValue('kibana-*'); | ||
| const indicesPreview = find('ccrAutoFollowPatternIndexPreview'); | ||
|
|
||
| expect(indicesPreview.length).toBe(3); | ||
| expect(indicesPreview.at(0).text()).toContain('kibana-'); | ||
| }); | ||
|
|
||
| test('should only display 1 index example when *not* providing a wildcard', () => { | ||
| form.setIndexPatternValue('kibana'); | ||
| const indicesPreview = find('ccrAutoFollowPatternIndexPreview'); | ||
|
|
||
| expect(indicesPreview.length).toBe(1); | ||
| expect(indicesPreview.at(0).text()).toEqual('kibana'); | ||
| }); | ||
|
|
||
| test('should add the prefix and the suffix to the preview', () => { | ||
| const prefix = getRandomString(); | ||
| const suffix = getRandomString(); | ||
|
|
||
| form.setIndexPatternValue('kibana'); | ||
| form.setInputValue('ccrAutoFollowPatternFormPrefixInput', prefix); | ||
| form.setInputValue('ccrAutoFollowPatternFormSuffixInput', suffix); | ||
|
|
||
| const indicesPreview = find('ccrAutoFollowPatternIndexPreview'); | ||
| const textPreview = indicesPreview.at(0).text(); | ||
|
|
||
| expect(textPreview).toContain(prefix); | ||
| expect(textPreview).toContain(suffix); | ||
| }); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about adding some newlines so we don't need to disable the max-len rule? This will also make the code easier to read when the code editor is narrow. This comment applies to the other test files, too.