@applitools/eyes-storybook 3.55.9 → 3.56.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 +39 -0
- package/bin/eyes-setup.js +2 -0
- package/package.json +8 -4
- package/src/eyes-setup.js +272 -0
- package/src/eyesStorybook.js +5 -1
- package/src/generateConfig.js +20 -6
- package/src/types/types.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.56.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.55.9...js/eyes-storybook@3.56.0) (2025-07-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* eyes-setup script | AD-9543 ([#3075](https://github.com/Applitools-Dev/sdk/issues/3075)) ([27f15f9](https://github.com/Applitools-Dev/sdk/commit/27f15f9b54ba93c8189214a5df424b543d564120))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* use strict mode to get config | AD-10156 ([#3092](https://github.com/Applitools-Dev/sdk/issues/3092)) ([6b2d21b](https://github.com/Applitools-Dev/sdk/commit/6b2d21b23219f03b56d27604d0afe768eaae6fc2))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Dependencies
|
|
17
|
+
|
|
18
|
+
* @applitools/nml-client bumped to 1.10.0
|
|
19
|
+
#### Features
|
|
20
|
+
|
|
21
|
+
* android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
* @applitools/core-base bumped to 1.26.0
|
|
26
|
+
#### Features
|
|
27
|
+
|
|
28
|
+
* batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
|
|
29
|
+
* @applitools/ec-client bumped to 1.11.1
|
|
30
|
+
|
|
31
|
+
* @applitools/core bumped to 4.43.0
|
|
32
|
+
#### Features
|
|
33
|
+
|
|
34
|
+
* android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
|
|
35
|
+
* batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
* @applitools/eyes bumped to 1.35.3
|
|
40
|
+
|
|
41
|
+
|
|
3
42
|
## [3.55.9](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.55.8...js/eyes-storybook@3.55.9) (2025-07-15)
|
|
4
43
|
|
|
5
44
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/eyes-storybook",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.56.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"applitools",
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"homepage": "https://applitools.com/tutorials/sdks/storybook",
|
|
15
15
|
"license": "SEE LICENSE IN LICENSE",
|
|
16
16
|
"author": "Applitools Team <team@applitools.com>",
|
|
17
|
-
"bin":
|
|
17
|
+
"bin": {
|
|
18
|
+
"eyes-setup": "./bin/eyes-setup.js",
|
|
19
|
+
"eyes-storybook": "./bin/eyes-storybook.js"
|
|
20
|
+
},
|
|
18
21
|
"files": [
|
|
19
22
|
"src",
|
|
20
23
|
"bin",
|
|
@@ -53,15 +56,16 @@
|
|
|
53
56
|
"up:framework": "cd test/fixtures/storybook-versions/${APPLITOOLS_FRAMEWORK_VERSION} && npm ci"
|
|
54
57
|
},
|
|
55
58
|
"dependencies": {
|
|
56
|
-
"@applitools/core": "4.
|
|
59
|
+
"@applitools/core": "4.43.0",
|
|
57
60
|
"@applitools/driver": "1.22.1",
|
|
58
|
-
"@applitools/eyes": "1.35.
|
|
61
|
+
"@applitools/eyes": "1.35.3",
|
|
59
62
|
"@applitools/functional-commons": "1.6.0",
|
|
60
63
|
"@applitools/logger": "2.1.5",
|
|
61
64
|
"@applitools/monitoring-commons": "1.0.19",
|
|
62
65
|
"@applitools/spec-driver-puppeteer": "1.5.1",
|
|
63
66
|
"@applitools/ufg-client": "1.16.14",
|
|
64
67
|
"@applitools/utils": "1.9.0",
|
|
68
|
+
"@inquirer/prompts": "7.0.1",
|
|
65
69
|
"boxen": "4.2.0",
|
|
66
70
|
"chalk": "3.0.0",
|
|
67
71
|
"detect-port": "1.3.0",
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const {input, confirm} = require('@inquirer/prompts');
|
|
5
|
+
const yargs = require('yargs/yargs');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const {pathToFileURL} = require('url');
|
|
8
|
+
const utils = require('@applitools/utils');
|
|
9
|
+
|
|
10
|
+
const {hideBin} = require('yargs/helpers');
|
|
11
|
+
yargs(hideBin(process.argv))
|
|
12
|
+
.command({
|
|
13
|
+
command: '*',
|
|
14
|
+
builder: yargs => {
|
|
15
|
+
const args = yargs.options({
|
|
16
|
+
apiKey: {
|
|
17
|
+
describe:
|
|
18
|
+
"Your Applitools Team's API key (here's how to obtain it: https://applitools.com/docs/topics/overview/obtain-api-key.html)",
|
|
19
|
+
type: 'string',
|
|
20
|
+
},
|
|
21
|
+
serverUrl: {describe: 'Your Eyes dedicated cloud server URL', type: 'string'},
|
|
22
|
+
});
|
|
23
|
+
return args;
|
|
24
|
+
},
|
|
25
|
+
handler: handleError(init),
|
|
26
|
+
})
|
|
27
|
+
.help()
|
|
28
|
+
.parse();
|
|
29
|
+
|
|
30
|
+
function handleError(asyncFunc) {
|
|
31
|
+
return async (...args) =>
|
|
32
|
+
asyncFunc(...args).catch(err => {
|
|
33
|
+
if (err.name === 'ExitPromptError') {
|
|
34
|
+
log('See you next time!');
|
|
35
|
+
} else {
|
|
36
|
+
error(`Error while setting up Eyes: ${err.message}`);
|
|
37
|
+
}
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function init(args) {
|
|
43
|
+
let shouldUpdate = true;
|
|
44
|
+
let fileName;
|
|
45
|
+
|
|
46
|
+
log(chalk.yellow('Setting up Eyes-Storybook for your project:'));
|
|
47
|
+
|
|
48
|
+
let config = await loadExistingConfig();
|
|
49
|
+
if (config) {
|
|
50
|
+
shouldUpdate = false;
|
|
51
|
+
// this show a warning if the apiKey is actually 'process.env.APPLITOOLS_API_KEY' in the config file since we load it
|
|
52
|
+
// if (config.apiKey !== 'process.env.APPLITOOLS_API_KEY') {
|
|
53
|
+
// console.log(config.apiKey)
|
|
54
|
+
// log(
|
|
55
|
+
// chalk.yellow(
|
|
56
|
+
// `Detected 'apiKey' is not obscured. It is recommended to set this via environment variable APPLITOOLS_API_KEY.`,
|
|
57
|
+
// ),
|
|
58
|
+
// );
|
|
59
|
+
// }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let apiKey,
|
|
63
|
+
serverUrl,
|
|
64
|
+
shouldUseEnvApiKey = false,
|
|
65
|
+
shouldUseEnvServerUrl = false,
|
|
66
|
+
warnForApiKey = false;
|
|
67
|
+
if (shouldUpdate && utils.general.getEnvValue('API_KEY')) {
|
|
68
|
+
shouldUseEnvApiKey = await confirm({
|
|
69
|
+
message:
|
|
70
|
+
'Detected APPLITOOLS_API_KEY environment variable. Would you like it to be used? (default Yes):',
|
|
71
|
+
default: true,
|
|
72
|
+
});
|
|
73
|
+
apiKey = shouldUseEnvApiKey ? 'process.env.APPLITOOLS_API_KEY' : undefined;
|
|
74
|
+
warnForApiKey = !shouldUseEnvApiKey; // warn if the user doesn't want to use the env variable
|
|
75
|
+
}
|
|
76
|
+
for (const url of ['EYES_SERVER_URL', 'SERVER_URL']) {
|
|
77
|
+
if (shouldUpdate && utils.general.getEnvValue(url)) {
|
|
78
|
+
shouldUseEnvServerUrl = await confirm({
|
|
79
|
+
message: `Detected APPLITOOLS_${url} environment variable. Would you like it to be used? (default Yes):`,
|
|
80
|
+
default: true,
|
|
81
|
+
});
|
|
82
|
+
serverUrl = shouldUseEnvServerUrl ? `APPLITOOLS_${url}` : undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (shouldUpdate) {
|
|
87
|
+
if (!shouldUseEnvApiKey) {
|
|
88
|
+
apiKey =
|
|
89
|
+
args.apiKey ??
|
|
90
|
+
(await input({
|
|
91
|
+
message:
|
|
92
|
+
'Enter your API key (https://applitools.com/docs/topics/overview/obtain-api-key.html):',
|
|
93
|
+
}));
|
|
94
|
+
warnForApiKey = apiKey !== ''; // warn if the user did provide an API key
|
|
95
|
+
}
|
|
96
|
+
if (!shouldUseEnvServerUrl) {
|
|
97
|
+
serverUrl =
|
|
98
|
+
args.serverUrl ??
|
|
99
|
+
(await input({
|
|
100
|
+
message: 'Enter your Eyes server URL (default is https://eyes.applitools.com):',
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
config = {
|
|
105
|
+
...config,
|
|
106
|
+
appName: 'My Storybook App',
|
|
107
|
+
batchName: 'My Storybook',
|
|
108
|
+
showLogs: false,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const fileContent = generateConfigContent();
|
|
112
|
+
await fs.writeFile(fileName, fileContent, 'utf8');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
printPostlude();
|
|
116
|
+
|
|
117
|
+
async function loadExistingConfig() {
|
|
118
|
+
const configFiles = [
|
|
119
|
+
'applitools.config.js',
|
|
120
|
+
'applitools.config.mjs',
|
|
121
|
+
'applitools.config.cjs',
|
|
122
|
+
'eyes.config.js',
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
for (const file of configFiles) {
|
|
126
|
+
fileName = file;
|
|
127
|
+
try {
|
|
128
|
+
await fs.access(file);
|
|
129
|
+
const fileUrl = pathToFileURL(file).href;
|
|
130
|
+
const module = await import(fileUrl);
|
|
131
|
+
return module.default || module;
|
|
132
|
+
} catch (err) {
|
|
133
|
+
// try the next file if it doesn't exist
|
|
134
|
+
if (err.code === 'ENOENT') continue;
|
|
135
|
+
throw err; // we are only interested in the file not found error
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// no config file found
|
|
139
|
+
fileName = 'applitools.config.js';
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function generateConfigContent() {
|
|
144
|
+
const envConfigMap = {
|
|
145
|
+
batchName: 'APPLITOOLS_BATCH_NAME',
|
|
146
|
+
batchId: 'APPLITOOLS_BATCH_ID',
|
|
147
|
+
showLogs: 'APPLITOOLS_SHOW_LOGS',
|
|
148
|
+
batchSequenceName: 'APPLITOOLS_BATCH_SEQUENCE_NAME',
|
|
149
|
+
proxy: 'APPLITOOLS_PROXY',
|
|
150
|
+
notifyOnCompletion: 'APPLITOOLS_NOTIFY_ON_COMPLETION',
|
|
151
|
+
concurrentTabs: 'APPLITOOLS_CONCURRENT_TABS',
|
|
152
|
+
appName: 'APPLITOOLS_APP_NAME',
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const configLines = [];
|
|
156
|
+
|
|
157
|
+
// Handle apiKey
|
|
158
|
+
if (apiKey === 'process.env.APPLITOOLS_API_KEY') {
|
|
159
|
+
configLines.push('apiKey: process.env.APPLITOOLS_API_KEY,');
|
|
160
|
+
} else if (apiKey) {
|
|
161
|
+
configLines.push(
|
|
162
|
+
`apiKey: '${apiKey}', // Warning: 'apiKey' is not obscured, consider setting it via environment variable APPLITOOLS_API_KEY`,
|
|
163
|
+
);
|
|
164
|
+
} else {
|
|
165
|
+
configLines.push(`// apiKey: '',`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Handle serverUrl
|
|
169
|
+
if (serverUrl && serverUrl.startsWith('process.env.')) {
|
|
170
|
+
configLines.push(`serverUrl: ${serverUrl},`);
|
|
171
|
+
} else if (serverUrl) {
|
|
172
|
+
configLines.push(`serverUrl: '${serverUrl}',`);
|
|
173
|
+
} else {
|
|
174
|
+
configLines.push(`// serverUrl: '',`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Handle other config lines
|
|
178
|
+
const otherKeys = [
|
|
179
|
+
'appName',
|
|
180
|
+
'batchName',
|
|
181
|
+
'batchId',
|
|
182
|
+
'showLogs',
|
|
183
|
+
'batchSequenceName',
|
|
184
|
+
'proxy',
|
|
185
|
+
'notifyOnCompletion',
|
|
186
|
+
'concurrentTabs',
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
for (const key of otherKeys) {
|
|
190
|
+
const line = getConfigLine(key);
|
|
191
|
+
if (line) {
|
|
192
|
+
configLines.push(line);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return `/**
|
|
197
|
+
* @type {import('@applitools/eyes-storybook').ApplitoolsConfig}
|
|
198
|
+
**/
|
|
199
|
+
module.exports = {
|
|
200
|
+
${configLines.join('\n ')}
|
|
201
|
+
// browsersInfo: [
|
|
202
|
+
// {width: 1024, height: 768, name: 'firefox'},
|
|
203
|
+
// {width: 1024, height: 768, name: 'chrome'},
|
|
204
|
+
// {iosDeviceInfo: {deviceName: 'iPhone 16'}},
|
|
205
|
+
// {chromeEmulationInfo: {deviceName: 'Galaxy S20'}},
|
|
206
|
+
// ]
|
|
207
|
+
};
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
function getConfigLine(key, override = undefined) {
|
|
211
|
+
const envVar = envConfigMap[key];
|
|
212
|
+
if (override) {
|
|
213
|
+
return config[key];
|
|
214
|
+
}
|
|
215
|
+
if (utils.types.isArray(envVar)) {
|
|
216
|
+
for (const v of envVar) {
|
|
217
|
+
if (utils.general.getEnvValue(v.replace('APPLITOOLS_', ''))) {
|
|
218
|
+
return `${key}: process.env.${v},`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else if (envVar && utils.general.getEnvValue(envVar.replace('APPLITOOLS_', ''))) {
|
|
222
|
+
return `${key}: process.env.${envVar},`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check if the key exists in the config object before using its value.
|
|
226
|
+
// Using Object.prototype.hasOwnProperty.call is a safe way to check.
|
|
227
|
+
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
|
228
|
+
const value = config[key];
|
|
229
|
+
// Format the value based on its type.
|
|
230
|
+
return typeof value === 'string' ? `${key}: '${value}',` : `${key}: ${value},`;
|
|
231
|
+
} else {
|
|
232
|
+
return '';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function printPostlude() {
|
|
238
|
+
log('');
|
|
239
|
+
if (shouldUpdate) {
|
|
240
|
+
log(
|
|
241
|
+
chalk.green('✔ Success!'),
|
|
242
|
+
chalk.bold('\n'),
|
|
243
|
+
chalk.bold('Eyes Storybook is now set up!'),
|
|
244
|
+
chalk.bold('Please visit our Storybook documentation to learn more.'),
|
|
245
|
+
chalk.bold('https://applitools.com/tutorials/sdks/storybook/quickstart'),
|
|
246
|
+
);
|
|
247
|
+
} else {
|
|
248
|
+
log(
|
|
249
|
+
chalk.green('✔ Good news! Eyes Storybook is already properly configured!'),
|
|
250
|
+
chalk.bold('\n'),
|
|
251
|
+
chalk.bold('Please visit our Storybook documentation to learn more.'),
|
|
252
|
+
chalk.bold('https://applitools.com/tutorials/sdks/storybook/quickstart'),
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (warnForApiKey) {
|
|
257
|
+
log(
|
|
258
|
+
chalk.yellow(
|
|
259
|
+
'Please consider setting your API key via environment variable APPLITOOLS_API_KEY to avoid exposing it in the config file.',
|
|
260
|
+
),
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function log(...args) {
|
|
267
|
+
console.log(...args);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function error(...args) {
|
|
271
|
+
console.error(...args);
|
|
272
|
+
}
|
package/src/eyesStorybook.js
CHANGED
|
@@ -91,7 +91,11 @@ async function eyesStorybook({
|
|
|
91
91
|
},
|
|
92
92
|
})
|
|
93
93
|
.catch(async error => {
|
|
94
|
-
if (
|
|
94
|
+
if (
|
|
95
|
+
error &&
|
|
96
|
+
error.message &&
|
|
97
|
+
error.message.includes('Please check your API key and try again.')
|
|
98
|
+
) {
|
|
95
99
|
const failMsg = 'Incorrect API Key';
|
|
96
100
|
logger.log(failMsg);
|
|
97
101
|
await browser.close();
|
package/src/generateConfig.js
CHANGED
|
@@ -10,7 +10,12 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
|
|
|
10
10
|
const defaultConfigParams = Object.keys(defaultConfig);
|
|
11
11
|
const configPaths = argv.conf ? [resolve(process.cwd(), argv.conf)] : undefined;
|
|
12
12
|
const configParams = uniq(defaultConfigParams.concat(externalConfigParams));
|
|
13
|
-
const config = utils.config.getConfig({
|
|
13
|
+
const config = utils.config.getConfig({
|
|
14
|
+
paths: configPaths,
|
|
15
|
+
params: configParams,
|
|
16
|
+
strict: true,
|
|
17
|
+
traverse: false,
|
|
18
|
+
});
|
|
14
19
|
const argvConfig = lodash.pick(argv, configParams);
|
|
15
20
|
const result = Object.assign({}, defaultConfig, config, argvConfig);
|
|
16
21
|
|
|
@@ -87,12 +92,23 @@ function transformConfig(result) {
|
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
function transformBrowser(result) {
|
|
95
|
+
if (result.browsersInfo) {
|
|
96
|
+
transformBrowsersInfo(result.browsersInfo);
|
|
97
|
+
delete result.browsersInfo;
|
|
98
|
+
}
|
|
90
99
|
if (result.browser) {
|
|
100
|
+
transformBrowsersInfo(result.browser);
|
|
101
|
+
delete result.browser;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
|
|
106
|
+
function transformBrowsersInfo(info) {
|
|
91
107
|
result.environments = [];
|
|
92
|
-
if (!
|
|
93
|
-
|
|
108
|
+
if (!utils.types.isArray(info)) {
|
|
109
|
+
info = [info];
|
|
94
110
|
}
|
|
95
|
-
result.environments =
|
|
111
|
+
result.environments = info.map(browser => {
|
|
96
112
|
if (browser.deviceName) {
|
|
97
113
|
return {chromeEmulationInfo: browser};
|
|
98
114
|
} else if (utils.types.has(browser, 'iosDeviceInfo')) {
|
|
@@ -104,8 +120,6 @@ function transformBrowser(result) {
|
|
|
104
120
|
return browser;
|
|
105
121
|
});
|
|
106
122
|
}
|
|
107
|
-
delete result.browser;
|
|
108
|
-
return result;
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
function transformLayoutBreakpoints(result) {
|