[Workplace Search] Add source logic and sources logic unit tests (#89247)

* Move shared data to mock

* Change name of mock

Everywhere else we don’t use the “mock” prefix for mocked data so I’m changing here to match.

Also added missing “size” prop from mock.

* Remove unused actions

These were missed on the migration to the new add_source_logic file. All of that logic lives there now

* Add tests for source logic

* REmove resetFlashMessages

This is no longer used as Kibana resets its own. This was removed from the component already.

* Export items for use in tests

* Remove unnecessary condition

It’s literally not possible for this function to receive an empty contentSources parameter. Not sure why this was added. Even if the server sends response with no privateContentSources, the reducer falls back to an empty array.

* Add tests for sources logic

* Fix typo
This commit is contained in:
Scotty Bollinger 2021-01-26 10:06:38 -06:00 committed by GitHub
parent a4c884b92b
commit 110e880fbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 785 additions and 36 deletions

View file

@ -323,3 +323,14 @@ export const mostRecentIndexJob = {
activeReindexJobId: '123',
numDocumentsWithErrors: 1,
};
export const contentItems = [
{
id: '1234',
last_updated: '2021-01-21',
},
{
id: '1235',
last_updated: '2021-01-20',
},
];

View file

@ -6,10 +6,11 @@
import { DEFAULT_META } from '../../shared/constants';
export const mockMeta = {
export const meta = {
...DEFAULT_META,
page: {
current: 1,
size: 5,
total_results: 50,
total_pages: 5,
},

View file

@ -20,8 +20,8 @@ import {
EuiLink,
} from '@elastic/eui';
import { mockMeta } from '../../../__mocks__/meta.mock';
import { fullContentSources } from '../../../__mocks__/content_sources.mock';
import { meta } from '../../../__mocks__/meta.mock';
import { fullContentSources, contentItems } from '../../../__mocks__/content_sources.mock';
import { DEFAULT_META } from '../../../../shared/constants';
import { ComponentLoader } from '../../../components/shared/component_loader';
@ -38,17 +38,8 @@ describe('SourceContent', () => {
const mockValues = {
contentSource: fullContentSources[0],
contentMeta: mockMeta,
contentItems: [
{
id: '1234',
last_updated: '2021-01-21',
},
{
id: '1235',
last_updated: '2021-01-20',
},
],
contentMeta: meta,
contentItems,
contentFilterValue: '',
dataLoading: false,
sectionLoading: false,

View file

@ -0,0 +1,444 @@
/*
* 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 {
LogicMounter,
mockFlashMessageHelpers,
mockHttpValues,
mockKibanaValues,
expectedAsyncError,
} from '../../../__mocks__';
import { AppLogic } from '../../app_logic';
jest.mock('../../app_logic', () => ({
AppLogic: { values: { isOrganization: true } },
}));
import {
fullContentSources,
sourceConfigData,
contentItems,
} from '../../__mocks__/content_sources.mock';
import { meta } from '../../__mocks__/meta.mock';
import { DEFAULT_META } from '../../../shared/constants';
import { NOT_FOUND_PATH } from '../../routes';
import { SourceLogic } from './source_logic';
describe('SourceLogic', () => {
const { http } = mockHttpValues;
const {
clearFlashMessages,
flashAPIErrors,
setSuccessMessage,
setQueuedSuccessMessage,
} = mockFlashMessageHelpers;
const { navigateToUrl } = mockKibanaValues;
const { mount, getListeners } = new LogicMounter(SourceLogic);
const contentSource = fullContentSources[0];
const defaultValues = {
contentSource: {},
contentItems: [],
sourceConfigData: {},
dataLoading: true,
sectionLoading: true,
buttonLoading: false,
contentMeta: DEFAULT_META,
contentFilterValue: '',
};
const searchServerResponse = {
results: contentItems,
meta,
};
beforeEach(() => {
jest.clearAllMocks();
mount();
});
it('has expected default values', () => {
expect(SourceLogic.values).toEqual(defaultValues);
});
describe('actions', () => {
it('onInitializeSource', () => {
SourceLogic.actions.onInitializeSource(contentSource);
expect(SourceLogic.values.contentSource).toEqual(contentSource);
expect(SourceLogic.values.dataLoading).toEqual(false);
});
it('onUpdateSourceName', () => {
const NAME = 'foo';
SourceLogic.actions.onInitializeSource(contentSource);
SourceLogic.actions.onUpdateSourceName(NAME);
expect(SourceLogic.values.contentSource).toEqual({
...contentSource,
name: NAME,
});
expect(setSuccessMessage).toHaveBeenCalled();
});
it('setSourceConfigData', () => {
SourceLogic.actions.setSourceConfigData(sourceConfigData);
expect(SourceLogic.values.sourceConfigData).toEqual(sourceConfigData);
expect(SourceLogic.values.dataLoading).toEqual(false);
});
it('setSearchResults', () => {
SourceLogic.actions.setSearchResults(searchServerResponse);
expect(SourceLogic.values.contentItems).toEqual(contentItems);
expect(SourceLogic.values.contentMeta).toEqual(meta);
expect(SourceLogic.values.sectionLoading).toEqual(false);
});
it('setContentFilterValue', () => {
const VALUE = 'bar';
SourceLogic.actions.setSearchResults(searchServerResponse);
SourceLogic.actions.onInitializeSource(contentSource);
SourceLogic.actions.setContentFilterValue(VALUE);
expect(SourceLogic.values.contentMeta).toEqual({
...meta,
page: {
...meta.page,
current: DEFAULT_META.page.current,
},
});
expect(SourceLogic.values.contentFilterValue).toEqual(VALUE);
});
it('setActivePage', () => {
const PAGE = 2;
SourceLogic.actions.setSearchResults(searchServerResponse);
SourceLogic.actions.setActivePage(PAGE);
expect(SourceLogic.values.contentMeta).toEqual({
...meta,
page: {
...meta.page,
current: PAGE,
},
});
});
it('setButtonNotLoading', () => {
// Set button state to loading
SourceLogic.actions.removeContentSource(contentSource.id);
SourceLogic.actions.setButtonNotLoading();
expect(SourceLogic.values.buttonLoading).toEqual(false);
});
});
describe('listeners', () => {
describe('initializeSource', () => {
it('calls API and sets values (org)', async () => {
const onInitializeSourceSpy = jest.spyOn(SourceLogic.actions, 'onInitializeSource');
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeSource(contentSource.id);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/sources/123');
await promise;
expect(onInitializeSourceSpy).toHaveBeenCalledWith(contentSource);
});
it('calls API and sets values (account)', async () => {
AppLogic.values.isOrganization = false;
const onInitializeSourceSpy = jest.spyOn(SourceLogic.actions, 'onInitializeSource');
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeSource(contentSource.id);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/account/sources/123');
await promise;
expect(onInitializeSourceSpy).toHaveBeenCalledWith(contentSource);
});
it('handles federated source', async () => {
AppLogic.values.isOrganization = false;
const initializeFederatedSummarySpy = jest.spyOn(
SourceLogic.actions,
'initializeFederatedSummary'
);
const promise = Promise.resolve({
...contentSource,
isFederatedSource: true,
});
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeSource(contentSource.id);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/account/sources/123');
await promise;
expect(initializeFederatedSummarySpy).toHaveBeenCalledWith(contentSource.id);
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeSource(contentSource.id);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
it('handles not found state', async () => {
const error = {
response: {
error: 'this is an error',
status: 404,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeSource(contentSource.id);
await expectedAsyncError(promise);
expect(navigateToUrl).toHaveBeenCalledWith(NOT_FOUND_PATH);
});
});
describe('initializeFederatedSummary', () => {
it('calls API and sets values', async () => {
const onUpdateSummarySpy = jest.spyOn(SourceLogic.actions, 'onUpdateSummary');
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeFederatedSummary(contentSource.id);
expect(http.get).toHaveBeenCalledWith(
'/api/workplace_search/org/sources/123/federated_summary'
);
await promise;
expect(onUpdateSummarySpy).toHaveBeenCalledWith(contentSource.summary);
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
SourceLogic.actions.initializeFederatedSummary(contentSource.id);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('searchContentSourceDocuments', () => {
const mockBreakpoint = jest.fn();
const values = { contentMeta: meta, contentFilterValue: '' };
const actions = { setSearchResults: jest.fn() };
const { searchContentSourceDocuments } = getListeners({
values,
actions,
});
it('calls API and sets values (org)', async () => {
AppLogic.values.isOrganization = true;
const promise = Promise.resolve(searchServerResponse);
http.post.mockReturnValue(promise);
await searchContentSourceDocuments({ sourceId: contentSource.id }, mockBreakpoint);
expect(http.post).toHaveBeenCalledWith('/api/workplace_search/org/sources/123/documents', {
body: JSON.stringify({ query: '', page: meta.page }),
});
await promise;
expect(actions.setSearchResults).toHaveBeenCalledWith(searchServerResponse);
});
it('calls API and sets values (account)', async () => {
AppLogic.values.isOrganization = false;
const promise = Promise.resolve(searchServerResponse);
http.post.mockReturnValue(promise);
SourceLogic.actions.searchContentSourceDocuments(contentSource.id);
await searchContentSourceDocuments({ sourceId: contentSource.id }, mockBreakpoint);
expect(http.post).toHaveBeenCalledWith(
'/api/workplace_search/account/sources/123/documents',
{
body: JSON.stringify({ query: '', page: meta.page }),
}
);
await promise;
expect(actions.setSearchResults).toHaveBeenCalledWith(searchServerResponse);
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.post.mockReturnValue(promise);
await searchContentSourceDocuments({ sourceId: contentSource.id }, mockBreakpoint);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('updateContentSource', () => {
it('calls API and sets values (org)', async () => {
AppLogic.values.isOrganization = true;
const onUpdateSourceNameSpy = jest.spyOn(SourceLogic.actions, 'onUpdateSourceName');
const promise = Promise.resolve(contentSource);
http.patch.mockReturnValue(promise);
SourceLogic.actions.updateContentSource(contentSource.id, contentSource);
expect(http.patch).toHaveBeenCalledWith('/api/workplace_search/org/sources/123/settings', {
body: JSON.stringify({ content_source: contentSource }),
});
await promise;
expect(onUpdateSourceNameSpy).toHaveBeenCalledWith(contentSource.name);
});
it('calls API and sets values (account)', async () => {
AppLogic.values.isOrganization = false;
const onUpdateSourceNameSpy = jest.spyOn(SourceLogic.actions, 'onUpdateSourceName');
const promise = Promise.resolve(contentSource);
http.patch.mockReturnValue(promise);
SourceLogic.actions.updateContentSource(contentSource.id, contentSource);
expect(http.patch).toHaveBeenCalledWith(
'/api/workplace_search/account/sources/123/settings',
{
body: JSON.stringify({ content_source: contentSource }),
}
);
await promise;
expect(onUpdateSourceNameSpy).toHaveBeenCalledWith(contentSource.name);
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.patch.mockReturnValue(promise);
SourceLogic.actions.updateContentSource(contentSource.id, contentSource);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('removeContentSource', () => {
it('calls API and sets values (org)', async () => {
AppLogic.values.isOrganization = true;
const setButtonNotLoadingSpy = jest.spyOn(SourceLogic.actions, 'setButtonNotLoading');
const promise = Promise.resolve(contentSource);
http.delete.mockReturnValue(promise);
SourceLogic.actions.removeContentSource(contentSource.id);
expect(clearFlashMessages).toHaveBeenCalled();
expect(http.delete).toHaveBeenCalledWith('/api/workplace_search/org/sources/123');
await promise;
expect(setQueuedSuccessMessage).toHaveBeenCalled();
expect(setButtonNotLoadingSpy).toHaveBeenCalled();
});
it('calls API and sets values (account)', async () => {
AppLogic.values.isOrganization = false;
const setButtonNotLoadingSpy = jest.spyOn(SourceLogic.actions, 'setButtonNotLoading');
const promise = Promise.resolve(contentSource);
http.delete.mockReturnValue(promise);
SourceLogic.actions.removeContentSource(contentSource.id);
expect(clearFlashMessages).toHaveBeenCalled();
expect(http.delete).toHaveBeenCalledWith('/api/workplace_search/account/sources/123');
await promise;
expect(setButtonNotLoadingSpy).toHaveBeenCalled();
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.delete.mockReturnValue(promise);
SourceLogic.actions.removeContentSource(contentSource.id);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('getSourceConfigData', () => {
const serviceType = 'github';
it('calls API and sets values', async () => {
AppLogic.values.isOrganization = true;
const setSourceConfigDataSpy = jest.spyOn(SourceLogic.actions, 'setSourceConfigData');
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
SourceLogic.actions.getSourceConfigData(serviceType);
expect(http.get).toHaveBeenCalledWith(
`/api/workplace_search/org/settings/connectors/${serviceType}`
);
await promise;
expect(setSourceConfigDataSpy).toHaveBeenCalled();
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
SourceLogic.actions.getSourceConfigData(serviceType);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
it('resetSourceState', () => {
SourceLogic.actions.resetSourceState();
expect(clearFlashMessages).toHaveBeenCalled();
});
});
});

View file

@ -126,29 +126,22 @@ export const SourceLogic = kea<MakeLogicType<SourceValues, SourceActions>>({
onInitializeSource: () => false,
setSourceConfigData: () => false,
resetSourceState: () => false,
setPreContentSourceConfigData: () => false,
},
],
buttonLoading: [
false,
{
setButtonNotLoading: () => false,
setSourceConnectData: () => false,
setSourceConfigData: () => false,
resetSourceState: () => false,
removeContentSource: () => true,
saveSourceConfig: () => true,
getSourceConnectData: () => true,
createContentSource: () => true,
},
],
sectionLoading: [
true,
{
searchContentSourceDocuments: () => true,
getPreContentSourceConfigData: () => true,
setSearchResults: () => false,
setPreContentSourceConfigData: () => false,
},
],
contentItems: [

View file

@ -0,0 +1,319 @@
/*
* 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 {
LogicMounter,
mockFlashMessageHelpers,
mockHttpValues,
expectedAsyncError,
} from '../../../__mocks__';
import { AppLogic } from '../../app_logic';
jest.mock('../../app_logic', () => ({
AppLogic: { values: { isOrganization: true } },
}));
import { configuredSources, contentSources } from '../../__mocks__/content_sources.mock';
import { SourcesLogic, fetchSourceStatuses, POLLING_INTERVAL } from './sources_logic';
describe('SourcesLogic', () => {
const { http } = mockHttpValues;
const { flashAPIErrors, setQueuedSuccessMessage } = mockFlashMessageHelpers;
const { mount, unmount } = new LogicMounter(SourcesLogic);
const contentSource = contentSources[0];
const defaultValues = {
contentSources: [],
privateContentSources: [],
sourceData: [],
availableSources: [],
configuredSources: [],
serviceTypes: [],
permissionsModal: null,
dataLoading: true,
serverStatuses: null,
};
const serverStatuses = [
{
id: '123',
name: 'my source',
service_type: 'github',
status: {
status: 'this is a thing',
synced_at: '2021-01-25',
error_reason: 1,
},
},
];
const serverResponse = {
contentSources,
privateContentSources: contentSources,
serviceTypes: configuredSources,
};
beforeEach(() => {
jest.useFakeTimers();
jest.clearAllMocks();
mount();
});
it('has expected default values', () => {
expect(SourcesLogic.values).toEqual(defaultValues);
});
it('handles unmounting', async () => {
unmount();
expect(clearInterval).toHaveBeenCalled();
});
describe('actions', () => {
describe('onInitializeSources', () => {
it('sets values', () => {
SourcesLogic.actions.onInitializeSources(serverResponse);
expect(SourcesLogic.values.contentSources).toEqual(contentSources);
expect(SourcesLogic.values.privateContentSources).toEqual(contentSources);
expect(SourcesLogic.values.serviceTypes).toEqual(configuredSources);
expect(SourcesLogic.values.dataLoading).toEqual(false);
});
it('fallbacks', () => {
SourcesLogic.actions.onInitializeSources({
contentSources,
serviceTypes: undefined as any,
});
expect(SourcesLogic.values.serviceTypes).toEqual([]);
expect(SourcesLogic.values.privateContentSources).toEqual([]);
});
});
it('setServerSourceStatuses', () => {
SourcesLogic.actions.setServerSourceStatuses(serverStatuses);
const source = serverStatuses[0];
expect(SourcesLogic.values.serverStatuses).toEqual({
[source.id]: source.status.status,
});
});
it('onSetSearchability', () => {
const id = contentSources[0].id;
const updatedSources = [...contentSources];
updatedSources[0].searchable = false;
SourcesLogic.actions.onInitializeSources(serverResponse);
SourcesLogic.actions.onSetSearchability(id, false);
expect(SourcesLogic.values.contentSources).toEqual(updatedSources);
expect(SourcesLogic.values.privateContentSources).toEqual(updatedSources);
});
describe('setAddedSource', () => {
it('configured', () => {
const name = contentSources[0].name;
SourcesLogic.actions.setAddedSource(name, false, 'custom');
expect(SourcesLogic.values.permissionsModal).toEqual({
addedSourceName: name,
additionalConfiguration: false,
serviceType: 'custom',
});
expect(setQueuedSuccessMessage).toHaveBeenCalledWith('Successfully connected source. ');
});
it('unconfigured', () => {
const name = contentSources[0].name;
SourcesLogic.actions.setAddedSource(name, true, 'custom');
expect(SourcesLogic.values.permissionsModal).toEqual({
addedSourceName: name,
additionalConfiguration: true,
serviceType: 'custom',
});
expect(setQueuedSuccessMessage).toHaveBeenCalledWith(
'Successfully connected source. This source requires additional configuration.'
);
});
});
it('resetPermissionsModal', () => {
SourcesLogic.actions.resetPermissionsModal();
expect(SourcesLogic.values.permissionsModal).toEqual(null);
});
});
describe('listeners', () => {
describe('initializeSources', () => {
it('calls API and sets values (org)', async () => {
AppLogic.values.isOrganization = true;
const pollForSourceStatusChangesSpy = jest.spyOn(
SourcesLogic.actions,
'pollForSourceStatusChanges'
);
const onInitializeSourcesSpy = jest.spyOn(SourcesLogic.actions, 'onInitializeSources');
const promise = Promise.resolve(contentSources);
http.get.mockReturnValue(promise);
SourcesLogic.actions.initializeSources();
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/sources');
await promise;
expect(pollForSourceStatusChangesSpy).toHaveBeenCalled();
expect(onInitializeSourcesSpy).toHaveBeenCalledWith(contentSources);
});
it('calls API (account)', async () => {
AppLogic.values.isOrganization = false;
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
SourcesLogic.actions.initializeSources();
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/account/sources');
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
SourcesLogic.actions.initializeSources();
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('setSourceSearchability', () => {
const id = contentSources[0].id;
it('calls API and sets values (org)', async () => {
AppLogic.values.isOrganization = true;
const onSetSearchability = jest.spyOn(SourcesLogic.actions, 'onSetSearchability');
const promise = Promise.resolve(contentSources);
http.put.mockReturnValue(promise);
SourcesLogic.actions.setSourceSearchability(id, true);
expect(http.put).toHaveBeenCalledWith('/api/workplace_search/org/sources/123/searchable', {
body: JSON.stringify({ searchable: true }),
});
await promise;
expect(onSetSearchability).toHaveBeenCalledWith(id, true);
});
it('calls API (account)', async () => {
AppLogic.values.isOrganization = false;
const promise = Promise.resolve(contentSource);
http.put.mockReturnValue(promise);
SourcesLogic.actions.setSourceSearchability(id, true);
expect(http.put).toHaveBeenCalledWith(
'/api/workplace_search/account/sources/123/searchable',
{
body: JSON.stringify({ searchable: true }),
}
);
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.put.mockReturnValue(promise);
SourcesLogic.actions.setSourceSearchability(id, true);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
describe('pollForSourceStatusChanges', () => {
it('calls API and sets values', async () => {
AppLogic.values.isOrganization = true;
SourcesLogic.actions.setServerSourceStatuses(serverStatuses);
const setServerSourceStatusesSpy = jest.spyOn(
SourcesLogic.actions,
'setServerSourceStatuses'
);
const promise = Promise.resolve(contentSources);
http.get.mockReturnValue(promise);
SourcesLogic.actions.pollForSourceStatusChanges();
jest.advanceTimersByTime(POLLING_INTERVAL);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/sources/status');
await promise;
expect(setServerSourceStatusesSpy).toHaveBeenCalledWith(contentSources);
});
});
it('resetSourcesState', () => {
SourcesLogic.actions.resetSourcesState();
expect(clearInterval).toHaveBeenCalled();
});
});
describe('selectors', () => {
it('availableSources & configuredSources have correct length', () => {
SourcesLogic.actions.onInitializeSources(serverResponse);
expect(SourcesLogic.values.availableSources).toHaveLength(1);
expect(SourcesLogic.values.configuredSources).toHaveLength(5);
});
});
describe('fetchSourceStatuses', () => {
it('calls API and sets values (org)', async () => {
const setServerSourceStatusesSpy = jest.spyOn(
SourcesLogic.actions,
'setServerSourceStatuses'
);
const promise = Promise.resolve(contentSources);
http.get.mockReturnValue(promise);
fetchSourceStatuses(true);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/sources/status');
await promise;
expect(setServerSourceStatusesSpy).toHaveBeenCalledWith(contentSources);
});
it('calls API (account)', async () => {
const promise = Promise.resolve(contentSource);
http.get.mockReturnValue(promise);
fetchSourceStatuses(false);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/account/sources/status');
});
it('handles error', async () => {
const error = {
response: {
error: 'this is an error',
status: 400,
},
};
const promise = Promise.reject(error);
http.get.mockReturnValue(promise);
fetchSourceStatuses(true);
await expectedAsyncError(promise);
expect(flashAPIErrors).toHaveBeenCalledWith(error);
});
});
});

View file

@ -12,11 +12,7 @@ import { i18n } from '@kbn/i18n';
import { HttpLogic } from '../../../shared/http';
import {
flashAPIErrors,
setQueuedSuccessMessage,
clearFlashMessages,
} from '../../../shared/flash_messages';
import { flashAPIErrors, setQueuedSuccessMessage } from '../../../shared/flash_messages';
import { Connector, ContentSourceDetails, ContentSourceStatus, SourceDataItem } from '../../types';
@ -40,7 +36,6 @@ export interface ISourcesActions {
additionalConfiguration: boolean,
serviceType: string
): { addedSourceName: string; additionalConfiguration: boolean; serviceType: string };
resetFlashMessages(): void;
resetPermissionsModal(): void;
resetSourcesState(): void;
initializeSources(): void;
@ -78,7 +73,7 @@ interface ISourcesServerResponse {
}
let pollingInterval: number;
const POLLING_INTERVAL = 10000;
export const POLLING_INTERVAL = 10000;
export const SourcesLogic = kea<MakeLogicType<ISourcesValues, ISourcesActions>>({
path: ['enterprise_search', 'workplace_search', 'sources_logic'],
@ -91,7 +86,6 @@ export const SourcesLogic = kea<MakeLogicType<ISourcesValues, ISourcesActions>>(
additionalConfiguration: boolean,
serviceType: string
) => ({ addedSourceName, additionalConfiguration, serviceType }),
resetFlashMessages: () => true,
resetPermissionsModal: () => true,
resetSourcesState: () => true,
initializeSources: () => true,
@ -238,9 +232,6 @@ export const SourcesLogic = kea<MakeLogicType<ISourcesValues, ISourcesActions>>(
].join(' ')
);
},
resetFlashMessages: () => {
clearFlashMessages();
},
resetSourcesState: () => {
clearInterval(pollingInterval);
},
@ -252,7 +243,7 @@ export const SourcesLogic = kea<MakeLogicType<ISourcesValues, ISourcesActions>>(
}),
});
const fetchSourceStatuses = async (isOrganization: boolean) => {
export const fetchSourceStatuses = async (isOrganization: boolean) => {
const route = isOrganization
? '/api/workplace_search/org/sources/status'
: '/api/workplace_search/account/sources/status';
@ -273,7 +264,6 @@ const updateSourcesOnToggle = (
sourceId: string,
searchable: boolean
): ContentSourceDetails[] => {
if (!contentSources) return [];
const sources = cloneDeep(contentSources) as ContentSourceDetails[];
const index = findIndex(sources, ({ id }) => id === sourceId);
const updatedSource = sources[index];

View file

@ -7,7 +7,7 @@
import '../../../__mocks__/shallow_useeffect.mock';
import { setMockActions, setMockValues } from '../../../__mocks__';
import { groups } from '../../__mocks__/groups.mock';
import { mockMeta } from '../../__mocks__/meta.mock';
import { meta } from '../../__mocks__/meta.mock';
import React from 'react';
import { shallow } from 'enzyme';
@ -46,7 +46,7 @@ const mockValues = {
newGroup: null,
groupListLoading: false,
hasFiltersSet: false,
groupsMeta: mockMeta,
groupsMeta: meta,
filteredSources: [],
filteredUsers: [],
filterValue: '',