diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx new file mode 100644 index 0000000000000..19ea683eb878c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx @@ -0,0 +1,56 @@ +/* + * 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 { EngineOverviewHeader } from '../engine_overview_header'; +import { mountWithKibanaContext } from '../../../test_utils/helpers'; + +describe('EngineOverviewHeader', () => { + describe('when enterpriseSearchUrl is set', () => { + let wrapper; + + beforeEach(() => { + wrapper = mountWithKibanaContext(, { + enterpriseSearchUrl: 'http://localhost:3002', + }); + }); + + describe('the Launch App Search button', () => { + const subject = () => wrapper.find('EuiButton[data-test-subj="launchButton"]'); + + it('should not be disabled', () => { + expect(subject().props().isDisabled).toBeFalsy(); + }); + + it('should use the enterpriseSearchUrl as the base path for its href', () => { + expect(subject().props().href).toBe('http://localhost:3002/as'); + }); + }); + }); + + describe('when enterpriseSearchUrl is not set', () => { + let wrapper; + + beforeEach(() => { + wrapper = mountWithKibanaContext(, { + enterpriseSearchUrl: undefined, + }); + }); + + describe('the Launch App Search button', () => { + const subject = () => wrapper.find('EuiButton[data-test-subj="launchButton"]'); + + it('should be disabled', () => { + expect(subject().props().isDisabled).toBe(true); + }); + + it('should not have an href', () => { + expect(subject().props().href).toBeUndefined(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx index 14b2d00668c0d..69bfb9ad124eb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx @@ -15,6 +15,7 @@ export const EngineOverviewHeader: React.FC<> = () => { const buttonProps = { fill: true, iconType: 'popout', + ['data-test-subj']: 'launchButton', }; if (enterpriseSearchUrl) { buttonProps.href = `${enterpriseSearchUrl}/as`; diff --git a/x-pack/plugins/enterprise_search/public/applications/index.test.ts b/x-pack/plugins/enterprise_search/public/applications/index.test.ts new file mode 100644 index 0000000000000..7ece7e153c154 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/index.test.ts @@ -0,0 +1,20 @@ +/* + * 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 { coreMock } from 'src/core/public/mocks'; +import { renderApp } from '../applications'; + +describe('renderApp', () => { + it('mounts and unmounts UI', () => { + const params = coreMock.createAppMountParamters(); + const core = coreMock.createStart(); + + const unmount = renderApp(core, params, {}); + expect(params.element.querySelector('.setup-guide')).not.toBeNull(); + unmount(); + expect(params.element.innerHTML).toEqual(''); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/generate_breadcrumbs.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/generate_breadcrumbs.test.ts new file mode 100644 index 0000000000000..aa2b584d98425 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/generate_breadcrumbs.test.ts @@ -0,0 +1,151 @@ +/* + * 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 { appSearchBreadcrumbs, enterpriseSearchBreadcrumbs } from '../kibana_breadcrumbs'; + +jest.mock('../react_router_helpers', () => ({ + letBrowserHandleEvent: () => false, +})); + +describe('appSearchBreadcrumbs', () => { + const historyMock = { + createHref: jest.fn().mockImplementation(path => path.pathname), + push: jest.fn(), + }; + + const breadCrumbs = [ + { + text: 'Page 1', + path: '/page1', + }, + { + text: 'Page 2', + path: '/page2', + }, + ]; + + afterEach(() => { + jest.clearAllMocks(); + }); + + const subject = () => appSearchBreadcrumbs(historyMock)(breadCrumbs); + + it('Builds a chain of breadcrumbs with Enterprise Search and App Search at the root', () => { + expect(subject()).toEqual([ + { + href: '/', + onClick: expect.any(Function), + text: 'Enterprise Search', + }, + { + href: '/app_search', + onClick: expect.any(Function), + text: 'App Search', + }, + { + href: '/page1', + onClick: expect.any(Function), + text: 'Page 1', + }, + { + href: '/page2', + onClick: expect.any(Function), + text: 'Page 2', + }, + ]); + }); + + describe('links', () => { + const eventMock = { + preventDefault: jest.fn(), + }; + + it('has a link to Enterprise Search Home page first', () => { + subject()[0].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/'); + }); + + it('has a link to App Search second', () => { + subject()[1].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/app_search'); + }); + + it('has a link to page 1 third', () => { + subject()[2].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/page1'); + }); + + it('has a link to page 2 last', () => { + subject()[3].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/page2'); + }); + }); +}); + +describe('enterpriseSearchBreadcrumbs', () => { + const historyMock = { + createHref: jest.fn(), + push: jest.fn(), + }; + + const breadCrumbs = [ + { + text: 'Page 1', + path: '/page1', + }, + { + text: 'Page 2', + path: '/page2', + }, + ]; + + afterEach(() => { + jest.clearAllMocks(); + }); + + const subject = () => enterpriseSearchBreadcrumbs(historyMock)(breadCrumbs); + + it('Builds a chain of breadcrumbs with Enterprise Search at the root', () => { + expect(subject()).toEqual([ + { + href: undefined, + onClick: expect.any(Function), + text: 'Enterprise Search', + }, + { + href: undefined, + onClick: expect.any(Function), + text: 'Page 1', + }, + { + href: undefined, + onClick: expect.any(Function), + text: 'Page 2', + }, + ]); + }); + + describe('links', () => { + const eventMock = { + preventDefault: jest.fn(), + }; + + it('has a link to Enterprise Search Home page first', () => { + subject()[0].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/'); + }); + + it('has a link to page 1 second', () => { + subject()[1].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/page1'); + }); + + it('has a link to page 2 last', () => { + subject()[2].onClick(eventMock); + expect(historyMock.push).toHaveBeenCalledWith('/page2'); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/set_breadcrumbs.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/set_breadcrumbs.test.tsx new file mode 100644 index 0000000000000..788800d86ec84 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_breadcrumbs/set_breadcrumbs.test.tsx @@ -0,0 +1,75 @@ +/* + * 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 { SetAppSearchBreadcrumbs } from '../kibana_breadcrumbs'; +import { mountWithKibanaContext } from '../../test_utils/helpers'; + +jest.mock('./generate_breadcrumbs', () => ({ + appSearchBreadcrumbs: jest.fn(), +})); +import { appSearchBreadcrumbs } from './generate_breadcrumbs'; + +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + createHref: jest.fn(), + push: jest.fn(), + location: { + pathname: '/current-path', + }, + }), +})); + +describe('SetAppSearchBreadcrumbs', () => { + const setBreadcrumbs = jest.fn(); + const builtBreadcrumbs = []; + const appSearchBreadCrumbsInnerCall = jest.fn().mockReturnValue(builtBreadcrumbs); + const appSearchBreadCrumbsOuterCall = jest.fn().mockReturnValue(appSearchBreadCrumbsInnerCall); + appSearchBreadcrumbs.mockImplementation(appSearchBreadCrumbsOuterCall); + + afterEach(() => { + jest.clearAllMocks(); + }); + + const mountSetAppSearchBreadcrumbs = props => { + return mountWithKibanaContext(, { + http: {}, + enterpriseSearchUrl: 'http://localhost:3002', + setBreadcrumbs, + }); + }; + + describe('when isRoot is false', () => { + const subject = () => mountSetAppSearchBreadcrumbs({ text: 'Page 1', isRoot: false }); + + it('calls appSearchBreadcrumbs to build breadcrumbs, then registers them with Kibana', () => { + subject(); + + // calls appSearchBreadcrumbs to build breadcrumbs with the target page and current location + expect(appSearchBreadCrumbsInnerCall).toHaveBeenCalledWith([ + { text: 'Page 1', path: '/current-path' }, + ]); + + // then registers them with Kibana + expect(setBreadcrumbs).toHaveBeenCalledWith(builtBreadcrumbs); + }); + }); + + describe('when isRoot is true', () => { + const subject = () => mountSetAppSearchBreadcrumbs({ text: 'Page 1', isRoot: true }); + + it('calls appSearchBreadcrumbs to build breadcrumbs with an empty breadcrumb, then registers them with Kibana', () => { + subject(); + + // uses an empty bredcrumb + expect(appSearchBreadCrumbsInnerCall).toHaveBeenCalledWith([]); + + // then registers them with Kibana + expect(setBreadcrumbs).toHaveBeenCalledWith(builtBreadcrumbs); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.test.ts new file mode 100644 index 0000000000000..49ab5ed920e36 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.test.ts @@ -0,0 +1,102 @@ +/* + * 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 { letBrowserHandleEvent } from '../react_router_helpers'; + +describe('letBrowserHandleEvent', () => { + const event = { + defaultPrevented: false, + metaKey: false, + altKey: false, + ctrlKey: false, + shiftKey: false, + button: 0, + target: { + getAttribute: () => '_self', + }, + }; + + describe('the browser should handle the link when', () => { + it('default is prevented', () => { + expect(letBrowserHandleEvent({ ...event, defaultPrevented: true })).toBe(true); + }); + + it('is modified with metaKey', () => { + expect(letBrowserHandleEvent({ ...event, metaKey: true })).toBe(true); + }); + + it('is modified with altKey', () => { + expect(letBrowserHandleEvent({ ...event, altKey: true })).toBe(true); + }); + + it('is modified with ctrlKey', () => { + expect(letBrowserHandleEvent({ ...event, ctrlKey: true })).toBe(true); + }); + + it('is modified with shiftKey', () => { + expect(letBrowserHandleEvent({ ...event, shiftKey: true })).toBe(true); + }); + + it('it is not a left click event', () => { + expect(letBrowserHandleEvent({ ...event, button: 2 })).toBe(true); + }); + + it('the target is anything value other than _self', () => { + expect( + letBrowserHandleEvent({ + ...event, + target: targetValue('_blank'), + }) + ).toBe(true); + }); + }); + + describe('the browser should NOT handle the link when', () => { + it('default is not prevented', () => { + expect(letBrowserHandleEvent({ ...event, defaultPrevented: false })).toBe(false); + }); + + it('is not modified', () => { + expect( + letBrowserHandleEvent({ + ...event, + metaKey: false, + altKey: false, + ctrlKey: false, + shiftKey: false, + }) + ).toBe(false); + }); + + it('it is a left click event', () => { + expect(letBrowserHandleEvent({ ...event, button: 0 })).toBe(false); + }); + + it('the target is a value of _self', () => { + expect( + letBrowserHandleEvent({ + ...event, + target: targetValue('_self'), + }) + ).toBe(false); + }); + + it('the target has no value', () => { + expect( + letBrowserHandleEvent({ + ...event, + target: targetValue(null), + }) + ).toBe(false); + }); + }); +}); + +const targetValue = value => { + return { + getAttribute: () => value, + }; +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.ts similarity index 95% rename from x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.tsx rename to x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.ts index dba5d576faa7d..bb87ecaf6877b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/link_events.ts @@ -26,5 +26,5 @@ const isLeftClickEvent: THandleEvent = event => event.button === 0; const isTargetBlank: THandleEvent = event => { const target = event.target.getAttribute('target'); - return target && target !== '_self'; + return !!target && target !== '_self'; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/test_utils/helpers.tsx b/x-pack/plugins/enterprise_search/public/applications/test_utils/helpers.tsx new file mode 100644 index 0000000000000..9343e927e82ac --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/test_utils/helpers.tsx @@ -0,0 +1,25 @@ +/* + * 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 { mount } from 'enzyme'; + +import { KibanaContext } from '..'; + +export const mountWithKibanaContext = (node, contextProps) => { + return mount( + + {node} + + ); +};