Ir al contenido

Percy Cheat Sheet

Overview

Percy is a visual testing and review platform (now part of BrowserStack) that captures screenshots of your UI across different browsers and screen sizes, then compares them against approved baselines to detect visual regressions. It integrates into your existing test suite and CI/CD pipeline, providing a visual diff review workflow similar to code review.

Percy supports Cypress, Playwright, Puppeteer, Selenium, Storybook, static sites, and custom SDK integrations. It renders pages in real browsers (Chrome and Firefox), captures responsive snapshots at configurable widths, and provides a web dashboard for reviewing and approving visual changes with your team.

Installation

# Percy CLI
npm install -D @percy/cli

# Cypress integration
npm install -D @percy/cypress

# Playwright integration
npm install -D @percy/playwright

# Puppeteer integration
npm install -D @percy/puppeteer

# Selenium (Node.js)
npm install -D @percy/selenium-webdriver

# Storybook integration
npm install -D @percy/storybook

# Static site snapshots
npm install -D @percy/cli

Core Commands

CommandDescription
percy snapshotTake snapshots of static pages
percy storybookSnapshot Storybook stories
percy execRun a command with Percy enabled
percy uploadUpload a directory of images
percy config:validateValidate Percy configuration
percy build:waitWait for a build to complete

Basic Usage

With Cypress

// cypress/e2e/visual.cy.js
describe("Visual Tests", () => {
  it("should match homepage", () => {
    cy.visit("/");
    cy.percySnapshot("Homepage");
  });

  it("should match dashboard", () => {
    cy.visit("/dashboard");
    cy.percySnapshot("Dashboard", {
      widths: [375, 768, 1280],
      minHeight: 1024,
    });
  });
});
# Run Cypress with Percy
export PERCY_TOKEN=your_token_here
npx percy exec -- npx cypress run

With Playwright

const { test } = require("@playwright/test");
const percySnapshot = require("@percy/playwright");

test("homepage visual test", async ({ page }) => {
  await page.goto("https://example.com");
  await percySnapshot(page, "Homepage");
});

test("responsive visual test", async ({ page }) => {
  await page.goto("https://example.com/pricing");
  await percySnapshot(page, "Pricing Page", {
    widths: [375, 768, 1280],
  });
});
npx percy exec -- npx playwright test

With Storybook

# Snapshot all stories
npx percy storybook http://localhost:6006

# Snapshot from a built Storybook
npx percy storybook ./storybook-static

# With filtering
npx percy storybook --include "Button*" http://localhost:6006
npx percy storybook --exclude "*Dark*" http://localhost:6006

Static Site Snapshots

# Snapshot a list of URLs
npx percy snapshot snapshots.yml

# Snapshot a directory of HTML files
npx percy snapshot ./public
# snapshots.yml
- name: Homepage
  url: https://example.com/
  widths: [375, 768, 1280]

- name: About Page
  url: https://example.com/about
  waitForSelector: ".content-loaded"

- name: Dashboard
  url: https://example.com/dashboard
  execute: |
    await page.click('.load-data');
    await page.waitForSelector('.data-loaded');

Configuration

# .percy.yml
version: 2
snapshot:
  widths: [375, 768, 1280]
  minHeight: 1024
  percyCSS: |
    .dynamic-content { visibility: hidden; }
    .timestamp { display: none; }

discovery:
  allowedHostnames:
    - "cdn.example.com"
    - "fonts.googleapis.com"
  networkIdleTimeout: 500
  concurrency: 5

storybook:
  include: ["**"]
  exclude: ["**/internal/**"]
  args: ["--no-open"]

Snapshot Options

OptionDescription
widthsArray of viewport widths (default: [375, 1280])
minHeightMinimum screenshot height in pixels
percyCSSCSS to inject before snapshot
enableJavaScriptEnable JavaScript rendering
waitForSelectorWait for a CSS selector before snapshot
waitForTimeoutWait N milliseconds before snapshot
scopeCSS selector to scope the snapshot
enableLayoutEnable layout snapshot mode
// Cypress example with all options
cy.percySnapshot("Complex Page", {
  widths: [375, 768, 1024, 1280, 1920],
  minHeight: 1024,
  percyCSS: ".ad-banner { display: none; }",
  enableJavaScript: true,
  scope: "#main-content",
});

Advanced Usage

Handling Dynamic Content

# .percy.yml - Hide dynamic elements
version: 2
snapshot:
  percyCSS: |
    [data-percy-hide], .ad-slot, .live-chat {
      visibility: hidden !important;
    }
    .dynamic-date {
      color: transparent;
    }
    .animated-element {
      animation: none !important;
      transition: none !important;
    }
// Freeze animations and dynamic content in tests
cy.percySnapshot("Stable Page", {
  percyCSS: `
    *, *::before, *::after {
      animation-duration: 0s !important;
      transition-duration: 0s !important;
    }
  `,
});

Responsive Testing Strategy

// Test critical breakpoints
const breakpoints = {
  mobile: 375,
  tablet: 768,
  desktop: 1280,
  wide: 1920,
};

cy.percySnapshot("Responsive Layout", {
  widths: Object.values(breakpoints),
});

Upload Directory of Images

# Upload pre-rendered images for comparison
npx percy upload ./screenshots

# With custom naming
npx percy upload --strip-extensions ./screenshots

CI/CD Integration

# GitHub Actions
name: Visual Tests
on: [pull_request]
jobs:
  percy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx percy exec -- npx cypress run
        env:
          PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
# Environment variables
export PERCY_TOKEN="your_project_token"
export PERCY_BRANCH="feature-branch"          # Auto-detected in CI
export PERCY_TARGET_BRANCH="main"             # Baseline branch
export PERCY_PARALLEL_TOTAL=4                 # Parallel shards
export PERCY_PARALLEL_NONCE="unique-build-id" # Group parallel builds

Parallel Builds

# Shard 1
PERCY_PARALLEL_TOTAL=3 PERCY_PARALLEL_NONCE=$BUILD_ID \
  npx percy exec -- npx cypress run --spec "cypress/e2e/shard1/**"

# Shard 2
PERCY_PARALLEL_TOTAL=3 PERCY_PARALLEL_NONCE=$BUILD_ID \
  npx percy exec -- npx cypress run --spec "cypress/e2e/shard2/**"

# Shard 3
PERCY_PARALLEL_TOTAL=3 PERCY_PARALLEL_NONCE=$BUILD_ID \
  npx percy exec -- npx cypress run --spec "cypress/e2e/shard3/**"

Troubleshooting

IssueSolution
No snapshots capturedVerify PERCY_TOKEN is set; check percy exec wraps test command
Dynamic content diffsAdd percyCSS to hide timestamps, ads, animations
Missing assets (CSS/fonts)Add CDN hostnames to discovery.allowedHostnames
Snapshot timeoutIncrease discovery.networkIdleTimeout; add waitForSelector
Build not finalizingUse percy build:finalize or check parallel nonce settings
Too many diffsReview baseline; approve intentional changes in dashboard
Storybook stories missingCheck include/exclude patterns; verify Storybook URL
Slow buildsReduce widths; limit snapshot count; increase discovery.concurrency