Skip to content

Commit

Permalink
Add unit and functional tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdover committed Oct 2, 2019
1 parent 7aa1a8b commit 47e9126
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 15 deletions.
24 changes: 24 additions & 0 deletions src/legacy/ui/public/new_platform/new_platform.test.mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export const setRootControllerMock = jest.fn();

jest.doMock('ui/chrome', () => ({
setRootController: setRootControllerMock,
}));
83 changes: 83 additions & 0 deletions src/legacy/ui/public/new_platform/new_platform.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { setRootControllerMock } from './new_platform.test.mocks';
import { legacyAppRegister, __reset__ } from './new_platform';

describe('ui/new_platform', () => {
describe('legacyAppRegister', () => {
beforeEach(() => {
setRootControllerMock.mockReset();
__reset__();
});

const registerApp = () => {
const unmountMock = jest.fn();
const mountMock = jest.fn(() => unmountMock);
legacyAppRegister({
id: 'test',
title: 'Test',
mount: mountMock,
});
return { mountMock, unmountMock };
};

test('sets ui/chrome root controller', () => {
registerApp();
expect(setRootControllerMock).toHaveBeenCalledWith('test', expect.any(Function));
});

test('throws if called more than once', () => {
registerApp();
expect(registerApp).toThrowErrorMatchingInlineSnapshot(
`"core.application.register may only be called once for legacy plugins."`
);
});

test('controller calls app.mount when invoked', () => {
const { mountMock } = registerApp();
const controller = setRootControllerMock.mock.calls[0][1];
const scopeMock = { $on: jest.fn() };
const elementMock = [document.createElement('div')];

controller(scopeMock, elementMock);
expect(mountMock).toHaveBeenCalledWith(expect.any(Object), {
element: elementMock[0],
appBasePath: '',
});
});

test('controller calls unmount when $scope.$destroy', async () => {
const { unmountMock } = registerApp();
const controller = setRootControllerMock.mock.calls[0][1];
const scopeMock = { $on: jest.fn() };
const elementMock = [document.createElement('div')];

controller(scopeMock, elementMock);
// Flush promise queue. Must be done this way because the controller cannot return a Promise without breaking
// angular.
await new Promise(resolve => setTimeout(resolve, 1));

const [event, eventHandler] = scopeMock.$on.mock.calls[0];
expect(event).toEqual('$destroy');
eventHandler();
expect(unmountMock).toHaveBeenCalled();
});
});
});
41 changes: 28 additions & 13 deletions src/legacy/ui/public/new_platform/new_platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,44 @@ export function __reset__() {
npSetup.plugins = {} as any;
npStart.core = (null as unknown) as LegacyCoreStart;
npStart.plugins = {} as any;
legacyAppRegistered = false;
}

export function __setup__(coreSetup: LegacyCoreSetup, plugins: PluginsSetup) {
npSetup.core = coreSetup;
npSetup.plugins = plugins;

// Setup compatibility layer for AppService in legacy platform
npSetup.core.application.register = (app: App) => {
require('ui/chrome').setRootController(app.id, ($scope: IScope, $element: JQLite) => {
const element = $element[0];

// Root controller cannot return a Promise so use an internal async function and call it
(async () => {
const unmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
$scope.$on('$destroy', () => {
unmount();
});
})();
});
};
npSetup.core.application.register = legacyAppRegister;
}

export function __start__(coreStart: LegacyCoreStart, plugins: PluginsStart) {
npStart.core = coreStart;
npStart.plugins = plugins;
}

/** Flag used to ensure `legacyAppRegister` is only called once. */
let legacyAppRegistered = false;

/**
* Exported for testing only. Use `npSetup.core.application.register` in legacy apps.
* @internal
*/
export const legacyAppRegister = (app: App) => {
if (legacyAppRegistered) {
throw new Error(`core.application.register may only be called once for legacy plugins.`);
}
legacyAppRegistered = true;

require('ui/chrome').setRootController(app.id, ($scope: IScope, $element: JQLite) => {
const element = $element[0];

// Root controller cannot return a Promise so use an internal async function and call it immediately
(async () => {
const unmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
$scope.$on('$destroy', () => {
unmount();
});
})();
});
};
35 changes: 35 additions & 0 deletions test/plugin_functional/plugins/core_legacy_compat/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { Server } from 'hapi';

// eslint-disable-next-line import/no-default-export
export default function(kibana: any) {
return new kibana.Plugin({
uiExports: {
app: {
title: 'Core Legacy Compat',
description: 'This is a sample plugin to test core to legacy compatibility',
main: 'plugins/core_legacy_compat/index',
},
},

init(server: Server) {},
});
}
17 changes: 17 additions & 0 deletions test/plugin_functional/plugins/core_legacy_compat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "core_legacy_compat",
"version": "1.0.0",
"main": "target/test/plugin_functional/plugins/core_legacy_compat",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Apache-2.0",
"scripts": {
"kbn": "node ../../../../scripts/kbn.js",
"build": "rm -rf './target' && tsc"
},
"devDependencies": {
"typescript": "3.5.3"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import ReactDOM from 'react-dom';

import { AppMountContext, AppMountParameters } from 'kibana/public';

const App = () => <h1 data-test-subj="coreLegacyCompatH1">core_legacy_compat</h1>;

export const renderApp = (
context: AppMountContext,
{ appBasePath, element }: AppMountParameters
) => {
ReactDOM.render(<App />, element);

return () => ReactDOM.unmountComponentAtNode(element);
};
29 changes: 29 additions & 0 deletions test/plugin_functional/plugins/core_legacy_compat/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { npSetup } from 'ui/new_platform';

npSetup.core.application.register({
id: 'core_legacy_compat',
title: 'Core Legacy Compat',
async mount(...args) {
const { renderApp } = await import('./application');
return renderApp(...args);
},
});
14 changes: 14 additions & 0 deletions test/plugin_functional/plugins/core_legacy_compat/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"outDir": "./target",
"skipLibCheck": true
},
"include": [
"index.ts",
"public/**/*.ts",
"public/**/*.tsx",
"../../../../typings/**/*"
],
"exclude": []
}
4 changes: 2 additions & 2 deletions test/plugin_functional/test_suites/core_plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
export default function ({ loadTestFile }) {
describe('core plugins', () => {
loadTestFile(require.resolve('./applications'));
loadTestFile(require.resolve('./legacy_plugins'));
loadTestFile(require.resolve('./server_plugins'));
loadTestFile(require.resolve('./ui_plugins'));
loadTestFile(require.resolve('./server_plugins.js'));
loadTestFile(require.resolve('./legacy_plugins.js'));
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import expect from '@kbn/expect';
export default function ({ getService, getPageObjects }) {
const PageObjects = getPageObjects(['common']);
const browser = getService('browser');
const testSubjects = getService('testSubjects');

describe('legacy plugins', function describeIndexTests() {
it('have access to New Platform HTTP service', async () => {
Expand All @@ -31,5 +32,12 @@ export default function ({ getService, getPageObjects }) {
const pageSource = await browser.execute('return window.document.body.textContent;');
expect(pageSource).to.equal('Pong in legacy via new platform: true');
});

describe('application service compatibility layer', function describeIndexTests() {
it('can render legacy apps', async () => {
await PageObjects.common.navigateToApp('core_legacy_compat');
expect(await testSubjects.exists('coreLegacyCompatH1')).to.be(true);
});
});
});
}

0 comments on commit 47e9126

Please sign in to comment.