Skip to content

Commit

Permalink
[App Search] EnginesLogic + minor UX fix (#87561)
Browse files Browse the repository at this point in the history
* [Misc cleanup] DRY out type def

EnginesTableData was made before we started importing more types over from ent-search; we should reuse the more complete EngineDetails instead of re-declaring our own

* Add EnginesLogic file + tests
- based on current state inside EnginesOverview

- Not a 1:1 translation from ent-search's EnginesLogic b/c the table component/view is different
- also missing engine creation which will be a separate PR

* Update EnginesOverview to use EnginesLogic

- should be significantly simpler
- tests no longer need mountAsync

* [Extra] Make up for lost icon.tsx coverage

- because we no longer use mount() in the engines overview tests, I'm adding an extra set of quick shallow render tests to cover the icon .tsx lines

* [Misc] Rename fetchX to loadY (copying Kea)
  • Loading branch information
Constance authored Jan 13, 2021
1 parent 6e3a06b commit 0e118c2
Show file tree
Hide file tree
Showing 8 changed files with 388 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 React from 'react';
import { shallow } from 'enzyme';

import { EngineIcon } from './engine_icon';
import { MetaEngineIcon } from './meta_engine_icon';

describe('Engines icons', () => {
it('renders an engine icon', () => {
const wrapper = shallow(<EngineIcon />);
expect(wrapper.hasClass('engineIcon')).toBe(true);
});

it('renders a meta engine icon', () => {
const wrapper = shallow(<MetaEngineIcon />);
expect(wrapper.hasClass('engineIcon')).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* 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 } from '../../../__mocks__/kea.mock';

jest.mock('../../../shared/http', () => ({
HttpLogic: { values: { http: { get: jest.fn() } } },
}));
import { HttpLogic } from '../../../shared/http';

import { EngineDetails } from '../engine/types';
import { EnginesLogic } from './';

describe('EnginesLogic', () => {
const DEFAULT_VALUES = {
dataLoading: true,
engines: [],
enginesTotal: 0,
enginesPage: 1,
metaEngines: [],
metaEnginesTotal: 0,
metaEnginesPage: 1,
};

const MOCK_ENGINE = {
name: 'hello-world',
created_at: 'Fri, 1 Jan 1970 12:00:00 +0000',
document_count: 50,
field_count: 10,
} as EngineDetails;
const MOCK_ENGINES_API_RESPONSE = {
results: [MOCK_ENGINE],
meta: {
page: {
current: 1,
total_pages: 10,
total_results: 100,
size: 10,
},
},
};

const { mount } = new LogicMounter(EnginesLogic);

beforeEach(() => {
jest.clearAllMocks();
});

it('has expected default values', () => {
mount();
expect(EnginesLogic.values).toEqual(DEFAULT_VALUES);
});

describe('actions', () => {
describe('onEnginesLoad', () => {
describe('dataLoading', () => {
it('should be set to false', () => {
mount();
EnginesLogic.actions.onEnginesLoad({ engines: [], total: 0 });

expect(EnginesLogic.values).toEqual({
...DEFAULT_VALUES,
dataLoading: false,
});
});
});

describe('engines & enginesTotal', () => {
it('should be set to the provided value', () => {
mount();
EnginesLogic.actions.onEnginesLoad({ engines: [MOCK_ENGINE], total: 100 });

expect(EnginesLogic.values).toEqual({
...DEFAULT_VALUES,
dataLoading: false,
engines: [MOCK_ENGINE],
enginesTotal: 100,
});
});
});
});

describe('onMetaEnginesLoad', () => {
describe('engines & enginesTotal', () => {
it('should be set to the provided value', () => {
mount();
EnginesLogic.actions.onMetaEnginesLoad({ engines: [MOCK_ENGINE], total: 1 });

expect(EnginesLogic.values).toEqual({
...DEFAULT_VALUES,
metaEngines: [MOCK_ENGINE],
metaEnginesTotal: 1,
});
});
});
});

describe('onEnginesPagination', () => {
describe('enginesPage', () => {
it('should be set to the provided value', () => {
mount();
EnginesLogic.actions.onEnginesPagination(2);

expect(EnginesLogic.values).toEqual({
...DEFAULT_VALUES,
enginesPage: 2,
});
});
});
});

describe('onMetaEnginesPagination', () => {
describe('metaEnginesPage', () => {
it('should be set to the provided value', () => {
mount();
EnginesLogic.actions.onMetaEnginesPagination(99);

expect(EnginesLogic.values).toEqual({
...DEFAULT_VALUES,
metaEnginesPage: 99,
});
});
});
});

describe('loadEngines', () => {
it('should call the engines API endpoint and set state based on the results', async () => {
const promise = Promise.resolve(MOCK_ENGINES_API_RESPONSE);
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
mount({ enginesPage: 10 });
jest.spyOn(EnginesLogic.actions, 'onEnginesLoad');

EnginesLogic.actions.loadEngines();
await promise;

expect(HttpLogic.values.http.get).toHaveBeenCalledWith('/api/app_search/engines', {
query: { type: 'indexed', pageIndex: 10 },
});
expect(EnginesLogic.actions.onEnginesLoad).toHaveBeenCalledWith({
engines: [MOCK_ENGINE],
total: 100,
});
});
});

describe('loadMetaEngines', () => {
it('should call the engines API endpoint and set state based on the results', async () => {
const promise = Promise.resolve(MOCK_ENGINES_API_RESPONSE);
(HttpLogic.values.http.get as jest.Mock).mockReturnValueOnce(promise);
mount({ metaEnginesPage: 99 });
jest.spyOn(EnginesLogic.actions, 'onMetaEnginesLoad');

EnginesLogic.actions.loadMetaEngines();
await promise;

expect(HttpLogic.values.http.get).toHaveBeenCalledWith('/api/app_search/engines', {
query: { type: 'meta', pageIndex: 99 },
});
expect(EnginesLogic.actions.onMetaEnginesLoad).toHaveBeenCalledWith({
engines: [MOCK_ENGINE],
total: 100,
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* 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 { kea, MakeLogicType } from 'kea';

import { HttpLogic } from '../../../shared/http';

import { EngineDetails } from '../engine/types';

interface EnginesValues {
dataLoading: boolean;
engines: EngineDetails[];
enginesTotal: number;
enginesPage: number;
metaEngines: EngineDetails[];
metaEnginesTotal: number;
metaEnginesPage: number;
}

interface OnEnginesLoad {
engines: EngineDetails[];
total: number;
}
interface EnginesActions {
onEnginesLoad({ engines, total }: OnEnginesLoad): OnEnginesLoad;
onMetaEnginesLoad({ engines, total }: OnEnginesLoad): OnEnginesLoad;
onEnginesPagination(page: number): { page: number };
onMetaEnginesPagination(page: number): { page: number };
loadEngines(): void;
loadMetaEngines(): void;
}

export const EnginesLogic = kea<MakeLogicType<EnginesValues, EnginesActions>>({
path: ['enterprise_search', 'app_search', 'engines_logic'],
actions: {
onEnginesLoad: ({ engines, total }) => ({ engines, total }),
onMetaEnginesLoad: ({ engines, total }) => ({ engines, total }),
onEnginesPagination: (page) => ({ page }),
onMetaEnginesPagination: (page) => ({ page }),
loadEngines: true,
loadMetaEngines: true,
},
reducers: {
dataLoading: [
true,
{
onEnginesLoad: () => false,
},
],
engines: [
[],
{
onEnginesLoad: (_, { engines }) => engines,
},
],
enginesTotal: [
0,
{
onEnginesLoad: (_, { total }) => total,
},
],
enginesPage: [
1,
{
onEnginesPagination: (_, { page }) => page,
},
],
metaEngines: [
[],
{
onMetaEnginesLoad: (_, { engines }) => engines,
},
],
metaEnginesTotal: [
0,
{
onMetaEnginesLoad: (_, { total }) => total,
},
],
metaEnginesPage: [
1,
{
onMetaEnginesPagination: (_, { page }) => page,
},
],
},
listeners: ({ actions, values }) => ({
loadEngines: async () => {
const { http } = HttpLogic.values;
const { enginesPage } = values;

const response = await http.get('/api/app_search/engines', {
query: { type: 'indexed', pageIndex: enginesPage },
});
actions.onEnginesLoad({
engines: response.results,
total: response.meta.page.total_results,
});
},
loadMetaEngines: async () => {
const { http } = HttpLogic.values;
const { metaEnginesPage } = values;

const response = await http.get('/api/app_search/engines', {
query: { type: 'meta', pageIndex: metaEnginesPage },
});
actions.onMetaEnginesLoad({
engines: response.results,
total: response.meta.page.total_results,
});
},
}),
});
Loading

0 comments on commit 0e118c2

Please sign in to comment.