From 2a77307af18ebce2422da9e9b2c91a0abdeb4ff3 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Mon, 27 Jul 2020 09:22:37 -0500 Subject: [PATCH] [APM] Use core.chrome to set window title (#73232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed there's a `core.chrome.docTitle.change` method. It can take a string or array of strings and provides its own separator character if given an array. Replace our setting of `window.document.title` directly in the APM and Observability plugins with using the chrome method. This changes the title to be, for example, "トランザクション - opbeans-node - サービス - APM - Elastic" instead of "トランザクション | opbeans-node | サービス | APM | Elastic", using " - " as a separator instead of " | ". --- .../app/Main/UpdateBreadcrumbs.test.tsx | 55 +++++++++++-------- .../components/app/Main/UpdateBreadcrumbs.tsx | 9 ++- .../public/application/application.test.tsx | 29 ++++++++++ .../public/application/index.tsx | 7 +-- 4 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 x-pack/plugins/observability/public/application/application.test.tsx diff --git a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx index 6aec6e9bf181a..2c19356a7fd52 100644 --- a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx @@ -16,6 +16,7 @@ import { } from '../../../context/ApmPluginContext/MockApmPluginContext'; const setBreadcrumbs = jest.fn(); +const changeTitle = jest.fn(); function mountBreadcrumb(route: string, params = '') { mount( @@ -27,6 +28,7 @@ function mountBreadcrumb(route: string, params = '') { ...mockApmPluginContextValue.core, chrome: { ...mockApmPluginContextValue.core.chrome, + docTitle: { change: changeTitle }, setBreadcrumbs, }, }, @@ -42,23 +44,14 @@ function mountBreadcrumb(route: string, params = '') { } describe('UpdateBreadcrumbs', () => { - let realDoc: Document; - beforeEach(() => { - realDoc = window.document; - (window.document as any) = { - title: 'Kibana', - }; setBreadcrumbs.mockReset(); + changeTitle.mockReset(); }); - afterEach(() => { - (window.document as any) = realDoc; - }); - - it('Homepage', () => { + it('Changes the homepage title', () => { mountBreadcrumb('/'); - expect(window.document.title).toMatchInlineSnapshot(`"APM"`); + expect(changeTitle).toHaveBeenCalledWith(['APM']); }); it('/services/:serviceName/errors/:groupId', () => { @@ -90,9 +83,13 @@ describe('UpdateBreadcrumbs', () => { }, { text: 'myGroupId', href: undefined }, ]); - expect(window.document.title).toMatchInlineSnapshot( - `"myGroupId | Errors | opbeans-node | Services | APM"` - ); + expect(changeTitle).toHaveBeenCalledWith([ + 'myGroupId', + 'Errors', + 'opbeans-node', + 'Services', + 'APM', + ]); }); it('/services/:serviceName/errors', () => { @@ -104,9 +101,12 @@ describe('UpdateBreadcrumbs', () => { { text: 'opbeans-node', href: '#/services/opbeans-node?kuery=myKuery' }, { text: 'Errors', href: undefined }, ]); - expect(window.document.title).toMatchInlineSnapshot( - `"Errors | opbeans-node | Services | APM"` - ); + expect(changeTitle).toHaveBeenCalledWith([ + 'Errors', + 'opbeans-node', + 'Services', + 'APM', + ]); }); it('/services/:serviceName/transactions', () => { @@ -118,9 +118,12 @@ describe('UpdateBreadcrumbs', () => { { text: 'opbeans-node', href: '#/services/opbeans-node?kuery=myKuery' }, { text: 'Transactions', href: undefined }, ]); - expect(window.document.title).toMatchInlineSnapshot( - `"Transactions | opbeans-node | Services | APM"` - ); + expect(changeTitle).toHaveBeenCalledWith([ + 'Transactions', + 'opbeans-node', + 'Services', + 'APM', + ]); }); it('/services/:serviceName/transactions/view?transactionName=my-transaction-name', () => { @@ -139,8 +142,12 @@ describe('UpdateBreadcrumbs', () => { }, { text: 'my-transaction-name', href: undefined }, ]); - expect(window.document.title).toMatchInlineSnapshot( - `"my-transaction-name | Transactions | opbeans-node | Services | APM"` - ); + expect(changeTitle).toHaveBeenCalledWith([ + 'my-transaction-name', + 'Transactions', + 'opbeans-node', + 'Services', + 'APM', + ]); }); }); diff --git a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx index 7a27eae6e89f7..e7657c63f41bb 100644 --- a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx @@ -22,10 +22,7 @@ interface Props { } function getTitleFromBreadCrumbs(breadcrumbs: Breadcrumb[]) { - return breadcrumbs - .map(({ value }) => value) - .reverse() - .join(' | '); + return breadcrumbs.map(({ value }) => value).reverse(); } class UpdateBreadcrumbsComponent extends React.Component { @@ -43,7 +40,9 @@ class UpdateBreadcrumbsComponent extends React.Component { } ); - document.title = getTitleFromBreadCrumbs(this.props.breadcrumbs); + this.props.core.chrome.docTitle.change( + getTitleFromBreadCrumbs(this.props.breadcrumbs) + ); this.props.core.chrome.setBreadcrumbs(breadcrumbs); } diff --git a/x-pack/plugins/observability/public/application/application.test.tsx b/x-pack/plugins/observability/public/application/application.test.tsx new file mode 100644 index 0000000000000..db7fca140be89 --- /dev/null +++ b/x-pack/plugins/observability/public/application/application.test.tsx @@ -0,0 +1,29 @@ +/* + * 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 { renderApp } from './'; +import { Observable } from 'rxjs'; +import { CoreStart, AppMountParameters } from 'src/core/public'; + +describe('renderApp', () => { + it('renders', () => { + const core = ({ + application: { currentAppId$: new Observable(), navigateToUrl: () => {} }, + chrome: { docTitle: { change: () => {} }, setBreadcrumbs: () => {} }, + i18n: { Context: ({ children }: { children: React.ReactNode }) => children }, + uiSettings: { get: () => false }, + } as unknown) as CoreStart; + const params = ({ + element: window.document.createElement('div'), + } as unknown) as AppMountParameters; + + expect(() => { + const unmount = renderApp(core, params); + unmount(); + }).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx index b0134ed8b746b..4c0147dc3cd51 100644 --- a/x-pack/plugins/observability/public/application/index.tsx +++ b/x-pack/plugins/observability/public/application/index.tsx @@ -23,10 +23,7 @@ const observabilityLabelBreadcrumb = { }; function getTitleFromBreadCrumbs(breadcrumbs: Breadcrumbs) { - return breadcrumbs - .map(({ text }) => text) - .reverse() - .join(' | '); + return breadcrumbs.map(({ text }) => text).reverse(); } function App() { @@ -42,7 +39,7 @@ function App() { const breadcrumb = [observabilityLabelBreadcrumb, ...route.breadcrumb]; useEffect(() => { core.chrome.setBreadcrumbs(breadcrumb); - document.title = getTitleFromBreadCrumbs(breadcrumb); + core.chrome.docTitle.change(getTitleFromBreadCrumbs(breadcrumb)); }, [core, breadcrumb]); const { query, path: pathParams } = useRouteParams(route.params);