@vizzly-testing/cli
Version:
Visual review platform for UI developers and designers
524 lines (411 loc) • 12.8 kB
Markdown
# Test Integration Guide
The `vizzly run` command integrates Vizzly directly into your test suite, automatically capturing screenshots during test execution and processing them through Vizzly's visual comparison pipeline.
## Command Options
**`--build-name <name>`** - Custom build name
```bash
vizzly run "npm test" --build-name "PR-123"
```
**`--environment <env>`** - Environment name (default: "test")
```bash
vizzly run "npm test" --environment "staging"
```
**`--branch <branch>`** - Git branch override
```bash
vizzly run "npm test" --branch "feature/new-ui"
```
**`--commit <sha>`** - Git commit SHA override
```bash
vizzly run "npm test" --commit "abc123def456"
```
**`--message <msg>`** - Commit message override
```bash
vizzly run "npm test" --message "Add new component"
```## Basic Usage
```bash
vizzly run "<your-test-command>"
```
Examples with different test frameworks:
```bash
vizzly run "npm test"
vizzly run "npx playwright test"
vizzly run "npx cypress run"
vizzly run "bundle exec rspec"
vizzly run "python -m pytest"
```
## How It Works
When you run `vizzly run`:
1. **Starts a local server** - Creates a screenshot capture endpoint
2. **Sets environment variables** - Makes Vizzly available to your tests
3. **Runs your test command** - Executes your normal test suite
4. **Captures screenshots** - Collects screenshots from `vizzlyScreenshot()` calls
5. **Uploads results** - Sends all screenshots to Vizzly for processing
## Environment Variables
The CLI automatically sets these variables for your test process:
- `VIZZLY_SERVER_URL` - Local server URL for screenshot uploads
- `VIZZLY_BUILD_ID` - Unique identifier for this test run
- `VIZZLY_ENABLED` - Set to `true` to enable screenshot capture
- `VIZZLY_TDD_MODE` - Set to `true` when using `--tdd` flag
## Adding Screenshots to Tests
Import the client and use `vizzlyScreenshot()` in your tests. You can pass either a **Buffer** or a **file path**:
### Using a Buffer
```javascript
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
// Your test framework takes the screenshot
const screenshot = await page.screenshot();
// Send to Vizzly
await vizzlyScreenshot('homepage', screenshot, {
properties: {
browser: 'chrome',
viewport: '1920x1080'
}
});
```
### Using a File Path
```javascript
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
// Save screenshot to file first
await page.screenshot({ path: './screenshots/homepage.png' });
// Send to Vizzly using file path
await vizzlyScreenshot('homepage', './screenshots/homepage.png', {
properties: {
browser: 'chrome',
viewport: '1920x1080'
}
});
```
**File path support:**
- Accepts both absolute and relative paths
- Works with any tool that generates PNG files
- Useful when screenshots are already saved to disk
## Framework Examples
### Playwright
```javascript
import { test } from '@playwright/test';
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
test('homepage test', async ({ page }) => {
await page.goto('/');
// Using a Buffer
const screenshot = await page.screenshot();
await vizzlyScreenshot('homepage', screenshot, {
properties: {
browser: 'chrome',
viewport: '1920x1080',
page: 'home'
}
});
// Using a file path
await page.screenshot({ path: './screenshots/homepage.png' });
await vizzlyScreenshot('homepage', './screenshots/homepage.png', {
properties: {
browser: 'chrome',
viewport: '1920x1080',
page: 'home'
}
});
});
```
### Cypress
```javascript
// cypress/support/commands.js
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
import { join } from 'path';
// Using file paths
Cypress.Commands.add('vizzlyScreenshot', (name, properties = {}) => {
// Cypress saves screenshots to cypress/screenshots by default
cy.screenshot(name, { capture: 'viewport' });
// Use file path directly
const screenshotPath = join(Cypress.config('screenshotsFolder'), `${name}.png`);
return cy.wrap(
vizzlyScreenshot(name, screenshotPath, {
properties: {
browser: Cypress.browser.name,
framework: 'cypress',
...properties
}
})
);
});
// In your test
describe('Homepage', () => {
it('should render correctly', () => {
cy.visit('/');
cy.vizzlyScreenshot('homepage', {
page: 'home',
state: 'logged-out'
});
});
});
```
### Puppeteer
```javascript
import puppeteer from 'puppeteer';
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
describe('Visual tests', () => {
test('homepage screenshot', async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('/');
// Using a Buffer
const screenshot = await page.screenshot();
await vizzlyScreenshot('homepage', screenshot, {
properties: {
browser: 'chrome',
framework: 'puppeteer'
}
});
// Using a file path
await page.screenshot({ path: './screenshots/homepage.png' });
await vizzlyScreenshot('homepage', './screenshots/homepage.png', {
properties: {
browser: 'chrome',
framework: 'puppeteer'
}
});
await browser.close();
});
});
```
## Command Options
### Server Configuration
**`--port <port>`** - Server port (default: 47392)
```bash
vizzly run "npm test" --port 3002
```
**`--timeout <ms>`** - Server timeout in milliseconds (default: 30000)
```bash
vizzly run "npm test" --timeout 60000
```
### Build Configuration
**`--build-name <name>`** - Custom build name
```bash
vizzly run "npm test" --build-name "PR-123"
```
**`--environment <env>`** - Environment name (default: "test")
```bash
vizzly run "npm test" --environment "staging"
```
**`--branch <branch>`** - Git branch override
```bash
vizzly run "npm test" --branch "feature/new-ui"
```
### Processing Options
**`--wait`** - Wait for build completion
```bash
vizzly run "npm test" --wait
```
**`--upload-all`** - Upload all screenshots without SHA deduplication
```bash
vizzly run "npm test" --upload-all
```
**`--threshold <number>`** - Comparison threshold (0-1, default: 0.01)
```bash
vizzly run "npm test" --threshold 0.02
```
### Parallel Execution
**`--parallel-id <id>`** - Unique identifier for parallel test execution
```bash
vizzly run "npm test" --parallel-id "ci-run-123"
```
When using parallel execution, multiple test runners can contribute screenshots to the same build. This is particularly useful for CI/CD pipelines with parallel jobs.
### Development Options
For TDD mode, use the dedicated `vizzly tdd` command. See [TDD Mode Guide](./tdd-mode.md) for details.
**`--allow-no-token`** - Allow running without API token
```bash
vizzly run "npm test" --allow-no-token
```
**`--token <token>`** - API token override
```bash
vizzly run "npm test" --token "your-token-here"
```
## Screenshot Properties
The `properties` object in `vizzlyScreenshot()` is flexible and can contain any metadata:
```javascript
await vizzlyScreenshot('dashboard', screenshot, {
properties: {
// Technical metadata
browser: 'chrome',
os: 'macos',
viewport: '1920x1080',
device: 'desktop',
// Organizational metadata
component: 'dashboard',
page: 'home',
feature: 'analytics',
theme: 'dark',
// Test metadata
testSuite: 'smoke-tests',
userType: 'admin',
state: 'logged-in',
// Custom metadata
buildNumber: process.env.BUILD_NUMBER,
environment: 'staging'
}
});
```
## CI/CD Integration
### GitHub Actions
```yaml
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: '20'
- run: npm ci
- run: npx vizzly run "npm test" --wait
env:
VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }}
# Optional: Enhanced git information from GitHub context
VIZZLY_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
VIZZLY_COMMIT_SHA: ${{ github.event.head_commit.id }}
VIZZLY_BRANCH: ${{ github.head_ref || github.ref_name }}
```
**Enhanced Git Information:** The `VIZZLY_*` environment variables ensure accurate git metadata is captured in your builds, avoiding issues with merge commits that can occur in CI environments.
### Parallel Builds in CI
For parallel test execution, use `--parallel-id` to ensure all shards contribute to the same build:
```yaml
# GitHub Actions with parallel matrix
jobs:
e2e-tests:
strategy:
matrix:
shard: [1/4, 2/4, 3/4, 4/4]
steps:
- name: Run tests with Vizzly
run: |
npx vizzly run "npm test -- --shard=${{ matrix.shard }}" \
--parallel-id="${{ github.run_id }}-${{ github.run_attempt }}"
env:
VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }}
finalize-e2e:
needs: e2e-tests
runs-on: ubuntu-latest
if: always() && needs.e2e-tests.result == 'success'
steps:
- name: Finalize parallel build
run: |
npx vizzly finalize "${{ github.run_id }}-${{ github.run_attempt }}"
env:
VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }}
```
**How Parallel Builds Work:**
1. All shards with the same `--parallel-id` contribute to one shared build
2. First shard creates the build, subsequent shards add screenshots to it
3. After all shards complete, use `vizzly finalize` to trigger comparison processing
4. Use GitHub's run ID + attempt for uniqueness across workflow runs
### GitLab CI
```yaml
visual-tests:
stage: test
image: node:20
script:
- npm ci
- npx vizzly run "npm test" --wait
variables:
VIZZLY_TOKEN: $VIZZLY_TOKEN
# Parallel execution example
visual-tests-parallel:
stage: test
parallel:
matrix:
- SHARD: "1/4"
- SHARD: "2/4"
- SHARD: "3/4"
- SHARD: "4/4"
script:
- npm ci
- npx vizzly run "npm test -- --shard=$SHARD" --parallel-id "$CI_PIPELINE_ID-$CI_JOB_ID"
variables:
VIZZLY_TOKEN: $VIZZLY_TOKEN
finalize-visual-tests:
stage: finalize
needs: ["visual-tests-parallel"]
script:
- npx vizzly finalize "$CI_PIPELINE_ID-$CI_JOB_ID"
variables:
VIZZLY_TOKEN: $VIZZLY_TOKEN
```
## Advanced Usage
### Conditional Screenshots
Only take screenshots when Vizzly is enabled:
```javascript
import { isVizzlyEnabled, vizzlyScreenshot } from '@vizzly-testing/cli/client';
if (isVizzlyEnabled()) {
const screenshot = await page.screenshot();
await vizzlyScreenshot('homepage', screenshot);
}
```
### Batch Screenshot Processing
Wait for all screenshots to be processed:
```javascript
import { vizzlyFlush } from '@vizzly-testing/cli/client';
// Take multiple screenshots
await vizzlyScreenshot('page1', screenshot1);
await vizzlyScreenshot('page2', screenshot2);
await vizzlyScreenshot('page3', screenshot3);
// Wait for all to be processed
await vizzlyFlush();
```
### Custom Configuration
Use a custom configuration per test run:
```javascript
import { configure } from '@vizzly-testing/cli/client';
// Configure before taking screenshots
configure({
serverUrl: 'http://localhost:3001',
enabled: true
});
```
## Troubleshooting
**Port already in use**
```bash
vizzly run "npm test" --port 3002
```
**Screenshots not captured**
- Verify you're calling `vizzlyScreenshot()` in your tests
- Check that your test framework supports the Buffer API
- Ensure the image data is valid PNG format
**Test command not found**
- Use absolute paths or ensure commands are in PATH
- Quote complex commands properly
- Test your command works independently first
**Server timeout**
- Increase timeout for long-running test suites
- Check for hanging processes or infinite loops
```bash
vizzly run "npm test" --timeout 120000 # 2 minutes
```
## Best Practices
### Screenshot Naming
Use descriptive, consistent names:
```javascript
// Good
await vizzlyScreenshot('homepage-logged-out', screenshot);
await vizzlyScreenshot('dashboard-admin-view', screenshot);
// Avoid
await vizzlyScreenshot('test1', screenshot);
await vizzlyScreenshot('screenshot', screenshot);
```
### Organizing Tests
Group related screenshots with properties:
```javascript
await vizzlyScreenshot('user-profile', screenshot, {
properties: {
component: 'profile',
state: 'editing',
userType: 'admin'
}
});
```
### Performance
- Take screenshots only when necessary
- Use appropriate image sizes
- Consider screenshot timing in your tests
## Next Steps
- Learn about [TDD Mode](./tdd-mode.md) for local development
- Explore [Upload Command](./upload-command.md) for direct uploads
- Check the [API Reference](./api-reference.md) for detailed function documentation