DEV Community

Liren Tu
Liren Tu

Posted on

Preview JavaScript Build Artifacts Directly in Pull Request with Stoat

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:

  1. Write a GitHub workflow to run the CI pipeline.
  2. 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()
Enter fullscreen mode Exit fullscreen mode

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 is jest --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
Enter fullscreen mode Exit fullscreen mode

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 to enabled reports the time it takes to run every GitHub job. The build data is tracked by the Stoat action attached to the ci job.
  • Task merged-test-coverage looks for the test coverage report under coverage/merged/lcov-report, and uses the Stoat static_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 under storybook-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:

javascript comment screenshot (with ids)

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
Enter fullscreen mode Exit fullscreen mode

Commit and push the change.

After another two minutes, the comment is updated with the new names and runtime chart:

javascript comment screenshot (with names)

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:

Top comments (0)