0
# Image Uploads
1
2
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.
3
4
## Capabilities
5
6
### Percy Upload
7
8
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.
9
10
```bash { .api }
11
/**
12
* Upload directory of images as snapshots
13
* Takes pre-captured images and uploads them to Percy for visual testing
14
*
15
* Usage: percy upload <dirname>
16
*
17
* Arguments:
18
* dirname Directory containing images to upload (required)
19
*
20
* Options:
21
* --files, -f <pattern> Glob patterns matching image files (multiple)
22
* Default: **/*.{png,jpg,jpeg}
23
* --ignore, -i <pattern> Glob patterns matching files to ignore (multiple)
24
* --strip-extensions, -e Strip file extensions from snapshot names
25
*
26
* Supported formats: .png, .jpg, .jpeg
27
* Supported projects: web and generic token types
28
*/
29
percy upload <dirname>
30
```
31
32
## Basic Usage
33
34
### Simple Directory Upload
35
36
Upload all images in a directory using default patterns:
37
38
```bash
39
# Upload all PNG, JPG, JPEG files
40
percy upload ./screenshots
41
42
# Directory structure:
43
# screenshots/
44
# ├── homepage.png → snapshot: "homepage.png"
45
# ├── about-page.jpg → snapshot: "about-page.jpg"
46
# ├── contact-form.jpeg → snapshot: "contact-form.jpeg"
47
# └── dashboard.png → snapshot: "dashboard.png"
48
```
49
50
### Custom File Patterns
51
52
Control which files are uploaded using glob patterns:
53
54
```bash
55
# Upload only PNG files
56
percy upload ./screenshots --files "**/*.png"
57
58
# Upload multiple specific patterns
59
percy upload ./screenshots \
60
--files "**/*.png" \
61
--files "**/mobile-*.jpg" \
62
--files "**/desktop-*.jpg"
63
64
# Upload from subdirectories
65
percy upload ./screenshots --files "**/final/*.{png,jpg}"
66
```
67
68
### Ignore Patterns
69
70
Exclude specific files or directories:
71
72
```bash
73
# Ignore temporary and backup files
74
percy upload ./screenshots \
75
--ignore "**/*-temp.*" \
76
--ignore "**/*.bak" \
77
--ignore "**/drafts/**"
78
79
# Ignore test and debug images
80
percy upload ./screenshots \
81
--ignore "**/test-*" \
82
--ignore "**/debug/**" \
83
--ignore "**/*.tmp"
84
```
85
86
### Clean Snapshot Names
87
88
Remove file extensions from snapshot names for cleaner URLs:
89
90
```bash
91
# Without strip-extensions
92
percy upload ./screenshots
93
# Creates: "homepage.png", "about-page.jpg", "contact.jpeg"
94
95
# With strip-extensions
96
percy upload ./screenshots --strip-extensions
97
# Creates: "homepage", "about-page", "contact"
98
```
99
100
## Integration Examples
101
102
### Playwright Screenshot Integration
103
104
```javascript
105
// playwright-screenshots.js
106
import { test } from '@playwright/test';
107
import path from 'path';
108
109
test.describe('Visual tests', () => {
110
test('capture screenshots', async ({ page }) => {
111
const screenshotDir = './percy-screenshots';
112
113
// Homepage
114
await page.goto('https://example.com');
115
await page.screenshot({
116
path: path.join(screenshotDir, 'homepage.png'),
117
fullPage: true
118
});
119
120
// About page
121
await page.goto('https://example.com/about');
122
await page.screenshot({
123
path: path.join(screenshotDir, 'about.png'),
124
fullPage: true
125
});
126
});
127
});
128
```
129
130
```bash
131
# Run Playwright tests to generate screenshots
132
npx playwright test
133
134
# Upload screenshots to Percy
135
percy upload ./percy-screenshots --strip-extensions
136
```
137
138
### Puppeteer Integration
139
140
```javascript
141
// puppeteer-screenshots.js
142
import puppeteer from 'puppeteer';
143
import fs from 'fs';
144
145
const browser = await puppeteer.launch();
146
const page = await browser.newPage();
147
148
// Ensure screenshot directory exists
149
fs.mkdirSync('./screenshots', { recursive: true });
150
151
// Capture multiple viewport sizes
152
const viewports = [
153
{ width: 375, height: 667, name: 'mobile' },
154
{ width: 768, height: 1024, name: 'tablet' },
155
{ width: 1280, height: 720, name: 'desktop' }
156
];
157
158
const pages = ['/', '/about', '/contact'];
159
160
for (const viewport of viewports) {
161
await page.setViewport(viewport);
162
163
for (const pagePath of pages) {
164
await page.goto(`https://example.com${pagePath}`);
165
const filename = `${pagePath.replace('/', 'home')}-${viewport.name}.png`;
166
await page.screenshot({
167
path: `./screenshots/${filename}`,
168
fullPage: true
169
});
170
}
171
}
172
173
await browser.close();
174
```
175
176
```bash
177
# Generate screenshots
178
node puppeteer-screenshots.js
179
180
# Upload to Percy
181
percy upload ./screenshots --strip-extensions
182
```
183
184
### Selenium Integration
185
186
```python
187
# selenium_screenshots.py
188
from selenium import webdriver
189
from selenium.webdriver.chrome.options import Options
190
import os
191
192
# Setup Chrome driver
193
options = Options()
194
options.add_argument('--headless')
195
driver = webdriver.Chrome(options=options)
196
197
# Create screenshots directory
198
os.makedirs('./screenshots', exist_ok=True)
199
200
# Test scenarios
201
scenarios = [
202
{'url': 'https://example.com', 'name': 'homepage'},
203
{'url': 'https://example.com/about', 'name': 'about'},
204
{'url': 'https://example.com/contact', 'name': 'contact'}
205
]
206
207
# Capture screenshots at different viewport sizes
208
viewports = [(375, 667), (768, 1024), (1280, 720)]
209
210
for width, height in viewports:
211
driver.set_window_size(width, height)
212
viewport_name = f"{width}x{height}"
213
214
for scenario in scenarios:
215
driver.get(scenario['url'])
216
filename = f"{scenario['name']}-{viewport_name}.png"
217
driver.save_screenshot(f"./screenshots/{filename}")
218
219
driver.quit()
220
```
221
222
```bash
223
# Generate screenshots
224
python selenium_screenshots.py
225
226
# Upload to Percy
227
percy upload ./screenshots --strip-extensions
228
```
229
230
### Mobile App Screenshots
231
232
```bash
233
# iOS Simulator screenshots (using xcrun simctl)
234
xcrun simctl io booted screenshot ./mobile-screenshots/ios-home.png
235
xcrun simctl io booted screenshot ./mobile-screenshots/ios-profile.png
236
237
# Android Emulator screenshots (using adb)
238
adb shell screencap -p /sdcard/android-home.png
239
adb pull /sdcard/android-home.png ./mobile-screenshots/
240
adb shell screencap -p /sdcard/android-profile.png
241
adb pull /sdcard/android-profile.png ./mobile-screenshots/
242
243
# Upload mobile screenshots
244
percy upload ./mobile-screenshots --strip-extensions
245
```
246
247
### External Tool Integration
248
249
```bash
250
# Storybook screenshot addon
251
npm run storybook:build
252
npm run storybook:screenshots # Generates screenshots
253
254
# Upload Storybook screenshots
255
percy upload ./storybook-screenshots \
256
--files "**/*.png" \
257
--ignore "**/temp/**" \
258
--strip-extensions
259
260
# BackstopJS integration
261
backstop test # Generates reference screenshots
262
263
# Upload BackstopJS screenshots
264
percy upload ./backstop_data/bitmaps_reference \
265
--files "**/*.png" \
266
--strip-extensions
267
```
268
269
## Advanced Configuration
270
271
### Complex Directory Structure
272
273
```bash
274
# Organized screenshot directory
275
screenshots/
276
├── desktop/
277
│ ├── homepage-1280x720.png
278
│ ├── about-1280x720.png
279
│ └── contact-1280x720.png
280
├── tablet/
281
│ ├── homepage-768x1024.png
282
│ ├── about-768x1024.png
283
│ └── contact-768x1024.png
284
├── mobile/
285
│ ├── homepage-375x667.png
286
│ ├── about-375x667.png
287
│ └── contact-375x667.png
288
└── temp/
289
└── draft-screenshot.png
290
291
# Upload with specific patterns
292
percy upload ./screenshots \
293
--files "**/desktop/*.png" \
294
--files "**/tablet/*.png" \
295
--files "**/mobile/*.png" \
296
--ignore "**/temp/**" \
297
--strip-extensions
298
```
299
300
### Naming Conventions
301
302
```bash
303
# Descriptive filenames become snapshot names
304
screenshots/
305
├── 01-homepage-desktop.png → "01-homepage-desktop"
306
├── 02-about-page-mobile.png → "02-about-page-mobile"
307
├── 03-contact-form-tablet.png → "03-contact-form-tablet"
308
├── 04-dashboard-logged-in.png → "04-dashboard-logged-in"
309
└── 05-profile-settings.png → "05-profile-settings"
310
311
percy upload ./screenshots --strip-extensions
312
```
313
314
### Batch Processing
315
316
```bash
317
# Upload multiple screenshot directories
318
for dir in ./test-results/*/screenshots/; do
319
if [ -d "$dir" ]; then
320
percy upload "$dir" --strip-extensions
321
fi
322
done
323
324
# Conditional upload based on file count
325
screenshot_count=$(find ./screenshots -name "*.png" | wc -l)
326
if [ "$screenshot_count" -gt 0 ]; then
327
echo "Uploading $screenshot_count screenshots"
328
percy upload ./screenshots --strip-extensions
329
else
330
echo "No screenshots found"
331
fi
332
```
333
334
## File Requirements
335
336
### Supported Formats
337
338
- **PNG**: Preferred format, supports transparency
339
- **JPG/JPEG**: Supported, good for photographs
340
- **Other formats**: Not supported (GIF, WebP, SVG, etc.)
341
342
### File Size Considerations
343
344
- **Maximum file size**: 25MB per image
345
- **Recommended size**: Under 5MB for optimal upload performance
346
- **Dimensions**: No hard limits, but very large images may timeout
347
348
### Quality Guidelines
349
350
```bash
351
# Good screenshot practices:
352
# - Use PNG for UI screenshots (better compression for flat colors)
353
# - Use consistent viewport sizes
354
# - Capture full page or specific components consistently
355
# - Remove dynamic content (timestamps, ads) before capturing
356
# - Use descriptive filenames
357
```
358
359
## Error Handling
360
361
### Common Upload Issues
362
363
```bash
364
# Handle missing directory
365
if [ ! -d "./screenshots" ]; then
366
echo "Screenshots directory not found"
367
exit 1
368
fi
369
370
# Check for supported file types
371
image_count=$(find ./screenshots -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" | wc -l)
372
if [ "$image_count" -eq 0 ]; then
373
echo "No supported image files found"
374
exit 1
375
fi
376
377
# Upload with error handling
378
percy upload ./screenshots --strip-extensions || {
379
echo "Percy upload failed"
380
exit 1
381
}
382
```
383
384
### File Access Issues
385
386
```bash
387
# Ensure proper permissions
388
chmod -R 644 ./screenshots/*.{png,jpg,jpeg}
389
390
# Check file accessibility
391
find ./screenshots -name "*.png" -not -readable | while read file; do
392
echo "Warning: Cannot read $file"
393
done
394
```
395
396
## Integration Patterns
397
398
### CI/CD Pipeline
399
400
```yaml
401
# GitHub Actions example
402
- name: Generate screenshots
403
run: npm run screenshots
404
405
- name: Upload to Percy
406
env:
407
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
408
run: percy upload ./screenshots --strip-extensions
409
```
410
411
### Development Workflow
412
413
```bash
414
# Development script
415
#!/bin/bash
416
set -e
417
418
echo "Cleaning old screenshots..."
419
rm -rf ./screenshots
420
421
echo "Generating new screenshots..."
422
npm run test:visual
423
424
echo "Uploading to Percy..."
425
percy upload ./screenshots --strip-extensions
426
427
echo "Screenshots uploaded successfully!"
428
```
429
430
### Multi-Environment Testing
431
432
```bash
433
# Upload screenshots from different environments
434
percy upload ./screenshots/staging --files "**/*.png" --strip-extensions
435
percy upload ./screenshots/production --files "**/*.png" --strip-extensions
436
```
437
438
## Token Requirements
439
440
### Project Types
441
442
- **Web projects**: Standard Percy tokens work normally
443
- **Generic projects**: Self-managed/BYOS tokens also supported
444
- **App projects**: Native app tokens supported for mobile screenshots
445
446
### Configuration
447
448
```bash
449
# Set Percy token
450
export PERCY_TOKEN=your-percy-token
451
452
# Verify token type
453
percy ping # Should respond if token is valid
454
```