Preview JavaScript Build Artifacts Directly in Pull Request with Stoat
Liren Tu
Posted on December 28, 2022
A typical build for a JavaScript / TypeScript project can generate a number of artifacts:
- Test reports (Jest, Mocha, etc.)
- Test coverage reports
- Integration test artifacts (Cypress screenshots/videos, etc.)
- Component previews (Storybook, Ladle, etc.)
- Documentation
Though useful for debugging and development, these outputs are usually disabled in continuous integration (CI) pipelines because the outputs are not easily accessible. It is almost impossible to look at those outputs from a CI pipeline running remotely. It can be equally difficult for developers to get to these outputs for local builds. Who would remember that the human-readable version of the Jest coverage report is under coverage/lcov-report
by default?
To solve this problem, we created Stoat. It is the easiest way to make all of this information trivial to consume for both local and remote builds. In this doc, we are going to show you how to create previews for these typical JavaScript build outputs.
We are going to use this repo as an example: penx/storybook-code-coverage, authored by Alasdair McLeay. The author wrote a detailed article about the set-up of this repo here: Combining Storybook, Cypress and Jest Code Coverage. This repo uses Jest for unit tests, Cypress for integration tests, and Storybook for visual previews. Each module generates their own test coverage reports, which can be merged together into one report.
The original repo doesn't have a GitHub workflow to build the entire project, but we will add one as part of the process.
We have two goals here:
- Write a GitHub workflow to run the CI pipeline.
- Use Stoat to provide previews for the latest test coverage reports, static Storybook pages, and Cypress videos on every pull request.
1. Add GitHub workflow
Create a YAML file at .github/workflows/ci.yaml
with the following content:
name: Continuous Integration
on:
# Trigger the ci pipeline for every comment on the default branch or a pull request.
# The default branch for the sample repo is `master`.
push:
branches:
- master
pull_request:
branches:
- master
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up node and cache
uses: actions/setup-node@v3
with:
node-version: '16.8.0'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile --prefer-offline
# This project has a `coverage` script that runs all the
# tests and merge all their coverage reports.
- name: Run tests and generate report
run: yarn coverage
- name: Generate storybook
run: yarn build-storybook
- name: Run stoat action
uses: stoat-dev/stoat-action@v0
if: always()
When you set it up for your own projects, most of the YAML file can be exactly the same. The only differences are:
- Replace
master
with the name of your default branch. - Replace
16.8.0
with the version of Node.js you are using. - Run the test script that is set in
package.json
. Typically, it isjest --coverage
for unit test.
Note that the Stoat action is appended at the end of the ci
job. This one step can carry out various tasks according to the Stoat config.
2. Install Stoat App
Install the Stoat application here.
3. Configure Stoat
Create a Stoat config file at .stoat/config.yaml
, and paste in the following content:
---
version: 1
enabled: true
plugins:
job_runtime:
enabled: true
static_hosting:
merged-test-coverage:
path: coverage/merged/lcov-report
storybook:
path: storybook-static
cypress-video:
path: cypress/videos/spec.js.mp4
The Stoat config is a YAML file that contains a list of tasks. Each task contains one Stoat plugin. In the example above, we have four tasks:
- Setting the
job_runtime
plugin toenabled
reports the time it takes to run every GitHub job. The build data is tracked by the Stoat action attached to theci
job. - Task
merged-test-coverage
looks for the test coverage report undercoverage/merged/lcov-report
, and uses the Stoatstatic_hosting
plugin to upload it to the Stoat server. The entire directory will be uploaded, so the preview will include all the HTML, JavaScript, and CSS files. - Task
storybook
is very similar. It looks for the static Storybook build understorybook-static
, and uploads them to the Stoat server. - Same for the
cypress-video
task. The only difference is that this task uploads a single file instead of a directory.
4. That's It!
Now, commit the two files to the codebase, and create a pull request.
After the build completes (about two minutes), you will be able to see the previews in a comment from the Stoat bot:
Now you can click on the links to see the previews or watch the Cypress video. This comment will be auto updated whenever the CI workflow is triggered and completed.
The Stoat comment is also highly customizable. For example, currently, in each row of the preview table, the Name
column is just the task ID in the Stoat config. You can change it to something more friendly by adding a metadata name
field to each of the task:
version: 1
enabled: true
plugins:
job_runtime:
enabled: true
static_hosting:
merged-test-coverage:
# The metadata and name fields are newly added here.
metadata:
name: Test coverage report
path: coverage/merged/lcov-report
storybook:
metadata:
name: Storybook
path: storybook-static
cypress-video:
metadata:
name: Cypress video
path: cypress/videos/spec.js.mp4
Commit and push the change.
After another two minutes, the comment is updated with the new names and runtime chart:
You can find the exact pull request used for this tutorial here.
Now you're ready to start using Stoat for your JavaScript and TypeScript projects!
Stoat can actually do much more. Check out these tutorials for more use cases:
Posted on December 28, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.