Skip to content
Closed
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
3 changes: 3 additions & 0 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@ function createSimpleClient(serverUrl, clientOptions = {}) {
* @param {number} [options.threshold] - CIEDE2000 Delta E threshold for this screenshot
* @param {number} [options.minClusterSize] - Minimum changed cluster size for this screenshot
* @param {boolean} [options.fullPage] - Whether this is a full page screenshot
* @param {string} [options.captureMode] - Capture coordinate mode
* @param {number} [options.deviceScaleFactor] - Bitmap pixels per CSS pixel
* @param {string} [options.selector] - Selector used for an element capture
*
* @returns {Promise<Object|null>} Screenshot result from the server, or null when capture is skipped
*
Expand Down
6 changes: 6 additions & 0 deletions src/types/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ export function vizzlyScreenshot(
threshold?: number;
minClusterSize?: number;
fullPage?: boolean;
/** Coordinate frame used by the harness that captured the image. */
captureMode?: 'viewport' | 'full_page' | 'element' | 'component';
/** Bitmap pixels per CSS pixel reported by the capture harness. */
deviceScaleFactor?: number;
/** Exact selector used when captureMode is element or component. */
selector?: string;
/** Transport-only build ID used to route the request. */
buildId?: string;
/** Client-side HTTP timeout in milliseconds; not stored as metadata. */
Expand Down
6 changes: 6 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ export interface ScreenshotOptions {
threshold?: number;
minClusterSize?: number;
fullPage?: boolean;
/** Coordinate frame used by the harness that captured the image. */
captureMode?: 'viewport' | 'full_page' | 'element' | 'component';
/** Bitmap pixels per CSS pixel reported by the capture harness. */
deviceScaleFactor?: number;
/** Exact selector used when captureMode is element or component. */
selector?: string;
/** Transport-only build ID used to route the request. */
buildId?: string;
/** Client-side HTTP timeout in milliseconds; not stored as metadata. */
Expand Down
38 changes: 38 additions & 0 deletions src/utils/screenshot-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ export let RESERVED_PROPERTY_OPTIONS = Object.freeze({
message:
'Move "fullPage" out of properties; properties is only for user metadata.',
},
captureMode: {
message:
'Move "captureMode" out of properties; properties is only for user metadata.',
},
deviceScaleFactor: {
message:
'Move "deviceScaleFactor" out of properties; properties is only for user metadata.',
},
selector: {
message:
'Move "selector" out of properties; properties is only for user metadata.',
},
buildId: {
message:
'Move "buildId" out of properties; properties is only for user metadata.',
Expand All @@ -36,6 +48,10 @@ function createReservedPropertyWarning(option) {
/**
* Normalize screenshot SDK options into the properties payload consumed by the
* local TDD server and cloud-compatible comparison path.
*
* Capture geometry is reserved because the cloud must receive the facts from the
* harness that took the image. Dropping these values would force the API to guess
* a coordinate space from bitmap dimensions after the capture already happened.
*/
export function normalizeScreenshotOptions(options = {}) {
let {
Expand All @@ -45,6 +61,9 @@ export function normalizeScreenshotOptions(options = {}) {
threshold,
minClusterSize,
fullPage,
captureMode,
deviceScaleFactor,
selector,
} = options;

let warnings = [];
Expand All @@ -59,6 +78,13 @@ export function normalizeScreenshotOptions(options = {}) {
minClusterSize = value;
}
if (key === 'fullPage' && fullPage === undefined) fullPage = value;
if (key === 'captureMode' && captureMode === undefined) {
captureMode = value;
}
if (key === 'deviceScaleFactor' && deviceScaleFactor === undefined) {
deviceScaleFactor = value;
}
if (key === 'selector' && selector === undefined) selector = value;
if (key === 'buildId' && buildId === undefined) buildId = value;
if (key === 'requestTimeout' && requestTimeout === undefined) {
requestTimeout = value;
Expand All @@ -82,6 +108,18 @@ export function normalizeScreenshotOptions(options = {}) {
normalizedProperties.fullPage = fullPage;
}

if (captureMode !== undefined) {
normalizedProperties.captureMode = captureMode;
}

if (deviceScaleFactor !== undefined) {
normalizedProperties.deviceScaleFactor = deviceScaleFactor;
}

if (selector !== undefined) {
normalizedProperties.selector = selector;
}

return {
buildId,
requestTimeout,
Expand Down
21 changes: 21 additions & 0 deletions tests/sdk/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,27 @@ describe('client/index httpPost integration tests', () => {
});
});

it('preserves capture geometry for cloud identity and region evidence', async () => {
await vizzlyScreenshot('test', Buffer.from('data'), {
captureMode: 'element',
deviceScaleFactor: 2,
selector: '[data-testid="account-card"]',
properties: {
browser: 'chromium',
viewport: { width: 1440, height: 900 },
},
});

assert.strictEqual(requests.length, 1);
assert.deepStrictEqual(requests[0].body.properties, {
browser: 'chromium',
viewport: { width: 1440, height: 900 },
captureMode: 'element',
deviceScaleFactor: 2,
selector: '[data-testid="account-card"]',
});
});

it('lets explicit comparison options override nested properties', async () => {
await vizzlyScreenshot('test', Buffer.from('data'), {
threshold: 0,
Expand Down