CI/CD Automation
This page is not meant to be every possible CI setup. It is the shortest set of patterns that map cleanly to the current CLI.
The core pattern
Most pipelines want one of these:
- Run tests and wait for visual results.
- Upload screenshots that were generated elsewhere.
- Finalize a parallel build after all shards finish.
For smoke jobs that intentionally have no cloud token, run with --allow-no-token. Vizzly still runs the command locally and skips creating a cloud build.
GitHub Actions
Fail when visual changes need review
name: Visual Tests
on: [push, pull_request]
jobs: visual-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22'
- run: npm ci
- name: Run visual tests env: VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }} run: vizzly run "npm test" --waitParallel shards
Use a shared parallel-id across shards, then finalize once at the end.
jobs: visual-tests: runs-on: ubuntu-latest strategy: matrix: shard: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' - run: npm ci - name: Run shard env: VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }} run: | vizzly run "npm test -- --shard=${{ matrix.shard }}/4" \ --parallel-id "${{ github.run_id }}"
finalize: needs: visual-tests if: ${{ always() }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' - run: npm ci - name: Finalize Vizzly build env: VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }} run: vizzly finalize "${{ github.run_id }}"GitLab CI
visual-tests: stage: test image: node:22 variables: VIZZLY_TOKEN: $VIZZLY_TOKEN script: - npm ci - vizzly run "npm test" --waitIf you do want to parse JSON in a node:22 image, install jq first or use a small Node script instead.
CircleCI
version: 2.1
jobs: visual-test: docker: - image: cimg/node:22.0 steps: - checkout - run: npm ci - run: name: Run visual tests command: vizzly run "npm test" --wait
workflows: test: jobs: - visual-testUpload-only pipelines
If your test framework already captured screenshots and you just need to upload them:
vizzly upload ./screenshots --wait --jsonThat works well when screenshot capture and Vizzly upload happen in separate steps.
Preview uploads
If you also want a static preview tied to the build:
npm run buildvizzly preview ./distvizzly preview uses the current session or an explicit build ID:
vizzly preview ./dist --build <build-id>Shell script example
#!/bin/bash
result=$(vizzly run "npm test" --wait --json)exit_code=$?
echo "$result"
if echo "$result" | jq -e '.data.uploads.failed > 0' >/dev/null; then echo "Vizzly is missing screenshots:" echo "$result" | jq -r '.data.uploads.failures[] | "\(.name): \(.error)"'fi
if [ "$exit_code" -ne 0 ]; then url=$(echo "$result" | jq -r '.data.url // empty') echo "The Vizzly run did not pass" [ -n "$url" ] && echo "$url" exit "$exit_code"fiThis script reports missing uploads without changing the test result. vizzly run preserves your test command’s exit code when uploads fail; --wait can still fail the job for visual differences after successful uploads. A zero exit code alone doesn’t confirm a complete visual build.
Comparison counts are included only when the API returned them, so scripts should not invent missing counts as zero.
Tips
- Use Node 22 in CI to match the current CLI package requirement.
- Use
vizzly run --waitto fail on visual differences, and check upload results for missing screenshots. - Use
vizzly finalizeonly when you are intentionally running parallel shards. - Save the JSON output if later jobs need the build ID or URL.