@applitools/core 4.67.1 → 4.68.0
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/CHANGELOG.md +71 -0
- package/dist/autonomous/create-render-results.js +6 -1
- package/dist/autonomous/start-renders.js +16 -7
- package/dist/figma/client/figma-req.js +46 -0
- package/dist/figma/client/figma-rest.js +189 -0
- package/dist/figma/client/index.js +21 -0
- package/dist/figma/figma-images.js +62 -0
- package/dist/figma/figma.js +168 -0
- package/dist/figma/index.js +27 -0
- package/dist/figma/run-figma-check.js +82 -0
- package/dist/figma/seam.js +91 -0
- package/dist/figma/target-config.js +52 -0
- package/dist/figma/types.js +2 -0
- package/dist/figma/utils.js +128 -0
- package/dist/offline/run-offline-snapshots.js +18 -3
- package/dist/open-eyes.js +2 -0
- package/dist/ufg/build-accessibility-report-options.js +40 -0
- package/dist/ufg/check-and-close.js +14 -5
- package/dist/ufg/check.js +10 -1
- package/package.json +16 -15
- package/types/automation/types.d.ts +9 -0
- package/types/autonomous/types.d.ts +1 -0
- package/types/figma/client/figma-req.d.ts +9 -0
- package/types/figma/client/figma-rest.d.ts +24 -0
- package/types/figma/client/index.d.ts +2 -0
- package/types/figma/figma-images.d.ts +6 -0
- package/types/figma/figma.d.ts +21 -0
- package/types/figma/index.d.ts +8 -0
- package/types/figma/run-figma-check.d.ts +13 -0
- package/types/figma/seam.d.ts +12 -0
- package/types/figma/target-config.d.ts +7 -0
- package/types/figma/types.d.ts +69 -0
- package/types/figma/utils.d.ts +26 -0
- package/types/types.d.ts +1 -0
- package/types/ufg/build-accessibility-report-options.d.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.68.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.67.2...js/core@4.68.0) (2026-08-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add figmaOptions open config to all SDKs | AD-15464 ([#4052](https://github.com/Applitools-Dev/sdk/issues/4052)) ([cff2a2d](https://github.com/Applitools-Dev/sdk/commit/cff2a2d2f3d905dbfd9e12a9b7b26c61c2348935))
|
|
9
|
+
* figmaBaselines first-class open-config, in-repo resolver, all SDKs | AD-15462 ([#4021](https://github.com/Applitools-Dev/sdk/issues/4021)) ([998b3b3](https://github.com/Applitools-Dev/sdk/commit/998b3b38486669d2997f9eb11316067abbe85230))
|
|
10
|
+
* forward accessibilityReportOptions (axe-core) from render-info into the UFG render request | AD-15104 ([#4004](https://github.com/Applitools-Dev/sdk/issues/4004)) ([eef1b59](https://github.com/Applitools-Dev/sdk/commit/eef1b59feac63a488fdb9e7de73d3063cf43c8ca))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Dependencies
|
|
14
|
+
|
|
15
|
+
* @applitools/image bumped to 1.3.0
|
|
16
|
+
#### Features
|
|
17
|
+
|
|
18
|
+
* figmaBaselines first-class open-config, in-repo resolver, all SDKs | AD-15462 ([#4021](https://github.com/Applitools-Dev/sdk/issues/4021)) ([998b3b3](https://github.com/Applitools-Dev/sdk/commit/998b3b38486669d2997f9eb11316067abbe85230))
|
|
19
|
+
* @applitools/ufg-client bumped to 1.23.0
|
|
20
|
+
#### Features
|
|
21
|
+
|
|
22
|
+
* forward accessibilityReportOptions (axe-core) from render-info into the UFG render request | AD-15104 ([#4004](https://github.com/Applitools-Dev/sdk/issues/4004)) ([eef1b59](https://github.com/Applitools-Dev/sdk/commit/eef1b59feac63a488fdb9e7de73d3063cf43c8ca))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
* @applitools/screenshoter bumped to 3.12.27
|
|
27
|
+
|
|
28
|
+
* @applitools/nml-client bumped to 1.11.39
|
|
29
|
+
|
|
30
|
+
* @applitools/core-base bumped to 1.38.0
|
|
31
|
+
#### Features
|
|
32
|
+
|
|
33
|
+
* forward accessibilityReportOptions (axe-core) from render-info into the UFG render request | AD-15104 ([#4004](https://github.com/Applitools-Dev/sdk/issues/4004)) ([eef1b59](https://github.com/Applitools-Dev/sdk/commit/eef1b59feac63a488fdb9e7de73d3063cf43c8ca))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
* @applitools/ec-client bumped to 1.12.41
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## [4.67.2](https://github.com/Applitools-Dev/sdk/compare/js/core@4.67.1...js/core@4.67.2) (2026-07-30)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Dependencies
|
|
44
|
+
|
|
45
|
+
* @applitools/dom-snapshot bumped to 4.17.8
|
|
46
|
+
#### Bug Fixes
|
|
47
|
+
|
|
48
|
+
* strip basic auth from stylesheet sheet.href | FLD-4738 ([#4036](https://github.com/Applitools-Dev/sdk/issues/4036)) ([2ff5259](https://github.com/Applitools-Dev/sdk/commit/2ff525919157598df8e22650a69f59efdb448311))
|
|
49
|
+
* use sheet.href for stylesheet links | FLD-4738 ([#4033](https://github.com/Applitools-Dev/sdk/issues/4033)) ([20d2e65](https://github.com/Applitools-Dev/sdk/commit/20d2e65fb83b9680729a0565e5f4301d2ea79e04))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
* @applitools/snippets bumped to 2.9.5
|
|
54
|
+
#### Bug Fixes
|
|
55
|
+
|
|
56
|
+
* honor maxAmountToScroll in lazyLoad when scrollTop overshoots ([#4032](https://github.com/Applitools-Dev/sdk/issues/4032)) ([b4393d7](https://github.com/Applitools-Dev/sdk/commit/b4393d76cc9457c2a36896dc1bb6cbaa0c6ed2b4))
|
|
57
|
+
* @applitools/driver bumped to 1.26.7
|
|
58
|
+
|
|
59
|
+
* @applitools/spec-driver-webdriver bumped to 1.6.7
|
|
60
|
+
|
|
61
|
+
* @applitools/spec-driver-selenium bumped to 1.8.7
|
|
62
|
+
|
|
63
|
+
* @applitools/spec-driver-playwright bumped to 1.9.7
|
|
64
|
+
|
|
65
|
+
* @applitools/spec-driver-puppeteer bumped to 1.8.7
|
|
66
|
+
|
|
67
|
+
* @applitools/screenshoter bumped to 3.12.26
|
|
68
|
+
|
|
69
|
+
* @applitools/nml-client bumped to 1.11.38
|
|
70
|
+
|
|
71
|
+
* @applitools/ec-client bumped to 1.12.40
|
|
72
|
+
|
|
73
|
+
|
|
3
74
|
## [4.67.1](https://github.com/Applitools-Dev/sdk/compare/js/core@4.67.0...js/core@4.67.1) (2026-07-29)
|
|
4
75
|
|
|
5
76
|
|
|
@@ -23,6 +23,7 @@ function makeCreateRenderResults({ logger }) {
|
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
return results.map(({ selectorRegions, renderId, status, error, ...baseTarget }, index) => {
|
|
26
|
+
var _a;
|
|
26
27
|
const { elementReferences: selectors, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({
|
|
27
28
|
settings: renders[index].settings,
|
|
28
29
|
});
|
|
@@ -38,7 +39,11 @@ function makeCreateRenderResults({ logger }) {
|
|
|
38
39
|
return {
|
|
39
40
|
status,
|
|
40
41
|
error,
|
|
41
|
-
target: {
|
|
42
|
+
target: {
|
|
43
|
+
...baseTarget,
|
|
44
|
+
isTransformed: true,
|
|
45
|
+
accessibilityReportLocation: (_a = baseTarget.accessibilityReportLocation) !== null && _a !== void 0 ? _a : renders[index].accessibilityReportLocation,
|
|
46
|
+
},
|
|
42
47
|
settings: baseSettings,
|
|
43
48
|
environment: renders[index].environment,
|
|
44
49
|
account: renders[index].account,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.makeStartRenders = void 0;
|
|
4
4
|
const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
|
|
5
|
+
const build_accessibility_report_options_1 = require("../ufg/build-accessibility-report-options");
|
|
5
6
|
function makeStartRenders({ core, logger: defaultLogger }) {
|
|
6
7
|
return async function startRenders({ targets, logger = defaultLogger, }) {
|
|
7
8
|
const clients = await targets.reduce(async (promise, target) => {
|
|
@@ -25,9 +26,12 @@ function makeStartRenders({ core, logger: defaultLogger }) {
|
|
|
25
26
|
});
|
|
26
27
|
}, Promise.resolve(new Map()));
|
|
27
28
|
const renders = await Promise.all(Array.from(clients.entries(), async ([ufgClient, targets]) => {
|
|
29
|
+
const accessibilityReportOptions = targets.map(target => target.settings.accessibilitySettings
|
|
30
|
+
? (0, build_accessibility_report_options_1.buildAccessibilityReportOptions)({ accessibilityOptions: target.account.accessibilityOptions })
|
|
31
|
+
: undefined);
|
|
28
32
|
const [renders, ...environments] = await Promise.all([
|
|
29
33
|
ufgClient.startRenders({
|
|
30
|
-
renders: targets.map(target => {
|
|
34
|
+
renders: targets.map((target, index) => {
|
|
31
35
|
var _a;
|
|
32
36
|
const { elementReferences: selectors } = (0, to_base_check_settings_1.toBaseCheckSettings)({ settings: target.settings });
|
|
33
37
|
return {
|
|
@@ -41,6 +45,7 @@ function makeStartRenders({ core, logger: defaultLogger }) {
|
|
|
41
45
|
environment: target.environment,
|
|
42
46
|
uploadUrl: target.account.uploadUrl,
|
|
43
47
|
stitchingServiceUrl: target.account.stitchingServiceUrl,
|
|
48
|
+
accessibilityReportOptions: accessibilityReportOptions[index],
|
|
44
49
|
},
|
|
45
50
|
};
|
|
46
51
|
}),
|
|
@@ -54,12 +59,16 @@ function makeStartRenders({ core, logger: defaultLogger }) {
|
|
|
54
59
|
return { ...environment, properties: target.environment.properties };
|
|
55
60
|
}),
|
|
56
61
|
]);
|
|
57
|
-
return renders.map((render, index) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
return renders.map((render, index) => {
|
|
63
|
+
var _a;
|
|
64
|
+
return ({
|
|
65
|
+
render,
|
|
66
|
+
settings: targets[index].settings,
|
|
67
|
+
environment: environments[index],
|
|
68
|
+
account: targets[index].account,
|
|
69
|
+
accessibilityReportLocation: (_a = accessibilityReportOptions[index]) === null || _a === void 0 ? void 0 : _a.uploadUrl,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
63
72
|
}));
|
|
64
73
|
return renders.flat();
|
|
65
74
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeFigmaReq = exports.FIGMA_API = void 0;
|
|
4
|
+
// The Figma REST transport: `@applitools/req` configured for Figma's rate limits.
|
|
5
|
+
const req_1 = require("@applitools/req");
|
|
6
|
+
exports.FIGMA_API = 'https://api.figma.com/v1';
|
|
7
|
+
// `limit` is what bounds the number of retries, not `retryTimeout`: Figma may answer `Retry-After: 0`, and
|
|
8
|
+
// a zero delay never advances an elapsed-time budget.
|
|
9
|
+
const RETRY_LIMIT = 5;
|
|
10
|
+
// Only used when Figma omits `Retry-After`.
|
|
11
|
+
const RETRY_BACKOFF_MS = [1000, 2000, 5000, 10000];
|
|
12
|
+
function makeFigmaReq({ proxy, logger, maxRateLimitWaitSeconds = 60 } = {}) {
|
|
13
|
+
const maxWaitMs = maxRateLimitWaitSeconds * 1000;
|
|
14
|
+
return (0, req_1.makeReq)({
|
|
15
|
+
proxy,
|
|
16
|
+
retry: {
|
|
17
|
+
limit: RETRY_LIMIT,
|
|
18
|
+
timeout: RETRY_BACKOFF_MS,
|
|
19
|
+
/**
|
|
20
|
+
* Deciding here rather than with `statuses: [429]` is what enforces the wait budget. `req` sleeps
|
|
21
|
+
* `Retry-After` in full and only compares `retryTimeout` against time already ELAPSED, so accepting a
|
|
22
|
+
* retry commits to the whole delay: an hour, a day or a week each block for their full duration.
|
|
23
|
+
* (Beyond ~24.8 days it overflows `setTimeout` and fires almost immediately — wrong in the other
|
|
24
|
+
* direction.) Refusing the retry surfaces the 429 to the caller instead.
|
|
25
|
+
*/
|
|
26
|
+
validate: ({ response }) => {
|
|
27
|
+
if ((response === null || response === void 0 ? void 0 : response.status) !== 429)
|
|
28
|
+
return false;
|
|
29
|
+
const retryAfterMs = Number(response.headers.get('Retry-After')) * 1000;
|
|
30
|
+
// Unparseable (e.g. an HTTP-date) reads as NaN: retry on the backoff schedule rather than trust it.
|
|
31
|
+
if (!Number.isFinite(retryAfterMs))
|
|
32
|
+
return true;
|
|
33
|
+
if (retryAfterMs > maxWaitMs) {
|
|
34
|
+
logger === null || logger === void 0 ? void 0 : logger.log(`Figma rate limit — Retry-After of ${retryAfterMs / 1000}s exceeds the ${maxRateLimitWaitSeconds}s budget; giving up.`);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
// Logged here because `beforeRetry` fires only after the sleep, leaving a long wait unexplained.
|
|
38
|
+
if (retryAfterMs > 0)
|
|
39
|
+
logger === null || logger === void 0 ? void 0 : logger.log(`Figma rate limit — waiting ${retryAfterMs / 1000}s before retry...`);
|
|
40
|
+
return true;
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
retryTimeout: maxWaitMs,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
exports.makeFigmaReq = makeFigmaReq;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.fetchFigmaImages = exports.fetchFigmaMetadata = exports.figmaImageCacheFileName = exports.figmaNodesCacheFileName = void 0;
|
|
27
|
+
// Figma REST layer: batched /nodes + /images calls and their on-disk caches. Rate limiting, proxying and
|
|
28
|
+
// timeouts belong to the `req` instance (./figma-req).
|
|
29
|
+
// All metadata flows through fetchFigmaFileNodes so /nodes is fetched at most once per file.
|
|
30
|
+
const crypto = __importStar(require("crypto"));
|
|
31
|
+
const fs = __importStar(require("fs"));
|
|
32
|
+
const os = __importStar(require("os"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
34
|
+
const buffer_1 = require("buffer");
|
|
35
|
+
const utils_1 = require("../utils");
|
|
36
|
+
const figma_req_1 = require("./figma-req");
|
|
37
|
+
const DEFAULT_NODES_CACHE_TTL_SECONDS = 120;
|
|
38
|
+
/**
|
|
39
|
+
* Cache names are hashed because Figma node ids are not filename-safe — an instance node id looks like
|
|
40
|
+
* `I1:2;3:4`, and `:` / `;` are illegal on Windows.
|
|
41
|
+
*
|
|
42
|
+
* `test/fixtures/figma-cache/seed.mjs` mirrors both functions — keep them in sync.
|
|
43
|
+
*/
|
|
44
|
+
function figmaNodesCacheFileName(fileId, uniqueNodeIds) {
|
|
45
|
+
const hash = crypto
|
|
46
|
+
.createHash('sha1')
|
|
47
|
+
.update(`${fileId}:${[...uniqueNodeIds].sort().join(',')}`)
|
|
48
|
+
.digest('hex');
|
|
49
|
+
return `figma-nodes-${hash}.json`;
|
|
50
|
+
}
|
|
51
|
+
exports.figmaNodesCacheFileName = figmaNodesCacheFileName;
|
|
52
|
+
function figmaImageCacheFileName(fileId, nodeId, lastModifiedUnix) {
|
|
53
|
+
const hash = crypto.createHash('sha1').update(`${fileId}:${nodeId}:${lastModifiedUnix}`).digest('hex');
|
|
54
|
+
return `figma-image-${hash}.png`;
|
|
55
|
+
}
|
|
56
|
+
exports.figmaImageCacheFileName = figmaImageCacheFileName;
|
|
57
|
+
async function figmaGet(req, endpoint, accessToken) {
|
|
58
|
+
const response = await req(`${figma_req_1.FIGMA_API}${endpoint}`, {
|
|
59
|
+
headers: { 'X-Figma-Token': accessToken },
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const body = await response.text().catch(() => '');
|
|
63
|
+
throw new Error(`Figma API error ${response.status}${body ? `: ${body}` : ''}`);
|
|
64
|
+
}
|
|
65
|
+
return response.json();
|
|
66
|
+
}
|
|
67
|
+
// Grouping by file is what keeps API usage proportional to files touched, not URLs requested.
|
|
68
|
+
function groupByFile(urls) {
|
|
69
|
+
const byFile = new Map();
|
|
70
|
+
urls.forEach((url, urlIndex) => {
|
|
71
|
+
const { fileId, nodeId } = (0, utils_1.parseFigmaNodeUrl)(url);
|
|
72
|
+
if (!byFile.has(fileId))
|
|
73
|
+
byFile.set(fileId, []);
|
|
74
|
+
byFile.get(fileId).push({ nodeId, urlIndex });
|
|
75
|
+
});
|
|
76
|
+
return byFile;
|
|
77
|
+
}
|
|
78
|
+
// The single source of node metadata — both entry points route through here, so /nodes is never fetched twice.
|
|
79
|
+
async function fetchFigmaFileNodes(urls, accessToken, opts) {
|
|
80
|
+
const resolved = [];
|
|
81
|
+
for (const [fileId, nodes] of groupByFile(urls)) {
|
|
82
|
+
const uniqueNodeIds = [...new Set(nodes.map(n => n.nodeId))].sort();
|
|
83
|
+
const nodesFilePath = path.join(opts.tempPath, figmaNodesCacheFileName(fileId, uniqueNodeIds));
|
|
84
|
+
let nodesResp;
|
|
85
|
+
if (fs.existsSync(nodesFilePath)) {
|
|
86
|
+
const stat = fs.statSync(nodesFilePath);
|
|
87
|
+
const ageSeconds = (Date.now() - stat.mtimeMs) / 1000;
|
|
88
|
+
if (opts.skipApi || ageSeconds < opts.ttlSeconds) {
|
|
89
|
+
nodesResp = JSON.parse(fs.readFileSync(nodesFilePath, 'utf8'));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!nodesResp) {
|
|
93
|
+
if (opts.skipApi) {
|
|
94
|
+
throw new Error(`APPLITOOLS_FIGMA_SKIP_API is set but no nodes cache found at ${nodesFilePath}`);
|
|
95
|
+
}
|
|
96
|
+
const ids = uniqueNodeIds.map(id => encodeURIComponent(id)).join(',');
|
|
97
|
+
nodesResp = await figmaGet(opts.req, `/files/${fileId}/nodes?ids=${ids}`, accessToken);
|
|
98
|
+
fs.writeFileSync(nodesFilePath, JSON.stringify(nodesResp));
|
|
99
|
+
}
|
|
100
|
+
resolved.push({ fileId, nodesResp, nodes });
|
|
101
|
+
}
|
|
102
|
+
return resolved;
|
|
103
|
+
}
|
|
104
|
+
function metadataFromNodesResp(nodesResp, fileId, nodeId) {
|
|
105
|
+
var _a, _b, _c;
|
|
106
|
+
const nodeData = (_a = nodesResp.nodes) === null || _a === void 0 ? void 0 : _a[nodeId];
|
|
107
|
+
if (!nodeData) {
|
|
108
|
+
throw new Error(`Node "${nodeId}" not found in file "${fileId}"`);
|
|
109
|
+
}
|
|
110
|
+
const doc = nodeData.document;
|
|
111
|
+
const box = (_b = doc.absoluteBoundingBox) !== null && _b !== void 0 ? _b : doc.absoluteRenderBounds;
|
|
112
|
+
if (!box) {
|
|
113
|
+
throw new Error(`Node "${nodeId}" has no bounding box`);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
name: doc.name,
|
|
117
|
+
type: doc.type,
|
|
118
|
+
width: Math.round(box.width),
|
|
119
|
+
height: Math.round(box.height),
|
|
120
|
+
revision: String((_c = nodesResp.version) !== null && _c !== void 0 ? _c : 'unknown'),
|
|
121
|
+
lastModifiedAt: nodesResp.lastModified,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function resolveRestOptions(opts) {
|
|
125
|
+
var _a, _b, _c, _d;
|
|
126
|
+
return {
|
|
127
|
+
tempPath: (_a = opts === null || opts === void 0 ? void 0 : opts.tempPath) !== null && _a !== void 0 ? _a : os.tmpdir(),
|
|
128
|
+
ttlSeconds: (_b = opts === null || opts === void 0 ? void 0 : opts.nodesCacheTtlSeconds) !== null && _b !== void 0 ? _b : DEFAULT_NODES_CACHE_TTL_SECONDS,
|
|
129
|
+
skipApi: (_c = opts === null || opts === void 0 ? void 0 : opts.skipApi) !== null && _c !== void 0 ? _c : false,
|
|
130
|
+
req: (_d = opts === null || opts === void 0 ? void 0 : opts.req) !== null && _d !== void 0 ? _d : (0, figma_req_1.makeFigmaReq)({
|
|
131
|
+
proxy: opts === null || opts === void 0 ? void 0 : opts.proxy,
|
|
132
|
+
logger: opts === null || opts === void 0 ? void 0 : opts.logger,
|
|
133
|
+
maxRateLimitWaitSeconds: opts === null || opts === void 0 ? void 0 : opts.maxRateLimitWaitSeconds,
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// No /images render or PNG download — `test-baseline` mode sizes the viewport from metadata alone.
|
|
138
|
+
async function fetchFigmaMetadata(urls, accessToken, opts) {
|
|
139
|
+
const { tempPath, ttlSeconds, skipApi, req } = resolveRestOptions(opts);
|
|
140
|
+
const fileGroups = await fetchFigmaFileNodes(urls, accessToken, { tempPath, ttlSeconds, skipApi, req });
|
|
141
|
+
const results = new Array(urls.length);
|
|
142
|
+
for (const { fileId, nodesResp, nodes } of fileGroups) {
|
|
143
|
+
for (const { nodeId, urlIndex } of nodes) {
|
|
144
|
+
results[urlIndex] = metadataFromNodesResp(nodesResp, fileId, nodeId);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
exports.fetchFigmaMetadata = fetchFigmaMetadata;
|
|
150
|
+
async function fetchFigmaImages(urls, accessToken, opts) {
|
|
151
|
+
const { tempPath, skipApi, req } = resolveRestOptions(opts);
|
|
152
|
+
// Pass `req` through so an injected stub or proxy applies to the /nodes leg too.
|
|
153
|
+
const metadataList = await fetchFigmaMetadata(urls, accessToken, { ...opts, req });
|
|
154
|
+
const results = new Array(urls.length);
|
|
155
|
+
for (const [fileId, nodes] of groupByFile(urls)) {
|
|
156
|
+
const uniqueNodeIds = [...new Set(nodes.map(n => n.nodeId))].sort();
|
|
157
|
+
// lastModified is file-level, so any node of this file carries it. Absent ⇒ NaN, which would poison
|
|
158
|
+
// the cache key.
|
|
159
|
+
const lastModifiedMs = new Date(metadataList[nodes[0].urlIndex].lastModifiedAt).getTime();
|
|
160
|
+
const lastModifiedUnix = Number.isFinite(lastModifiedMs) ? Math.floor(lastModifiedMs / 1000) : 0;
|
|
161
|
+
const imagePathFor = (nodeId) => path.join(tempPath, figmaImageCacheFileName(fileId, nodeId, lastModifiedUnix));
|
|
162
|
+
const missNodeIds = uniqueNodeIds.filter(nodeId => !fs.existsSync(imagePathFor(nodeId)));
|
|
163
|
+
if (missNodeIds.length > 0) {
|
|
164
|
+
if (skipApi) {
|
|
165
|
+
throw new Error(`APPLITOOLS_FIGMA_SKIP_API is set but no image cache found for node ${missNodeIds[0]} in file ${fileId}`);
|
|
166
|
+
}
|
|
167
|
+
const ids = missNodeIds.map(id => encodeURIComponent(id)).join(',');
|
|
168
|
+
const imagesResp = await figmaGet(req, `/images/${fileId}?ids=${ids}&format=png&scale=1`, accessToken);
|
|
169
|
+
await Promise.all(missNodeIds.map(async (nodeId) => {
|
|
170
|
+
var _a;
|
|
171
|
+
const imageUrl = (_a = imagesResp.images) === null || _a === void 0 ? void 0 : _a[nodeId];
|
|
172
|
+
if (!imageUrl) {
|
|
173
|
+
throw new Error(`No image URL returned for node "${nodeId}"`);
|
|
174
|
+
}
|
|
175
|
+
// The CDN URL is pre-signed and carries no Figma token — no auth header here.
|
|
176
|
+
const imageResponse = await req(imageUrl);
|
|
177
|
+
if (!imageResponse.ok) {
|
|
178
|
+
throw new Error(`Failed to download Figma image: HTTP ${imageResponse.status}`);
|
|
179
|
+
}
|
|
180
|
+
fs.writeFileSync(imagePathFor(nodeId), buffer_1.Buffer.from(await imageResponse.arrayBuffer()));
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
for (const { nodeId, urlIndex } of nodes) {
|
|
184
|
+
results[urlIndex] = { imagePath: imagePathFor(nodeId), metadata: metadataList[urlIndex] };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return results;
|
|
188
|
+
}
|
|
189
|
+
exports.fetchFigmaImages = fetchFigmaImages;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// The Figma REST client: transport configuration (./figma-req) plus the batched /nodes + /images calls
|
|
18
|
+
// and their disk caches (./figma-rest). Takes logger, proxy, token, skipApi and cache settings as inputs —
|
|
19
|
+
// it reads no environment of its own.
|
|
20
|
+
__exportStar(require("./figma-req"), exports);
|
|
21
|
+
__exportStar(require("./figma-rest"), exports);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createPaddedDesignImage = exports.createPlaceholderPng = void 0;
|
|
27
|
+
// Image helpers for the Figma resolver: the white placeholder PNG for '' steps and the minViewportSize
|
|
28
|
+
// padding that centers a small design on a larger canvas. Both keyed by output dimensions so repeats reuse the file.
|
|
29
|
+
const fs = __importStar(require("fs"));
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
const image_1 = require("@applitools/image");
|
|
32
|
+
const utils_1 = require("./utils");
|
|
33
|
+
// Writes (or reuses) a placeholder PNG keyed by dimensions alone — content is always identical.
|
|
34
|
+
async function createPlaceholderPng(width, height, tempPath) {
|
|
35
|
+
const imagePath = path.join(tempPath, `figma-placeholder-${width}x${height}.png`);
|
|
36
|
+
if (!fs.existsSync(imagePath)) {
|
|
37
|
+
fs.writeFileSync(imagePath, await (0, image_1.generateWhitePng)(width, height));
|
|
38
|
+
}
|
|
39
|
+
return imagePath;
|
|
40
|
+
}
|
|
41
|
+
exports.createPlaceholderPng = createPlaceholderPng;
|
|
42
|
+
// Pads imagePath onto a centered white canvas at paddedDesignSize, returning the new path + canvas size
|
|
43
|
+
// (unchanged if it already meets minSize on both axes). Keyed by basename + canvas size so repeats reuse the file.
|
|
44
|
+
async function createPaddedDesignImage(imagePath, width, height, minSize, tempPath) {
|
|
45
|
+
const canvas = (0, utils_1.paddedDesignSize)(width, height, minSize);
|
|
46
|
+
if (canvas.width === width && canvas.height === height) {
|
|
47
|
+
return { imagePath, width, height };
|
|
48
|
+
}
|
|
49
|
+
const baseName = path.basename(imagePath, path.extname(imagePath));
|
|
50
|
+
const outputPath = path.join(tempPath, `figma-padded-${baseName}-${canvas.width}x${canvas.height}.png`);
|
|
51
|
+
if (!fs.existsSync(outputPath)) {
|
|
52
|
+
const canvasImage = (0, image_1.makeImage)(await (0, image_1.generateWhitePng)(canvas.width, canvas.height));
|
|
53
|
+
canvasImage.copy((0, image_1.makeImage)(imagePath), {
|
|
54
|
+
x: Math.floor((canvas.width - width) / 2),
|
|
55
|
+
y: Math.floor((canvas.height - height) / 2),
|
|
56
|
+
});
|
|
57
|
+
// toPng (not toFile) — Image.toFile writes the pre-transform pixels, dropping the copy above.
|
|
58
|
+
fs.writeFileSync(outputPath, await canvasImage.toPng());
|
|
59
|
+
}
|
|
60
|
+
return { imagePath: outputPath, ...canvas };
|
|
61
|
+
}
|
|
62
|
+
exports.createPaddedDesignImage = createPaddedDesignImage;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.setFigmaBaseline = exports.setFigmaBaselineFlow = void 0;
|
|
27
|
+
// Figma baseline resolver (AD-14881): orchestration only, operating directly on core's OpenSettings
|
|
28
|
+
// (the eyes/cypress/non-JS bindings adapt the flat config to this shape). Helpers split into ./utils,
|
|
29
|
+
// ./client, ./figma-images, ./target-config.
|
|
30
|
+
const os = __importStar(require("os"));
|
|
31
|
+
const logger_1 = require("@applitools/logger");
|
|
32
|
+
const utils_1 = require("./utils");
|
|
33
|
+
const target_config_1 = require("./target-config");
|
|
34
|
+
const client_1 = require("./client");
|
|
35
|
+
const figma_images_1 = require("./figma-images");
|
|
36
|
+
const run_figma_check_1 = require("./run-figma-check");
|
|
37
|
+
async function setFigmaBaselineFlow(figmaUrls, originalConfig, deps, mode = 'auto-baseline', viewportOpts = {}, logger = (0, logger_1.makeLogger)()) {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const maxViewportHeight = (_a = viewportOpts.maxViewportHeight) !== null && _a !== void 0 ? _a : target_config_1.DEFAULT_MAX_VIEWPORT_HEIGHT;
|
|
40
|
+
const minViewportSize = (_b = viewportOpts.minViewportSize) !== null && _b !== void 0 ? _b : null;
|
|
41
|
+
for (const url of figmaUrls) {
|
|
42
|
+
if (url !== '' && !(0, utils_1.isFigmaUrl)(url)) {
|
|
43
|
+
throw new Error(`setFigmaBaseline: "${url}" is not a valid Figma URL. ` + `To skip a test, use an empty string.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// '' entries are placeholder steps; resolveFigmaUrls guarantees at least one real URL here.
|
|
47
|
+
const realUrls = figmaUrls.filter(url => url !== '');
|
|
48
|
+
if (mode === 'test-baseline') {
|
|
49
|
+
logger.log(`Fetching Figma design metadata: ${realUrls[0]}${realUrls.length > 1 ? ` (+${realUrls.length - 1} more)` : ''}`);
|
|
50
|
+
const rawMetadataList = await deps.fetchFigmaMetadata(realUrls);
|
|
51
|
+
logger.log(`Figma node: "${rawMetadataList[0].name}" (${rawMetadataList[0].type}) ${rawMetadataList[0].width}x${rawMetadataList[0].height}, last modified ${rawMetadataList[0].lastModifiedAt}`);
|
|
52
|
+
logger.log(`Mode is test-baseline — skipping Figma change detection; adjusting viewport only.`);
|
|
53
|
+
// test-baseline never fetches images, so minViewportSize floors the metadata dimensions directly.
|
|
54
|
+
const metadataList = minViewportSize != null
|
|
55
|
+
? rawMetadataList.map(m => ({ ...m, ...(0, utils_1.paddedDesignSize)(m.width, m.height, minViewportSize) }))
|
|
56
|
+
: rawMetadataList;
|
|
57
|
+
const stepViewports = metadataList.map(m => ({ width: m.width, height: m.height }));
|
|
58
|
+
const figmaViewport = (0, utils_1.computeFigmaViewport)(stepViewports, maxViewportHeight);
|
|
59
|
+
logger.log(`Figma viewport: ${figmaViewport.width}x${figmaViewport.height}`);
|
|
60
|
+
return (0, target_config_1.buildTargetTestConfig)(originalConfig, metadataList[0], figmaViewport, null, mode);
|
|
61
|
+
}
|
|
62
|
+
logger.log(`Fetching Figma design: ${realUrls[0]}${realUrls.length > 1 ? ` (+${realUrls.length - 1} more)` : ''}`);
|
|
63
|
+
const rawResults = await deps.fetchFigmaImages(realUrls);
|
|
64
|
+
logger.log(`Figma node: "${rawResults[0].metadata.name}" (${rawResults[0].metadata.type}) ${rawResults[0].metadata.width}x${rawResults[0].metadata.height}, last modified ${rawResults[0].metadata.lastModifiedAt}`);
|
|
65
|
+
const realResults = minViewportSize != null
|
|
66
|
+
? await Promise.all(rawResults.map(async (r) => {
|
|
67
|
+
const padded = await deps.padDesignImage(r.imagePath, r.metadata.width, r.metadata.height, minViewportSize);
|
|
68
|
+
return { imagePath: padded.imagePath, metadata: { ...r.metadata, width: padded.width, height: padded.height } };
|
|
69
|
+
}))
|
|
70
|
+
: rawResults;
|
|
71
|
+
// The figma viewport bounds every step, so a multi-step test with differently-sized frames renders at one consistent size.
|
|
72
|
+
const stepViewports = realResults.map(r => ({ width: r.metadata.width, height: r.metadata.height }));
|
|
73
|
+
const figmaViewport = (0, utils_1.computeFigmaViewport)(stepViewports, maxViewportHeight);
|
|
74
|
+
const figmaEnvName = `Figma ${figmaViewport.width}x${figmaViewport.height}`;
|
|
75
|
+
logger.log(`Figma viewport: ${figmaViewport.width}x${figmaViewport.height}`);
|
|
76
|
+
// Splice placeholder steps back at their original positions, using a blank image at the shared figma viewport.
|
|
77
|
+
const results = [];
|
|
78
|
+
let realResultIndex = 0;
|
|
79
|
+
for (const url of figmaUrls) {
|
|
80
|
+
if (url === '') {
|
|
81
|
+
const imagePath = await deps.createPlaceholderImage(figmaViewport.width, figmaViewport.height);
|
|
82
|
+
results.push({
|
|
83
|
+
imagePath,
|
|
84
|
+
metadata: {
|
|
85
|
+
name: target_config_1.PLACEHOLDER_TAG,
|
|
86
|
+
type: 'PLACEHOLDER',
|
|
87
|
+
width: figmaViewport.width,
|
|
88
|
+
height: figmaViewport.height,
|
|
89
|
+
revision: 'placeholder',
|
|
90
|
+
lastModifiedAt: '',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
results.push(realResults[realResultIndex]);
|
|
96
|
+
realResultIndex++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
logger.log(`Establishing Figma baseline...`);
|
|
100
|
+
const figmaReferenceConfig = {
|
|
101
|
+
apiKey: originalConfig.apiKey,
|
|
102
|
+
// Same server + proxy as the real test — otherwise on-prem users get the baseline on the public cloud.
|
|
103
|
+
eyesServerUrl: originalConfig.eyesServerUrl,
|
|
104
|
+
proxy: originalConfig.proxy,
|
|
105
|
+
batch: originalConfig.batch,
|
|
106
|
+
appName: originalConfig.appName,
|
|
107
|
+
testName: originalConfig.testName,
|
|
108
|
+
environment: { hostingApp: 'Figma', os: '', viewportSize: figmaViewport },
|
|
109
|
+
properties: (0, utils_1.figmaMetadataToProperties)(realResults[0].metadata, mode),
|
|
110
|
+
baselineEnvName: figmaEnvName,
|
|
111
|
+
saveNewTests: true,
|
|
112
|
+
saveDiffs: true,
|
|
113
|
+
keepBatchOpen: true,
|
|
114
|
+
};
|
|
115
|
+
if (originalConfig.branchName !== undefined)
|
|
116
|
+
figmaReferenceConfig.branchName = originalConfig.branchName;
|
|
117
|
+
const checks = results.map(({ imagePath }, i) => ({
|
|
118
|
+
imagePath,
|
|
119
|
+
tag: figmaUrls[i] === '' ? target_config_1.PLACEHOLDER_TAG : (0, utils_1.figmaStepTag)(figmaUrls[i]),
|
|
120
|
+
}));
|
|
121
|
+
const { isNew: figmaIsNew, diffs: figmaDiffs } = await deps.runFigmaCheck(figmaReferenceConfig, checks);
|
|
122
|
+
logger.log(`Figma baseline: ${figmaIsNew ? 'new (first run)' : !figmaDiffs ? 'passed (design unchanged)' : 'changed (design updated)'}`);
|
|
123
|
+
logger.log(`Linking test to Figma baseline: ${figmaEnvName}`);
|
|
124
|
+
return (0, target_config_1.buildTargetTestConfig)(originalConfig, realResults[0].metadata, figmaViewport, { figmaEnvName, useLatestEnvBaseline: mode === 'auto-baseline' }, mode);
|
|
125
|
+
}
|
|
126
|
+
exports.setFigmaBaselineFlow = setFigmaBaselineFlow;
|
|
127
|
+
async function setFigmaBaseline(configuration, figmaBaselines, opts) {
|
|
128
|
+
var _a;
|
|
129
|
+
const logger = (_a = opts === null || opts === void 0 ? void 0 : opts.logger) !== null && _a !== void 0 ? _a : (0, logger_1.makeLogger)();
|
|
130
|
+
const mode = (0, utils_1.resolveFigmaMode)(opts === null || opts === void 0 ? void 0 : opts.mode);
|
|
131
|
+
if (mode === 'disabled') {
|
|
132
|
+
logger.log('setFigmaBaseline: disabled (APPLITOOLS_FIGMA_MODE=disabled) — skipping.');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const getToken = () => {
|
|
136
|
+
var _a;
|
|
137
|
+
if (!(opts === null || opts === void 0 ? void 0 : opts.skipApi) && !(opts === null || opts === void 0 ? void 0 : opts.accessToken)) {
|
|
138
|
+
throw new Error('setFigmaBaseline: no Figma access token. ' +
|
|
139
|
+
'Pass accessToken or set the FIGMA_ACCESS_TOKEN environment variable.');
|
|
140
|
+
}
|
|
141
|
+
return (_a = opts === null || opts === void 0 ? void 0 : opts.accessToken) !== null && _a !== void 0 ? _a : '';
|
|
142
|
+
};
|
|
143
|
+
const restOpts = {
|
|
144
|
+
tempPath: opts === null || opts === void 0 ? void 0 : opts.tempPath,
|
|
145
|
+
nodesCacheTtlSeconds: opts === null || opts === void 0 ? void 0 : opts.nodesCacheTtlSeconds,
|
|
146
|
+
maxRateLimitWaitSeconds: opts === null || opts === void 0 ? void 0 : opts.maxRateLimitWaitSeconds,
|
|
147
|
+
skipApi: opts === null || opts === void 0 ? void 0 : opts.skipApi,
|
|
148
|
+
proxy: opts === null || opts === void 0 ? void 0 : opts.proxy,
|
|
149
|
+
req: opts === null || opts === void 0 ? void 0 : opts.req,
|
|
150
|
+
logger,
|
|
151
|
+
};
|
|
152
|
+
const deps = {
|
|
153
|
+
fetchFigmaImages: urlList => (0, client_1.fetchFigmaImages)(urlList, getToken(), restOpts),
|
|
154
|
+
fetchFigmaMetadata: urlList => (0, client_1.fetchFigmaMetadata)(urlList, getToken(), restOpts),
|
|
155
|
+
createPlaceholderImage: (width, height) => { var _a; return (0, figma_images_1.createPlaceholderPng)(width, height, (_a = opts === null || opts === void 0 ? void 0 : opts.tempPath) !== null && _a !== void 0 ? _a : os.tmpdir()); },
|
|
156
|
+
padDesignImage: (imagePath, width, height, minViewportSize) => { var _a; return (0, figma_images_1.createPaddedDesignImage)(imagePath, width, height, minViewportSize, (_a = opts === null || opts === void 0 ? void 0 : opts.tempPath) !== null && _a !== void 0 ? _a : os.tmpdir()); },
|
|
157
|
+
runFigmaCheck: run_figma_check_1.runFigmaCheck,
|
|
158
|
+
};
|
|
159
|
+
const figmaUrls = (0, utils_1.resolveFigmaUrls)(figmaBaselines, configuration.testName);
|
|
160
|
+
if (figmaUrls === null)
|
|
161
|
+
return;
|
|
162
|
+
const updated = await setFigmaBaselineFlow(figmaUrls, configuration, deps, mode, {
|
|
163
|
+
maxViewportHeight: opts === null || opts === void 0 ? void 0 : opts.maxViewportHeight,
|
|
164
|
+
minViewportSize: opts === null || opts === void 0 ? void 0 : opts.minViewportSize,
|
|
165
|
+
}, logger);
|
|
166
|
+
Object.assign(configuration, updated);
|
|
167
|
+
}
|
|
168
|
+
exports.setFigmaBaseline = setFigmaBaseline;
|