Skip to content

Commit

Permalink
Merge branch 'master' into flaky-test-custom-retry
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Sep 9, 2021
2 parents d0b1f0c + c1697a1 commit a0de601
Show file tree
Hide file tree
Showing 228 changed files with 1,772 additions and 821 deletions.
24 changes: 24 additions & 0 deletions dev_docs/key_concepts/anatomy_of_a_plugin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ plugins/
plugin.ts
common
index.ts
jest.config.js
```

### kibana.json
Expand Down Expand Up @@ -209,6 +210,29 @@ considerations related to how plugins integrate with core APIs and APIs exposed

`common/index.ts` is the entry-point into code that can be used both server-side or client side.

### jest.config.js

If you are adding unit tests (which we recommend), you will need to add a `jest.config.js` file. Here is an example file that you would use if adding a plugin into the `examples` directory.

```js
module.exports = {
// Default Jest settings, defined in kbn-test package
preset: '@kbn/test',
// The root of the directory containing package.json
rootDir: '../../..',
// The directory which Jest should use to search for files in
roots: ['<rootDir>/src/plugins/demo'],
// The directory where Jest should output plugin coverage details, e.g. html report
coverageDirectory: '<rootDir>/target/kibana-coverage/jest/src/plugins/demo',
// A list of reporter names that Jest uses when writing coverage reports, default: ["json"]
// "text" is available in console and is good for quick check
// "html" helps to dig into specific files and fix coverage
coverageReporters: ['text', 'html'],
// An array of regexp pattern strings that matched files to include/exclude for code coverage
collectCoverageFrom: ['<rootDir>/src/plugins/demo/{common,public,server}/**/*.{ts,tsx}'],
};
```

## How plugin's interact with each other, and Core

The lifecycle-specific contracts exposed by core services are always passed as the first argument to the equivalent lifecycle function in a plugin.
Expand Down
11 changes: 11 additions & 0 deletions dev_docs/tutorials/testing_plugins.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,17 @@ describe('Case migrations v7.7.0 -> v7.8.0', () => {
});
```
You can generate code coverage report for a single plugin.
```bash
yarn jest --coverage --config src/plugins/console/jest.config.js
```
Html report should be available in `target/kibana-coverage/jest/src/plugins/console` path
We run code coverage daily on CI and ["Kibana Stats cluster"](https://kibana-stats.elastic.dev/s/code-coverage/app/home)
can be used to view statistics. The report combines code coverage for all jest tests within Kibana repository.
#### Integration testing
With more complicated migrations, the behavior of the migration may be dependent on values from other plugins which may
be difficult or even impossible to test with unit tests. You need to actually bootstrap Kibana, load the plugins, and
Expand Down
8 changes: 8 additions & 0 deletions docs/developer/contributing/development-tests.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ kibana/src/plugins/dashboard/server$ yarn test:jest --coverage
yarn jest --coverage --verbose --config /home/tyler/elastic/kibana/src/plugins/dashboard/jest.config.js server
----

You can generate code coverage report for a single plugin.

[source,bash]
----
yarn jest --coverage --config src/plugins/console/jest.config.js
----

Html report is available in target/kibana-coverage/jest/path/to/plugin

[discrete]
=== Running browser automation tests
Expand Down
30 changes: 18 additions & 12 deletions packages/kbn-typed-react-router-config/src/create_router.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ describe('createRouter', () => {
}),
},
{
path: '/services/:serviceName',
path: '/services',
element: <></>,
params: t.type({
path: t.type({
serviceName: t.string,
}),
query: t.type({
transactionType: t.string,
environment: t.string,
}),
}),
children: [
{
element: <></>,
path: '/services/{serviceName}',
params: t.type({
path: t.type({
serviceName: t.string,
}),
query: t.type({
transactionType: t.string,
environment: t.string,
}),
}),
},
],
},
{
path: '/traces',
Expand Down Expand Up @@ -131,7 +137,7 @@ describe('createRouter', () => {
'/services/opbeans-java?rangeFrom=now-15m&rangeTo=now&environment=production&transactionType=request'
);

const serviceOverviewParams = router.getParams('/services/:serviceName', history.location);
const serviceOverviewParams = router.getParams('/services/{serviceName}', history.location);

expect(serviceOverviewParams).toEqual({
path: {
Expand Down Expand Up @@ -250,7 +256,7 @@ describe('createRouter', () => {

describe('link', () => {
it('returns a link for the given route', () => {
const serviceOverviewLink = router.link('/services/:serviceName', {
const serviceOverviewLink = router.link('/services/{serviceName}', {
path: { serviceName: 'opbeans-java' },
query: {
rangeFrom: 'now-15m',
Expand Down
23 changes: 13 additions & 10 deletions packages/kbn-typed-react-router-config/src/create_router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,24 @@ import { Route, Router } from './types';
const deepExactRt: typeof deepExactRtTyped = deepExactRtNonTyped;
const mergeRt: typeof mergeRtTyped = mergeRtNonTyped;

function toReactRouterPath(path: string) {
return path.replace(/(?:{([^\/]+)})/, ':$1');
}

export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<TRoutes> {
const routesByReactRouterConfig = new Map<ReactRouterConfig, Route>();
const reactRouterConfigsByRoute = new Map<Route, ReactRouterConfig>();

const reactRouterConfigs = routes.map((route) => toReactRouterConfigRoute(route));

function toReactRouterConfigRoute(route: Route, prefix: string = ''): ReactRouterConfig {
const path = `${prefix}${route.path}`.replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
function toReactRouterConfigRoute(route: Route): ReactRouterConfig {
const reactRouterConfig: ReactRouterConfig = {
component: () => route.element,
routes:
(route.children as Route[] | undefined)?.map((child) =>
toReactRouterConfigRoute(child, path)
) ?? [],
(route.children as Route[] | undefined)?.map((child) => toReactRouterConfigRoute(child)) ??
[],
exact: !route.children?.length,
path,
path: toReactRouterPath(route.path),
};

routesByReactRouterConfig.set(reactRouterConfig, route);
Expand Down Expand Up @@ -71,11 +73,11 @@ export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<T

for (const path of paths) {
const greedy = path.endsWith('/*') || args.length === 0;
matches = matchRoutesConfig(reactRouterConfigs, location.pathname);
matches = matchRoutesConfig(reactRouterConfigs, toReactRouterPath(location.pathname));

matchIndex = greedy
? matches.length - 1
: findLastIndex(matches, (match) => match.route.path === path);
: findLastIndex(matches, (match) => match.route.path === toReactRouterPath(path));

if (matchIndex !== -1) {
break;
Expand Down Expand Up @@ -135,11 +137,12 @@ export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<T
path = path
.split('/')
.map((part) => {
return part.startsWith(':') ? paramsWithBuiltInDefaults.path[part.split(':')[1]] : part;
const match = part.match(/(?:{([a-zA-Z]+)})/);
return match ? paramsWithBuiltInDefaults.path[match[1]] : part;
})
.join('/');

const matches = matchRoutesConfig(reactRouterConfigs, path);
const matches = matchRoutesConfig(reactRouterConfigs, toReactRouterPath(path));

if (!matches.length) {
throw new Error(`No matching route found for ${path}`);
Expand Down
Loading

0 comments on commit a0de601

Please sign in to comment.