CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-percy--cli

Command line interface for Percy visual testing platform that enables developers to capture, upload, and manage visual snapshots for web applications.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

image-uploads.mddocs/

Image Uploads

Direct upload of image files as visual snapshots, useful for integrating with external screenshot tools or uploading pre-captured images to Percy for visual comparison.

Capabilities

Percy Upload

Upload a directory of images directly to Percy as snapshots. Perfect for integrating with external screenshot tools, mobile app screenshots, or any workflow that generates image files.

/**
 * Upload directory of images as snapshots
 * Takes pre-captured images and uploads them to Percy for visual testing
 * 
 * Usage: percy upload <dirname>
 * 
 * Arguments:
 *   dirname                       Directory containing images to upload (required)
 * 
 * Options:
 *   --files, -f <pattern>         Glob patterns matching image files (multiple)
 *                                Default: **/*.{png,jpg,jpeg}
 *   --ignore, -i <pattern>        Glob patterns matching files to ignore (multiple)
 *   --strip-extensions, -e        Strip file extensions from snapshot names
 * 
 * Supported formats: .png, .jpg, .jpeg
 * Supported projects: web and generic token types
 */
percy upload <dirname>

Basic Usage

Simple Directory Upload

Upload all images in a directory using default patterns:

# Upload all PNG, JPG, JPEG files
percy upload ./screenshots

# Directory structure:
# screenshots/
# ├── homepage.png          → snapshot: "homepage.png"
# ├── about-page.jpg        → snapshot: "about-page.jpg"
# ├── contact-form.jpeg     → snapshot: "contact-form.jpeg"
# └── dashboard.png         → snapshot: "dashboard.png"

Custom File Patterns

Control which files are uploaded using glob patterns:

# Upload only PNG files
percy upload ./screenshots --files "**/*.png"

# Upload multiple specific patterns
percy upload ./screenshots \
  --files "**/*.png" \
  --files "**/mobile-*.jpg" \
  --files "**/desktop-*.jpg"

# Upload from subdirectories
percy upload ./screenshots --files "**/final/*.{png,jpg}"

Ignore Patterns

Exclude specific files or directories:

# Ignore temporary and backup files
percy upload ./screenshots \
  --ignore "**/*-temp.*" \
  --ignore "**/*.bak" \
  --ignore "**/drafts/**"

# Ignore test and debug images
percy upload ./screenshots \
  --ignore "**/test-*" \
  --ignore "**/debug/**" \
  --ignore "**/*.tmp"

Clean Snapshot Names

Remove file extensions from snapshot names for cleaner URLs:

# Without strip-extensions
percy upload ./screenshots
# Creates: "homepage.png", "about-page.jpg", "contact.jpeg"

# With strip-extensions
percy upload ./screenshots --strip-extensions
# Creates: "homepage", "about-page", "contact"

Integration Examples

Playwright Screenshot Integration

// playwright-screenshots.js
import { test } from '@playwright/test';
import path from 'path';

test.describe('Visual tests', () => {
  test('capture screenshots', async ({ page }) => {
    const screenshotDir = './percy-screenshots';
    
    // Homepage
    await page.goto('https://example.com');
    await page.screenshot({ 
      path: path.join(screenshotDir, 'homepage.png'),
      fullPage: true 
    });
    
    // About page
    await page.goto('https://example.com/about');
    await page.screenshot({ 
      path: path.join(screenshotDir, 'about.png'),
      fullPage: true 
    });
  });
});
# Run Playwright tests to generate screenshots
npx playwright test

# Upload screenshots to Percy
percy upload ./percy-screenshots --strip-extensions

Puppeteer Integration

// puppeteer-screenshots.js
import puppeteer from 'puppeteer';
import fs from 'fs';

const browser = await puppeteer.launch();
const page = await browser.newPage();

// Ensure screenshot directory exists
fs.mkdirSync('./screenshots', { recursive: true });

// Capture multiple viewport sizes
const viewports = [
  { width: 375, height: 667, name: 'mobile' },
  { width: 768, height: 1024, name: 'tablet' },
  { width: 1280, height: 720, name: 'desktop' }
];

const pages = ['/', '/about', '/contact'];

for (const viewport of viewports) {
  await page.setViewport(viewport);
  
  for (const pagePath of pages) {
    await page.goto(`https://example.com${pagePath}`);
    const filename = `${pagePath.replace('/', 'home')}-${viewport.name}.png`;
    await page.screenshot({ 
      path: `./screenshots/${filename}`,
      fullPage: true 
    });
  }
}

await browser.close();
# Generate screenshots
node puppeteer-screenshots.js

# Upload to Percy
percy upload ./screenshots --strip-extensions

Selenium Integration

# selenium_screenshots.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os

# Setup Chrome driver
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)

# Create screenshots directory
os.makedirs('./screenshots', exist_ok=True)

# Test scenarios
scenarios = [
    {'url': 'https://example.com', 'name': 'homepage'},
    {'url': 'https://example.com/about', 'name': 'about'},
    {'url': 'https://example.com/contact', 'name': 'contact'}
]

# Capture screenshots at different viewport sizes
viewports = [(375, 667), (768, 1024), (1280, 720)]

for width, height in viewports:
    driver.set_window_size(width, height)
    viewport_name = f"{width}x{height}"
    
    for scenario in scenarios:
        driver.get(scenario['url'])
        filename = f"{scenario['name']}-{viewport_name}.png"
        driver.save_screenshot(f"./screenshots/{filename}")

driver.quit()
# Generate screenshots
python selenium_screenshots.py

# Upload to Percy
percy upload ./screenshots --strip-extensions

Mobile App Screenshots

# iOS Simulator screenshots (using xcrun simctl)
xcrun simctl io booted screenshot ./mobile-screenshots/ios-home.png
xcrun simctl io booted screenshot ./mobile-screenshots/ios-profile.png

# Android Emulator screenshots (using adb)
adb shell screencap -p /sdcard/android-home.png
adb pull /sdcard/android-home.png ./mobile-screenshots/
adb shell screencap -p /sdcard/android-profile.png  
adb pull /sdcard/android-profile.png ./mobile-screenshots/

# Upload mobile screenshots
percy upload ./mobile-screenshots --strip-extensions

External Tool Integration

# Storybook screenshot addon
npm run storybook:build
npm run storybook:screenshots  # Generates screenshots

# Upload Storybook screenshots
percy upload ./storybook-screenshots \
  --files "**/*.png" \
  --ignore "**/temp/**" \
  --strip-extensions

# BackstopJS integration
backstop test  # Generates reference screenshots

# Upload BackstopJS screenshots
percy upload ./backstop_data/bitmaps_reference \
  --files "**/*.png" \
  --strip-extensions

Advanced Configuration

Complex Directory Structure

# Organized screenshot directory
screenshots/
├── desktop/
│   ├── homepage-1280x720.png
│   ├── about-1280x720.png
│   └── contact-1280x720.png
├── tablet/
│   ├── homepage-768x1024.png
│   ├── about-768x1024.png
│   └── contact-768x1024.png
├── mobile/
│   ├── homepage-375x667.png
│   ├── about-375x667.png
│   └── contact-375x667.png
└── temp/
    └── draft-screenshot.png

# Upload with specific patterns
percy upload ./screenshots \
  --files "**/desktop/*.png" \
  --files "**/tablet/*.png" \
  --files "**/mobile/*.png" \
  --ignore "**/temp/**" \
  --strip-extensions

Naming Conventions

# Descriptive filenames become snapshot names
screenshots/
├── 01-homepage-desktop.png       → "01-homepage-desktop"
├── 02-about-page-mobile.png      → "02-about-page-mobile" 
├── 03-contact-form-tablet.png    → "03-contact-form-tablet"
├── 04-dashboard-logged-in.png    → "04-dashboard-logged-in"
└── 05-profile-settings.png       → "05-profile-settings"

percy upload ./screenshots --strip-extensions

Batch Processing

# Upload multiple screenshot directories
for dir in ./test-results/*/screenshots/; do
  if [ -d "$dir" ]; then
    percy upload "$dir" --strip-extensions
  fi
done

# Conditional upload based on file count
screenshot_count=$(find ./screenshots -name "*.png" | wc -l)
if [ "$screenshot_count" -gt 0 ]; then
  echo "Uploading $screenshot_count screenshots"
  percy upload ./screenshots --strip-extensions
else
  echo "No screenshots found"
fi

File Requirements

Supported Formats

  • PNG: Preferred format, supports transparency
  • JPG/JPEG: Supported, good for photographs
  • Other formats: Not supported (GIF, WebP, SVG, etc.)

File Size Considerations

  • Maximum file size: 25MB per image
  • Recommended size: Under 5MB for optimal upload performance
  • Dimensions: No hard limits, but very large images may timeout

Quality Guidelines

# Good screenshot practices:
# - Use PNG for UI screenshots (better compression for flat colors)
# - Use consistent viewport sizes
# - Capture full page or specific components consistently
# - Remove dynamic content (timestamps, ads) before capturing
# - Use descriptive filenames

Error Handling

Common Upload Issues

# Handle missing directory
if [ ! -d "./screenshots" ]; then
  echo "Screenshots directory not found"
  exit 1
fi

# Check for supported file types
image_count=$(find ./screenshots -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" | wc -l)
if [ "$image_count" -eq 0 ]; then
  echo "No supported image files found"
  exit 1
fi

# Upload with error handling
percy upload ./screenshots --strip-extensions || {
  echo "Percy upload failed"
  exit 1
}

File Access Issues

# Ensure proper permissions
chmod -R 644 ./screenshots/*.{png,jpg,jpeg}

# Check file accessibility
find ./screenshots -name "*.png" -not -readable | while read file; do
  echo "Warning: Cannot read $file"
done

Integration Patterns

CI/CD Pipeline

# GitHub Actions example
- name: Generate screenshots
  run: npm run screenshots

- name: Upload to Percy
  env:
    PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
  run: percy upload ./screenshots --strip-extensions

Development Workflow

# Development script
#!/bin/bash
set -e

echo "Cleaning old screenshots..."
rm -rf ./screenshots

echo "Generating new screenshots..."
npm run test:visual

echo "Uploading to Percy..."
percy upload ./screenshots --strip-extensions

echo "Screenshots uploaded successfully!"

Multi-Environment Testing

# Upload screenshots from different environments
percy upload ./screenshots/staging --files "**/*.png" --strip-extensions
percy upload ./screenshots/production --files "**/*.png" --strip-extensions

Token Requirements

Project Types

  • Web projects: Standard Percy tokens work normally
  • Generic projects: Self-managed/BYOS tokens also supported
  • App projects: Native app tokens supported for mobile screenshots

Configuration

# Set Percy token
export PERCY_TOKEN=your-percy-token

# Verify token type
percy ping  # Should respond if token is valid

Install with Tessl CLI

npx tessl i tessl/npm-percy--cli

docs

app-snapshots.md

build-management.md

configuration.md

core-operations.md

image-uploads.md

index.md

programmatic-api.md

static-snapshots.md

tile.json