@applitools/eyes-storybook 3.56.0 → 3.57.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 CHANGED
@@ -1,5 +1,82 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.57.1](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.57.0...js/eyes-storybook@3.57.1) (2025-08-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * add showLogs to validator keys ([#3160](https://github.com/Applitools-Dev/sdk/issues/3160)) ([d8f095a](https://github.com/Applitools-Dev/sdk/commit/d8f095ab9ae3531ed0fd7f8a8fcaf0c5cec17217))
9
+
10
+ ## [3.57.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-storybook@3.56.0...js/eyes-storybook@3.57.0) (2025-08-05)
11
+
12
+
13
+ ### Features
14
+
15
+ * improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
16
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
17
+
18
+
19
+ ### Dependencies
20
+
21
+ * @applitools/utils bumped to 1.11.0
22
+ #### Features
23
+
24
+ * improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
25
+ * make utils.general.guid crypto secured ([#3137](https://github.com/Applitools-Dev/sdk/issues/3137)) ([775df08](https://github.com/Applitools-Dev/sdk/commit/775df08307e41402a6603812205bc857bd3f936e))
26
+ * @applitools/eyes bumped to 1.36.0
27
+ #### Features
28
+
29
+ * improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
30
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
31
+
32
+
33
+
34
+ * @applitools/snaptdout bumped to 1.1.0
35
+ #### Features
36
+
37
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
38
+ * @applitools/test-server bumped to 1.3.0
39
+ #### Features
40
+
41
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
42
+
43
+
44
+
45
+ * @applitools/logger bumped to 2.2.1
46
+
47
+ * @applitools/dom-snapshot bumped to 4.13.1
48
+
49
+ * @applitools/socket bumped to 1.3.1
50
+
51
+ * @applitools/req bumped to 1.8.1
52
+
53
+ * @applitools/image bumped to 1.2.1
54
+
55
+ * @applitools/dom-capture bumped to 11.6.1
56
+
57
+ * @applitools/driver bumped to 1.23.1
58
+
59
+ * @applitools/spec-driver-webdriver bumped to 1.4.1
60
+
61
+ * @applitools/spec-driver-selenium bumped to 1.7.1
62
+
63
+ * @applitools/spec-driver-puppeteer bumped to 1.6.1
64
+
65
+ * @applitools/screenshoter bumped to 3.12.1
66
+
67
+ * @applitools/nml-client bumped to 1.11.1
68
+
69
+ * @applitools/tunnel-client bumped to 1.10.2
70
+
71
+ * @applitools/ufg-client bumped to 1.17.1
72
+
73
+ * @applitools/core-base bumped to 1.27.1
74
+
75
+ * @applitools/ec-client bumped to 1.12.2
76
+
77
+ * @applitools/core bumped to 4.44.2
78
+
79
+
3
80
  ## [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
81
 
5
82
 
@@ -0,0 +1,39 @@
1
+ import type { ConfigurationPlain, DesktopBrowserInfo, ChromeEmulationInfo, IOSDeviceInfo, IOSMultiDeviceInfo } from '@applitools/eyes';
2
+ /**
3
+ * https://applitools.com/tutorials/sdks/storybook/config
4
+ */
5
+ export type ApplitoolsConfig = Omit<ConfigurationPlain, 'waitBeforeScreenshots'> & {
6
+ storybookUrl?: string;
7
+ storybookPort?: number;
8
+ storybookHost?: string;
9
+ storybookConfigDir?: string;
10
+ storybookStaticDir?: string;
11
+ showStorybookOutput?: boolean;
12
+ runInDocker?: boolean;
13
+ include?: ((story: {
14
+ name: string;
15
+ kind: string;
16
+ storyTitle?: string;
17
+ parameters?: any;
18
+ }) => boolean) | string | RegExp;
19
+ variations?: Record<string, any>;
20
+ readStoriesTimeout?: number;
21
+ puppeteerOptions?: Record<string, any>;
22
+ puppeteerExtraHTTPHeaders?: Record<string, string>;
23
+ navigationWaitUntil?: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
24
+ browserCacheRequests?: boolean;
25
+ browser?: (DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)[];
26
+ envName?: string;
27
+ testConcurrency?: number;
28
+ showLogs?: boolean;
29
+ exitcode?: boolean;
30
+ ignoreRegions?: any[];
31
+ floatingRegions?: any[];
32
+ layoutRegions?: any[];
33
+ strictRegions?: any[];
34
+ contentRegions?: any[];
35
+ accessibilityRegions?: any[];
36
+ jsonFilePath?: string;
37
+ tapFilePath?: string;
38
+ xmlFilePath?: string;
39
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-storybook",
3
- "version": "3.56.0",
3
+ "version": "3.57.1",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "applitools",
@@ -14,6 +14,7 @@
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
+ "types": "dist/index.d.ts",
17
18
  "bin": {
18
19
  "eyes-setup": "./bin/eyes-setup.js",
19
20
  "eyes-storybook": "./bin/eyes-storybook.js"
@@ -25,7 +26,8 @@
25
26
  ],
26
27
  "scripts": {
27
28
  "lint": "run --top-level eslint '**/*.js'",
28
- "build": "rollup -c rollup.config.js",
29
+ "build:types": "tsc --project tsconfig.types.json",
30
+ "build": "rollup -c rollup.config.js && yarn build:types",
29
31
  "build:heavy": "node scripts/bitmap.js",
30
32
  "test": "yarn build && yarn test:mocha",
31
33
  "test:mocha": "run --top-level mocha 'test/{unit,it,e2e}/*.test.js'",
@@ -56,15 +58,15 @@
56
58
  "up:framework": "cd test/fixtures/storybook-versions/${APPLITOOLS_FRAMEWORK_VERSION} && npm ci"
57
59
  },
58
60
  "dependencies": {
59
- "@applitools/core": "4.43.0",
60
- "@applitools/driver": "1.22.1",
61
- "@applitools/eyes": "1.35.3",
61
+ "@applitools/core": "4.44.2",
62
+ "@applitools/driver": "1.23.1",
63
+ "@applitools/eyes": "1.36.0",
62
64
  "@applitools/functional-commons": "1.6.0",
63
- "@applitools/logger": "2.1.5",
65
+ "@applitools/logger": "2.2.1",
64
66
  "@applitools/monitoring-commons": "1.0.19",
65
- "@applitools/spec-driver-puppeteer": "1.5.1",
66
- "@applitools/ufg-client": "1.16.14",
67
- "@applitools/utils": "1.9.0",
67
+ "@applitools/spec-driver-puppeteer": "1.6.1",
68
+ "@applitools/ufg-client": "1.17.1",
69
+ "@applitools/utils": "1.11.0",
68
70
  "@inquirer/prompts": "7.0.1",
69
71
  "boxen": "4.2.0",
70
72
  "chalk": "3.0.0",
@@ -79,8 +81,8 @@
79
81
  },
80
82
  "devDependencies": {
81
83
  "@applitools/bongo": "^5.10.0",
82
- "@applitools/snaptdout": "^1.0.0",
83
- "@applitools/test-server": "^1.2.3",
84
+ "@applitools/snaptdout": "^1.1.0",
85
+ "@applitools/test-server": "^1.3.0",
84
86
  "@applitools/test-utils": "^1.5.17",
85
87
  "@storybook/addon-interactions": "^6.4.18",
86
88
  "@storybook/react": "^6.5.16",
@@ -96,6 +98,7 @@
96
98
  "react-dom": "^16.12.0",
97
99
  "rollup": "^1.28.0",
98
100
  "rollup-plugin-commonjs": "^10.1.0",
101
+ "typescript": "^5.3.3",
99
102
  "ua-parser-js": "^0.7.21"
100
103
  },
101
104
  "engines": {
package/src/eyes-setup.js CHANGED
@@ -40,50 +40,59 @@ function handleError(asyncFunc) {
40
40
  }
41
41
 
42
42
  async function init(args) {
43
- let shouldUpdate = true;
44
- let fileName;
45
-
46
43
  log(chalk.yellow('Setting up Eyes-Storybook for your project:'));
47
44
 
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
- }
45
+ let {config, fileName, isCorrupted} = await loadExistingConfig();
61
46
 
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({
47
+ if (isCorrupted) {
48
+ log(chalk.yellow(`\nWarning: Your configuration file '${fileName}' appears to be corrupted.`));
49
+ const shouldOverwrite = await confirm({
69
50
  message:
70
- 'Detected APPLITOOLS_API_KEY environment variable. Would you like it to be used? (default Yes):',
51
+ 'Would you like to create a new one? This will replace the corrupted file (Default Yes):',
71
52
  default: true,
72
53
  });
73
- apiKey = shouldUseEnvApiKey ? 'process.env.APPLITOOLS_API_KEY' : undefined;
74
- warnForApiKey = !shouldUseEnvApiKey; // warn if the user doesn't want to use the env variable
54
+
55
+ if (!shouldOverwrite) {
56
+ log('Aborting setup. Please fix your configuration file manually or remove it.');
57
+ process.exit(0);
58
+ }
59
+ // By letting this block finish, the script proceeds as if no config was found
75
60
  }
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):`,
61
+
62
+ // If no config exists or is corrupted, run the interactive setup
63
+ let apiKey,
64
+ serverUrl,
65
+ warnForApiKey = false;
66
+
67
+ let shouldUpdate = !config;
68
+ if (shouldUpdate) {
69
+ let shouldUseEnvApiKey = false;
70
+ if (utils.general.getEnvValue('API_KEY')) {
71
+ shouldUseEnvApiKey = await confirm({
72
+ message:
73
+ 'Detected APPLITOOLS_API_KEY environment variable. Would you like it to be used? (default Yes):',
80
74
  default: true,
81
75
  });
82
- serverUrl = shouldUseEnvServerUrl ? `APPLITOOLS_${url}` : undefined;
76
+ if (shouldUseEnvApiKey) {
77
+ apiKey = 'process.env.APPLITOOLS_API_KEY';
78
+ }
79
+ warnForApiKey = !shouldUseEnvApiKey; // Warn if the user has an env var but doesn't use it
80
+ }
81
+
82
+ let shouldUseEnvServerUrl = false;
83
+ for (const url of ['EYES_SERVER_URL', 'SERVER_URL']) {
84
+ if (utils.general.getEnvValue(url)) {
85
+ shouldUseEnvServerUrl = await confirm({
86
+ message: `Detected APPLITOOLS_${url} environment variable. Would you like it to be used? (default Yes):`,
87
+ default: true,
88
+ });
89
+ if (shouldUseEnvServerUrl) {
90
+ serverUrl = `process.env.APPLITOOLS_${url}`;
91
+ break; // Use the first one found
92
+ }
93
+ }
83
94
  }
84
- }
85
95
 
86
- if (shouldUpdate) {
87
96
  if (!shouldUseEnvApiKey) {
88
97
  apiKey =
89
98
  args.apiKey ??
@@ -91,8 +100,9 @@ async function init(args) {
91
100
  message:
92
101
  'Enter your API key (https://applitools.com/docs/topics/overview/obtain-api-key.html):',
93
102
  }));
94
- warnForApiKey = apiKey !== ''; // warn if the user did provide an API key
103
+ warnForApiKey = apiKey !== ''; // Warn if the user provided any API key directly
95
104
  }
105
+
96
106
  if (!shouldUseEnvServerUrl) {
97
107
  serverUrl =
98
108
  args.serverUrl ??
@@ -102,7 +112,7 @@ async function init(args) {
102
112
  }
103
113
 
104
114
  config = {
105
- ...config,
115
+ ...(config || {}),
106
116
  appName: 'My Storybook App',
107
117
  batchName: 'My Storybook',
108
118
  showLogs: false,
@@ -114,6 +124,8 @@ async function init(args) {
114
124
 
115
125
  printPostlude();
116
126
 
127
+ // --- Helper Functions ---
128
+
117
129
  async function loadExistingConfig() {
118
130
  const configFiles = [
119
131
  'applitools.config.js',
@@ -123,21 +135,24 @@ async function init(args) {
123
135
  ];
124
136
 
125
137
  for (const file of configFiles) {
126
- fileName = file;
127
138
  try {
128
- await fs.access(file);
129
139
  const fileUrl = pathToFileURL(file).href;
130
- const module = await import(fileUrl);
131
- return module.default || module;
140
+ const module = await import(`${fileUrl}?t=${Date.now()}`); // Append timestamp to bypass cache
141
+
142
+ return {config: module.default || module, fileName: file, isCorrupted: false};
132
143
  } 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
144
+ if (err.code === 'ERR_MODULE_NOT_FOUND') {
145
+ // This file doesn't exist, so we continue searching for the one that does.
146
+ continue;
147
+ }
148
+
149
+ return {config: null, fileName: file, isCorrupted: true};
136
150
  }
137
151
  }
138
- // no config file found
139
- fileName = 'applitools.config.js';
140
- return null;
152
+
153
+ // No file was found in any of the possible locations.
154
+ // We return a default filename for a new file to be created.
155
+ return {config: null, fileName: 'applitools.config.js', isCorrupted: false};
141
156
  }
142
157
 
143
158
  function generateConfigContent() {
@@ -170,11 +185,9 @@ async function init(args) {
170
185
  configLines.push(`serverUrl: ${serverUrl},`);
171
186
  } else if (serverUrl) {
172
187
  configLines.push(`serverUrl: '${serverUrl}',`);
173
- } else {
174
- configLines.push(`// serverUrl: '',`);
175
188
  }
176
189
 
177
- // Handle other config lines
190
+ // Handle other config lines by prioritizing env vars over defaults
178
191
  const otherKeys = [
179
192
  'appName',
180
193
  'batchName',
@@ -184,12 +197,22 @@ async function init(args) {
184
197
  'proxy',
185
198
  'notifyOnCompletion',
186
199
  'concurrentTabs',
200
+ 'navigationWaitUntil',
201
+ 'waitBeforeCapture',
187
202
  ];
188
203
 
189
204
  for (const key of otherKeys) {
190
- const line = getConfigLine(key);
191
- if (line) {
192
- configLines.push(line);
205
+ const envVar = envConfigMap[key];
206
+ // Check if an environment variable for this key is set
207
+ if (envVar && utils.general.getEnvValue(envVar.replace('APPLITOOLS_', ''))) {
208
+ configLines.push(`${key}: process.env.${envVar},`);
209
+ } else if (Object.prototype.hasOwnProperty.call(config, key)) {
210
+ // Otherwise, use the default value from the config object
211
+ const value = config[key];
212
+ if (value !== undefined) {
213
+ const line = typeof value === 'string' ? `${key}: '${value}',` : `${key}: ${value},`;
214
+ configLines.push(line);
215
+ }
193
216
  }
194
217
  }
195
218
 
@@ -206,32 +229,6 @@ module.exports = {
206
229
  // ]
207
230
  };
208
231
  `;
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
232
  }
236
233
 
237
234
  function printPostlude() {
@@ -256,7 +253,7 @@ module.exports = {
256
253
  if (warnForApiKey) {
257
254
  log(
258
255
  chalk.yellow(
259
- 'Please consider setting your API key via environment variable APPLITOOLS_API_KEY to avoid exposing it in the config file.',
256
+ '\nWarning: Consider setting your API key via the APPLITOOLS_API_KEY environment variable.',
260
257
  ),
261
258
  );
262
259
  }
@@ -10,12 +10,7 @@ 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({
14
- paths: configPaths,
15
- params: configParams,
16
- strict: true,
17
- traverse: false,
18
- });
13
+ const config = getAndParseConfig({configPaths, configParams});
19
14
  const argvConfig = lodash.pick(argv, configParams);
20
15
  const result = Object.assign({}, defaultConfig, config, argvConfig);
21
16
 
@@ -86,6 +81,27 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
86
81
  return result;
87
82
  }
88
83
 
84
+ function getAndParseConfig({configPaths, configParams}) {
85
+ try {
86
+ return utils.config.getConfig({
87
+ paths: configPaths,
88
+ params: configParams,
89
+ strict: true,
90
+ traverse: false,
91
+ });
92
+ } catch (error) {
93
+ if (error.message.includes('Could not find configuration file')) {
94
+ return utils.config.populateConfigParams({config: {}, params: configParams});
95
+ }
96
+ const documentationUrl = 'https://applitools.com/tutorials/sdks/storybook/config#properties';
97
+ throw new Error(
98
+ `Your configuration file is invalid. Please review our documentation for valid configuration settings: ${documentationUrl}.
99
+ Additionally, you can generate a new configuration by running 'npx eyes-setup'.
100
+ \n\nError details: ${error.message}`.trim(),
101
+ );
102
+ }
103
+ }
104
+
89
105
  function transformConfig(result) {
90
106
  transformLayoutBreakpoints(result);
91
107
  transformBrowser(result);
package/src/index.ts ADDED
@@ -0,0 +1,35 @@
1
+ import type {ConfigurationPlain, DesktopBrowserInfo, ChromeEmulationInfo, IOSDeviceInfo, IOSMultiDeviceInfo} from '@applitools/eyes'
2
+
3
+ /**
4
+ * https://applitools.com/tutorials/sdks/storybook/config
5
+ */
6
+ export type ApplitoolsConfig = Omit<ConfigurationPlain, 'waitBeforeScreenshots'> & {
7
+ storybookUrl?: string;
8
+ storybookPort?: number;
9
+ storybookHost?: string;
10
+ storybookConfigDir?: string;
11
+ storybookStaticDir?: string;
12
+ showStorybookOutput?: boolean;
13
+ runInDocker?: boolean;
14
+ include?: ((story: { name: string; kind: string; storyTitle?: string; parameters?: any }) => boolean) | string | RegExp;
15
+ variations?: Record<string, any>;
16
+ readStoriesTimeout?: number;
17
+ puppeteerOptions?: Record<string, any>;
18
+ puppeteerExtraHTTPHeaders?: Record<string, string>;
19
+ navigationWaitUntil?: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
20
+ browserCacheRequests?: boolean;
21
+ browser?: (DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)[];
22
+ envName?: string;
23
+ testConcurrency?: number;
24
+ showLogs?: boolean;
25
+ exitcode?: boolean;
26
+ ignoreRegions?: any[];
27
+ floatingRegions?: any[];
28
+ layoutRegions?: any[];
29
+ strictRegions?: any[];
30
+ contentRegions?: any[];
31
+ accessibilityRegions?: any[];
32
+ jsonFilePath?: string;
33
+ tapFilePath?: string;
34
+ xmlFilePath?: string;
35
+ }
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+ const chalk = require('chalk');
3
+ const {Configuration} = require('@applitools/eyes');
4
+
5
+ // Get all keys directly from the base Configuration class
6
+ const dynamicBaseKeys = [
7
+ ...Object.getOwnPropertyNames(Object.getPrototypeOf(new Configuration())),
8
+ ].filter(
9
+ prop =>
10
+ !prop.startsWith('get') &&
11
+ !prop.startsWith('set') &&
12
+ !prop.startsWith('to') &&
13
+ !prop.startsWith('_') &&
14
+ prop !== 'constructor',
15
+ );
16
+
17
+ // known aliases that are not on the Configuration prototype
18
+ const knownAliases = [
19
+ 'envName',
20
+ 'testConcurrency',
21
+ 'concurrency',
22
+ 'eyesServerUrl',
23
+ 'batchId',
24
+ 'batchName',
25
+ 'batchSequenceName',
26
+ 'keepBatchOpen',
27
+ 'environments',
28
+ ];
29
+
30
+ const applitoolsBaseKeys = [...dynamicBaseKeys, ...knownAliases];
31
+
32
+ // A list of all keys specific to the eyes-storybook package.
33
+ const storybookSpecificKeys = [
34
+ 'storybookPort',
35
+ 'storybookHost',
36
+ 'storybookConfigDir',
37
+ 'storybookUrl',
38
+ 'storybookStaticDir',
39
+ 'showStorybookOutput',
40
+ 'exitcode',
41
+ 'include',
42
+ 'variations',
43
+ 'runInDocker',
44
+ 'readStoriesTimeout',
45
+ 'reloadPagePerStory',
46
+ 'startStorybookServerTimeout',
47
+ 'showLogs',
48
+
49
+ // Browser & Puppeteer Control
50
+ 'browser',
51
+ 'puppeteerOptions',
52
+ 'puppeteerExtraHTTPHeaders',
53
+ 'navigationWaitUntil',
54
+ 'networkBlockPatterns',
55
+ 'browserRequestsTimeout',
56
+ 'browserHeadersOverride',
57
+ 'browserCacheRequests',
58
+
59
+ // Region Matching
60
+ 'ignoreRegions',
61
+ 'floatingRegions',
62
+ 'layoutRegions',
63
+ 'strictRegions',
64
+ 'contentRegions',
65
+ 'accessibilityRegions',
66
+
67
+ // Reporting
68
+ 'tapFilePath',
69
+ 'xmlFilePath',
70
+ 'jsonFilePath',
71
+
72
+ // Legacy & Internal
73
+ 'waitBeforeScreenshot', // backward compatibility
74
+ 'waitBeforeScreenshots', // backward compatibility
75
+ 'waitBeforeCapture',
76
+ 'fakeIE',
77
+ 'storyConfiguration',
78
+ 'storyDataGap',
79
+ 'packagePath',
80
+ ];
81
+
82
+ // Combine all known keys into a single Set for efficient O(1) lookups.
83
+ const knownKeys = new Set([...storybookSpecificKeys, ...applitoolsBaseKeys]);
84
+
85
+ /**
86
+ * Checks the user's config object for any keys that are not recognized
87
+ * and logs a warning to the console if any are found.
88
+ * @param {object} config - The user's configuration object.
89
+ * @param {object} logger - The logger instance.
90
+ */
91
+ function logUnrecognizedKeys(config, logger) {
92
+ const unrecognizedKeys = Object.keys(config).filter(key => !knownKeys.has(key));
93
+
94
+ if (unrecognizedKeys.length > 0) {
95
+ // uses a warning sign emoji - ⚠️
96
+ console.log(
97
+ chalk.yellow(
98
+ `\n\u26A0 The following configuration keys are unrecognized and will be ignored:`,
99
+ ),
100
+ );
101
+ unrecognizedKeys.forEach(key => {
102
+ console.log(chalk.yellow(` - ${key}`));
103
+ });
104
+ logger.log('\n');
105
+
106
+ const docsUrl = 'https://applitools.com/tutorials/sdks/storybook/config#properties';
107
+ console.log(
108
+ chalk.bold(`Please review our documentation for valid configuration settings: ${docsUrl}`),
109
+ );
110
+ }
111
+ }
112
+
113
+ module.exports = {
114
+ logUnrecognizedKeys,
115
+ // Exporting the set is optional but can be useful for other utilities
116
+ knownKeys,
117
+ };
@@ -13,9 +13,11 @@ const startStorybookServer = require('./startStorybookServer');
13
13
  const {isIE} = require('./shouldRenderIE');
14
14
  const {makeLogger} = require('@applitools/logger');
15
15
  const determineStorybookVersion = require('./utils/determineStorybookVersion');
16
+ const {logUnrecognizedKeys} = require('./utils/config-validator');
17
+ const utils = require('@applitools/utils');
16
18
 
17
19
  async function validateAndPopulateConfig({config, packagePath = '', logger = makeLogger()}) {
18
- if (!config.apiKey) {
20
+ if (!config.apiKey && !utils.general.getEnvValue('API_KEY')) {
19
21
  throw new Error(missingApiKeyFailMsg);
20
22
  }
21
23
 
@@ -77,5 +79,8 @@ async function validateAndPopulateConfig({config, packagePath = '', logger = mak
77
79
  ),
78
80
  );
79
81
  }
82
+
83
+ logUnrecognizedKeys(config, logger);
80
84
  }
85
+
81
86
  module.exports = validateAndPopulateConfig;
@@ -1,4 +0,0 @@
1
- import {Configuration} from '@applitools/eyes'
2
-
3
- // should we omit more properties?
4
- export type ApplitoolsConfig = Omit<Configuration, 'waitBeforeScreenshots'>