Set up MirajeJS in Storybook

Allow using MirajeJS to mock API requests
in Storybook. Improves the yarn storybook:start
command to prompt the user about generating
the fixtures needed by MirajeJS.
This commit is contained in:
Enrique Alcantara 2021-09-17 11:02:26 -04:00 committed by Enrique Alcántara
parent 5cc73aac19
commit 9800a90aea
13 changed files with 102 additions and 7 deletions

View file

@ -100,6 +100,7 @@ overrides:
- 'scripts/**/*'
- '*.config.js'
- '*.config.*.js'
- storybook/config/*.js
rules:
'@gitlab/require-i18n-strings': off
import/no-extraneous-dependencies: off

View file

@ -366,6 +366,11 @@ compile-storybook:
extends:
- .compile-storybook-base
- .frontend:rules:default-frontend-jobs
needs:
- job: "rspec frontend_fixture"
- job: "rspec-ee frontend_fixture"
optional: true
- job: "graphql-schema-dump"
artifacts:
name: storybook
expire_in: 31d
@ -378,3 +383,6 @@ compile-storybook as-if-foss:
- .compile-storybook-base
- .as-if-foss
- .frontend:rules:default-frontend-jobs-as-if-foss
needs:
- job: "graphql-schema-dump"
- job: "rspec frontend_fixture as-if-foss"

View file

@ -49,3 +49,9 @@ To add a story:
- Specify the `title` field of the story as the component's file path from the `javascripts/` directory,
e.g. if the component is located at `app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.vue`, specify the `title` as
`vue_shared/components/To-do Button`. This will ensure the Storybook navigation maps closely to our internal directory structure.
## Mock backend APIs
GitLabs Storybook uses [MirajeJS](https://miragejs.com/) to mock REST and GraphQL APIs. Storybook shares the MirajeJS server
with the [frontend integration tests](../testing_guide/testing_levels.md#frontend-integration-tests). You can find the MirajeJS
configuration files in `spec/frontend_integration/mock_server`.

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true
require 'yaml'
unless Rails.env.production?
namespace :frontend do
@ -13,12 +14,28 @@ unless Rails.env.production?
t.rspec_opts = '--format documentation'
end
desc 'GitLab | Frontend | Generate fixtures for JavaScript integration tests'
RSpec::Core::RakeTask.new(:mock_server_rspec_fixtures) do |t, args|
base_path = Pathname.new('spec/frontend_integration/fixture_generators.yml')
ee_path = Pathname.new('ee') + base_path
fixtures = YAML.safe_load(base_path.read)
fixtures.concat(Array(YAML.safe_load(ee_path.read))) if Gitlab.ee? && ee_path.exist?
t.pattern = fixtures.join(',')
ENV['NO_KNAPSACK'] = 'true'
t.rspec_opts = '--format documentation'
end
desc 'GitLab | Frontend | Run JavaScript tests'
task tests: ['yarn:check'] do
sh "yarn test" do |ok, res|
abort('rake frontend:tests failed') unless ok
end
end
desc 'GitLab | Frontend | Shortcut for generating all fixtures used by MirajeJS mock server'
task mock_server_fixtures: ['frontend:mock_server_rspec_fixtures', 'gitlab:graphql:schema:dump']
end
desc 'GitLab | Frontend | Shortcut for frontend:fixtures and frontend:tests'

View file

@ -40,7 +40,7 @@
"postinstall": "node ./scripts/frontend/postinstall.js",
"storybook:install": "yarn --cwd ./storybook install",
"storybook:build": "yarn --cwd ./storybook build",
"storybook:start": "yarn --cwd ./storybook start",
"storybook:start": "./scripts/frontend/start_storybook.sh",
"stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js",
"webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js",
"webpack-vendor": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.vendor.config.js",

View file

@ -0,0 +1,18 @@
#!/bin/bash
bold=$(tput bold)
normal=$(tput sgr0)
echo -e "Storybook provides a mock server that allows creating stories for components that make HTTP requests."
echo -e "${bold}Storybook will fail to start if it cant find the fixtures used by the mock server.${normal}\n"
read -rp "Would you like to generate/update the frontend fixtures used by the mock server (y/N)? " answer
if [[ "$answer" =~ ^(Y|y)$ ]] ; then
bundle exec rake frontend:mock_server_fixtures
fi
if ! [[ -d storybook/node_modules ]] ; then
yarn storybook:install
fi
yarn --cwd ./storybook start

View file

@ -0,0 +1,5 @@
- spec/frontend/fixtures/api_projects.rb
- spec/frontend/fixtures/api_merge_requests.rb
- spec/frontend/fixtures/projects_json.rb
- spec/frontend/fixtures/merge_requests_diffs.rb
- spec/frontend/fixtures/raw.rb

View file

@ -1,4 +1,3 @@
/* eslint-disable import/no-commonjs */
const IS_EE = require('../../config/helpers/is_ee_env');
module.exports = {
@ -6,5 +5,5 @@ module.exports = {
'../../app/assets/javascripts/**/*.stories.js',
IS_EE && '../../ee/app/assets/javascripts/**/*.stories.js',
].filter(Boolean),
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'],
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y', 'storybook-mirage'],
};

View file

@ -1,6 +1,7 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { withServer } from 'storybook-mirage'; // eslint-disable-line import/no-unresolved
import Vue from 'vue';
import translateMixin from '../../app/assets/javascripts/vue_shared/translate';
import { createMockServer } from 'test_helpers/mock_server';
import translateMixin from '~/vue_shared/translate';
const stylesheetsRequireCtx = require.context(
'../../app/assets/stylesheets',
@ -13,3 +14,5 @@ translateMixin(Vue);
stylesheetsRequireCtx('./application.scss');
stylesheetsRequireCtx('./application_utilities.scss');
export const decorators = [withServer(createMockServer)];

View file

@ -5,6 +5,7 @@ const path = require('path');
const sass = require('node-sass'); // eslint-disable-line import/no-unresolved
const { buildIncludePaths, resolveGlobUrl } = require('node-sass-magic-importer/dist/toolbox'); // eslint-disable-line import/no-unresolved
const webpack = require('webpack');
const IS_EE = require('../../config/helpers/is_ee_env');
const IS_JH = require('../../config/helpers/is_jh_env');
const gitlabWebpackConfig = require('../../config/webpack.config');
@ -98,13 +99,31 @@ module.exports = function storybookWebpackConfig({ config }) {
},
],
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
{
test: /\.(zip)$/,
loader: 'file-loader',
options: {
esModule: false,
},
},
];
// Silence webpack warnings about moment/pikaday not being able to resolve.
config.plugins.push(new webpack.IgnorePlugin(/moment/, /pikaday/));
const baseIntegrationTestHelpersPath = 'spec/frontend_integration/test_helpers';
// Add any missing aliases from the main GitLab webpack config
Object.assign(config.resolve.alias, gitlabWebpackConfig.resolve.alias);
Object.assign(config.resolve.alias, gitlabWebpackConfig.resolve.alias, {
test_helpers: path.resolve(ROOT, baseIntegrationTestHelpersPath),
ee_else_ce_test_helpers: path.resolve(ROOT, IS_EE ? 'ee' : '', baseIntegrationTestHelpersPath),
test_fixtures: path.resolve(ROOT, 'tmp/tests/frontend', IS_EE ? 'fixtures-ee' : 'fixtures'),
});
// The main GitLab project aliases this `icons.svg` file to app/assets/javascripts/lib/utils/icons_path.js,
// which depends on the existence of a global `gon` variable.
// By deleting the alias, imports of this path will resolve as expected.

View file

@ -14,9 +14,11 @@
"@storybook/addon-controls": "^6.2.9",
"@storybook/addon-essentials": "^6.2.9",
"@storybook/vue": "6.2.9",
"graphql-tag": "^2.12.5",
"node-sass": "^4.14.1",
"node-sass-magic-importer": "^5.3.2",
"postcss-loader": "3.0.0",
"sass-loader": "^7.1.0"
"sass-loader": "^7.1.0",
"storybook-mirage": "^0.0.4"
}
}

View file

@ -5388,6 +5388,13 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
graphql-tag@^2.12.5:
version "2.12.5"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f"
integrity sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ==
dependencies:
tslib "^2.1.0"
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
@ -9546,6 +9553,11 @@ store2@^2.12.0:
resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf"
integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==
storybook-mirage@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/storybook-mirage/-/storybook-mirage-0.0.4.tgz#572e5d310ad8f0dd963e5c341aa2402f8ed07749"
integrity sha512-oGjsxyxmedXQtsVW1DDwKM1RocAD5zClFeOFtAhK46NcGXLJ31m2WQg5kL7YqrsriorrCZq4vvSy05DVCD7BKQ==
stream-browserify@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
@ -10057,6 +10069,11 @@ tslib@^2.0.1, tslib@^2.0.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tslib@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"