Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,19 @@ vizzly tdd run "npm test"
```javascript
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';

// Your test framework takes the screenshot
// Option 1: Using a Buffer
const screenshot = await page.screenshot();

// Send to Vizzly for review
await vizzlyScreenshot('homepage', screenshot, {
browser: 'chrome',
viewport: '1920x1080'
});

// Option 2: Using a file path
await page.screenshot({ path: './screenshots/homepage.png' });
await vizzlyScreenshot('homepage', './screenshots/homepage.png', {
browser: 'chrome',
viewport: '1920x1080'
});
```

> **Multi-Language Support**: Currently available as a JavaScript/Node.js SDK with Python, Ruby, and
Expand Down Expand Up @@ -360,9 +365,14 @@ The `--wait` flag ensures the process:
### `vizzlyScreenshot(name, imageBuffer, properties)`
Send a screenshot to Vizzly.
- `name` (string): Screenshot identifier
- `imageBuffer` (Buffer): Image data
- `imageBuffer` (Buffer | string): Image data as Buffer, or file path to an image
- `properties` (object): Metadata for organization

**File Path Support:**
- Accepts both absolute and relative paths
- Automatically reads the file and converts to Buffer internally
- Works with any PNG image file

### `isVizzlyEnabled()`
Check if Vizzly is enabled in the current environment.

Expand Down
63 changes: 59 additions & 4 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ Capture a screenshot for visual regression testing.

**Parameters:**
- `name` (string) - Unique screenshot identifier
- `imageBuffer` (Buffer) - PNG image data as Buffer
- `imageBuffer` (Buffer | string) - PNG image data as Buffer, or file path to an image
- `options` (object, optional) - Configuration and metadata

**Options:**
```javascript
{
// Comparison settings
threshold: 0.01, // Pixel difference threshold (0-1)

// Metadata for organization (all optional)
properties: {
browser: 'chrome', // Browser name
Expand All @@ -39,7 +39,10 @@ Capture a screenshot for visual regression testing.

**Returns:** `Promise<void>`

**Example:**
**Examples:**

Using a Buffer:

```javascript
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';

Expand All @@ -54,6 +57,31 @@ await vizzlyScreenshot('homepage', screenshot, {
});
```

Using a file path:

```javascript
import { vizzlyScreenshot } from '@vizzly-testing/cli/client';

// Save screenshot to file
await page.screenshot({ path: './screenshots/homepage.png' });

// Send to Vizzly using file path
await vizzlyScreenshot('homepage', './screenshots/homepage.png', {
threshold: 0.02,
properties: {
browser: 'chrome',
viewport: '1920x1080',
component: 'hero-section'
}
});
```

**File Path Support:**
- Accepts both absolute and relative paths
- Automatically reads the file and converts to Buffer internally
- Throws error if file doesn't exist or cannot be read
- Works with any PNG image file

### `vizzlyFlush()`

Wait for all queued screenshots to be processed.
Expand Down Expand Up @@ -201,10 +229,24 @@ Stop the Vizzly server and cleanup resources.
**Returns:** `Promise<void>`

##### `screenshot(name, imageBuffer, options)`
Capture a screenshot (same as client API).
Capture a screenshot.

**Parameters:**
- `name` (string) - Unique screenshot identifier
- `imageBuffer` (Buffer | string) - PNG image data as Buffer, or file path to an image
- `options` (object, optional) - Configuration and metadata

**Returns:** `Promise<void>`

**Example:**
```javascript
// Using a Buffer
await vizzly.screenshot('homepage', buffer);

// Using a file path
await vizzly.screenshot('homepage', './screenshots/homepage.png');
```

##### `upload(options)`
Upload screenshots to Vizzly.

Expand All @@ -224,8 +266,21 @@ Upload screenshots to Vizzly.
##### `compare(name, imageBuffer)`
Run local comparison (TDD mode).

**Parameters:**
- `name` (string) - Screenshot name
- `imageBuffer` (Buffer | string) - PNG image data as Buffer, or file path to an image

**Returns:** `Promise<ComparisonResult>`

**Example:**
```javascript
// Using a Buffer
const result = await vizzly.compare('homepage', buffer);

// Using a file path
const result = await vizzly.compare('homepage', './screenshots/homepage.png');
```

##### `getConfig()`
Get current SDK configuration.

Expand Down
70 changes: 60 additions & 10 deletions docs/test-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ The CLI automatically sets these variables for your test process:

## Adding Screenshots to Tests

Import the client and use `vizzlyScreenshot()` in your 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';
Expand All @@ -81,6 +83,28 @@ await vizzlyScreenshot('homepage', screenshot, {
});
```

### 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
Expand All @@ -91,7 +115,8 @@ 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: {
Expand All @@ -100,6 +125,16 @@ test('homepage test', async ({ page }) => {
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'
}
});
});
```

Expand All @@ -108,20 +143,25 @@ test('homepage test', async ({ page }) => {
```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' });

cy.readFile(`cypress/screenshots/${name}.png`, 'base64').then((imageBase64) => {
const imageBuffer = Buffer.from(imageBase64, 'base64');
return vizzlyScreenshot(name, imageBuffer, {

// 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
Expand All @@ -147,15 +187,25 @@ describe('Visual tests', () => {
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();
});
});
Expand Down
16 changes: 13 additions & 3 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
isTddMode,
setVizzlyEnabled,
} from '../utils/environment-config.js';
import { resolveImageBuffer } from '../utils/file-helpers.js';
import { existsSync, readFileSync } from 'fs';
import { join, parse, dirname } from 'path';

Expand Down Expand Up @@ -220,7 +221,7 @@ function createSimpleClient(serverUrl) {
* Take a screenshot for visual regression testing
*
* @param {string} name - Unique name for the screenshot
* @param {Buffer} imageBuffer - PNG image data as a Buffer
* @param {Buffer|string} imageBuffer - PNG image data as a Buffer, or a file path to an image
* @param {Object} [options] - Optional configuration
* @param {Record<string, any>} [options.properties] - Additional properties to attach to the screenshot
* @param {number} [options.threshold=0] - Pixel difference threshold (0-100)
Expand All @@ -229,13 +230,17 @@ function createSimpleClient(serverUrl) {
* @returns {Promise<void>}
*
* @example
* // Basic usage
* // Basic usage with Buffer
* import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
*
* const screenshot = await page.screenshot();
* await vizzlyScreenshot('homepage', screenshot);
*
* @example
* // Basic usage with file path
* await vizzlyScreenshot('homepage', './screenshots/homepage.png');
*
* @example
* // With properties and threshold
* await vizzlyScreenshot('checkout-form', screenshot, {
* properties: {
Expand All @@ -246,6 +251,8 @@ function createSimpleClient(serverUrl) {
* });
*
* @throws {VizzlyError} When screenshot capture fails or client is not initialized
* @throws {VizzlyError} When file path is provided but file doesn't exist
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
*/
export async function vizzlyScreenshot(name, imageBuffer, options = {}) {
if (isVizzlyDisabled()) {
Expand All @@ -264,7 +271,10 @@ export async function vizzlyScreenshot(name, imageBuffer, options = {}) {
return;
}

return client.screenshot(name, imageBuffer, options);
// Resolve Buffer or file path using shared utility
const buffer = resolveImageBuffer(imageBuffer, 'screenshot');

return client.screenshot(name, buffer, options);
}

/**
Expand Down
20 changes: 16 additions & 4 deletions src/sdk/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

import { EventEmitter } from 'events';
import { resolveImageBuffer } from '../utils/file-helpers.js';
import { createUploader } from '../services/uploader.js';
import { createTDDService } from '../services/tdd-service.js';
import { ScreenshotServer } from '../services/screenshot-server.js';
Expand Down Expand Up @@ -228,9 +229,12 @@ export class VizzlySDK extends EventEmitter {
/**
* Capture a screenshot
* @param {string} name - Screenshot name
* @param {Buffer} imageBuffer - Image data
* @param {Buffer|string} imageBuffer - Image data as a Buffer, or a file path to an image
* @param {import('../types').ScreenshotOptions} [options] - Options
* @returns {Promise<void>}
* @throws {VizzlyError} When server is not running
* @throws {VizzlyError} When file path is provided but file doesn't exist
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
*/
async screenshot(name, imageBuffer, options = {}) {
if (!this.server || !this.server.isRunning()) {
Expand All @@ -240,12 +244,15 @@ export class VizzlySDK extends EventEmitter {
);
}

// Resolve Buffer or file path using shared utility
const buffer = resolveImageBuffer(imageBuffer, 'screenshot');

// Generate or use provided build ID
const buildId = options.buildId || this.currentBuildId || 'default';
this.currentBuildId = buildId;

// Convert Buffer to base64 for JSON transport
const imageBase64 = imageBuffer.toString('base64');
const imageBase64 = buffer.toString('base64');

const screenshotData = {
buildId,
Expand Down Expand Up @@ -346,8 +353,10 @@ export class VizzlySDK extends EventEmitter {
/**
* Run local comparison in TDD mode
* @param {string} name - Screenshot name
* @param {Buffer} imageBuffer - Current image
* @param {Buffer|string} imageBuffer - Current image as a Buffer, or a file path to an image
* @returns {Promise<import('../types').ComparisonResult>} Comparison result
* @throws {VizzlyError} When file path is provided but file doesn't exist
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
*/
async compare(name, imageBuffer) {
if (!this.services?.tddService) {
Expand All @@ -357,10 +366,13 @@ export class VizzlySDK extends EventEmitter {
});
}

// Resolve Buffer or file path using shared utility
const buffer = resolveImageBuffer(imageBuffer, 'compare');

try {
const result = await this.services.tddService.compareScreenshot(
name,
imageBuffer
buffer
);
this.emit('comparison:completed', result);
return result;
Expand Down
Loading