diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md
index 9a3fa1a1bb48a..f22e70b0e7bee 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md
@@ -44,7 +44,6 @@ import { MyPluginDepsStart } from './plugin';
export renderApp = ({ element, history }: AppMountParameters) => {
ReactDOM.render(
- // pass `appBasePath` to `basename`
,
diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.onappleave.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.onappleave.md
index 283ae34f14c54..6c5b89ffda05b 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountparameters.onappleave.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.onappleave.md
@@ -26,7 +26,7 @@ import { BrowserRouter, Route } from 'react-router-dom';
import { CoreStart, AppMountParams } from 'src/core/public';
import { MyPluginDepsStart } from './plugin';
-export renderApp = ({ appBasePath, element, onAppLeave }: AppMountParams) => {
+export renderApp = ({ element, history, onAppLeave }: AppMountParams) => {
const { renderApp, hasUnsavedChanges } = await import('./application');
onAppLeave(actions => {
if(hasUnsavedChanges()) {
@@ -34,7 +34,7 @@ export renderApp = ({ appBasePath, element, onAppLeave }: AppMountParams) => {
}
return actions.default();
});
- return renderApp(params);
+ return renderApp({ element, history });
}
```
diff --git a/src/core/CONVENTIONS.md b/src/core/CONVENTIONS.md
index 2769079757bc3..0f592d108c561 100644
--- a/src/core/CONVENTIONS.md
+++ b/src/core/CONVENTIONS.md
@@ -148,8 +148,8 @@ import { MyAppRoot } from './components/app.ts';
/**
* This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle.
*/
-export const renderApp = (core: CoreStart, deps: MyPluginDepsStart, { element, appBasePath }: AppMountParams) => {
- ReactDOM.render(, element);
+export const renderApp = (core: CoreStart, deps: MyPluginDepsStart, { element, history }: AppMountParams) => {
+ ReactDOM.render(, element);
return () => ReactDOM.unmountComponentAtNode(element);
}
```
diff --git a/src/core/TESTING.md b/src/core/TESTING.md
index aac54a4a14680..5a86e7da522d8 100644
--- a/src/core/TESTING.md
+++ b/src/core/TESTING.md
@@ -454,7 +454,7 @@ describe('Plugin', () => {
const [coreStartMock, startDepsMock] = await coreSetup.getStartServices();
const unmountMock = jest.fn();
renderAppMock.mockReturnValue(unmountMock);
- const params = { element: document.createElement('div'), appBasePath: '/fake/base/path' };
+ const params = coreMock.createAppMountParamters('/fake/base/path');
new Plugin(coreMock.createPluginInitializerContext()).setup(coreSetup);
// Grab registered mount function
@@ -479,7 +479,7 @@ import ReactDOM from 'react-dom';
import { AppMountParams, CoreStart } from 'src/core/public';
import { AppRoot } from './components/app_root';
-export const renderApp = ({ element, appBasePath }: AppMountParams, core: CoreStart, plugins: MyPluginDepsStart) => {
+export const renderApp = ({ element, history }: AppMountParams, core: CoreStart, plugins: MyPluginDepsStart) => {
// Hide the chrome while this app is mounted for a full screen experience
core.chrome.setIsVisible(false);
@@ -492,7 +492,7 @@ export const renderApp = ({ element, appBasePath }: AppMountParams, core: CoreSt
// Render app
ReactDOM.render(
- ,
+ ,
element
);
@@ -513,12 +513,14 @@ In testing `renderApp` you should be verifying that:
```typescript
/** public/application.test.ts */
+import { createMemoryHistory } from 'history';
+import { ScopedHistory } from 'src/core/public';
import { coreMock } from 'src/core/public/mocks';
import { renderApp } from './application';
describe('renderApp', () => {
it('mounts and unmounts UI', () => {
- const params = { element: document.createElement('div'), appBasePath: '/fake/base/path' };
+ const params = coreMock.createAppMountParamters('/fake/base/path');
const core = coreMock.createStart();
// Verify some expected DOM element is rendered into the element
@@ -530,7 +532,7 @@ describe('renderApp', () => {
});
it('unsubscribes from uiSettings', () => {
- const params = { element: document.createElement('div'), appBasePath: '/fake/base/path' };
+ const params = coreMock.createAppMountParamters('/fake/base/path');
const core = coreMock.createStart();
// Create a fake Subject you can use to monitor observers
const settings$ = new Subject();
@@ -545,7 +547,7 @@ describe('renderApp', () => {
});
it('resets chrome visibility', () => {
- const params = { element: document.createElement('div'), appBasePath: '/fake/base/path' };
+ const params = coreMock.createAppMountParamters('/fake/base/path');
const core = coreMock.createStart();
// Verify stateful Core API was called on mount
diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts
index facb818c60ff9..318afb652999e 100644
--- a/src/core/public/application/types.ts
+++ b/src/core/public/application/types.ts
@@ -347,7 +347,6 @@ export interface AppMountParameters {
*
* export renderApp = ({ element, history }: AppMountParameters) => {
* ReactDOM.render(
- * // pass `appBasePath` to `basename`
*
*
* ,
@@ -429,7 +428,7 @@ export interface AppMountParameters {
* import { CoreStart, AppMountParams } from 'src/core/public';
* import { MyPluginDepsStart } from './plugin';
*
- * export renderApp = ({ appBasePath, element, onAppLeave }: AppMountParams) => {
+ * export renderApp = ({ element, history, onAppLeave }: AppMountParams) => {
* const { renderApp, hasUnsavedChanges } = await import('./application');
* onAppLeave(actions => {
* if(hasUnsavedChanges()) {
@@ -437,7 +436,7 @@ export interface AppMountParameters {
* }
* return actions.default();
* });
- * return renderApp(params);
+ * return renderApp({ element, history });
* }
* ```
*/
diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts
index 8ea672890ca29..c860e9de8334e 100644
--- a/src/core/public/mocks.ts
+++ b/src/core/public/mocks.ts
@@ -16,9 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { createMemoryHistory } from 'history';
+
+// Only import types from '.' to avoid triggering default Jest mocks.
+import { CoreContext, PluginInitializerContext, AppMountParameters } from '.';
+// Import values from their individual modules instead.
+import { ScopedHistory } from './application';
+
import { applicationServiceMock } from './application/application_service.mock';
import { chromeServiceMock } from './chrome/chrome_service.mock';
-import { CoreContext, PluginInitializerContext } from '.';
import { docLinksServiceMock } from './doc_links/doc_links_service.mock';
import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
import { httpServiceMock } from './http/http_service.mock';
@@ -139,10 +145,27 @@ function createStorageMock() {
return storageMock;
}
+function createAppMountParametersMock(appBasePath = '') {
+ // Assemble an in-memory history mock using the provided basePath
+ const rawHistory = createMemoryHistory();
+ rawHistory.push(appBasePath);
+ const history = new ScopedHistory(rawHistory, appBasePath);
+
+ const params: jest.Mocked = {
+ appBasePath,
+ element: document.createElement('div'),
+ history,
+ onAppLeave: jest.fn(),
+ };
+
+ return params;
+}
+
export const coreMock = {
createCoreContext,
createSetup: createCoreSetupMock,
createStart: createCoreStartMock,
createPluginInitializerContext: pluginInitializerContextMock,
createStorage: createStorageMock,
+ createAppMountParamters: createAppMountParametersMock,
};