@applitools/core 4.67.2 → 4.68.1
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 +187 -0
- package/dist/autonomous/create-render-results.js +6 -1
- package/dist/autonomous/start-renders.js +16 -7
- package/dist/check-and-close.js +7 -1
- package/dist/check.js +8 -1
- package/dist/classic/utils/extract-default-environments.js +17 -2
- 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 +4 -2
- 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 +23 -22
- package/types/automation/types.d.ts +9 -0
- package/types/autonomous/types.d.ts +1 -0
- package/types/check-and-close.d.ts +3 -2
- package/types/check.d.ts +3 -2
- 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,192 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.68.1](https://github.com/Applitools-Dev/sdk/compare/js/core@4.68.0...js/core@4.68.1) (2026-08-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
9
|
+
* omit the empty os from the figma reference env so the design baseline persists | AD-15527 ([#4067](https://github.com/Applitools-Dev/sdk/issues/4067)) ([8395814](https://github.com/Applitools-Dev/sdk/commit/8395814feb6b20eee1c1322dc1539aa4642663d8))
|
|
10
|
+
* use an authoritative CSS viewport in classic mode | FLD-4814 ([#4047](https://github.com/Applitools-Dev/sdk/issues/4047)) ([c46497e](https://github.com/Applitools-Dev/sdk/commit/c46497e573fd7fd2da4913452239beea082b148f))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Dependencies
|
|
14
|
+
|
|
15
|
+
* @applitools/utils bumped to 1.15.2
|
|
16
|
+
#### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
19
|
+
* @applitools/logger bumped to 2.3.1
|
|
20
|
+
#### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
* @applitools/dom-shared bumped to 1.2.3
|
|
27
|
+
#### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
30
|
+
* @applitools/dom-snapshot bumped to 4.17.9
|
|
31
|
+
#### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
* @applitools/socket bumped to 1.3.16
|
|
38
|
+
#### Bug Fixes
|
|
39
|
+
|
|
40
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
* @applitools/req bumped to 1.11.3
|
|
45
|
+
#### Bug Fixes
|
|
46
|
+
|
|
47
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
* @applitools/image bumped to 1.3.1
|
|
52
|
+
#### Bug Fixes
|
|
53
|
+
|
|
54
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
* @applitools/snippets bumped to 2.9.6
|
|
59
|
+
#### Bug Fixes
|
|
60
|
+
|
|
61
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
* @applitools/dom-capture bumped to 11.8.5
|
|
66
|
+
#### Bug Fixes
|
|
67
|
+
|
|
68
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
* @applitools/driver bumped to 1.26.8
|
|
73
|
+
#### Bug Fixes
|
|
74
|
+
|
|
75
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
76
|
+
* use an authoritative CSS viewport in classic mode | FLD-4814 ([#4047](https://github.com/Applitools-Dev/sdk/issues/4047)) ([c46497e](https://github.com/Applitools-Dev/sdk/commit/c46497e573fd7fd2da4913452239beea082b148f))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
* @applitools/spec-driver-webdriver bumped to 1.6.8
|
|
81
|
+
#### Bug Fixes
|
|
82
|
+
|
|
83
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
* @applitools/spec-driver-selenium bumped to 1.8.8
|
|
88
|
+
#### Bug Fixes
|
|
89
|
+
|
|
90
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
* @applitools/spec-driver-playwright bumped to 1.9.8
|
|
95
|
+
#### Bug Fixes
|
|
96
|
+
|
|
97
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
* @applitools/spec-driver-puppeteer bumped to 1.8.8
|
|
102
|
+
#### Bug Fixes
|
|
103
|
+
|
|
104
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
* @applitools/screenshoter bumped to 3.12.28
|
|
109
|
+
#### Bug Fixes
|
|
110
|
+
|
|
111
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
* @applitools/nml-client bumped to 1.11.40
|
|
116
|
+
#### Bug Fixes
|
|
117
|
+
|
|
118
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
* @applitools/tunnel-client bumped to 1.12.3
|
|
123
|
+
#### Bug Fixes
|
|
124
|
+
|
|
125
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
* @applitools/ufg-client bumped to 1.23.1
|
|
130
|
+
#### Bug Fixes
|
|
131
|
+
|
|
132
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
* @applitools/core-base bumped to 1.38.1
|
|
137
|
+
#### Bug Fixes
|
|
138
|
+
|
|
139
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
* @applitools/ec-client bumped to 1.12.42
|
|
144
|
+
#### Bug Fixes
|
|
145
|
+
|
|
146
|
+
* apply the figma UFG environments rewrite to the renders | AD-15528 ([#4072](https://github.com/Applitools-Dev/sdk/issues/4072)) ([bd6b143](https://github.com/Applitools-Dev/sdk/commit/bd6b143f855750ae93701f8e44da6129ff7ae84c))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
* @applitools/test-server bumped to 1.4.7
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## [4.68.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.67.2...js/core@4.68.0) (2026-08-05)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
### Features
|
|
157
|
+
|
|
158
|
+
* 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))
|
|
159
|
+
* 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))
|
|
160
|
+
* 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))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
### Dependencies
|
|
164
|
+
|
|
165
|
+
* @applitools/image bumped to 1.3.0
|
|
166
|
+
#### Features
|
|
167
|
+
|
|
168
|
+
* 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))
|
|
169
|
+
* @applitools/ufg-client bumped to 1.23.0
|
|
170
|
+
#### Features
|
|
171
|
+
|
|
172
|
+
* 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))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
* @applitools/screenshoter bumped to 3.12.27
|
|
177
|
+
|
|
178
|
+
* @applitools/nml-client bumped to 1.11.39
|
|
179
|
+
|
|
180
|
+
* @applitools/core-base bumped to 1.38.0
|
|
181
|
+
#### Features
|
|
182
|
+
|
|
183
|
+
* 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))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
* @applitools/ec-client bumped to 1.12.41
|
|
188
|
+
|
|
189
|
+
|
|
3
190
|
## [4.67.2](https://github.com/Applitools-Dev/sdk/compare/js/core@4.67.1...js/core@4.67.2) (2026-07-30)
|
|
4
191
|
|
|
5
192
|
|
|
@@ -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
|
};
|
package/dist/check-and-close.js
CHANGED
|
@@ -26,10 +26,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.makeCheckAndClose = void 0;
|
|
27
27
|
const driver_1 = require("@applitools/driver");
|
|
28
28
|
const utils = __importStar(require("@applitools/utils"));
|
|
29
|
-
function makeCheckAndClose({ type: defaultType = 'classic', eyes, target: defaultTarget, spec, logger: mainLogger, }) {
|
|
29
|
+
function makeCheckAndClose({ type: defaultType = 'classic', eyes, target: defaultTarget, environments: openEnvironments, spec, logger: mainLogger, }) {
|
|
30
30
|
return async function checkAndClose({ type = defaultType, target = defaultTarget, settings = {}, config, logger = mainLogger, } = {}) {
|
|
31
31
|
logger = logger.extend(mainLogger, { tags: [`check-and-close-${type}-${utils.general.shortid()}`] });
|
|
32
|
+
// Same environments precedence as in check.ts.
|
|
33
|
+
const explicitEnvironments = settings != null && 'environments' in settings;
|
|
32
34
|
settings = { ...config === null || config === void 0 ? void 0 : config.screenshot, ...config === null || config === void 0 ? void 0 : config.check, ...config === null || config === void 0 ? void 0 : config.close, ...settings };
|
|
35
|
+
if (type === 'ufg' && (openEnvironments === null || openEnvironments === void 0 ? void 0 : openEnvironments.length) && !explicitEnvironments) {
|
|
36
|
+
;
|
|
37
|
+
settings.environments = openEnvironments;
|
|
38
|
+
}
|
|
33
39
|
const driver = (0, driver_1.isDriver)(target, spec)
|
|
34
40
|
? await (0, driver_1.makeDriver)({ spec, driver: target, reset: target === defaultTarget, logger })
|
|
35
41
|
: null;
|
package/dist/check.js
CHANGED
|
@@ -32,13 +32,20 @@ const defaults_1 = require("./automation/utils/defaults");
|
|
|
32
32
|
const utils = __importStar(require("@applitools/utils"));
|
|
33
33
|
const lang = __importStar(require("./lang"));
|
|
34
34
|
const chalk_1 = __importDefault(require("chalk"));
|
|
35
|
-
function makeCheck({ type: defaultType = 'classic', eyes, target: defaultTarget, spec, logger: mainLogger, }) {
|
|
35
|
+
function makeCheck({ type: defaultType = 'classic', eyes, target: defaultTarget, environments: openEnvironments, spec, logger: mainLogger, }) {
|
|
36
36
|
let stepIndex = 0;
|
|
37
37
|
return async function check({ type = defaultType, target = defaultTarget, settings, config, logger = mainLogger, } = {}) {
|
|
38
38
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
39
39
|
var _t, _u, _v, _w, _x;
|
|
40
40
|
logger = logger.extend(mainLogger, { tags: [`check-${type}-${utils.general.shortid()}`] });
|
|
41
|
+
// Open-time environments (possibly rewritten by the figma seam) win over the config's per-check
|
|
42
|
+
// re-send; environments passed explicitly to this call win over both.
|
|
43
|
+
const explicitEnvironments = settings != null && 'environments' in settings;
|
|
41
44
|
settings = { ...config === null || config === void 0 ? void 0 : config.screenshot, ...config === null || config === void 0 ? void 0 : config.check, ...settings };
|
|
45
|
+
if (type === 'ufg' && (openEnvironments === null || openEnvironments === void 0 ? void 0 : openEnvironments.length) && !explicitEnvironments) {
|
|
46
|
+
;
|
|
47
|
+
settings.environments = openEnvironments;
|
|
48
|
+
}
|
|
42
49
|
(_a = settings.fully) !== null && _a !== void 0 ? _a : (settings.fully = !settings.region && (!settings.frames || settings.frames.length === 0));
|
|
43
50
|
(_b = settings.waitBeforeCapture) !== null && _b !== void 0 ? _b : (settings.waitBeforeCapture = defaults_1.DEFAULT_WAIT_BEFORE_CAPTURE);
|
|
44
51
|
(_c = settings.hideScrollbars) !== null && _c !== void 0 ? _c : (settings.hideScrollbars = true);
|
|
@@ -34,8 +34,23 @@ async function extractDefaultEnvironments({ driver, settings, }) {
|
|
|
34
34
|
try {
|
|
35
35
|
const driverEnvironment = await driver.getEnvironment();
|
|
36
36
|
const viewport = await driver.getViewport();
|
|
37
|
-
//
|
|
38
|
-
|
|
37
|
+
// The reported viewport is part of the baseline key: it must stay identical to the historical
|
|
38
|
+
// derivation (`layout viewport × visualViewport.scale`) for every viewport already reported
|
|
39
|
+
// correctly (FLD-4359). The framework-reported CSS viewport may substitute only to correct
|
|
40
|
+
// sub-pixel rounding noise in that derivation (FLD-4814): integral on both axes, within < 1px
|
|
41
|
+
// per axis, and viewportScale <= 1 — the residue bound the backward-compatibility proof depends
|
|
42
|
+
// on. The value must come from getCssViewportSize(), never getViewportSize(), whose fallback is
|
|
43
|
+
// the unscaled layout viewport. Full derivation, proof and history: llm-docs/CLASSIC.md →
|
|
44
|
+
// Reported viewport.
|
|
45
|
+
const derivedViewportSize = utils.geometry.scale(viewport.viewportSize, viewport.viewportScale);
|
|
46
|
+
const cssViewportSize = await driver.getCssViewportSize();
|
|
47
|
+
const corroboratesDerivedSize = !!cssViewportSize &&
|
|
48
|
+
viewport.viewportScale <= 1 &&
|
|
49
|
+
Number.isInteger(cssViewportSize.width) &&
|
|
50
|
+
Number.isInteger(cssViewportSize.height) &&
|
|
51
|
+
Math.abs(cssViewportSize.width - derivedViewportSize.width) < 1 &&
|
|
52
|
+
Math.abs(cssViewportSize.height - derivedViewportSize.height) < 1;
|
|
53
|
+
environment.viewportSize = corroboratesDerivedSize ? cssViewportSize : derivedViewportSize;
|
|
39
54
|
environment.environmentId = utils.general.guid();
|
|
40
55
|
if (driverEnvironment.isEC)
|
|
41
56
|
environment.ecSessionId = (_a = (await driver.getSessionId())) !== null && _a !== void 0 ? _a : undefined;
|
|
@@ -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);
|