doc/development/fe_guide/storybook.md
The Storybook for the gitlab-org/gitlab project is available on our GitLab Pages site.
Storybook dependencies and configuration are located under the storybook/ directory.
To build and launch Storybook locally, in the root directory of the gitlab project:
Install Storybook dependencies:
yarn storybook:install
Build the Storybook site:
yarn storybook:start
Test Storybook entries:
yarn storybook:dev:test
Discover more details about automated accessibility tests with Accessibility Storybook tests.
Stories can be added for any Vue component in the gitlab repository.
To add a story:
Create a new .stories.js file in the same directory as the Vue component.
The filename should have the same prefix as the Vue component.
vue_shared/
├─ components/
│ ├─ sidebar
│ | ├─ todo_toggle
│ | | ├─ todo_button.vue
│ │ | ├─ todo_button.stories.js
Stories should demonstrate each significantly different UI state related to the component's exposed props and events.
For instructions on how to write stories, refer to the official Storybook instructions
[!note] Specify the
titlefield of the story as the component's file path from thejavascripts/directory, without the/componentspart. For example, if the component is located atapp/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.vue, specify the storytitleasvue_shared/sidebar/todo_toggle/todo_button. If the component is located in theee/directory, make sure to prefix the story's title withee/as well. This will ensure the Storybook navigation maps closely to our internal directory structure.
To write a story for a component that uses Apollo Client for GraphQL, use createMockApollo from helpers/mock_apollo_helper.
Pass it an array of [query, handlerFn] tuples — each handler receives the query variables and must return a Promise resolving to the expected response shape.
import createMockApollo from 'helpers/mock_apollo_helper';
import myQuery from './graphql/my_query.query.graphql';
import MyComponent from './my_component.vue';
const MOCK_DATA = [{ id: '1', name: 'Example' }];
export default {
component: MyComponent,
title: 'path/to/my_component',
};
const Template = (args, { argTypes }) => ({
components: { MyComponent },
apolloProvider: createMockApollo([
[
myQuery,
() =>
Promise.resolve({
data: {
currentUser: {
id: 'gid://gitlab/User/1',
items: { nodes: MOCK_DATA },
},
},
}),
],
]),
props: Object.keys(argTypes),
template: '<my-component v-bind="$props" />',
});
export const Default = Template.bind({});
Default.args = {};
Each story variant can pass a different handler to simulate distinct states such as loading, empty, or error:
export const Empty = (args, { argTypes }) => ({
components: { MyComponent },
apolloProvider: createMockApollo([
[myQuery, () => Promise.resolve({ data: { currentUser: { id: '1', items: { nodes: [] } } } })],
]),
props: Object.keys(argTypes),
template: '<my-component v-bind="$props" />',
});
export const LoadingState = (args, { argTypes }) => ({
components: { MyComponent },
apolloProvider: createMockApollo([[myQuery, () => new Promise(() => {})]]),
props: Object.keys(argTypes),
template: '<my-component v-bind="$props" />',
});
To write a story for a component that requires access to a Vuex store, use the createVuexStore method provided in
the Story context.
import { withVuexStore } from 'storybook_addons/vuex_store';
import DurationChart from './duration-chart.vue';
const Template = (_, { argTypes, createVuexStore }) => {
return {
components: { DurationChart },
store: createVuexStore({
state: {},
getters: {},
modules: {},
}),
props: Object.keys(argTypes),
template: '<duration-chart />',
};
};
export default {
component: DurationChart,
title: 'ee/analytics/cycle_analytics/components/duration_chart',
decorators: [withVuexStore],
};
export const Default = Template.bind({});
Default.args = {};