@vizzly-testing/cli 0.35.3-beta.3 → 0.35.3-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/dist/api/core.js +12 -5
- package/dist/api/endpoints.js +4 -4
- package/dist/client/index.js +2 -1
- package/dist/screenshot-server/core.js +5 -1
- package/dist/sdk/index.js +2 -1
- package/dist/server/handlers/api-handler.js +18 -2
- package/dist/server/handlers/tdd-handler.js +10 -4
- package/dist/server/routers/screenshot.js +25 -2
- package/dist/tdd/tdd-service.js +3 -3
- package/dist/types/index.d.ts +5 -1
- package/dist/utils/screenshot-options.js +61 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,10 +153,9 @@ test('homepage looks correct', async ({ page }) => {
|
|
|
153
153
|
|
|
154
154
|
`properties` is your metadata bag for baseline grouping, filtering, and
|
|
155
155
|
debugging. SDK options such as `threshold`, `minClusterSize`, `fullPage`,
|
|
156
|
-
`requestTimeout`, and `buildId` stay at the top level.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
be cleaned up.
|
|
156
|
+
`requestTimeout`, and `buildId` stay at the top level. Reserved SDK and capture
|
|
157
|
+
fields inside `properties` are ignored and produce a warning; they are never
|
|
158
|
+
interpreted as options or stored as user metadata.
|
|
160
159
|
|
|
161
160
|
The client SDK is lightweight. It posts screenshots to the local Vizzly server
|
|
162
161
|
or the cloud build wrapper. It works with any test runner.
|
package/dist/api/core.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import crypto from 'node:crypto';
|
|
9
9
|
import { URLSearchParams } from 'node:url';
|
|
10
|
+
import { createScreenshotProperties, getScreenshotOptionsPayload } from '../utils/screenshot-options.js';
|
|
10
11
|
|
|
11
12
|
// ============================================================================
|
|
12
13
|
// Header Building
|
|
@@ -77,11 +78,14 @@ export function buildRequestHeaders({
|
|
|
77
78
|
* @param {string|null} sha256 - Pre-computed SHA256 hash (optional)
|
|
78
79
|
* @returns {Object} Screenshot upload payload
|
|
79
80
|
*/
|
|
80
|
-
export function buildScreenshotPayload(name, buffer, metadata = {}, sha256 = null) {
|
|
81
|
+
export function buildScreenshotPayload(name, buffer, metadata = {}, sha256 = null, screenshotOptions = {}) {
|
|
81
82
|
let payload = {
|
|
82
83
|
name,
|
|
83
|
-
properties:
|
|
84
|
+
properties: createScreenshotProperties({
|
|
85
|
+
properties: metadata
|
|
86
|
+
})
|
|
84
87
|
};
|
|
88
|
+
Object.assign(payload, getScreenshotOptionsPayload(screenshotOptions));
|
|
85
89
|
if (buffer) {
|
|
86
90
|
payload.image_data = buffer.toString('base64');
|
|
87
91
|
}
|
|
@@ -98,8 +102,8 @@ export function buildScreenshotPayload(name, buffer, metadata = {}, sha256 = nul
|
|
|
98
102
|
* @param {string} sha256 - Pre-computed SHA256 hash
|
|
99
103
|
* @returns {Object} Screenshot resolution payload
|
|
100
104
|
*/
|
|
101
|
-
export function buildScreenshotResolvePayload(name, metadata = {}, sha256) {
|
|
102
|
-
return buildScreenshotPayload(name, null, metadata, sha256);
|
|
105
|
+
export function buildScreenshotResolvePayload(name, metadata = {}, sha256, screenshotOptions = {}) {
|
|
106
|
+
return buildScreenshotPayload(name, null, metadata, sha256, screenshotOptions);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
/**
|
|
@@ -180,13 +184,16 @@ export function buildShaCheckPayload(screenshots, buildId) {
|
|
|
180
184
|
*/
|
|
181
185
|
export function buildScreenshotCheckObject(sha256, name, metadata = {}) {
|
|
182
186
|
let meta = metadata || {};
|
|
187
|
+
let properties = createScreenshotProperties({
|
|
188
|
+
properties: meta
|
|
189
|
+
});
|
|
183
190
|
return {
|
|
184
191
|
sha256,
|
|
185
192
|
name,
|
|
186
193
|
browser: meta.browser || 'chrome',
|
|
187
194
|
viewport_width: meta.viewport?.width || meta.viewport_width || 1920,
|
|
188
195
|
viewport_height: meta.viewport?.height || meta.viewport_height || 1080,
|
|
189
|
-
properties
|
|
196
|
+
properties
|
|
190
197
|
};
|
|
191
198
|
}
|
|
192
199
|
|
package/dist/api/endpoints.js
CHANGED
|
@@ -179,10 +179,10 @@ function canUploadBytesAfterShaResolveError(error) {
|
|
|
179
179
|
* @param {boolean} skipDedup - Skip SHA deduplication (uploadAll mode)
|
|
180
180
|
* @returns {Promise<Object>} Upload result
|
|
181
181
|
*/
|
|
182
|
-
export async function uploadScreenshot(client, buildId, name, buffer, metadata = {}, skipDedup = false) {
|
|
182
|
+
export async function uploadScreenshot(client, buildId, name, buffer, metadata = {}, skipDedup = false, screenshotOptions = {}) {
|
|
183
183
|
// Skip SHA deduplication if requested
|
|
184
184
|
if (skipDedup) {
|
|
185
|
-
let payload = buildScreenshotPayload(name, buffer, metadata);
|
|
185
|
+
let payload = buildScreenshotPayload(name, buffer, metadata, null, screenshotOptions);
|
|
186
186
|
return client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
187
187
|
method: 'POST',
|
|
188
188
|
headers: {
|
|
@@ -194,7 +194,7 @@ export async function uploadScreenshot(client, buildId, name, buffer, metadata =
|
|
|
194
194
|
|
|
195
195
|
// Normal flow with server-side SHA resolution.
|
|
196
196
|
let sha256 = computeSha256(buffer);
|
|
197
|
-
let resolvePayload = buildScreenshotResolvePayload(name, metadata, sha256);
|
|
197
|
+
let resolvePayload = buildScreenshotResolvePayload(name, metadata, sha256, screenshotOptions);
|
|
198
198
|
try {
|
|
199
199
|
let resolveResult = await client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
200
200
|
method: 'POST',
|
|
@@ -222,7 +222,7 @@ export async function uploadScreenshot(client, buildId, name, buffer, metadata =
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
// File doesn't exist, or resolve failed; proceed with upload.
|
|
225
|
-
let payload = buildScreenshotPayload(name, buffer, metadata, sha256);
|
|
225
|
+
let payload = buildScreenshotPayload(name, buffer, metadata, sha256, screenshotOptions);
|
|
226
226
|
return client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
227
227
|
method: 'POST',
|
|
228
228
|
headers: {
|
package/dist/client/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { request as httpRequest } from 'node:http';
|
|
|
8
8
|
import { request as httpsRequest } from 'node:https';
|
|
9
9
|
import { dirname, join, parse } from 'node:path';
|
|
10
10
|
import { getBuildId, getServerUrl, isTddMode, setVizzlyEnabled } from '../utils/environment-config.js';
|
|
11
|
-
import { normalizeScreenshotOptions } from '../utils/screenshot-options.js';
|
|
11
|
+
import { getScreenshotOptionsPayload, normalizeScreenshotOptions } from '../utils/screenshot-options.js';
|
|
12
12
|
|
|
13
13
|
// Internal client state
|
|
14
14
|
let currentClient = null;
|
|
@@ -219,6 +219,7 @@ function createSimpleClient(serverUrl, clientOptions = {}) {
|
|
|
219
219
|
type,
|
|
220
220
|
properties: normalizedOptions.properties
|
|
221
221
|
};
|
|
222
|
+
Object.assign(screenshotData, getScreenshotOptionsPayload(normalizedOptions));
|
|
222
223
|
if (normalizedOptions.warnings.length > 0) {
|
|
223
224
|
screenshotData.warnings = normalizedOptions.warnings;
|
|
224
225
|
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* No I/O, no side effects - just data transformations.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { getScreenshotOptionsPayload } from '../utils/screenshot-options.js';
|
|
8
|
+
|
|
7
9
|
// ============================================================================
|
|
8
10
|
// Request Validation
|
|
9
11
|
// ============================================================================
|
|
@@ -149,9 +151,11 @@ export function buildServerStoppedMessage() {
|
|
|
149
151
|
* @returns {{ name: string, image: string, properties?: Object }}
|
|
150
152
|
*/
|
|
151
153
|
export function extractScreenshotData(body) {
|
|
152
|
-
|
|
154
|
+
let screenshotData = {
|
|
153
155
|
name: body.name,
|
|
154
156
|
image: body.image,
|
|
155
157
|
properties: body.properties
|
|
156
158
|
};
|
|
159
|
+
Object.assign(screenshotData, getScreenshotOptionsPayload(body));
|
|
160
|
+
return screenshotData;
|
|
157
161
|
}
|
package/dist/sdk/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { createUploader } from '../uploader/index.js';
|
|
|
19
19
|
import { loadConfig } from '../utils/config-loader.js';
|
|
20
20
|
import { resolveImageBuffer } from '../utils/file-helpers.js';
|
|
21
21
|
import * as output from '../utils/output.js';
|
|
22
|
-
import { normalizeScreenshotOptions } from '../utils/screenshot-options.js';
|
|
22
|
+
import { getScreenshotOptionsPayload, normalizeScreenshotOptions } from '../utils/screenshot-options.js';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Create a new Vizzly instance with custom configuration
|
|
@@ -314,6 +314,7 @@ export class VizzlySDK extends EventEmitter {
|
|
|
314
314
|
type: 'base64',
|
|
315
315
|
properties: normalizedOptions.properties
|
|
316
316
|
};
|
|
317
|
+
Object.assign(screenshotData, getScreenshotOptionsPayload(normalizedOptions));
|
|
317
318
|
if (normalizedOptions.warnings.length > 0) {
|
|
318
319
|
screenshotData.warnings = normalizedOptions.warnings;
|
|
319
320
|
}
|
|
@@ -4,6 +4,7 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
import { uploadScreenshot as defaultUploadScreenshot } from '../../api/index.js';
|
|
5
5
|
import { detectImageInputType } from '../../utils/image-input-detector.js';
|
|
6
6
|
import * as output from '../../utils/output.js';
|
|
7
|
+
import { normalizeScreenshotOptions } from '../../utils/screenshot-options.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* API Handler - Non-blocking screenshot upload
|
|
@@ -47,8 +48,23 @@ export const createApiHandler = (client, {
|
|
|
47
48
|
let vizzlyDisabled = false;
|
|
48
49
|
let screenshotCount = 0;
|
|
49
50
|
let uploadPromises = [];
|
|
50
|
-
const handleScreenshot = async (buildId, name, image, properties = {}, type, warnings = []) => {
|
|
51
|
+
const handleScreenshot = async (buildId, name, image, properties = {}, type, warnings = [], screenshotOptions = {}) => {
|
|
51
52
|
let handlerStart = Date.now();
|
|
53
|
+
let normalizedOptions = normalizeScreenshotOptions({
|
|
54
|
+
...screenshotOptions,
|
|
55
|
+
properties
|
|
56
|
+
});
|
|
57
|
+
properties = normalizedOptions.properties;
|
|
58
|
+
screenshotOptions = {
|
|
59
|
+
...screenshotOptions,
|
|
60
|
+
threshold: normalizedOptions.threshold,
|
|
61
|
+
minClusterSize: normalizedOptions.minClusterSize,
|
|
62
|
+
fullPage: normalizedOptions.fullPage,
|
|
63
|
+
captureMode: normalizedOptions.captureMode,
|
|
64
|
+
deviceScaleFactor: normalizedOptions.deviceScaleFactor,
|
|
65
|
+
selector: normalizedOptions.selector
|
|
66
|
+
};
|
|
67
|
+
warnings = [...(warnings || []), ...normalizedOptions.warnings];
|
|
52
68
|
output.debug('upload', `${name} received`, {
|
|
53
69
|
buildId: buildId?.slice(0, 8)
|
|
54
70
|
});
|
|
@@ -131,7 +147,7 @@ export const createApiHandler = (client, {
|
|
|
131
147
|
let uploadStart = Date.now();
|
|
132
148
|
|
|
133
149
|
// Fire upload in background - DON'T AWAIT!
|
|
134
|
-
let uploadPromise = uploadScreenshot(client, buildId, name, imageBuffer, properties ?? {}).then(result => {
|
|
150
|
+
let uploadPromise = uploadScreenshot(client, buildId, name, imageBuffer, properties ?? {}, false, screenshotOptions).then(result => {
|
|
135
151
|
let duration = Date.now() - uploadStart;
|
|
136
152
|
if (!result.skipped) {
|
|
137
153
|
output.debug('upload', `${name} completed`, {
|
|
@@ -5,6 +5,7 @@ import { getDimensionsSync as defaultGetDimensionsSync } from '@vizzly-testing/h
|
|
|
5
5
|
import { TddService as DefaultTddService } from '../../tdd/tdd-service.js';
|
|
6
6
|
import { detectImageInputType as defaultDetectImageInputType } from '../../utils/image-input-detector.js';
|
|
7
7
|
import * as defaultOutput from '../../utils/output.js';
|
|
8
|
+
import { normalizeScreenshotOptions } from '../../utils/screenshot-options.js';
|
|
8
9
|
import { safePath as defaultSafePath, sanitizeScreenshotName as defaultSanitizeScreenshotName, validateScreenshotProperties as defaultValidateScreenshotProperties } from '../../utils/security.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -305,7 +306,7 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
305
306
|
output.debug('tdd', `baseline: ${baseline.buildName}`);
|
|
306
307
|
}
|
|
307
308
|
};
|
|
308
|
-
const handleScreenshot = async (_buildId, name, image, properties = {}, type, warnings = []) => {
|
|
309
|
+
const handleScreenshot = async (_buildId, name, image, properties = {}, type, warnings = [], screenshotOptions = {}) => {
|
|
309
310
|
let handlerStart = Date.now();
|
|
310
311
|
output.debug('tdd', `${name} received`);
|
|
311
312
|
|
|
@@ -324,13 +325,18 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
324
325
|
};
|
|
325
326
|
}
|
|
326
327
|
|
|
327
|
-
//
|
|
328
|
+
// Preserve the old nested wrapper for older clients, then filter user
|
|
329
|
+
// properties before local comparison/report serialization.
|
|
328
330
|
let unwrappedProperties = unwrapProperties(properties);
|
|
331
|
+
let normalizedProperties = normalizeScreenshotOptions({
|
|
332
|
+
properties: unwrappedProperties
|
|
333
|
+
});
|
|
334
|
+
warnings = [...(warnings || []), ...normalizedProperties.warnings];
|
|
329
335
|
|
|
330
336
|
// Validate and sanitize properties
|
|
331
337
|
let validatedProperties;
|
|
332
338
|
try {
|
|
333
|
-
validatedProperties = validateScreenshotProperties(
|
|
339
|
+
validatedProperties = validateScreenshotProperties(normalizedProperties.properties);
|
|
334
340
|
} catch (error) {
|
|
335
341
|
return {
|
|
336
342
|
statusCode: 400,
|
|
@@ -419,7 +425,7 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
|
|
|
419
425
|
|
|
420
426
|
// Use the sanitized name as-is (no modification with browser/viewport)
|
|
421
427
|
// Baseline matching uses signature logic (name + viewport_width + browser)
|
|
422
|
-
const comparison = await tddService.compareScreenshot(sanitizedName, imageBuffer, extractedProperties);
|
|
428
|
+
const comparison = await tddService.compareScreenshot(sanitizedName, imageBuffer, extractedProperties, screenshotOptions);
|
|
423
429
|
|
|
424
430
|
// Comparison tracked by tdd.js event handler
|
|
425
431
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as output from '../../utils/output.js';
|
|
7
|
+
import { normalizeScreenshotOptions } from '../../utils/screenshot-options.js';
|
|
7
8
|
import { parseJsonBody } from '../middleware/json-parser.js';
|
|
8
9
|
import { sendError, sendJson } from '../middleware/response.js';
|
|
9
10
|
|
|
@@ -33,7 +34,13 @@ export function createScreenshotRouter({
|
|
|
33
34
|
properties,
|
|
34
35
|
image,
|
|
35
36
|
type,
|
|
36
|
-
warnings
|
|
37
|
+
warnings,
|
|
38
|
+
threshold,
|
|
39
|
+
minClusterSize,
|
|
40
|
+
fullPage,
|
|
41
|
+
captureMode,
|
|
42
|
+
deviceScaleFactor,
|
|
43
|
+
selector
|
|
37
44
|
} = body;
|
|
38
45
|
if (!name || !image) {
|
|
39
46
|
sendError(res, 400, 'name and image are required');
|
|
@@ -42,7 +49,23 @@ export function createScreenshotRouter({
|
|
|
42
49
|
|
|
43
50
|
// Use buildId from request body, or fall back to server's buildId
|
|
44
51
|
const effectiveBuildId = buildId || defaultBuildId;
|
|
45
|
-
const
|
|
52
|
+
const normalizedOptions = normalizeScreenshotOptions({
|
|
53
|
+
properties,
|
|
54
|
+
threshold,
|
|
55
|
+
minClusterSize,
|
|
56
|
+
fullPage,
|
|
57
|
+
captureMode,
|
|
58
|
+
deviceScaleFactor,
|
|
59
|
+
selector
|
|
60
|
+
});
|
|
61
|
+
const result = await screenshotHandler.handleScreenshot(effectiveBuildId, name, image, normalizedOptions.properties, type, [...(warnings || []), ...normalizedOptions.warnings], {
|
|
62
|
+
threshold: normalizedOptions.threshold,
|
|
63
|
+
minClusterSize: normalizedOptions.minClusterSize,
|
|
64
|
+
fullPage: normalizedOptions.fullPage,
|
|
65
|
+
captureMode: normalizedOptions.captureMode,
|
|
66
|
+
deviceScaleFactor: normalizedOptions.deviceScaleFactor,
|
|
67
|
+
selector: normalizedOptions.selector
|
|
68
|
+
});
|
|
46
69
|
sendJson(res, result.statusCode, result.body);
|
|
47
70
|
return true;
|
|
48
71
|
} catch (error) {
|
package/dist/tdd/tdd-service.js
CHANGED
|
@@ -752,7 +752,7 @@ export class TddService {
|
|
|
752
752
|
/**
|
|
753
753
|
* Compare a screenshot against baseline
|
|
754
754
|
*/
|
|
755
|
-
async compareScreenshot(name, imageBuffer, properties = {}) {
|
|
755
|
+
async compareScreenshot(name, imageBuffer, properties = {}, screenshotOptions = {}) {
|
|
756
756
|
// Destructure dependencies
|
|
757
757
|
let {
|
|
758
758
|
output,
|
|
@@ -850,8 +850,8 @@ export class TddService {
|
|
|
850
850
|
}
|
|
851
851
|
|
|
852
852
|
// Baseline exists - compare
|
|
853
|
-
let effectiveThreshold = typeof
|
|
854
|
-
let effectiveMinClusterSize = Number.isInteger(
|
|
853
|
+
let effectiveThreshold = typeof screenshotOptions.threshold === 'number' && screenshotOptions.threshold >= 0 ? screenshotOptions.threshold : this.threshold;
|
|
854
|
+
let effectiveMinClusterSize = Number.isInteger(screenshotOptions.minClusterSize) && screenshotOptions.minClusterSize >= 1 ? screenshotOptions.minClusterSize : this.minClusterSize;
|
|
855
855
|
try {
|
|
856
856
|
let honeydiffResult = await compareImages(baselineImagePath, currentImagePath, diffImagePath, {
|
|
857
857
|
threshold: effectiveThreshold,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -401,7 +401,11 @@ export interface TddService {
|
|
|
401
401
|
compareScreenshot(
|
|
402
402
|
name: string,
|
|
403
403
|
imageBuffer: Buffer,
|
|
404
|
-
properties?: Record<string, unknown
|
|
404
|
+
properties?: Record<string, unknown>,
|
|
405
|
+
screenshotOptions?: Pick<
|
|
406
|
+
ScreenshotOptions,
|
|
407
|
+
'threshold' | 'minClusterSize' | 'fullPage'
|
|
408
|
+
>
|
|
405
409
|
): Promise<ComparisonResult>;
|
|
406
410
|
|
|
407
411
|
getResults(): TddResults;
|
|
@@ -9,16 +9,62 @@ export let RESERVED_PROPERTY_OPTIONS = Object.freeze({
|
|
|
9
9
|
minClusterSize: {
|
|
10
10
|
message: 'Move "minClusterSize" out of properties; properties is only for user metadata.'
|
|
11
11
|
},
|
|
12
|
+
min_cluster_size: {
|
|
13
|
+
message: 'Move "min_cluster_size" out of properties; properties is only for user metadata.'
|
|
14
|
+
},
|
|
12
15
|
fullPage: {
|
|
13
16
|
message: 'Move "fullPage" out of properties; properties is only for user metadata.'
|
|
14
17
|
},
|
|
18
|
+
full_page: {
|
|
19
|
+
message: 'Move "full_page" out of properties; properties is only for user metadata.'
|
|
20
|
+
},
|
|
21
|
+
captureMode: {
|
|
22
|
+
message: 'Move "captureMode" out of properties; properties is only for user metadata.'
|
|
23
|
+
},
|
|
24
|
+
capture_mode: {
|
|
25
|
+
message: 'Move "capture_mode" out of properties; properties is only for user metadata.'
|
|
26
|
+
},
|
|
27
|
+
deviceScaleFactor: {
|
|
28
|
+
message: 'Move "deviceScaleFactor" out of properties; properties is only for user metadata.'
|
|
29
|
+
},
|
|
30
|
+
device_scale_factor: {
|
|
31
|
+
message: 'Move "device_scale_factor" out of properties; properties is only for user metadata.'
|
|
32
|
+
},
|
|
33
|
+
pixelRatio: {
|
|
34
|
+
message: 'Move "pixelRatio" out of properties; properties is only for user metadata.'
|
|
35
|
+
},
|
|
36
|
+
dpr: {
|
|
37
|
+
message: 'Move "dpr" out of properties; properties is only for user metadata.'
|
|
38
|
+
},
|
|
39
|
+
selector: {
|
|
40
|
+
message: 'Move "selector" out of properties; properties is only for user metadata.'
|
|
41
|
+
},
|
|
42
|
+
component: {
|
|
43
|
+
message: 'Move "component" out of properties; properties is only for user metadata.'
|
|
44
|
+
},
|
|
45
|
+
elementSelector: {
|
|
46
|
+
message: 'Move "elementSelector" out of properties; properties is only for user metadata.'
|
|
47
|
+
},
|
|
48
|
+
element_selector: {
|
|
49
|
+
message: 'Move "element_selector" out of properties; properties is only for user metadata.'
|
|
50
|
+
},
|
|
15
51
|
buildId: {
|
|
16
52
|
message: 'Move "buildId" out of properties; properties is only for user metadata.'
|
|
17
53
|
},
|
|
54
|
+
build_id: {
|
|
55
|
+
message: 'Move "build_id" out of properties; properties is only for user metadata.'
|
|
56
|
+
},
|
|
18
57
|
requestTimeout: {
|
|
19
58
|
message: 'Move "requestTimeout" out of properties; properties is only for user metadata.'
|
|
59
|
+
},
|
|
60
|
+
request_timeout: {
|
|
61
|
+
message: 'Move "request_timeout" out of properties; properties is only for user metadata.'
|
|
20
62
|
}
|
|
21
63
|
});
|
|
64
|
+
export let SCREENSHOT_OPTION_NAMES = Object.freeze(['threshold', 'minClusterSize', 'fullPage', 'captureMode', 'deviceScaleFactor', 'selector']);
|
|
65
|
+
export function getScreenshotOptionsPayload(options = {}) {
|
|
66
|
+
return Object.fromEntries(SCREENSHOT_OPTION_NAMES.filter(option => options[option] !== undefined).map(option => [option, options[option]]));
|
|
67
|
+
}
|
|
22
68
|
function createReservedPropertyWarning(option) {
|
|
23
69
|
return {
|
|
24
70
|
code: 'reserved-property-option',
|
|
@@ -28,8 +74,9 @@ function createReservedPropertyWarning(option) {
|
|
|
28
74
|
}
|
|
29
75
|
|
|
30
76
|
/**
|
|
31
|
-
* Normalize screenshot SDK options into the
|
|
32
|
-
*
|
|
77
|
+
* Normalize screenshot SDK options into the local and cloud upload payload.
|
|
78
|
+
* Reserved names found inside properties are discarded instead of being promoted
|
|
79
|
+
* into options.
|
|
33
80
|
*/
|
|
34
81
|
export function normalizeScreenshotOptions(options = {}) {
|
|
35
82
|
let {
|
|
@@ -38,38 +85,30 @@ export function normalizeScreenshotOptions(options = {}) {
|
|
|
38
85
|
requestTimeout,
|
|
39
86
|
threshold,
|
|
40
87
|
minClusterSize,
|
|
41
|
-
fullPage
|
|
88
|
+
fullPage,
|
|
89
|
+
captureMode,
|
|
90
|
+
deviceScaleFactor,
|
|
91
|
+
selector
|
|
42
92
|
} = options;
|
|
43
93
|
let warnings = [];
|
|
44
94
|
let normalizedProperties = {};
|
|
45
|
-
|
|
95
|
+
let sourceProperties = properties && typeof properties === 'object' && !Array.isArray(properties) ? properties : {};
|
|
96
|
+
for (let [key, value] of Object.entries(sourceProperties)) {
|
|
46
97
|
if (RESERVED_PROPERTY_OPTIONS[key]) {
|
|
47
98
|
warnings.push(createReservedPropertyWarning(key));
|
|
48
|
-
if (key === 'threshold' && threshold === undefined) threshold = value;
|
|
49
|
-
if (key === 'minClusterSize' && minClusterSize === undefined) {
|
|
50
|
-
minClusterSize = value;
|
|
51
|
-
}
|
|
52
|
-
if (key === 'fullPage' && fullPage === undefined) fullPage = value;
|
|
53
|
-
if (key === 'buildId' && buildId === undefined) buildId = value;
|
|
54
|
-
if (key === 'requestTimeout' && requestTimeout === undefined) {
|
|
55
|
-
requestTimeout = value;
|
|
56
|
-
}
|
|
57
99
|
continue;
|
|
58
100
|
}
|
|
59
101
|
normalizedProperties[key] = value;
|
|
60
102
|
}
|
|
61
|
-
if (threshold !== undefined) {
|
|
62
|
-
normalizedProperties.threshold = threshold;
|
|
63
|
-
}
|
|
64
|
-
if (minClusterSize !== undefined) {
|
|
65
|
-
normalizedProperties.minClusterSize = minClusterSize;
|
|
66
|
-
}
|
|
67
|
-
if (fullPage !== undefined) {
|
|
68
|
-
normalizedProperties.fullPage = fullPage;
|
|
69
|
-
}
|
|
70
103
|
return {
|
|
71
104
|
buildId,
|
|
72
105
|
requestTimeout,
|
|
106
|
+
threshold,
|
|
107
|
+
minClusterSize,
|
|
108
|
+
fullPage,
|
|
109
|
+
captureMode,
|
|
110
|
+
deviceScaleFactor,
|
|
111
|
+
selector,
|
|
73
112
|
properties: normalizedProperties,
|
|
74
113
|
warnings
|
|
75
114
|
};
|