Motivation
I am such a huge fan of Storybook, and I have been using it for quite some time now. Since Storybook is purely based on React, I thought of this addon as the best way to appeal to more Angular developers. I really hope this will be a good addon to use alongside Storybook for Angular projects, maybe someday integrate these features into official Storybook libraries. I will be working on new features all the time. Your feedback is much appreciated.
Table of Contents
Getting started
- Install the addon:
yarn add @sheriffmoose/storybook-ngx -D
- Add the addon into your main.js
module.exports = {
...
"addons": [
"@sheriffmoose/storybook-ngx",
...
],
...
}
- Refer to the sections below for the documentation of the built-in features.
Demo
Find the published demo storybook on chromatic here
Features
- ⚡️ Zero config setup
- 📚 Supports latest Storybook Implementation
- 📔 Coverage Instrumentation for Test-Runner
- 🧪 Auto injector for Angular services
- 🦥 Lazy loading documentation
- 💬 Source code display
- 💻 Console Logs Panel
- 🌯 Toolbar setup for Story Wrappers
Test Runner Coverage Instrumentation
Credits to JS Devtools
for their amazing coverage istanbul loader
. This addon simply imports @jsdevtools/coverage-istanbul-loader
into webpack configuration to enable the coverage instrumentation.
Read more about the coverage instrumentation in the official Test Runner documentation here.
Simply running test-storybook --coverage
will show you test results coverage in the terminal and also will save the coverage results into coverage/storybook.
Angular Services Unit Testing
- This feature is for developers who want their testing to all run in the same place.
- Particulary this is helpful when you want to move business logic from components into services.
- But you still want to test it through Storybook.
- This feature does not require any setup. It relies on the official
@storybook/angular
implementation. - It simply injects the service into an
APP_INITIALIZER
which runs before the Angular
application starts. - When the initializer runs, it puts the service instance into
parameters.providers
which you can retrieve in the play function like so:
const meta: Meta = {
title: 'Services/AppService',
decorators: [
moduleMetadata({
imports: [AppModule, CommonModule],
providers: [AppService],
}),
]
};
export default meta;
export const Primary: StoryObj = {
play: async ({ parameters: { providers } }) => {
const appService: AppService = providers.AppService;
expect(appService).toBeTruthy();
},
};
Documentation Lazy Loading
- This feature uses
node-fetch
to load the documentation.json
file during runtime, specifically in the preview iframe before the load of each story. - This is very helpful if you are doing active development and your documentation is being updated regularly.
- This is also helpful if your application is already published along with its documentation and you need to load that remotely served documentation.
Here is a simple example of the first scenario:
module.exports = {
staticDirs: [{ from: '<DOCS_DIR_PATH>', to: '/<DOCS_SERVE_DIR>' }],
};
- Next, enable the documentation lazy loading in the
preview.js
file like so:
export const parameters = {
...
docs: {
inlineStories: true,
...
lazyLoad: true,
url: '<DOCS_SERVE_DIR>/documentation.json'
}
}
The url property here can be a full url like http://example.com/storybook/docs/documentation.json
or a relative path to the current storybook instance like ../dist/docs/documentation.json
.
You can also provide data
property to be something like require('<DOCS_DIR_PATH>/documentation.json')
, this way you don't need to call setCompodocJson
method, it will be called automatically on your behalf, and the docs will be stored in memory for later usage.
Source Code
Console Logs
- This feature uses the
Actions
panel from @storybook/addon-actions
to display the console output. - This is helpful if you need to focus on the console output of the application.
- To enable the feature use the parameters in
preview.js
like so:
export const parameters = {
console: {
disable: false,
patterns: [/^dev$/],
omitFirst: true,
},
};
Currently, the patterns property is used to match the first argument of the console
methods debug
, log
, info
, warn
& error
. This allows developers to use special context for their app logs. For example: console.log('dev', data);
will be matched using the /^dev$/
pattern, and will trigger an action that shows up in the Actions
panel. You can use the omitFirst
property to make sure the dev
item does not show, only other arguments will show up.
Wrappers Selector
- This feature uses
componentWrapperDecorator
from the official @storybook/angular
to render wrapper elements dynamically around stories. - This simply reads a list of pre-defined wrapper elements from the global parameters or each individual story parameters.
- This allows you to change the wrapper element during runtime instead of having static decorator all the time.
- This is very helpful specially if you want to see how your components render inside a root component with header and footer, or just simply inside a specific parent element.
Configuration
- This toolbar menu works very similar to the official
@storybook/addon-backgrounds
addon. - The configuration looks something like this:
In preview.js
or preview.ts
:
export const parameters = {
wrappers: {
disable: false,
default: 'None',
values: [
{ name: 'None', value: '' },
{ name: 'Container', value: 'app-container' },
{ name: 'Root', value: 'app-root' },
],
},
};
In a story file like button.stories.ts
:
import { type StoryObj, type Meta } from '@storybook/angular';
import Button from './button.component';
const meta: Meta<Button> = {
title: 'Example/Button',
component: Button,
parameters: {
wrappers: {
default: 'None',
values: [
{ name: 'None', value: '' },
{
name: 'Button Container',
value: 'btn-container',
options: {
class: 'small',
style: 'padding:5px;',
},
},
{ name: 'Container', value: 'app-container' },
{ name: 'Root', value: 'app-root' },
],
},
},
};
export default meta;
The wrapper item can also contain an options
property which will be translated into HTML attributes for the wrapper. For example; the configuration above will render the following if Button Container
is selected:
<btn-container class="small" style="padding:5px;"></btn-container>
Credits
- Thanks for
JS Devtools
for their amazing coverage istanbul loader
. - Thanks for
@storybook/addon-backgrounds
for the inspiration. - This would not have been possible without the official
@storybook/angular
framework. - Thanks for the team behind the official
Storybook Addon Kit
for the amazing work they put into this kit that was very helpful for generating this addon.
Roadmap
Please feel free to request features, I will try to add them as soon as humanly possible. Currently the following features are in my pipeline:
- Auto markdown documentation.
- UI representation of Angular Service.
- Swagger UI integration.