@ashartariq/flowdiff
v0.1.1
Published
PR UX diff tool for Cypress journeys — CLI
Readme
@ashartariq/flowdiff
PR UX diff tool for Cypress journeys. Captures named keyframe screenshots on every PR, diffs them pixel-by-pixel against a baseline, and posts a rich HTML report as a GitHub Actions artifact with an inline PR comment.
Works with any existing Cypress test suite — no test rewrites needed, just add cy.flowSnap() calls at the UI moments you care about.
How it works
main push → capture baseline screenshots → upload artifact
PR open → capture candidate screenshots → diff vs baseline → HTML report → PR comment- Baseline run (on push to
main): Cypress runs,cy.flowSnap()captures keyframes,flowdiff collectsaves them as theflowdiff-baselineartifact. - PR run (on pull request to
main): Same Cypress run captures the candidate.flowdiff comparediffs every step pixel-by-pixel and generates a self-containedindex.htmlreport. - PR comment: Shows changed/unchanged counts and links to the downloadable HTML report.
Install
npm install --save-dev @ashartariq/flowdiff
# or
pnpm add -D @ashartariq/flowdiffAlso install the Cypress plugin:
npm install --save-dev cypress-flowdiffCypress setup
See cypress-flowdiff for the full plugin setup. Quick start:
cypress.config.ts
import { installFlowDiffPlugin } from 'cypress-flowdiff';
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
installFlowDiffPlugin(on, config);
return config;
},
},
});cypress/support/e2e.ts
import { addFlowSnapCommand } from 'cypress-flowdiff';
addFlowSnapCommand();In your tests
cy.visit('/login');
cy.flowSnap('login page');
cy.get('[data-cy=submit]').click();
cy.flowSnap('after submit');CLI
flowdiff collect --cwd <dir> [--screenshots <dir>] [--run-id <id>]
flowdiff compare --cwd <dir> [--baseline <dir>] [--candidate <dir>] [--output <dir>] [--threshold <n>] [--artifact-url <url>]
flowdiff github-comment --repo <owner/repo> --pr <number> --report <path> [--artifact-url <url>]collect
Scans cypress/screenshots/flowsnap/ and copies files into .flowdiff/candidate/ with a manifest.json.
node_modules/.bin/flowdiff collect --cwd .compare
Diffs candidate against baseline, writes diff images and a self-contained index.html report to .flowdiff/report/.
node_modules/.bin/flowdiff compare \
--cwd . \
--baseline .flowdiff/baseline \
--candidate .flowdiff/candidate \
--output .flowdiff/reportExit codes: 0 = no diffs, 1 = error, 2 = diffs detected (use for CI gating).
github-comment
Upserts a PR comment via the GitHub API. Usually called automatically by the composite action.
node_modules/.bin/flowdiff github-comment \
--repo owner/repo \
--pr 42 \
--report .flowdiff/report/report.json \
--artifact-url https://github.com/.../artifacts/...Configuration
Create a flowdiff.config.ts (or .js, .json, or a "flowdiff" key in package.json):
import type { FlowDiffConfig } from '@ashartariq/flowdiff';
const config: FlowDiffConfig = {
screenshotsDir: 'cypress/screenshots', // where Cypress saves screenshots
outputDir: '.flowdiff', // working directory for collect/compare output
diffThreshold: 0.1, // per-channel diff sensitivity (0–1)
pixelChangeFailThreshold: 0.02, // % of changed pixels that counts as "changed" (0–1)
maxKeyframesPerJourney: 20, // cap on steps per journey
maskRegions: [], // pixel regions to ignore during diff
};
export default config;GitHub Actions
Add two workflow files to your repository:
.github/workflows/flowdiff-baseline.yml
Runs on push to main. Captures the baseline.
name: FlowDiff Baseline
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: flowdiff-baseline
cancel-in-progress: false
jobs:
baseline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Start app
run: npx serve public -p 4000 &
- name: Run Cypress
uses: cypress-io/github-action@v6
with:
install: false
env:
CYPRESS_BASE_URL: 'http://localhost:4000'
- name: Collect screenshots
run: npx flowdiff collect --cwd .
- name: Upload baseline
uses: actions/upload-artifact@v4
with:
name: flowdiff-baseline
path: .flowdiff/candidate/
retention-days: 90
overwrite: true.github/workflows/flowdiff-pr.yml
Runs on PRs targeting main. Compares and comments.
name: FlowDiff PR
on:
pull_request:
branches: [main]
jobs:
flowdiff:
runs-on: ubuntu-latest
permissions:
pull-requests: write
actions: read
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Start app
run: npx serve public -p 4000 &
- name: Run Cypress
uses: cypress-io/github-action@v6
with:
install: false
env:
CYPRESS_BASE_URL: 'http://localhost:4000'
continue-on-error: true
- name: Collect candidate screenshots
run: npx flowdiff collect --cwd .
- name: Download baseline
uses: actions/download-artifact@v4
with:
name: flowdiff-baseline
path: .flowdiff/baseline/
continue-on-error: true
- name: Compare
run: |
npx flowdiff compare \
--cwd . \
--baseline .flowdiff/baseline \
--candidate .flowdiff/candidate \
--output .flowdiff/report
continue-on-error: true
- name: Post PR comment
run: |
npx flowdiff github-comment \
--repo ${{ github.repository }} \
--pr ${{ github.event.pull_request.number }} \
--report .flowdiff/report/report.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Upload report
uses: actions/upload-artifact@v4
if: always()
with:
name: flowdiff-report-pr-${{ github.event.pull_request.number }}
path: .flowdiff/report/
retention-days: 30Report UI features
The generated index.html is fully self-contained (no CDN). Open it locally or download it from the Actions artifact.
- Journey tabs — switch between different spec files
- Step card grid — thumbnail previews with status badges and pixel-change %
- Hover to diff — hover a card to reveal the diff overlay image
- Click for detail — opens a 3-column panel (Baseline | Diff | Candidate)
- Category toggles — 11 detection categories (colors, layout, typography, etc.) with sensitivity thresholds that update the "changed" count live
- Baseline section — collapsible strip showing all baseline screenshots
License
MIT
