@applitools/eyes-storybook 3.55.9 → 3.57.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 +109 -0
- package/bin/eyes-setup.js +2 -0
- package/dist/index.d.ts +39 -0
- package/package.json +19 -12
- package/src/eyes-setup.js +269 -0
- package/src/eyesStorybook.js +5 -1
- package/src/generateConfig.js +36 -6
- package/src/index.ts +35 -0
- package/src/utils/config-validator.js +116 -0
- package/src/validateAndPopulateConfig.js +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,114 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [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)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
|
|
9
|
+
* release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Dependencies
|
|
13
|
+
|
|
14
|
+
* @applitools/utils bumped to 1.11.0
|
|
15
|
+
#### Features
|
|
16
|
+
|
|
17
|
+
* improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
|
|
18
|
+
* make utils.general.guid crypto secured ([#3137](https://github.com/Applitools-Dev/sdk/issues/3137)) ([775df08](https://github.com/Applitools-Dev/sdk/commit/775df08307e41402a6603812205bc857bd3f936e))
|
|
19
|
+
* @applitools/eyes bumped to 1.36.0
|
|
20
|
+
#### Features
|
|
21
|
+
|
|
22
|
+
* improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
|
|
23
|
+
* release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
* @applitools/snaptdout bumped to 1.1.0
|
|
28
|
+
#### Features
|
|
29
|
+
|
|
30
|
+
* release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
|
|
31
|
+
* @applitools/test-server bumped to 1.3.0
|
|
32
|
+
#### Features
|
|
33
|
+
|
|
34
|
+
* release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
* @applitools/logger bumped to 2.2.1
|
|
39
|
+
|
|
40
|
+
* @applitools/dom-snapshot bumped to 4.13.1
|
|
41
|
+
|
|
42
|
+
* @applitools/socket bumped to 1.3.1
|
|
43
|
+
|
|
44
|
+
* @applitools/req bumped to 1.8.1
|
|
45
|
+
|
|
46
|
+
* @applitools/image bumped to 1.2.1
|
|
47
|
+
|
|
48
|
+
* @applitools/dom-capture bumped to 11.6.1
|
|
49
|
+
|
|
50
|
+
* @applitools/driver bumped to 1.23.1
|
|
51
|
+
|
|
52
|
+
* @applitools/spec-driver-webdriver bumped to 1.4.1
|
|
53
|
+
|
|
54
|
+
* @applitools/spec-driver-selenium bumped to 1.7.1
|
|
55
|
+
|
|
56
|
+
* @applitools/spec-driver-puppeteer bumped to 1.6.1
|
|
57
|
+
|
|
58
|
+
* @applitools/screenshoter bumped to 3.12.1
|
|
59
|
+
|
|
60
|
+
* @applitools/nml-client bumped to 1.11.1
|
|
61
|
+
|
|
62
|
+
* @applitools/tunnel-client bumped to 1.10.2
|
|
63
|
+
|
|
64
|
+
* @applitools/ufg-client bumped to 1.17.1
|
|
65
|
+
|
|
66
|
+
* @applitools/core-base bumped to 1.27.1
|
|
67
|
+
|
|
68
|
+
* @applitools/ec-client bumped to 1.12.2
|
|
69
|
+
|
|
70
|
+
* @applitools/core bumped to 4.44.2
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## [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)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Features
|
|
77
|
+
|
|
78
|
+
* eyes-setup script | AD-9543 ([#3075](https://github.com/Applitools-Dev/sdk/issues/3075)) ([27f15f9](https://github.com/Applitools-Dev/sdk/commit/27f15f9b54ba93c8189214a5df424b543d564120))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### Bug Fixes
|
|
82
|
+
|
|
83
|
+
* 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))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Dependencies
|
|
87
|
+
|
|
88
|
+
* @applitools/nml-client bumped to 1.10.0
|
|
89
|
+
#### Features
|
|
90
|
+
|
|
91
|
+
* android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
* @applitools/core-base bumped to 1.26.0
|
|
96
|
+
#### Features
|
|
97
|
+
|
|
98
|
+
* batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
|
|
99
|
+
* @applitools/ec-client bumped to 1.11.1
|
|
100
|
+
|
|
101
|
+
* @applitools/core bumped to 4.43.0
|
|
102
|
+
#### Features
|
|
103
|
+
|
|
104
|
+
* android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
|
|
105
|
+
* batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
* @applitools/eyes bumped to 1.35.3
|
|
110
|
+
|
|
111
|
+
|
|
3
112
|
## [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
113
|
|
|
5
114
|
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Configuration, DesktopBrowserInfo, ChromeEmulationInfo, IOSDeviceInfo, IOSMultiDeviceInfo } from '@applitools/eyes';
|
|
2
|
+
/**
|
|
3
|
+
* https://applitools.com/tutorials/sdks/storybook/config
|
|
4
|
+
*/
|
|
5
|
+
export type ApplitoolsConfig = Omit<Configuration, '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.
|
|
3
|
+
"version": "3.57.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"applitools",
|
|
@@ -14,7 +14,11 @@
|
|
|
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
|
-
"
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"bin": {
|
|
19
|
+
"eyes-setup": "./bin/eyes-setup.js",
|
|
20
|
+
"eyes-storybook": "./bin/eyes-storybook.js"
|
|
21
|
+
},
|
|
18
22
|
"files": [
|
|
19
23
|
"src",
|
|
20
24
|
"bin",
|
|
@@ -22,7 +26,8 @@
|
|
|
22
26
|
],
|
|
23
27
|
"scripts": {
|
|
24
28
|
"lint": "run --top-level eslint '**/*.js'",
|
|
25
|
-
"build": "
|
|
29
|
+
"build:types": "tsc --project tsconfig.types.json",
|
|
30
|
+
"build": "rollup -c rollup.config.js && yarn build:types",
|
|
26
31
|
"build:heavy": "node scripts/bitmap.js",
|
|
27
32
|
"test": "yarn build && yarn test:mocha",
|
|
28
33
|
"test:mocha": "run --top-level mocha 'test/{unit,it,e2e}/*.test.js'",
|
|
@@ -53,15 +58,16 @@
|
|
|
53
58
|
"up:framework": "cd test/fixtures/storybook-versions/${APPLITOOLS_FRAMEWORK_VERSION} && npm ci"
|
|
54
59
|
},
|
|
55
60
|
"dependencies": {
|
|
56
|
-
"@applitools/core": "4.
|
|
57
|
-
"@applitools/driver": "1.
|
|
58
|
-
"@applitools/eyes": "1.
|
|
61
|
+
"@applitools/core": "4.44.2",
|
|
62
|
+
"@applitools/driver": "1.23.1",
|
|
63
|
+
"@applitools/eyes": "1.36.0",
|
|
59
64
|
"@applitools/functional-commons": "1.6.0",
|
|
60
|
-
"@applitools/logger": "2.1
|
|
65
|
+
"@applitools/logger": "2.2.1",
|
|
61
66
|
"@applitools/monitoring-commons": "1.0.19",
|
|
62
|
-
"@applitools/spec-driver-puppeteer": "1.
|
|
63
|
-
"@applitools/ufg-client": "1.
|
|
64
|
-
"@applitools/utils": "1.
|
|
67
|
+
"@applitools/spec-driver-puppeteer": "1.6.1",
|
|
68
|
+
"@applitools/ufg-client": "1.17.1",
|
|
69
|
+
"@applitools/utils": "1.11.0",
|
|
70
|
+
"@inquirer/prompts": "7.0.1",
|
|
65
71
|
"boxen": "4.2.0",
|
|
66
72
|
"chalk": "3.0.0",
|
|
67
73
|
"detect-port": "1.3.0",
|
|
@@ -75,8 +81,8 @@
|
|
|
75
81
|
},
|
|
76
82
|
"devDependencies": {
|
|
77
83
|
"@applitools/bongo": "^5.10.0",
|
|
78
|
-
"@applitools/snaptdout": "^1.
|
|
79
|
-
"@applitools/test-server": "^1.
|
|
84
|
+
"@applitools/snaptdout": "^1.1.0",
|
|
85
|
+
"@applitools/test-server": "^1.3.0",
|
|
80
86
|
"@applitools/test-utils": "^1.5.17",
|
|
81
87
|
"@storybook/addon-interactions": "^6.4.18",
|
|
82
88
|
"@storybook/react": "^6.5.16",
|
|
@@ -92,6 +98,7 @@
|
|
|
92
98
|
"react-dom": "^16.12.0",
|
|
93
99
|
"rollup": "^1.28.0",
|
|
94
100
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
101
|
+
"typescript": "^5.3.3",
|
|
95
102
|
"ua-parser-js": "^0.7.21"
|
|
96
103
|
},
|
|
97
104
|
"engines": {
|
|
@@ -0,0 +1,269 @@
|
|
|
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
|
+
log(chalk.yellow('Setting up Eyes-Storybook for your project:'));
|
|
44
|
+
|
|
45
|
+
let {config, fileName, isCorrupted} = await loadExistingConfig();
|
|
46
|
+
|
|
47
|
+
if (isCorrupted) {
|
|
48
|
+
log(chalk.yellow(`\nWarning: Your configuration file '${fileName}' appears to be corrupted.`));
|
|
49
|
+
const shouldOverwrite = await confirm({
|
|
50
|
+
message:
|
|
51
|
+
'Would you like to create a new one? This will replace the corrupted file (Default Yes):',
|
|
52
|
+
default: true,
|
|
53
|
+
});
|
|
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
|
|
60
|
+
}
|
|
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):',
|
|
74
|
+
default: true,
|
|
75
|
+
});
|
|
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
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!shouldUseEnvApiKey) {
|
|
97
|
+
apiKey =
|
|
98
|
+
args.apiKey ??
|
|
99
|
+
(await input({
|
|
100
|
+
message:
|
|
101
|
+
'Enter your API key (https://applitools.com/docs/topics/overview/obtain-api-key.html):',
|
|
102
|
+
}));
|
|
103
|
+
warnForApiKey = apiKey !== ''; // Warn if the user provided any API key directly
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!shouldUseEnvServerUrl) {
|
|
107
|
+
serverUrl =
|
|
108
|
+
args.serverUrl ??
|
|
109
|
+
(await input({
|
|
110
|
+
message: 'Enter your Eyes server URL (default is https://eyes.applitools.com):',
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
config = {
|
|
115
|
+
...(config || {}),
|
|
116
|
+
appName: 'My Storybook App',
|
|
117
|
+
batchName: 'My Storybook',
|
|
118
|
+
showLogs: false,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const fileContent = generateConfigContent();
|
|
122
|
+
await fs.writeFile(fileName, fileContent, 'utf8');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
printPostlude();
|
|
126
|
+
|
|
127
|
+
// --- Helper Functions ---
|
|
128
|
+
|
|
129
|
+
async function loadExistingConfig() {
|
|
130
|
+
const configFiles = [
|
|
131
|
+
'applitools.config.js',
|
|
132
|
+
'applitools.config.mjs',
|
|
133
|
+
'applitools.config.cjs',
|
|
134
|
+
'eyes.config.js',
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
for (const file of configFiles) {
|
|
138
|
+
try {
|
|
139
|
+
const fileUrl = pathToFileURL(file).href;
|
|
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};
|
|
143
|
+
} catch (err) {
|
|
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};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
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};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function generateConfigContent() {
|
|
159
|
+
const envConfigMap = {
|
|
160
|
+
batchName: 'APPLITOOLS_BATCH_NAME',
|
|
161
|
+
batchId: 'APPLITOOLS_BATCH_ID',
|
|
162
|
+
showLogs: 'APPLITOOLS_SHOW_LOGS',
|
|
163
|
+
batchSequenceName: 'APPLITOOLS_BATCH_SEQUENCE_NAME',
|
|
164
|
+
proxy: 'APPLITOOLS_PROXY',
|
|
165
|
+
notifyOnCompletion: 'APPLITOOLS_NOTIFY_ON_COMPLETION',
|
|
166
|
+
concurrentTabs: 'APPLITOOLS_CONCURRENT_TABS',
|
|
167
|
+
appName: 'APPLITOOLS_APP_NAME',
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const configLines = [];
|
|
171
|
+
|
|
172
|
+
// Handle apiKey
|
|
173
|
+
if (apiKey === 'process.env.APPLITOOLS_API_KEY') {
|
|
174
|
+
configLines.push('apiKey: process.env.APPLITOOLS_API_KEY,');
|
|
175
|
+
} else if (apiKey) {
|
|
176
|
+
configLines.push(
|
|
177
|
+
`apiKey: '${apiKey}', // Warning: 'apiKey' is not obscured, consider setting it via environment variable APPLITOOLS_API_KEY`,
|
|
178
|
+
);
|
|
179
|
+
} else {
|
|
180
|
+
configLines.push(`// apiKey: '',`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Handle serverUrl
|
|
184
|
+
if (serverUrl && serverUrl.startsWith('process.env.')) {
|
|
185
|
+
configLines.push(`serverUrl: ${serverUrl},`);
|
|
186
|
+
} else if (serverUrl) {
|
|
187
|
+
configLines.push(`serverUrl: '${serverUrl}',`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Handle other config lines by prioritizing env vars over defaults
|
|
191
|
+
const otherKeys = [
|
|
192
|
+
'appName',
|
|
193
|
+
'batchName',
|
|
194
|
+
'batchId',
|
|
195
|
+
'showLogs',
|
|
196
|
+
'batchSequenceName',
|
|
197
|
+
'proxy',
|
|
198
|
+
'notifyOnCompletion',
|
|
199
|
+
'concurrentTabs',
|
|
200
|
+
'navigationWaitUntil',
|
|
201
|
+
'waitBeforeCapture',
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
for (const key of otherKeys) {
|
|
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
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return `/**
|
|
220
|
+
* @type {import('@applitools/eyes-storybook').ApplitoolsConfig}
|
|
221
|
+
**/
|
|
222
|
+
module.exports = {
|
|
223
|
+
${configLines.join('\n ')}
|
|
224
|
+
// browsersInfo: [
|
|
225
|
+
// {width: 1024, height: 768, name: 'firefox'},
|
|
226
|
+
// {width: 1024, height: 768, name: 'chrome'},
|
|
227
|
+
// {iosDeviceInfo: {deviceName: 'iPhone 16'}},
|
|
228
|
+
// {chromeEmulationInfo: {deviceName: 'Galaxy S20'}},
|
|
229
|
+
// ]
|
|
230
|
+
};
|
|
231
|
+
`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function printPostlude() {
|
|
235
|
+
log('');
|
|
236
|
+
if (shouldUpdate) {
|
|
237
|
+
log(
|
|
238
|
+
chalk.green('✔ Success!'),
|
|
239
|
+
chalk.bold('\n'),
|
|
240
|
+
chalk.bold('Eyes Storybook is now set up!'),
|
|
241
|
+
chalk.bold('Please visit our Storybook documentation to learn more.'),
|
|
242
|
+
chalk.bold('https://applitools.com/tutorials/sdks/storybook/quickstart'),
|
|
243
|
+
);
|
|
244
|
+
} else {
|
|
245
|
+
log(
|
|
246
|
+
chalk.green('✔ Good news! Eyes Storybook is already properly configured!'),
|
|
247
|
+
chalk.bold('\n'),
|
|
248
|
+
chalk.bold('Please visit our Storybook documentation to learn more.'),
|
|
249
|
+
chalk.bold('https://applitools.com/tutorials/sdks/storybook/quickstart'),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (warnForApiKey) {
|
|
254
|
+
log(
|
|
255
|
+
chalk.yellow(
|
|
256
|
+
'\nWarning: Consider setting your API key via the APPLITOOLS_API_KEY environment variable.',
|
|
257
|
+
),
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function log(...args) {
|
|
264
|
+
console.log(...args);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function error(...args) {
|
|
268
|
+
console.error(...args);
|
|
269
|
+
}
|
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,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 =
|
|
13
|
+
const config = getAndParseConfig({configPaths, configParams});
|
|
14
14
|
const argvConfig = lodash.pick(argv, configParams);
|
|
15
15
|
const result = Object.assign({}, defaultConfig, config, argvConfig);
|
|
16
16
|
|
|
@@ -81,18 +81,50 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
|
|
|
81
81
|
return result;
|
|
82
82
|
}
|
|
83
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
|
+
|
|
84
105
|
function transformConfig(result) {
|
|
85
106
|
transformLayoutBreakpoints(result);
|
|
86
107
|
transformBrowser(result);
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
function transformBrowser(result) {
|
|
111
|
+
if (result.browsersInfo) {
|
|
112
|
+
transformBrowsersInfo(result.browsersInfo);
|
|
113
|
+
delete result.browsersInfo;
|
|
114
|
+
}
|
|
90
115
|
if (result.browser) {
|
|
116
|
+
transformBrowsersInfo(result.browser);
|
|
117
|
+
delete result.browser;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return result;
|
|
121
|
+
|
|
122
|
+
function transformBrowsersInfo(info) {
|
|
91
123
|
result.environments = [];
|
|
92
|
-
if (!
|
|
93
|
-
|
|
124
|
+
if (!utils.types.isArray(info)) {
|
|
125
|
+
info = [info];
|
|
94
126
|
}
|
|
95
|
-
result.environments =
|
|
127
|
+
result.environments = info.map(browser => {
|
|
96
128
|
if (browser.deviceName) {
|
|
97
129
|
return {chromeEmulationInfo: browser};
|
|
98
130
|
} else if (utils.types.has(browser, 'iosDeviceInfo')) {
|
|
@@ -104,8 +136,6 @@ function transformBrowser(result) {
|
|
|
104
136
|
return browser;
|
|
105
137
|
});
|
|
106
138
|
}
|
|
107
|
-
delete result.browser;
|
|
108
|
-
return result;
|
|
109
139
|
}
|
|
110
140
|
|
|
111
141
|
function transformLayoutBreakpoints(result) {
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type {Configuration, DesktopBrowserInfo, ChromeEmulationInfo, IOSDeviceInfo, IOSMultiDeviceInfo} from '@applitools/eyes'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* https://applitools.com/tutorials/sdks/storybook/config
|
|
5
|
+
*/
|
|
6
|
+
export type ApplitoolsConfig = Omit<Configuration, '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,116 @@
|
|
|
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
|
+
|
|
48
|
+
// Browser & Puppeteer Control
|
|
49
|
+
'browser',
|
|
50
|
+
'puppeteerOptions',
|
|
51
|
+
'puppeteerExtraHTTPHeaders',
|
|
52
|
+
'navigationWaitUntil',
|
|
53
|
+
'networkBlockPatterns',
|
|
54
|
+
'browserRequestsTimeout',
|
|
55
|
+
'browserHeadersOverride',
|
|
56
|
+
'browserCacheRequests',
|
|
57
|
+
|
|
58
|
+
// Region Matching
|
|
59
|
+
'ignoreRegions',
|
|
60
|
+
'floatingRegions',
|
|
61
|
+
'layoutRegions',
|
|
62
|
+
'strictRegions',
|
|
63
|
+
'contentRegions',
|
|
64
|
+
'accessibilityRegions',
|
|
65
|
+
|
|
66
|
+
// Reporting
|
|
67
|
+
'tapFilePath',
|
|
68
|
+
'xmlFilePath',
|
|
69
|
+
'jsonFilePath',
|
|
70
|
+
|
|
71
|
+
// Legacy & Internal
|
|
72
|
+
'waitBeforeScreenshot', // backward compatibility
|
|
73
|
+
'waitBeforeScreenshots', // backward compatibility
|
|
74
|
+
'waitBeforeCapture',
|
|
75
|
+
'fakeIE',
|
|
76
|
+
'storyConfiguration',
|
|
77
|
+
'storyDataGap',
|
|
78
|
+
'packagePath',
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// Combine all known keys into a single Set for efficient O(1) lookups.
|
|
82
|
+
const knownKeys = new Set([...storybookSpecificKeys, ...applitoolsBaseKeys]);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Checks the user's config object for any keys that are not recognized
|
|
86
|
+
* and logs a warning to the console if any are found.
|
|
87
|
+
* @param {object} config - The user's configuration object.
|
|
88
|
+
* @param {object} logger - The logger instance.
|
|
89
|
+
*/
|
|
90
|
+
function logUnrecognizedKeys(config, logger) {
|
|
91
|
+
const unrecognizedKeys = Object.keys(config).filter(key => !knownKeys.has(key));
|
|
92
|
+
|
|
93
|
+
if (unrecognizedKeys.length > 0) {
|
|
94
|
+
// uses a warning sign emoji - ⚠️
|
|
95
|
+
console.log(
|
|
96
|
+
chalk.yellow(
|
|
97
|
+
`\n\u26A0 The following configuration keys are unrecognized and will be ignored:`,
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
unrecognizedKeys.forEach(key => {
|
|
101
|
+
console.log(chalk.yellow(` - ${key}`));
|
|
102
|
+
});
|
|
103
|
+
logger.log('\n');
|
|
104
|
+
|
|
105
|
+
const docsUrl = 'https://applitools.com/tutorials/sdks/storybook/config#properties';
|
|
106
|
+
console.log(
|
|
107
|
+
chalk.bold(`Please review our documentation for valid configuration settings: ${docsUrl}`),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
logUnrecognizedKeys,
|
|
114
|
+
// Exporting the set is optional but can be useful for other utilities
|
|
115
|
+
knownKeys,
|
|
116
|
+
};
|
|
@@ -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;
|