Skip to content

Commit

Permalink
[7.x] [Plugin Generator] Add integration test (#43219) (#45044)
Browse files Browse the repository at this point in the history
* [Plugin Generator] Add integration test (#43219)

Addresses #17061

### Features Covered 
 - generating a plugin

#### Then from within the generated plugin's directory
 - running `yarn build`
 - running `yarn test:browser`
 - running `yarn test:server`
 - running `yarn start`
 - running `yarn preinstall`
 - running `yarn lint`
 - running `yarn kbn --help`
 - running `yarn es --help`

* Fixup parse error for intl file
  • Loading branch information
wayneseymour authored Sep 11, 2019
1 parent fd88942 commit 86a1f7b
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const { resolve } = require('path');

const { debug } = require('./debug');

const DEFAULT_PLUGIN_PATH = '../../kibana';
const DEFAULT_PLUGIN_PATH = '../..';

/*
* Resolves the path to Kibana, either from default setting or config
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* 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.
*/

/* eslint-disable no-restricted-syntax */
import { spawn } from 'child_process';
import { resolve } from 'path';
import util from 'util';
import { stat } from 'fs';
import { snakeCase } from 'lodash';
import del from 'del';
import { withProcRunner, ToolingLog } from '@kbn/dev-utils';
import { createEsTestCluster } from '@kbn/test';
import execa from 'execa';

const statP = util.promisify(stat);
const ROOT_DIR = resolve(__dirname, '../../../');
const oneMinute = 60000;

describe(`running the plugin-generator via 'node scripts/generate_plugin.js plugin-name' with default config`, () => {
const pluginName = 'ispec-plugin';
const snakeCased = snakeCase(pluginName);
const generatedPath = resolve(ROOT_DIR, `plugins/${snakeCased}`);
const collect = xs => data => xs.push(data + ''); // Coerce from Buffer to String

beforeAll(() => {
jest.setTimeout(oneMinute * 10);
});

beforeAll(done => {
const create = spawn(process.execPath, ['scripts/generate_plugin.js', pluginName], {
cwd: ROOT_DIR,
});
create.stdout.on('data', function selectDefaults() {
create.stdin.write('\n'); // Generate a plugin with default options.
});
create.on('close', done);
});

afterAll(() => {
del.sync(generatedPath, { force: true });
});

it(`should succeed on creating a plugin in a directory named 'plugins/${snakeCased}`, async () => {
const stats = await statP(generatedPath);
expect(stats.isDirectory()).toBe(true);
});

describe(`then running`, () => {
it(`'yarn test:browser' should exit 0`, async () => {
await execa('yarn', ['test:browser'], { cwd: generatedPath });
});

it(`'yarn test:server' should exit 0`, async () => {
await execa('yarn', ['test:server'], { cwd: generatedPath });
});

it(`'yarn build' should exit 0`, async () => {
await execa('yarn', ['build'], { cwd: generatedPath });
});

it(`'yarn start' should result in the spec plugin being initialized on kibana's stdout`, async () => {
const log = new ToolingLog();
const es = createEsTestCluster({ license: 'basic', log });
await es.start();
await withProcRunner(log, async proc => {
await proc.run('kibana', {
cmd: 'yarn',
args: ['start', '--optimize.enabled=false', '--logging.json=false'],
cwd: generatedPath,
wait: /ispec_plugin.+Status changed from uninitialized to green - Ready/,
});
await proc.stop('kibana');
});
await es.stop();
});

it(`'yarn preinstall' should exit 0`, async () => {
await execa('yarn', ['preinstall'], { cwd: generatedPath });
});

it(`'yarn lint' should exit 0`, async () => {
await execa('yarn', ['lint'], { cwd: generatedPath });
});

it(`'yarn kbn --help' should print out the kbn help msg`, done => {
const helpMsg = `
usage: kbn <command> [<args>]
By default commands are run for Kibana itself, all packages in the 'packages/'
folder and for all plugins in './plugins' and '../kibana-extra'.
Available commands:
bootstrap - Install dependencies and crosslink projects
clean - Remove the node_modules and target directories from all projects.
run - Run script defined in package.json in each package that contains that script.
watch - Runs \`kbn:watch\` script for every project.
Global options:
-e, --exclude Exclude specified project. Can be specified multiple times to exclude multiple projects, e.g. '-e kibana -e @kbn/pm'.
-i, --include Include only specified projects. If left unspecified, it defaults to including all projects.
--oss Do not include the x-pack when running command.
--skip-kibana-plugins Filter all plugins in ./plugins and ../kibana-extra when running command.
`;
const outData = [];
const kbnHelp = spawn('yarn', ['kbn', '--help'], { cwd: generatedPath });
kbnHelp.stdout.on('data', collect(outData));
kbnHelp.on('close', () => {
expect(outData.join('\n')).toContain(helpMsg);
done();
});
});

it(`'yarn es --help' should print out the es help msg`, done => {
const helpMsg = `
usage: es <command> [<args>]
Assists with running Elasticsearch for Kibana development
Available commands:
snapshot - Downloads and run from a nightly snapshot
source - Build and run from source
archive - Install and run from an Elasticsearch tar
build_snapshots - Build and collect ES snapshots
Global options:
--help
`;
const outData = [];
const kbnHelp = spawn('yarn', ['es', '--help'], { cwd: generatedPath });
kbnHelp.stdout.on('data', collect(outData));
kbnHelp.on('close', () => {
expect(outData.join('\n')).toContain(helpMsg);
done();
});
});
});
});
2 changes: 1 addition & 1 deletion packages/kbn-plugin-generator/sao_template/sao.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ module.exports = function({ name }) {
},
move: {
gitignore: '.gitignore',
eslintrc: '.eslintrc',
'eslintrc.js': '.eslintrc.js',
'package_template.json': 'package.json',
},
data: answers =>
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-plugin-generator/sao_template/sao.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,6 @@ describe('plugin generator sao integration', () => {
it('includes dotfiles', async () => {
const res = await sao.mockPrompt(template);
expect(res.files['.gitignore']).toBeTruthy();
expect(res.files['.eslintrc']).toBeTruthy();
expect(res.files['.eslintrc.js']).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"paths": {
"<%= camelCase(name) %>": "./"
}
},
"translations": [
"translations/zh-CN.json"
]
}

7 changes: 0 additions & 7 deletions packages/kbn-plugin-generator/sao_template/template/eslintrc

This file was deleted.

24 changes: 24 additions & 0 deletions packages/kbn-plugin-generator/sao_template/template/eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
root: true,
extends: ['@elastic/eslint-config-kibana', 'plugin:@elastic/eui/recommended'],
settings: {
'import/resolver': {
'@kbn/eslint-import-resolver-kibana': {
rootPackageName: '<%= snakeCase(name) %>',
},
},
},
overrides: [
{
files: ['**/public/**/*'],
settings: {
'import/resolver': {
'@kbn/eslint-import-resolver-kibana': {
forceNode: false,
rootPackageName: '<%= snakeCase(name) %>',
},
},
},
},
]
};
58 changes: 29 additions & 29 deletions packages/kbn-plugin-generator/sao_template/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,39 +43,39 @@ export default function (kibana) {

init(server, options) { // eslint-disable-line no-unused-vars
<%_ if (generateApp) { -%>
const xpackMainPlugin = server.plugins.xpack_main;
if (xpackMainPlugin) {
const featureId = '<%= snakeCase(name) %>';
const xpackMainPlugin = server.plugins.xpack_main;
if (xpackMainPlugin) {
const featureId = '<%= snakeCase(name) %>';

xpackMainPlugin.registerFeature({
id: featureId,
name: i18n.translate('<%= camelCase(name) %>.featureRegistry.featureName', {
defaultMessage: '<%= name %>',
}),
navLinkId: featureId,
icon: 'questionInCircle',
app: [featureId, 'kibana'],
catalogue: [],
privileges: {
all: {
api: [],
savedObject: {
all: [],
read: [],
},
ui: ['show'],
xpackMainPlugin.registerFeature({
id: featureId,
name: i18n.translate('<%= camelCase(name) %>.featureRegistry.featureName', {
defaultMessage: '<%= name %>',
}),
navLinkId: featureId,
icon: 'questionInCircle',
app: [featureId, 'kibana'],
catalogue: [],
privileges: {
all: {
api: [],
savedObject: {
all: [],
read: [],
},
read: {
api: [],
savedObject: {
all: [],
read: [],
},
ui: ['show'],
ui: ['show'],
},
read: {
api: [],
savedObject: {
all: [],
read: [],
},
ui: ['show'],
},
});
}
},
});
}
<%_ } -%>

<%_ if (generateApi) { -%>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { Main } from './main';
export { Main } from './main';
1 change: 1 addition & 0 deletions scripts/jest_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

var resolve = require('path').resolve;
process.argv.push('--config', resolve(__dirname, '../src/dev/jest/config.integration.js'));
process.argv.push('--runInBand');

require('../src/setup_node_env');
require('../src/dev/jest/cli');
4 changes: 2 additions & 2 deletions src/dev/jest/setup/after_env.integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
/* eslint-env jest */

/**
* Set the default timeout for the integration test suite to 30 seconds
* Set the default timeout for the integration test suite to 10 minutes
*/
jest.setTimeout(30 * 1000);
jest.setTimeout(10 * 60 * 1000);
12 changes: 5 additions & 7 deletions src/legacy/core_plugins/tests_bundle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,13 @@ export default (kibana) => {
}
} = kbnServer;

const testGlobs = [
'src/legacy/ui/public/**/*.js',
'!src/legacy/ui/public/flot-charts/**/*',
];
const testGlobs = [];

const testingPluginIds = config.get('tests_bundle.pluginId');

if (testingPluginIds) {
testGlobs.push('!src/legacy/ui/public/**/__tests__/**/*');
testingPluginIds.split(',').forEach((pluginId) => {
const plugin = plugins
.find(plugin => plugin.id === pluginId);
const plugin = plugins.find(plugin => plugin.id === pluginId);

if (!plugin) {
throw new Error('Invalid testingPluginId :: unknown plugin ' + pluginId);
Expand All @@ -78,6 +74,8 @@ export default (kibana) => {
testGlobs.push(`${plugin.publicDir}/**/__tests__/**/*.js`);
});
} else {
// add all since we are not just focused on specific plugins
testGlobs.push('src/legacy/ui/public/**/*.js', '!src/legacy/ui/public/flot-charts/**/*');
// add the modules from all of the apps
for (const app of uiApps) {
modules.add(app.getMainModuleId());
Expand Down

0 comments on commit 86a1f7b

Please sign in to comment.