-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* [Canvas] Storybook for testing and development (#29072) This PR adds [Storybook](https://storybook.js.org/) to our testing and development suite.  This will allow us to: 1. create a site outlining all components within Canvas, including their TS type information; 2. demonstrate usage of all components by example; 3. allow for individual component testing, both manually and by Jest; 4. iterate and fix bugs on individual components *without* having to start up Kibana, in a [HMR](https://webpack.js.org/concepts/hot-module-replacement/) environment; 5. automatically generate [snapshots](https://jestjs.io/docs/en/snapshot-testing) based on any examples written; This PR also converts a few components to Typescript and adds examples. I was inspired to add this when I was fixing #25342. In order to fix my changes, I had to run elasticsearch and kibana, as well as refresh my page whenever I needed to test a change. Had I had a Storybook instance, I would have been done much faster. In this PR, you'll see I converted `AdvancedFilter` from `renderers` and `FontPicker` and `ImageUpload` from `public/components`. Would you believe I discovered and fixed bugs just by converting to Typescript and writing examples? - `onChange` and `commit` are not marked as required in `propTypes`, but the component will error out if they're not supplied. - `commit` was actually being called twice when 'Apply' was clicked. This was shown in the 'Actions' panel when I was testing it. - The `fonts` collection was not strongly-typed, therefore any string could be passed to the `value` parameter without error. - While the code allows for any font string to be given to the component, there is no way to currently select that value, nor type it in within the control. This is likely a bug in design. - The `aria-labeledby` attribute in the drop down includes `undefined`. This is likely a bug in EUI:  - `cd x-pack/plugins/canvas/` - Run `node scripts/storybook` to start up a local development version, with HMR. - Run `node scripts/storybook_build` to build a complete static version of the book. - Run `node scripts/jest` which will run the Storyshots test; run `node scripts/jest --updateSnapshot` if source code has changed as expected. - Adding Jest coverage and output to the info panels, ([this](https://www.npmjs.com/package/@storybook/addon-jest) is *sick* functionality). - Adding automatic [a11y testing](https://www.npmjs.com/package/@storybook/addon-a11y), (currently [blocked](storybookjs/storybook#4889)). - Adding generic knobs for stories - Adding more example info, (e.g. who edited last, descriptions, etc). * Update based on errors in CI * Fix mismerge of dependencies * Fix yarn.lock as well
- Loading branch information
1 parent
d577e6f
commit aecaffc
Showing
24 changed files
with
4,183 additions
and
2,361 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"env": { | ||
"test": { | ||
"plugins": [ | ||
"require-context-hook" | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* 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 { configure, addDecorator } from '@storybook/react'; | ||
import { withKnobs } from '@storybook/addon-knobs/react'; | ||
import { withInfo } from '@storybook/addon-info'; | ||
import { withOptions } from '@storybook/addon-options'; | ||
|
||
// Import dependent CSS | ||
require('@elastic/eui/dist/eui_theme_light.css'); | ||
require('@kbn/ui-framework/dist/kui_light.css'); | ||
require('../../../../src/legacy/ui/public/styles/bootstrap_light.less'); | ||
|
||
// If we're running Storyshots, be sure to register the require context hook. | ||
// Otherwise, add the other decorators. | ||
if (process.env.NODE_ENV === 'test') { | ||
require('babel-plugin-require-context-hook/register')(); | ||
} else { | ||
// Customize the info for each story. | ||
addDecorator( | ||
withInfo({ | ||
inline: true, | ||
styles: { | ||
infoBody: { | ||
margin: 20 | ||
}, | ||
infoStory: { | ||
margin: '40px 60px' | ||
} | ||
} | ||
}) | ||
); | ||
|
||
// Add optional knobs to customize each story. | ||
addDecorator(withKnobs); | ||
} | ||
|
||
function loadStories() { | ||
// Pull in the built CSS produced by the Kibana server | ||
const css = require.context('../../../../built_assets/css', true, /light.css$/); | ||
css.keys().forEach(filename => css(filename)); | ||
|
||
// Include the legacy styles | ||
const uiStyles = require.context('../../../../src/legacy/ui/public/styles', false, /[\/\\](?!mixins|variables|_|\.|bootstrap_(light|dark))[^\/\\]+\.less/); | ||
uiStyles.keys().forEach(key => uiStyles(key)); | ||
|
||
// Find all files ending in *.examples.ts | ||
const req = require.context('./..', true, /.examples.tsx$/); | ||
req.keys().forEach(filename => req(filename)); | ||
} | ||
|
||
// Set up the Storybook environment with custom settings. | ||
addDecorator( | ||
withOptions({ | ||
goFullScreen: false, | ||
name: 'Canvas Storybook', | ||
showAddonsPanel: true, | ||
url: 'https://github.com/elastic/kibana/tree/master/x-pack/plugins/canvas' | ||
}) | ||
); | ||
|
||
configure(loadStories, module); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
const serve = require('serve-static'); | ||
const path = require('path'); | ||
|
||
// Extend the Storybook Middleware to include a route to access ui assets | ||
module.exports = function (router) { | ||
router.get('/ui', serve(path.resolve(__dirname, '../../../../src/legacy/ui/public/assets'))); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* | ||
* 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 path from 'path'; | ||
import initStoryshots, { multiSnapshotWithOptions } from '@storybook/addon-storyshots'; | ||
import styleSheetSerializer from 'jest-styled-components/src/styleSheetSerializer'; | ||
import { addSerializer } from 'jest-specific-snapshot' | ||
|
||
jest.mock(`@elastic/eui/lib/components/form/form_row/make_id`, () => () => `generated-id`); | ||
|
||
addSerializer(styleSheetSerializer); | ||
initStoryshots({ | ||
configPath: path.resolve(__dirname, './../.storybook'), | ||
test: multiSnapshotWithOptions({}), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
const path = require('path'); | ||
const TSDocgenPlugin = require('react-docgen-typescript-webpack-plugin'); | ||
|
||
// Extend the Storybook Webpack config with some customizations; | ||
module.exports = (_baseConfig, _env, config) => { | ||
// Include the React preset for Storybook JS files. | ||
config.module.rules.push({ | ||
test: /\.js$/, | ||
include: /\.storybook/, | ||
loaders: 'babel-loader', | ||
options: { | ||
presets: [require.resolve('@kbn/babel-preset/webpack_preset')], | ||
}, | ||
}); | ||
|
||
// Find and alter the CSS rule to replace the Kibana public path string with a path | ||
// to the route we've added in middleware.js | ||
const cssRule = config.module.rules.find(rule => rule.test.source.includes('.css$')); | ||
cssRule.use.push({ | ||
loader: 'string-replace-loader', | ||
options: { | ||
search: '__REPLACE_WITH_PUBLIC_PATH__', | ||
replace: '/', | ||
flags: 'g', | ||
}, | ||
}); | ||
|
||
// Configure loading LESS files from Kibana | ||
config.module.rules.push({ | ||
test: /\.less$/, | ||
use: [ | ||
{ loader: 'style-loader' }, | ||
{ loader: 'css-loader', options: { importLoaders: 2 } }, | ||
{ | ||
loader: 'postcss-loader', | ||
options: { | ||
config: { path: path.resolve(__dirname, './../../../../src/optimize/postcss.config.js') }, | ||
}, | ||
}, | ||
{ loader: 'less-loader' }, | ||
], | ||
}); | ||
|
||
// Support .ts/x files using the tsconfig from Kibana | ||
config.module.rules.push({ | ||
test: /\.tsx?$/, | ||
use: [ | ||
{ | ||
loader: 'babel-loader', | ||
options: { | ||
presets: [require.resolve('@kbn/babel-preset/webpack_preset')], | ||
}, | ||
}, | ||
require.resolve('react-docgen-typescript-loader'), | ||
], | ||
}); | ||
|
||
// Include the TSDocgen plugin to display Typescript param comments in the stories. | ||
config.plugins.push(new TSDocgenPlugin()); | ||
|
||
// Tell Webpack about the ts/x extensions | ||
config.resolve.extensions.push('.ts', '.tsx'); | ||
|
||
// Alias the any imports from ui/ to the proper directory. | ||
config.resolve.alias.ui = path.resolve(__dirname, './../../../../src/legacy/ui/public'); | ||
|
||
return config; | ||
}; |
67 changes: 67 additions & 0 deletions
67
..._src/renderers/advanced_filter/component/__snapshots__/advanced_filter.examples.storyshot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Storyshots renderers/AdvancedFilter default 1`] = ` | ||
<form | ||
className="canvasAdvancedFilter" | ||
onSubmit={[Function]} | ||
> | ||
<div | ||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--directionRow euiFlexGroup--responsive" | ||
> | ||
<div | ||
className="euiFlexItem" | ||
> | ||
<input | ||
className="canvasAdvancedFilter__input" | ||
onChange={[Function]} | ||
placeholder="Enter filter expression" | ||
type="text" | ||
value="" | ||
/> | ||
</div> | ||
<div | ||
className="euiFlexItem euiFlexItem--flexGrowZero" | ||
> | ||
<button | ||
className="canvasAdvancedFilter__button" | ||
type="submit" | ||
> | ||
Apply | ||
</button> | ||
</div> | ||
</div> | ||
</form> | ||
`; | ||
|
||
exports[`Storyshots renderers/AdvancedFilter with value 1`] = ` | ||
<form | ||
className="canvasAdvancedFilter" | ||
onSubmit={[Function]} | ||
> | ||
<div | ||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--directionRow euiFlexGroup--responsive" | ||
> | ||
<div | ||
className="euiFlexItem" | ||
> | ||
<input | ||
className="canvasAdvancedFilter__input" | ||
onChange={[Function]} | ||
placeholder="Enter filter expression" | ||
type="text" | ||
value="expression" | ||
/> | ||
</div> | ||
<div | ||
className="euiFlexItem euiFlexItem--flexGrowZero" | ||
> | ||
<button | ||
className="canvasAdvancedFilter__button" | ||
type="submit" | ||
> | ||
Apply | ||
</button> | ||
</div> | ||
</div> | ||
</form> | ||
`; |
16 changes: 16 additions & 0 deletions
16
...canvas/canvas_plugin_src/renderers/advanced_filter/component/advanced_filter.examples.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* 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 { action } from '@storybook/addon-actions'; | ||
import { storiesOf } from '@storybook/react'; | ||
import React from 'react'; | ||
import { AdvancedFilter } from './advanced_filter'; | ||
|
||
storiesOf('renderers/AdvancedFilter', module) | ||
.add('default', () => <AdvancedFilter onChange={action('onChange')} commit={action('commit')} />) | ||
.add('with value', () => ( | ||
<AdvancedFilter onChange={action('onChange')} commit={action('commit')} value="expression" /> | ||
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.