Though unit testing is powerful for situations where you need to maintain functional parity over time, sometimes a visual testing approach can be even more fruitful for maintaining a high-quality Gatsby implementation. One tool that has become popular for visual inspection and testing of JavaScript components is Storybook, a development environment for UI components that allows developers to see their components across various states and understand what components they can leverage and what props they accept.
To install and configure Storybook, the quickest way to get started is to use the npx
command, which comes packaged with NPM. NPX, used to execute packages (as opposed to the NPM installer), is useful because it will scaffold a directory structure with default configuration already in place to maximize productivity. Execute the following command in the root of your project:
$
npx
-p
@storybook/cli
sb
init
WARNING
If you’re using a version of NPM older than 5.2.0, because NPX is a newer addition to NPM, you will need to run the following instead:
$
npm
install
-g
@storybook/cli
$
sb
init
Though Storybook will scaffold a fully constructed set of directories and files within them in the .storybook directory, Gatsby requires some adjustments to Storybook’s default configuration. If you open .storybook/main.js, you’ll find this configuration:
// .storybook/main.js
module
.
exports
=
{
stories
:
[
"../src/**/*.stories.mdx"
,
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
addons
:
[
"@storybook/addon-actions"
,
"@storybook/addon-links"
],
}
You’ll need to extend this Storybook configuration to embrace Gatsby’s own ES6 code that remains untranspiled, similarly to how we configured Jest to do so in “Testing Gatsby”. Change your Storybook configuration to the following, adding webpackFinal
after the lines in the previous example, as follows:
// .storybook/main.js
module
.
exports
=
{
stories
:
[
"../src/**/*.stories.mdx"
,
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
addons
:
[
"@storybook/addon-actions"
,
"@storybook/addon-links"
],
>>>
webpackFinal
:
async
config
=>
{
config
.
module
.
rules
[
0
].
exclude
=
[
/node_modules\/(?!(gatsby)\/)/
]
config
.
module
.
rules
[
0
].
use
[
0
].
loader
=
require
.
resolve
(
"babel-loader"
)
config
.
module
.
rules
[
0
].
use
[
0
].
options
.
presets
=
[
require
.
resolve
(
"@babel/preset-react"
),
require
.
resolve
(
"@babel/preset-env"
),
]
config
.
module
.
rules
[
0
].
use
[
0
].
options
.
plugins
=
[
require
.
resolve
(
"@babel/plugin-proposal-class-properties"
),
require
.
resolve
(
"babel-plugin-remove-graphql-queries"
),
]
config
.
resolve
.
mainFields
=
[
"browser"
,
"module"
,
"main"
]
return
config
},
}
These lines configure Webpack to handle the Gatsby module correctly and to ensure that Storybook uses Gatsby’s ES6 entry point (which prepopulates dependencies) rather than the default CommonJS entry point (which executes dependencies on demand). Now, you need to provide a configuration file that will add certain global parameters and Storybook decorators to ensure Storybook works with Gatsby. Replace the contents of the file named preview.js in the .storybook directory with the following code:
// .storybook/preview.js
import
{
action
}
from
"@storybook/addon-actions"
// This prevents Gatsby Link from triggering errors in Storybook.
global.___loader
=
{
enqueue:
()
=>
{},
hovering:
()
=>
{},
}
// This global variable prevents the "__BASE_PATH__ is not defined" error
// inside Storybook.
global.__BASE_PATH__
=
"/"
// Navigating through a Gatsby app using gatsby-link or any other
// gatsby component will use the `___navigate` method. In Storybook
// it makes more sense to log an action than doing an actual navigate.
// Check out the actions addon docs for more info:
window.___navigate
=
pathname
=>
{
action("NavigateTo:")(pathname)
}
export
const
parameters
=
{
actions:
{
argTypesRegex:
"^on[A-Z].*"
},
controls:
{
matchers:
{
color:
/(background|color)$/i,
date:
/Date$/,
},
},
}
With both of these configuration files in place, you can now write Storybook stories. Storybook will seek any files with a .stories.js extension and load them automatically in your Storybook interface for you. For Gatsby components, these stories can live alongside the components in the same directory. But for Gatsby pages, since Gatsby restricts what JavaScript files are permitted in the src/pages directory, you’ll need to create a __stories__ directory in the src directory.
A full walkthrough of Storybook is outside the scope of this book, but as an example adapted from the Gatsby documentation, here’s a Storybook story, which in Storybook parlance describes a rendered component that is displayed in the Storybook interface:
// src/components/bio.stories.js
import
React
from
"react"
export
default
{
title
:
"Bio"
,
}
export
const
bioStory
=
()
=>
(
<
div
style
=
{{
padding
:
"1rem"
,
backgroundColor
:
"#ccc"
}}>
<
h1
style
=
{{
color
:
"blue"
}}>
Hello
world
and
Storybook
!
</
h1
>
</
div
>
)
NOTE
For a comprehensive introduction to Storybook, consult the Storybook documentation and Mathspy’s Gatsby starter containing both Jest and Storybook. The Gatsby documentation also has information about how to work with Storybook 4 and TypeScript implementations.
Leave a Reply