@applitools/eyes-storybook 3.29.4 → 3.30.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 +16 -0
- package/README.md +2 -2
- package/dist/getClientAPI.js +11 -3
- package/dist/getStories.js +16 -6
- package/dist/renderStoryWithClientAPI.js +13 -5
- package/dist/runRunAfterScript.js +17 -9
- package/dist/runRunBeforeScript.js +17 -9
- package/package.json +14 -10
- package/src/browser/getClientAPI.js +11 -3
- package/src/browser/getStories.js +5 -3
- package/src/browser/getStoryByIndex.js +4 -4
- package/src/browser/renderStoryWithClientAPI.js +2 -2
- package/src/browser/runRunAfterScript.js +2 -2
- package/src/browser/runRunBeforeScript.js +2 -2
- package/src/cli.js +2 -3
- package/src/configDigest.js +4 -3
- package/src/configParams.js +48 -0
- package/src/errMessages.js +9 -0
- package/src/eyesStorybook.js +81 -39
- package/src/generateConfig.js +43 -6
- package/src/getStoryData.js +5 -10
- package/src/processResults.js +20 -32
- package/src/renderStories.js +6 -13
- package/src/renderStory.js +135 -16
- package/src/shouldRenderIE.js +6 -6
- package/src/validateAndPopulateConfig.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
## 3.30.1 - 2023/1/3
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
- Additional internal event logs
|
|
10
|
+
### Bug fixes
|
|
11
|
+
- fixed bug in mobile environment
|
|
12
|
+
|
|
13
|
+
## 3.30.0 - 2022/12/19
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
- Deprecated "Content" match level value in favor of "IgnoreColors"
|
|
17
|
+
- Add Support for storyStoreV7 flag
|
|
18
|
+
### Bug fixes
|
|
19
|
+
- Handle fake shadowRoot with UFG
|
|
20
|
+
- Handed error during polling in long requests to eyes server
|
|
21
|
+
|
|
6
22
|
## 3.29.4 - 2022/9/12
|
|
7
23
|
|
|
8
24
|
### Features
|
package/README.md
CHANGED
|
@@ -154,8 +154,8 @@ In addition to command-line arguments, it's possible to define the following con
|
|
|
154
154
|
| `storybookStaticDir` | undefined | Path to Storybook's static files folder (also available as command-line argument). |
|
|
155
155
|
| `showStorybookOutput` | undefined | Whether or not you want to see Storybook output (also available as command-line argument). |
|
|
156
156
|
| `viewportSize` | { width: 1024, height: 600} | The size of the puppeteer browser's window. This is the browser window which renders the stories originally (and opens at the size provided in the `viewportSize` parameter), and then a DOM snapshot is uploaded to the server, which renders this snapshot on all the browsers and sizes provided in the `browser` parameter.|
|
|
157
|
-
| `exitcode` | true | If tests failed close with non-zero exit code (also available as command-line argument)
|
|
158
|
-
| `browser` | { width:
|
|
157
|
+
| `exitcode` | true | If tests failed or has visual differences close with non-zero exit code (also available as command-line argument).|
|
|
158
|
+
| `browser` | { width: 1024, height: 768, name: 'chrome' } | The size and browser of the generated screenshots. For more info and possible values, see the [browser section below](#configuring-the-browser).|
|
|
159
159
|
| `showLogs` | false | Whether or not you want to see logs of the Eyes-Storybook plugin. |
|
|
160
160
|
| `batch` | undefined | An object which describes different aspects of the batch. The following lines in this table depict the various ways to configure the batch. |
|
|
161
161
|
| `batch.id` | random | Provides ability to group tests into batches. Read more about batches [here](https://applitools.com/docs/topics/working-with-test-batches/how-to-group-tests-into-batches.html). |
|
package/dist/getClientAPI.js
CHANGED
|
@@ -98,12 +98,20 @@ function __getClientAPI(...args) {
|
|
|
98
98
|
|
|
99
99
|
case API_VERSIONS.v6_4: {
|
|
100
100
|
api = {
|
|
101
|
-
getStories: () => {
|
|
101
|
+
getStories: async () => {
|
|
102
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
103
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
104
|
+
}
|
|
102
105
|
return clientAPI.raw();
|
|
103
106
|
},
|
|
104
|
-
selectStory: async i => {
|
|
107
|
+
selectStory: async (i, id) => {
|
|
108
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
109
|
+
if (!storyId) {
|
|
110
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
111
|
+
storyId = clientAPI.raw()[i].id;
|
|
112
|
+
}
|
|
105
113
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
106
|
-
storyId
|
|
114
|
+
storyId,
|
|
107
115
|
});
|
|
108
116
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
109
117
|
},
|
package/dist/getStories.js
CHANGED
|
@@ -98,12 +98,20 @@ function __getStories(...args) {
|
|
|
98
98
|
|
|
99
99
|
case API_VERSIONS.v6_4: {
|
|
100
100
|
api = {
|
|
101
|
-
getStories: () => {
|
|
101
|
+
getStories: async () => {
|
|
102
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
103
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
104
|
+
}
|
|
102
105
|
return clientAPI.raw();
|
|
103
106
|
},
|
|
104
|
-
selectStory: async i => {
|
|
107
|
+
selectStory: async (i, id) => {
|
|
108
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
109
|
+
if (!storyId) {
|
|
110
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
111
|
+
storyId = clientAPI.raw()[i].id;
|
|
112
|
+
}
|
|
105
113
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
106
|
-
storyId
|
|
114
|
+
storyId,
|
|
107
115
|
});
|
|
108
116
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
109
117
|
},
|
|
@@ -246,9 +254,10 @@ function __getStories(...args) {
|
|
|
246
254
|
}
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
function getStoriesThroughClientAPI(clientApi) {
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
async function getStoriesThroughClientAPI(clientApi) {
|
|
258
|
+
const stories = await clientApi.getStories();
|
|
259
|
+
return stories.map((story, index) => {
|
|
260
|
+
const {name, kind, parameters, id} = story;
|
|
252
261
|
const hasEyesParameters =
|
|
253
262
|
parameters && parameters.eyes && typeof parameters.eyes === 'object';
|
|
254
263
|
let parametersIfSerialized, error;
|
|
@@ -278,6 +287,7 @@ function __getStories(...args) {
|
|
|
278
287
|
index,
|
|
279
288
|
name,
|
|
280
289
|
kind,
|
|
290
|
+
id,
|
|
281
291
|
parameters: parametersIfSerialized,
|
|
282
292
|
error,
|
|
283
293
|
};
|
|
@@ -98,12 +98,20 @@ function __renderStoryWithClientAPI(...args) {
|
|
|
98
98
|
|
|
99
99
|
case API_VERSIONS.v6_4: {
|
|
100
100
|
api = {
|
|
101
|
-
getStories: () => {
|
|
101
|
+
getStories: async () => {
|
|
102
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
103
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
104
|
+
}
|
|
102
105
|
return clientAPI.raw();
|
|
103
106
|
},
|
|
104
|
-
selectStory: async i => {
|
|
107
|
+
selectStory: async (i, id) => {
|
|
108
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
109
|
+
if (!storyId) {
|
|
110
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
111
|
+
storyId = clientAPI.raw()[i].id;
|
|
112
|
+
}
|
|
105
113
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
106
|
-
storyId
|
|
114
|
+
storyId,
|
|
107
115
|
});
|
|
108
116
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
109
117
|
},
|
|
@@ -142,12 +150,12 @@ function __renderStoryWithClientAPI(...args) {
|
|
|
142
150
|
|
|
143
151
|
var getClientAPI_1 = getClientAPI;
|
|
144
152
|
|
|
145
|
-
function renderStoryWithClientAPI(index) {
|
|
153
|
+
function renderStoryWithClientAPI(index, id) {
|
|
146
154
|
return new Promise(resolve => {
|
|
147
155
|
let api;
|
|
148
156
|
try {
|
|
149
157
|
api = getClientAPI_1();
|
|
150
|
-
api.selectStory(index);
|
|
158
|
+
api.selectStory(index, id);
|
|
151
159
|
api.onStoryRendered(resolve);
|
|
152
160
|
} catch (ex) {
|
|
153
161
|
resolve({message: ex.message, version: api ? api.version : undefined});
|
|
@@ -98,12 +98,20 @@ function __runRunAfterScript(...args) {
|
|
|
98
98
|
|
|
99
99
|
case API_VERSIONS.v6_4: {
|
|
100
100
|
api = {
|
|
101
|
-
getStories: () => {
|
|
101
|
+
getStories: async () => {
|
|
102
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
103
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
104
|
+
}
|
|
102
105
|
return clientAPI.raw();
|
|
103
106
|
},
|
|
104
|
-
selectStory: async i => {
|
|
107
|
+
selectStory: async (i, id) => {
|
|
108
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
109
|
+
if (!storyId) {
|
|
110
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
111
|
+
storyId = clientAPI.raw()[i].id;
|
|
112
|
+
}
|
|
105
113
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
106
|
-
storyId
|
|
114
|
+
storyId,
|
|
107
115
|
});
|
|
108
116
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
109
117
|
},
|
|
@@ -142,15 +150,15 @@ function __runRunAfterScript(...args) {
|
|
|
142
150
|
|
|
143
151
|
var getClientAPI_1 = getClientAPI;
|
|
144
152
|
|
|
145
|
-
function getStoryByIndex(index) {
|
|
153
|
+
async function getStoryByIndex(index) {
|
|
146
154
|
let api;
|
|
147
155
|
try {
|
|
148
156
|
api = getClientAPI_1();
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
157
|
+
const stories = await api.getStories();
|
|
158
|
+
if (!stories[index]) {
|
|
151
159
|
console.log('error cannot get story', index);
|
|
152
160
|
}
|
|
153
|
-
return
|
|
161
|
+
return stories[index];
|
|
154
162
|
} catch (ex) {
|
|
155
163
|
throw new Error(JSON.stringify({message: ex.message, version: api ? api.version : undefined}));
|
|
156
164
|
}
|
|
@@ -158,9 +166,9 @@ function __runRunAfterScript(...args) {
|
|
|
158
166
|
|
|
159
167
|
var getStoryByIndex_1 = getStoryByIndex;
|
|
160
168
|
|
|
161
|
-
function runRunAfterScript(index) {
|
|
169
|
+
async function runRunAfterScript(index) {
|
|
162
170
|
try {
|
|
163
|
-
const story = getStoryByIndex_1(index);
|
|
171
|
+
const story = await getStoryByIndex_1(index);
|
|
164
172
|
if (!story) return;
|
|
165
173
|
return story.parameters.eyes.runAfter({rootEl: document.getElementById('root'), story});
|
|
166
174
|
} catch (ex) {
|
|
@@ -98,12 +98,20 @@ function __runRunBeforeScript(...args) {
|
|
|
98
98
|
|
|
99
99
|
case API_VERSIONS.v6_4: {
|
|
100
100
|
api = {
|
|
101
|
-
getStories: () => {
|
|
101
|
+
getStories: async () => {
|
|
102
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
103
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
104
|
+
}
|
|
102
105
|
return clientAPI.raw();
|
|
103
106
|
},
|
|
104
|
-
selectStory: async i => {
|
|
107
|
+
selectStory: async (i, id) => {
|
|
108
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
109
|
+
if (!storyId) {
|
|
110
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
111
|
+
storyId = clientAPI.raw()[i].id;
|
|
112
|
+
}
|
|
105
113
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
106
|
-
storyId
|
|
114
|
+
storyId,
|
|
107
115
|
});
|
|
108
116
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
109
117
|
},
|
|
@@ -142,15 +150,15 @@ function __runRunBeforeScript(...args) {
|
|
|
142
150
|
|
|
143
151
|
var getClientAPI_1 = getClientAPI;
|
|
144
152
|
|
|
145
|
-
function getStoryByIndex(index) {
|
|
153
|
+
async function getStoryByIndex(index) {
|
|
146
154
|
let api;
|
|
147
155
|
try {
|
|
148
156
|
api = getClientAPI_1();
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
157
|
+
const stories = await api.getStories();
|
|
158
|
+
if (!stories[index]) {
|
|
151
159
|
console.log('error cannot get story', index);
|
|
152
160
|
}
|
|
153
|
-
return
|
|
161
|
+
return stories[index];
|
|
154
162
|
} catch (ex) {
|
|
155
163
|
throw new Error(JSON.stringify({message: ex.message, version: api ? api.version : undefined}));
|
|
156
164
|
}
|
|
@@ -158,9 +166,9 @@ function __runRunBeforeScript(...args) {
|
|
|
158
166
|
|
|
159
167
|
var getStoryByIndex_1 = getStoryByIndex;
|
|
160
168
|
|
|
161
|
-
function runRunBeforeScript(index) {
|
|
169
|
+
async function runRunBeforeScript(index) {
|
|
162
170
|
try {
|
|
163
|
-
const story = getStoryByIndex_1(index);
|
|
171
|
+
const story = await getStoryByIndex_1(index);
|
|
164
172
|
if (!story) return;
|
|
165
173
|
return story.parameters.eyes.runBefore({rootEl: document.getElementById('root'), story: story});
|
|
166
174
|
} catch (ex) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/eyes-storybook",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.30.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"applitools",
|
|
@@ -48,11 +48,13 @@
|
|
|
48
48
|
"storybook:csf-service": "cp -r test/fixtures/storybookCSF/.storybook/. test/fixtures/storybookCSF/.storybook-temp && rm test/fixtures/storybookCSF/.storybook-temp/config.js",
|
|
49
49
|
"storybook:heavy": "start-storybook -c test/fixtures/heavyStorybook -p 9002 -s test/fixtures",
|
|
50
50
|
"storybook:zeroStories": "start-storybook -c test/fixtures/zeroStoriesRetry -p 9003 -s test/fixtures",
|
|
51
|
+
"storybook:csf-v7": "start-storybook -c test/fixtures/storybookCSFV7/.storybook/ -p 9004 -s test/fixtures/",
|
|
51
52
|
"eyes-storybook": "node bin/eyes-storybook.js -f test/fixtures/applitools.config.js",
|
|
52
53
|
"eyes-storybook:jslayout": "node bin/eyes-storybook.js -f test/e2e/happy-config/layout-breakpoints-local.config.js",
|
|
53
54
|
"eyes-storybook:heavy": "node bin/eyes-storybook.js -f test/fixtures/heavyStorybook/applitools.config.js",
|
|
54
55
|
"eyes-storybook:configured": "node bin/eyes-storybook.js -f scripts/preconfigured.config.js",
|
|
55
56
|
"eyes-storybook:zeroStories": "node bin/eyes-storybook.js -f test/fixtures/zeroStoriesRetry/applitools.config.js",
|
|
57
|
+
"eyes-storybook:csf-v7": "node bin/eyes-storybook.js -f test/fixtures/storybookCSFV7/applitools.config.js",
|
|
56
58
|
"changelog": "git changelog -x -p -f v$npm_package_version > History.md && git add ./History.md && git commit -am 'changelog'",
|
|
57
59
|
"changelog:init": "git config changelog.format \"* %s [[%h]($(echo $npm_package_repository_url|cut -d+ -f2|cut -d. -f1-2)/commit/%H)]\"",
|
|
58
60
|
"changelog:install": "sudo apt-get install git-extras",
|
|
@@ -70,15 +72,15 @@
|
|
|
70
72
|
}
|
|
71
73
|
},
|
|
72
74
|
"dependencies": {
|
|
73
|
-
"@applitools/
|
|
74
|
-
"@applitools/
|
|
75
|
+
"@applitools/core": "1.3.7",
|
|
76
|
+
"@applitools/driver": "1.11.21",
|
|
75
77
|
"@applitools/functional-commons": "1.6.0",
|
|
76
|
-
"@applitools/logger": "1.1.
|
|
78
|
+
"@applitools/logger": "1.1.36",
|
|
77
79
|
"@applitools/monitoring-commons": "1.0.19",
|
|
78
|
-
"@applitools/spec-driver-puppeteer": "1.1.
|
|
79
|
-
"@applitools/test-server": "1.1.
|
|
80
|
-
"@applitools/
|
|
81
|
-
"@applitools/
|
|
80
|
+
"@applitools/spec-driver-puppeteer": "1.1.31",
|
|
81
|
+
"@applitools/test-server": "1.1.16",
|
|
82
|
+
"@applitools/ufg-client": "1.1.12",
|
|
83
|
+
"@applitools/utils": "1.3.22",
|
|
82
84
|
"boxen": "4.2.0",
|
|
83
85
|
"chalk": "3.0.0",
|
|
84
86
|
"detect-port": "1.3.0",
|
|
@@ -87,18 +89,20 @@
|
|
|
87
89
|
"ora": "3.4.0",
|
|
88
90
|
"puppeteer": "10.2.0",
|
|
89
91
|
"strip-ansi": "6.0.0",
|
|
92
|
+
"throat": "6.0.1",
|
|
90
93
|
"yargs": "15.4.1"
|
|
91
94
|
},
|
|
92
95
|
"devDependencies": {
|
|
93
96
|
"@applitools/bongo": "^2.2.0",
|
|
94
|
-
"@applitools/scripts": "^1.
|
|
95
|
-
"@applitools/sdk-shared": "0.9.
|
|
97
|
+
"@applitools/scripts": "^1.2.0",
|
|
98
|
+
"@applitools/sdk-shared": "0.9.15",
|
|
96
99
|
"@applitools/snaptdout": "^1.0.1",
|
|
97
100
|
"@storybook/addon-interactions": "^6.4.18",
|
|
98
101
|
"@storybook/react": "^6.4.18",
|
|
99
102
|
"@storybook/testing-library": "^0.0.9",
|
|
100
103
|
"@testing-library/dom": "^5.6.1",
|
|
101
104
|
"babel-core": "^6.26.3",
|
|
105
|
+
"babel-eslint": "^10.1.0",
|
|
102
106
|
"babel-loader": "^8.0.6",
|
|
103
107
|
"babel-preset-env": "^1.7.0",
|
|
104
108
|
"babel-preset-react": "^6.24.1",
|
|
@@ -95,12 +95,20 @@ function getClientAPI() {
|
|
|
95
95
|
|
|
96
96
|
case API_VERSIONS.v6_4: {
|
|
97
97
|
api = {
|
|
98
|
-
getStories: () => {
|
|
98
|
+
getStories: async () => {
|
|
99
|
+
if (clientAPI.storyStore.cacheAllCSFFiles) {
|
|
100
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
101
|
+
}
|
|
99
102
|
return clientAPI.raw();
|
|
100
103
|
},
|
|
101
|
-
selectStory: async i => {
|
|
104
|
+
selectStory: async (i, id) => {
|
|
105
|
+
let storyId = !clientAPI.storyStore.cacheAllCSFFiles ? clientAPI.raw()[i].id : id;
|
|
106
|
+
if (!storyId) {
|
|
107
|
+
await clientAPI.storyStore.cacheAllCSFFiles();
|
|
108
|
+
storyId = clientAPI.raw()[i].id;
|
|
109
|
+
}
|
|
102
110
|
frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
|
|
103
|
-
storyId
|
|
111
|
+
storyId,
|
|
104
112
|
});
|
|
105
113
|
await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
|
|
106
114
|
},
|
|
@@ -104,9 +104,10 @@ async function getStories({timeout = DEFAULT_TIMEOUT} = {timeout: DEFAULT_TIMEOU
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
function getStoriesThroughClientAPI(clientApi) {
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
async function getStoriesThroughClientAPI(clientApi) {
|
|
108
|
+
const stories = await clientApi.getStories();
|
|
109
|
+
return stories.map((story, index) => {
|
|
110
|
+
const {name, kind, parameters, id} = story;
|
|
110
111
|
const hasEyesParameters =
|
|
111
112
|
parameters && parameters.eyes && typeof parameters.eyes === 'object';
|
|
112
113
|
let parametersIfSerialized, error;
|
|
@@ -136,6 +137,7 @@ async function getStories({timeout = DEFAULT_TIMEOUT} = {timeout: DEFAULT_TIMEOU
|
|
|
136
137
|
index,
|
|
137
138
|
name,
|
|
138
139
|
kind,
|
|
140
|
+
id,
|
|
139
141
|
parameters: parametersIfSerialized,
|
|
140
142
|
error,
|
|
141
143
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const getClientAPI = require('./getClientAPI');
|
|
2
2
|
|
|
3
|
-
function getStoryByIndex(index) {
|
|
3
|
+
async function getStoryByIndex(index) {
|
|
4
4
|
let api;
|
|
5
5
|
try {
|
|
6
6
|
api = getClientAPI();
|
|
7
|
-
const
|
|
8
|
-
if (!
|
|
7
|
+
const stories = await api.getStories();
|
|
8
|
+
if (!stories[index]) {
|
|
9
9
|
console.log('error cannot get story', index);
|
|
10
10
|
}
|
|
11
|
-
return
|
|
11
|
+
return stories[index];
|
|
12
12
|
} catch (ex) {
|
|
13
13
|
throw new Error(JSON.stringify({message: ex.message, version: api ? api.version : undefined}));
|
|
14
14
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const getClientAPI = require('./getClientAPI');
|
|
2
2
|
|
|
3
|
-
function renderStoryWithClientAPI(index) {
|
|
3
|
+
function renderStoryWithClientAPI(index, id) {
|
|
4
4
|
return new Promise(resolve => {
|
|
5
5
|
let api;
|
|
6
6
|
try {
|
|
7
7
|
api = getClientAPI();
|
|
8
|
-
api.selectStory(index);
|
|
8
|
+
api.selectStory(index, id);
|
|
9
9
|
api.onStoryRendered(resolve);
|
|
10
10
|
} catch (ex) {
|
|
11
11
|
resolve({message: ex.message, version: api ? api.version : undefined});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const getStoryByIndex = require('./getStoryByIndex');
|
|
2
2
|
|
|
3
|
-
function runRunAfterScript(index) {
|
|
3
|
+
async function runRunAfterScript(index) {
|
|
4
4
|
try {
|
|
5
|
-
const story = getStoryByIndex(index);
|
|
5
|
+
const story = await getStoryByIndex(index);
|
|
6
6
|
if (!story) return;
|
|
7
7
|
return story.parameters.eyes.runAfter({rootEl: document.getElementById('root'), story});
|
|
8
8
|
} catch (ex) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const getStoryByIndex = require('./getStoryByIndex');
|
|
2
2
|
|
|
3
|
-
function runRunBeforeScript(index) {
|
|
3
|
+
async function runRunBeforeScript(index) {
|
|
4
4
|
try {
|
|
5
|
-
const story = getStoryByIndex(index);
|
|
5
|
+
const story = await getStoryByIndex(index);
|
|
6
6
|
if (!story) return;
|
|
7
7
|
return story.parameters.eyes.runBefore({rootEl: document.getElementById('root'), story: story});
|
|
8
8
|
} catch (ex) {
|
package/src/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const yargs = require('yargs');
|
|
3
3
|
const {makeLogger} = require('@applitools/logger');
|
|
4
|
-
const {configParams: externalConfigParams} = require('
|
|
4
|
+
const {configParams: externalConfigParams} = require('./configParams');
|
|
5
5
|
const VERSION = require('../package.json').version;
|
|
6
6
|
const eyesStorybook = require('./eyesStorybook');
|
|
7
7
|
const processResults = require('./processResults');
|
|
@@ -30,7 +30,6 @@ const {performance, timeItAsync} = makeTiming();
|
|
|
30
30
|
.options(yargsOptions).argv;
|
|
31
31
|
|
|
32
32
|
console.log(`Using @applitools/eyes-storybook version ${VERSION}.\n`);
|
|
33
|
-
|
|
34
33
|
const config = generateConfig({argv, defaultConfig, externalConfigParams});
|
|
35
34
|
const logger = makeLogger({level: config.showLogs ? 'info' : 'silent', label: 'eyes'});
|
|
36
35
|
await validateAndPopulateConfig({config, logger, packagePath: process.cwd()});
|
|
@@ -62,7 +61,7 @@ const {performance, timeItAsync} = makeTiming();
|
|
|
62
61
|
process.exit(config.exitcode ? exitCode : 0);
|
|
63
62
|
}
|
|
64
63
|
} catch (ex) {
|
|
65
|
-
console.log(ex
|
|
64
|
+
console.log(ex);
|
|
66
65
|
process.exit(1);
|
|
67
66
|
}
|
|
68
67
|
})();
|
package/src/configDigest.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const
|
|
3
|
-
const prettyValue =
|
|
2
|
+
const utils = require('@applitools/utils');
|
|
3
|
+
const prettyValue = (key, val) =>
|
|
4
|
+
!utils.types.isObject(val, {name: key}) ? val : JSON.stringify(val);
|
|
4
5
|
|
|
5
6
|
function configDigest(config) {
|
|
6
7
|
const maxKeyLen = Object.keys(config).reduce((len, key) => Math.max(len, key.length), 0);
|
|
7
8
|
return (
|
|
8
9
|
Object.entries(config)
|
|
9
|
-
.map(([key, value]) => `${key.padEnd(maxKeyLen + 1)}: ${prettyValue(value)}`)
|
|
10
|
+
.map(([key, value]) => `${key.padEnd(maxKeyLen + 1)}: ${prettyValue(key, value)}`)
|
|
10
11
|
.join('\n') + '\n'
|
|
11
12
|
);
|
|
12
13
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const configParams = [
|
|
4
|
+
'appName',
|
|
5
|
+
'testName',
|
|
6
|
+
'displayName',
|
|
7
|
+
'browser',
|
|
8
|
+
'url',
|
|
9
|
+
'apiKey',
|
|
10
|
+
'showLogs',
|
|
11
|
+
'batch',
|
|
12
|
+
'batchId',
|
|
13
|
+
'batchName',
|
|
14
|
+
'batchSequenceName',
|
|
15
|
+
'batchSequence',
|
|
16
|
+
'properties',
|
|
17
|
+
'baselineBranchName',
|
|
18
|
+
'baselineBranch',
|
|
19
|
+
'baselineEnvName',
|
|
20
|
+
'baselineName',
|
|
21
|
+
'envName',
|
|
22
|
+
'ignoreCaret',
|
|
23
|
+
'isDisabled',
|
|
24
|
+
'matchLevel',
|
|
25
|
+
'parentBranchName',
|
|
26
|
+
'parentBranch',
|
|
27
|
+
'branchName',
|
|
28
|
+
'branch',
|
|
29
|
+
'proxy',
|
|
30
|
+
'autProxy',
|
|
31
|
+
'saveDiffs',
|
|
32
|
+
'saveFailedTests',
|
|
33
|
+
'saveNewTests',
|
|
34
|
+
'compareWithParentBranch',
|
|
35
|
+
'ignoreBaseline',
|
|
36
|
+
'serverUrl',
|
|
37
|
+
'concurrency',
|
|
38
|
+
'testConcurrency',
|
|
39
|
+
'useDom',
|
|
40
|
+
'enablePatterns',
|
|
41
|
+
'ignoreDisplacements',
|
|
42
|
+
'accessibilitySettings',
|
|
43
|
+
'notifyOnCompletion',
|
|
44
|
+
'batchNotify',
|
|
45
|
+
'dontCloseBatches',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
module.exports = {configParams};
|
package/src/errMessages.js
CHANGED
|
@@ -37,9 +37,18 @@ function refineErrorMessage({prefix, error}) {
|
|
|
37
37
|
return `${prefix} ${error.message.replace('Evaluation failed: ', '')}`;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function deprecationWarning({deprecatedThing, newThing, isDead}) {
|
|
41
|
+
const msg = isDead
|
|
42
|
+
? `Notice: ${deprecatedThing} is no longer supported.`
|
|
43
|
+
: `Notice: ${deprecatedThing} has been renamed. Please use ${newThing} instead.\n`;
|
|
44
|
+
|
|
45
|
+
chalk.yellow(msg);
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
module.exports = {
|
|
41
49
|
missingApiKeyFailMsg,
|
|
42
50
|
missingAppNameAndPackageJsonFailMsg,
|
|
43
51
|
missingAppNameInPackageJsonFailMsg,
|
|
44
52
|
refineErrorMessage,
|
|
53
|
+
deprecationWarning,
|
|
45
54
|
};
|
package/src/eyesStorybook.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const puppeteer = require('puppeteer');
|
|
3
3
|
const getStories = require('../dist/getStories');
|
|
4
|
-
const {makeVisualGridClient} = require('@applitools/visual-grid-client');
|
|
5
4
|
const {presult, delay} = require('@applitools/functional-commons');
|
|
6
5
|
const chalk = require('chalk');
|
|
7
6
|
const makeInitPage = require('./initPage');
|
|
@@ -16,12 +15,14 @@ const memoryLog = require('./memoryLog');
|
|
|
16
15
|
const getIframeUrl = require('./getIframeUrl');
|
|
17
16
|
const createPagePool = require('./pagePool');
|
|
18
17
|
const getClientAPI = require('../dist/getClientAPI');
|
|
19
|
-
const {takeDomSnapshots} = require('@applitools/
|
|
18
|
+
const {takeDomSnapshots} = require('@applitools/core');
|
|
20
19
|
const {Driver} = require('@applitools/driver');
|
|
21
20
|
const spec = require('@applitools/spec-driver-puppeteer');
|
|
22
21
|
const {refineErrorMessage} = require('./errMessages');
|
|
23
22
|
const {splitConfigsByBrowser} = require('./shouldRenderIE');
|
|
24
23
|
const executeRenders = require('./executeRenders');
|
|
24
|
+
const {makeCore} = require('@applitools/core');
|
|
25
|
+
const {makeUFGClient} = require('@applitools/ufg-client');
|
|
25
26
|
|
|
26
27
|
const CONCURRENT_PAGES = 3;
|
|
27
28
|
const MAX_RETRIES = 10;
|
|
@@ -39,7 +40,15 @@ async function eyesStorybook({
|
|
|
39
40
|
let transitioning = false;
|
|
40
41
|
takeMemLoop();
|
|
41
42
|
logger.log('eyesStorybook started');
|
|
42
|
-
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
storybookUrl,
|
|
46
|
+
waitBeforeCapture,
|
|
47
|
+
readStoriesTimeout,
|
|
48
|
+
reloadPagePerStory,
|
|
49
|
+
proxy,
|
|
50
|
+
testConcurrency,
|
|
51
|
+
} = config;
|
|
43
52
|
|
|
44
53
|
let iframeUrl;
|
|
45
54
|
try {
|
|
@@ -48,24 +57,48 @@ async function eyesStorybook({
|
|
|
48
57
|
logger.log(ex);
|
|
49
58
|
throw new Error(`Storybook URL is not valid: ${storybookUrl}`);
|
|
50
59
|
}
|
|
51
|
-
|
|
60
|
+
const agentId = `eyes-storybook/${require('../package.json').version}`;
|
|
52
61
|
const browser = await puppeteer.launch(config.puppeteerOptions);
|
|
53
62
|
logger.log('browser launched');
|
|
54
63
|
const page = await browser.newPage();
|
|
55
|
-
const
|
|
64
|
+
const core = await makeCore({
|
|
65
|
+
spec,
|
|
66
|
+
concurrency: testConcurrency,
|
|
67
|
+
logger,
|
|
68
|
+
agentId,
|
|
69
|
+
});
|
|
70
|
+
const manager = await core.makeManager({
|
|
71
|
+
spec,
|
|
72
|
+
concurrency: testConcurrency,
|
|
73
|
+
agentId,
|
|
74
|
+
logger,
|
|
75
|
+
core,
|
|
76
|
+
type: 'ufg',
|
|
77
|
+
});
|
|
56
78
|
|
|
57
|
-
const {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
const settings = {
|
|
80
|
+
proxy: config.proxy,
|
|
81
|
+
serverUrl: config.serverUrl,
|
|
82
|
+
apiKey: config.apiKey,
|
|
83
|
+
agentId,
|
|
84
|
+
};
|
|
85
|
+
const [error, account] = await presult(core.getAccountInfo({settings, logger}));
|
|
86
|
+
|
|
87
|
+
if (error && error.message && error.message.includes('Unauthorized(401)')) {
|
|
88
|
+
const failMsg = 'Incorrect API Key';
|
|
89
|
+
logger.log(failMsg);
|
|
90
|
+
await browser.close();
|
|
91
|
+
clearTimeout(memoryTimeout);
|
|
92
|
+
throw new Error(failMsg);
|
|
93
|
+
}
|
|
94
|
+
const client = await makeUFGClient({
|
|
95
|
+
config: {
|
|
96
|
+
...account.ufg,
|
|
97
|
+
...account,
|
|
98
|
+
proxy,
|
|
99
|
+
concurrency: testConcurrency,
|
|
100
|
+
},
|
|
101
|
+
logger,
|
|
69
102
|
});
|
|
70
103
|
|
|
71
104
|
const initPage = makeInitPage({
|
|
@@ -78,21 +111,24 @@ async function eyesStorybook({
|
|
|
78
111
|
});
|
|
79
112
|
const pagePool = createPagePool({initPage, logger});
|
|
80
113
|
|
|
81
|
-
const doTakeDomSnapshots = async ({page,
|
|
114
|
+
const doTakeDomSnapshots = async ({page, renderers, layoutBreakpoints, waitBeforeCapture}) => {
|
|
82
115
|
const driver = await new Driver({spec, driver: page, logger}).init();
|
|
83
|
-
const skipResources =
|
|
116
|
+
const skipResources = client.getCachedResourceUrls();
|
|
84
117
|
const result = await takeDomSnapshots({
|
|
85
118
|
logger,
|
|
86
119
|
driver,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
settings: {
|
|
121
|
+
layoutBreakpoints:
|
|
122
|
+
layoutBreakpoints !== undefined ? layoutBreakpoints : config.layoutBreakpoints,
|
|
123
|
+
renderers,
|
|
124
|
+
waitBeforeCapture,
|
|
125
|
+
skipResources,
|
|
126
|
+
disableBrowserFetching: !!config.disableBrowserFetchin,
|
|
127
|
+
},
|
|
128
|
+
provides: {
|
|
129
|
+
getChromeEmulationDevices: client.getChromeEmulationDevices,
|
|
130
|
+
getIOSDevices: client.getIOSDevices,
|
|
131
|
+
},
|
|
96
132
|
});
|
|
97
133
|
return result;
|
|
98
134
|
};
|
|
@@ -105,7 +141,6 @@ async function eyesStorybook({
|
|
|
105
141
|
},
|
|
106
142
|
});
|
|
107
143
|
try {
|
|
108
|
-
await getSetRenderInfo();
|
|
109
144
|
const [stories] = await Promise.all(
|
|
110
145
|
[getStoriesWithSpinner()].concat(
|
|
111
146
|
new Array(CONCURRENT_PAGES).fill().map(async () => {
|
|
@@ -128,13 +163,22 @@ async function eyesStorybook({
|
|
|
128
163
|
takeDomSnapshots: doTakeDomSnapshots,
|
|
129
164
|
waitBeforeCapture,
|
|
130
165
|
});
|
|
131
|
-
|
|
166
|
+
const closeSettings = {
|
|
167
|
+
...settings,
|
|
168
|
+
updateBaselineIfNew: config.saveNewTests,
|
|
169
|
+
updateBaselineIfDifferent: config.saveFailedTests,
|
|
170
|
+
};
|
|
132
171
|
const renderStory = makeRenderStory({
|
|
133
172
|
logger: logger.extend({label: 'renderStory'}),
|
|
134
|
-
|
|
173
|
+
openEyes: manager.openEyes,
|
|
135
174
|
performance,
|
|
136
175
|
timeItAsync,
|
|
137
176
|
reloadPagePerStory,
|
|
177
|
+
storyDataGap: config.storyDataGap,
|
|
178
|
+
concurrency: testConcurrency,
|
|
179
|
+
appName: config.appName,
|
|
180
|
+
closeSettings,
|
|
181
|
+
serverSettings: settings,
|
|
138
182
|
});
|
|
139
183
|
|
|
140
184
|
const renderStories = makeRenderStories({
|
|
@@ -144,13 +188,10 @@ async function eyesStorybook({
|
|
|
144
188
|
storybookUrl,
|
|
145
189
|
logger,
|
|
146
190
|
stream: outputStream,
|
|
147
|
-
waitForQueuedRenders: globalState.waitForQueuedRenders,
|
|
148
|
-
storyDataGap: config.storyDataGap,
|
|
149
191
|
pagePool,
|
|
150
192
|
});
|
|
151
193
|
|
|
152
194
|
logger.log('finished creating functions');
|
|
153
|
-
|
|
154
195
|
const configs = config.fakeIE ? splitConfigsByBrowser(config) : [config];
|
|
155
196
|
const [error, results] = await presult(
|
|
156
197
|
executeRenders({
|
|
@@ -164,11 +205,12 @@ async function eyesStorybook({
|
|
|
164
205
|
timeItAsync,
|
|
165
206
|
}),
|
|
166
207
|
);
|
|
208
|
+
const [errorCloseManager, testResultsSummary] = await presult(
|
|
209
|
+
manager.closeManager({throwErr: false}),
|
|
210
|
+
);
|
|
167
211
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (closeBatchErr) {
|
|
171
|
-
logger.log('failed to close batch', closeBatchErr);
|
|
212
|
+
if (errorCloseManager) {
|
|
213
|
+
logger.log('failed to close manager', errorCloseManager);
|
|
172
214
|
}
|
|
173
215
|
|
|
174
216
|
if (error) {
|
|
@@ -176,7 +218,7 @@ async function eyesStorybook({
|
|
|
176
218
|
logger.log(error);
|
|
177
219
|
throw new Error(msg);
|
|
178
220
|
} else {
|
|
179
|
-
return results;
|
|
221
|
+
return {summary: testResultsSummary, results};
|
|
180
222
|
}
|
|
181
223
|
} finally {
|
|
182
224
|
logger.log('total time: ', performance['renderStories']);
|
package/src/generateConfig.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const pick = require('lodash.pick');
|
|
3
3
|
const utils = require('@applitools/utils');
|
|
4
|
-
const {GeneralUtils} = require('@applitools/eyes-sdk-core');
|
|
5
4
|
const {resolve} = require('path');
|
|
6
|
-
const {deprecationWarning} =
|
|
5
|
+
const {deprecationWarning} = require('./errMessages');
|
|
7
6
|
const uniq = require('./uniq');
|
|
7
|
+
const MAX_DATA_GAP = 60;
|
|
8
8
|
|
|
9
9
|
function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = []}) {
|
|
10
10
|
const defaultConfigParams = Object.keys(defaultConfig);
|
|
@@ -44,14 +44,51 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
|
|
|
44
44
|
result.showLogs = true;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
result.testConcurrency
|
|
47
|
+
result.testConcurrency = utils.types.isInteger(result.testConcurrency)
|
|
48
|
+
? result.testConcurrency
|
|
49
|
+
: utils.types.isInteger(result.concurrency)
|
|
50
|
+
? result.concurrency * 5
|
|
51
|
+
: 5;
|
|
52
|
+
|
|
53
|
+
result.serverUrl = result.serverUrl
|
|
54
|
+
? result.serverUrl
|
|
55
|
+
: utils.general.getEnvValue('SERVER_URL')
|
|
56
|
+
? utils.general.getEnvValue('SERVER_URL')
|
|
57
|
+
: 'https://eyesapi.applitools.com';
|
|
58
|
+
|
|
59
|
+
result.viewportSize = result.viewportSize ? result.viewportSize : {width: 1024, height: 600};
|
|
60
|
+
|
|
61
|
+
result.saveNewTests = result.saveNewTests === undefined ? true : result.saveNewTests;
|
|
62
|
+
result.keepBatchOpen = result.dontCloseBatches;
|
|
63
|
+
result.fully = result.fully === undefined ? true : false;
|
|
64
|
+
|
|
65
|
+
if (result.batchName) {
|
|
66
|
+
result.batch = {name: result.batchName, ...result.batch};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (result.batchId) {
|
|
70
|
+
result.batch = {id: result.batchId, ...result.batch};
|
|
49
71
|
}
|
|
50
72
|
|
|
51
73
|
if (result.storyDataGap === undefined) {
|
|
52
|
-
result.storyDataGap =
|
|
74
|
+
result.storyDataGap = Math.max(
|
|
75
|
+
Math.min(result.testConcurrency * 2, MAX_DATA_GAP),
|
|
76
|
+
result.testConcurrency,
|
|
77
|
+
);
|
|
53
78
|
}
|
|
79
|
+
|
|
80
|
+
if (!result.browser) {
|
|
81
|
+
result.renderers = [{name: 'chrome', width: 1024, height: 768}];
|
|
82
|
+
} else {
|
|
83
|
+
result.renderers = [];
|
|
84
|
+
if (!Array.isArray(result.browser)) {
|
|
85
|
+
result.browser = [result.browser];
|
|
86
|
+
}
|
|
87
|
+
result.renderers = result.browser.map(browser => {
|
|
88
|
+
return browser.deviceName ? {chromeEmulationInfo: browser} : browser;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
delete result.browser;
|
|
54
92
|
return result;
|
|
55
93
|
}
|
|
56
|
-
|
|
57
94
|
module.exports = generateConfig;
|
package/src/getStoryData.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const {presult, ptimeoutWithError} = require('@applitools/functional-commons');
|
|
3
|
-
const {ArgumentGuard} = require('@applitools/eyes-sdk-core');
|
|
4
3
|
const renderStoryWithClientAPI = require('../dist/renderStoryWithClientAPI');
|
|
5
4
|
const runRunBeforeScript = require('../dist/runRunBeforeScript');
|
|
6
5
|
const getStoryBaselineName = require('./getStoryBaselineName');
|
|
@@ -9,9 +8,10 @@ const runRunAfterScript = require('../dist/runRunAfterScript');
|
|
|
9
8
|
const waitFor = require('./waitFor');
|
|
10
9
|
const PAGE_EVALUATE_TIMEOUT = 120000;
|
|
11
10
|
const DOM_SNAPSHOTS_TIMEOUT = 5 * 60 * 1000;
|
|
11
|
+
const utils = require('@applitools/utils');
|
|
12
12
|
|
|
13
13
|
function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPagePerStory}) {
|
|
14
|
-
return async function getStoryData({story, storyUrl, page,
|
|
14
|
+
return async function getStoryData({story, storyUrl, page, renderers, waitBeforeStory}) {
|
|
15
15
|
const title = getStoryBaselineName(story);
|
|
16
16
|
logger.log(`getting data from story`, title);
|
|
17
17
|
|
|
@@ -22,7 +22,7 @@ function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPa
|
|
|
22
22
|
if (urlQueryParamsEquals(currentUrl, expectedQueryParams)) {
|
|
23
23
|
try {
|
|
24
24
|
const err = await ptimeoutWithError(
|
|
25
|
-
page.evaluate(renderStoryWithClientAPI, story.index),
|
|
25
|
+
page.evaluate(renderStoryWithClientAPI, story.index, story.id),
|
|
26
26
|
PAGE_EVALUATE_TIMEOUT,
|
|
27
27
|
new Error('page evaluate timed out!'),
|
|
28
28
|
);
|
|
@@ -45,11 +45,7 @@ function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPa
|
|
|
45
45
|
|
|
46
46
|
const wait = waitBeforeStory || waitBeforeCapture;
|
|
47
47
|
if (typeof wait === 'number') {
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
if (wait) {
|
|
51
|
-
logger.log(`waiting before screenshot of ${title} ${wait}`);
|
|
52
|
-
await waitFor(page, wait);
|
|
48
|
+
utils.guard.isGreaterThenOrEqual(wait, 0, {name: 'waitBeforeCapture'});
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
if (eyesParameters && eyesParameters.runBefore) {
|
|
@@ -59,10 +55,9 @@ function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPa
|
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
logger.log(`running takeDomSnapshot(s) for story ${title}`);
|
|
62
|
-
|
|
63
58
|
const domSnapshotsPromise = takeDomSnapshots({
|
|
64
59
|
page,
|
|
65
|
-
|
|
60
|
+
renderers,
|
|
66
61
|
layoutBreakpoints: eyesParameters ? eyesParameters.layoutBreakpoints : undefined,
|
|
67
62
|
waitBeforeCapture: wait
|
|
68
63
|
? async () => {
|
package/src/processResults.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const flatten = require('lodash.flatten');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const {TestResultsError, TestResultsFormatter} = require('@applitools/eyes-sdk-core');
|
|
5
4
|
const utils = require('@applitools/utils');
|
|
6
5
|
const uniq = require('./uniq');
|
|
7
6
|
const concurrencyMsg = require('./concurrencyMsg');
|
|
7
|
+
const {formatters} = require('@applitools/core');
|
|
8
8
|
|
|
9
9
|
function processResults({results = [], totalTime, testConcurrency, saveNewTests = true}) {
|
|
10
10
|
let outputStr = '\n';
|
|
11
|
-
const formatter = new TestResultsFormatter();
|
|
12
11
|
const pluralize = utils.general.pluralize;
|
|
13
|
-
let testResults = results.
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const newTests = testResults.filter(r => r.getIsNew());
|
|
12
|
+
let testResults = flatten(results.summary.results);
|
|
13
|
+
const unresolved = testResults.filter(r => r.result.isDifferent);
|
|
14
|
+
const passedOrNew = testResults.filter(r => r.result.status === 'Passed' || r.result.isNew);
|
|
15
|
+
const newTests = testResults.filter(r => r.result.isNew);
|
|
18
16
|
const newTestsSize = newTests.length;
|
|
19
17
|
const warnForUnsavedNewTests = !!(!saveNewTests && newTestsSize);
|
|
20
18
|
|
|
21
|
-
let errors = results.map(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
let errors = results.summary.results.map(result => [
|
|
20
|
+
{err: result.error, title: result.result.name},
|
|
21
|
+
]);
|
|
22
|
+
errors = flatten(errors).filter(
|
|
23
|
+
({err}) =>
|
|
24
|
+
err &&
|
|
25
|
+
!err.message.includes('detected differences') &&
|
|
26
|
+
!err.message.includes('Please approve the new baseline'),
|
|
25
27
|
);
|
|
26
|
-
errors = flatten(errors).filter(({err}) => err.constructor.name === 'Error');
|
|
27
28
|
|
|
28
29
|
const hasResults = unresolved.length || passedOrNew.length;
|
|
29
30
|
const seeDetailsStr =
|
|
30
|
-
hasResults && `See details at ${(passedOrNew[0] || unresolved[0]).
|
|
31
|
+
hasResults && `See details at ${(passedOrNew[0] || unresolved[0]).result.appUrls.batch}`;
|
|
31
32
|
|
|
32
33
|
if (hasResults) {
|
|
33
34
|
outputStr += `${seeDetailsStr}\n\n`;
|
|
@@ -82,7 +83,7 @@ function processResults({results = [], totalTime, testConcurrency, saveNewTests
|
|
|
82
83
|
const countText =
|
|
83
84
|
newTestsSize > 1
|
|
84
85
|
? `are ${newTestsSize} new tests`
|
|
85
|
-
: `is a new test: '${newTests[0].
|
|
86
|
+
: `is a new test: '${newTests[0].result.name}'`;
|
|
86
87
|
outputStr += chalk.red(
|
|
87
88
|
`\n'saveNewTests' was set to false and there ${countText}. Please approve ${pluralize(
|
|
88
89
|
newTestsSize,
|
|
@@ -101,20 +102,9 @@ function processResults({results = [], totalTime, testConcurrency, saveNewTests
|
|
|
101
102
|
// TODO require from core
|
|
102
103
|
outputStr += `\n${concurrencyMsg}\n`;
|
|
103
104
|
}
|
|
104
|
-
|
|
105
|
-
passedOrNew.forEach(formatter.addTestResults.bind(formatter));
|
|
106
|
-
unresolved.forEach(formatter.addTestResults.bind(formatter));
|
|
107
|
-
errors.forEach(error => {
|
|
108
|
-
formatter.addTestResults(
|
|
109
|
-
new TestResultsError({
|
|
110
|
-
name: error.title,
|
|
111
|
-
error: error.err,
|
|
112
|
-
}),
|
|
113
|
-
);
|
|
114
|
-
});
|
|
105
|
+
const formatter = formatters.toJsonOutput(results.summary);
|
|
115
106
|
const exitCode =
|
|
116
107
|
!warnForUnsavedNewTests && passedOrNew.length && !errors.length && !unresolved.length ? 0 : 1;
|
|
117
|
-
|
|
118
108
|
return {
|
|
119
109
|
outputStr,
|
|
120
110
|
formatter,
|
|
@@ -124,16 +114,14 @@ function processResults({results = [], totalTime, testConcurrency, saveNewTests
|
|
|
124
114
|
|
|
125
115
|
function testResultsOutput(results, warnForUnsavedNewTests) {
|
|
126
116
|
let outputStr = '';
|
|
127
|
-
const sortedTestResults = results.sort((a, b) => a.
|
|
117
|
+
const sortedTestResults = results.sort((a, b) => a.result.name.localeCompare(b.result.name));
|
|
128
118
|
sortedTestResults.forEach(result => {
|
|
129
|
-
const storyTitle = `${result.
|
|
130
|
-
.getHostDisplaySize()
|
|
131
|
-
.toString()}] - `;
|
|
119
|
+
const storyTitle = `${result.result.name} [${result.result.hostApp}] [${result.result.hostDisplaySize.width}x${result.result.hostDisplaySize.height}] - `;
|
|
132
120
|
|
|
133
|
-
if (result.
|
|
121
|
+
if (result.result.isNew) {
|
|
134
122
|
const newResColor = warnForUnsavedNewTests ? 'orange' : 'blue';
|
|
135
123
|
outputStr += `${storyTitle}${chalk.keyword(newResColor)('New')}\n`;
|
|
136
|
-
} else if (result.
|
|
124
|
+
} else if (!result.result.isDifferent) {
|
|
137
125
|
outputStr += `${storyTitle}${chalk.green('Passed')}\n`;
|
|
138
126
|
} else {
|
|
139
127
|
outputStr += `${storyTitle}${chalk.keyword('orange')(`Unresolved`)}\n`;
|
package/src/renderStories.js
CHANGED
|
@@ -12,8 +12,6 @@ function makeRenderStories({
|
|
|
12
12
|
storybookUrl,
|
|
13
13
|
logger,
|
|
14
14
|
stream,
|
|
15
|
-
waitForQueuedRenders,
|
|
16
|
-
storyDataGap,
|
|
17
15
|
getClientAPI,
|
|
18
16
|
maxPageTTL = 60000,
|
|
19
17
|
}) {
|
|
@@ -39,7 +37,6 @@ function makeRenderStories({
|
|
|
39
37
|
|
|
40
38
|
async function processStoryLoop() {
|
|
41
39
|
if (currIndex === stories.length) return;
|
|
42
|
-
|
|
43
40
|
const {page, pageId, markPageAsFree, removePage, getCreatedAt} = await pagePool.getFreePage();
|
|
44
41
|
const livedTime = Date.now() - getCreatedAt();
|
|
45
42
|
logger.log(`[prepareNewPage] got free page: ${pageId}, lived time: ${livedTime}`);
|
|
@@ -52,7 +49,7 @@ function makeRenderStories({
|
|
|
52
49
|
return processStoryLoop();
|
|
53
50
|
}
|
|
54
51
|
logger.log(`[page ${pageId}] waiting for queued renders`);
|
|
55
|
-
await waitForQueuedRenders(storyDataGap);
|
|
52
|
+
// await waitForQueuedRenders(storyDataGap);
|
|
56
53
|
logger.log(`[page ${pageId}] done waiting for queued renders`);
|
|
57
54
|
const storyPromise = processStory();
|
|
58
55
|
allStoriesPromise = allStoriesPromise.then(() => storyPromise);
|
|
@@ -69,7 +66,7 @@ function makeRenderStories({
|
|
|
69
66
|
getStoryData({
|
|
70
67
|
story,
|
|
71
68
|
storyUrl,
|
|
72
|
-
|
|
69
|
+
renderers: config.renderers,
|
|
73
70
|
page,
|
|
74
71
|
waitBeforeStory: waitBeforeCapture,
|
|
75
72
|
}),
|
|
@@ -95,7 +92,7 @@ function makeRenderStories({
|
|
|
95
92
|
getStoryData({
|
|
96
93
|
story,
|
|
97
94
|
storyUrl,
|
|
98
|
-
|
|
95
|
+
renderers: config.renderers,
|
|
99
96
|
page: newPageObj.page,
|
|
100
97
|
waitBeforeStory: waitBeforeCapture,
|
|
101
98
|
}),
|
|
@@ -112,15 +109,12 @@ function makeRenderStories({
|
|
|
112
109
|
logger.log(errMsg);
|
|
113
110
|
throw new Error(errMsg);
|
|
114
111
|
}
|
|
115
|
-
|
|
116
112
|
const testResults = await renderStory({
|
|
117
|
-
|
|
118
|
-
cookies: storyData.cookies,
|
|
113
|
+
snapshots: storyData,
|
|
119
114
|
url: storyUrl,
|
|
120
115
|
story,
|
|
121
116
|
config,
|
|
122
117
|
});
|
|
123
|
-
|
|
124
118
|
return onDoneStory(testResults, story);
|
|
125
119
|
} catch (ex) {
|
|
126
120
|
return onDoneStory(ex, story);
|
|
@@ -130,10 +124,9 @@ function makeRenderStories({
|
|
|
130
124
|
|
|
131
125
|
function didTestPass({resultsOrErr}) {
|
|
132
126
|
return (
|
|
127
|
+
resultsOrErr.constructor &&
|
|
133
128
|
resultsOrErr.constructor.name !== 'Error' &&
|
|
134
|
-
resultsOrErr.every(
|
|
135
|
-
r => r.constructor.name !== 'Error' && r.getStatus && r.getStatus() === 'Passed',
|
|
136
|
-
)
|
|
129
|
+
resultsOrErr.every(r => !r.isDifferent && !r.isAborted && !r.isNew)
|
|
137
130
|
);
|
|
138
131
|
}
|
|
139
132
|
|
package/src/renderStory.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const getStoryTitle = require('./getStoryTitle');
|
|
3
3
|
const getStoryBaselineName = require('./getStoryBaselineName');
|
|
4
|
-
const {deprecationWarning} = require('
|
|
4
|
+
const {deprecationWarning} = require('./errMessages');
|
|
5
|
+
const throat = require('throat');
|
|
5
6
|
|
|
6
|
-
function makeRenderStory({
|
|
7
|
-
|
|
7
|
+
function makeRenderStory({
|
|
8
|
+
logger,
|
|
9
|
+
openEyes,
|
|
10
|
+
performance,
|
|
11
|
+
timeItAsync,
|
|
12
|
+
storyDataGap,
|
|
13
|
+
appName,
|
|
14
|
+
closeSettings,
|
|
15
|
+
serverSettings,
|
|
16
|
+
}) {
|
|
17
|
+
const throttle = throat(storyDataGap);
|
|
18
|
+
return function renderStory({config, story, snapshots, url}) {
|
|
8
19
|
const {name, kind, parameters, hasPlayFunction} = story;
|
|
9
20
|
const baselineName = getStoryBaselineName({name, kind, parameters});
|
|
10
21
|
const title = getStoryTitle({name, kind, parameters});
|
|
@@ -36,6 +47,19 @@ function makeRenderStory({logger, testWindow, performance, timeItAsync}) {
|
|
|
36
47
|
visualGridOptions,
|
|
37
48
|
useDom,
|
|
38
49
|
enablePatterns,
|
|
50
|
+
renderers,
|
|
51
|
+
keepBatchOpen,
|
|
52
|
+
batch,
|
|
53
|
+
branchName,
|
|
54
|
+
parentBranchName,
|
|
55
|
+
baselineBranchName,
|
|
56
|
+
compareWithParentBranch,
|
|
57
|
+
ignoreGitMergeBase,
|
|
58
|
+
baselineEnvName,
|
|
59
|
+
envName,
|
|
60
|
+
ignoreCaret,
|
|
61
|
+
matchLevel,
|
|
62
|
+
ignoreBaseline,
|
|
39
63
|
} = eyesOptions;
|
|
40
64
|
|
|
41
65
|
if (sizeMode) {
|
|
@@ -62,21 +86,30 @@ function makeRenderStory({logger, testWindow, performance, timeItAsync}) {
|
|
|
62
86
|
const openParams = {
|
|
63
87
|
testName: baselineName,
|
|
64
88
|
displayName: title,
|
|
65
|
-
browser: config.browser,
|
|
66
89
|
properties: storyProperties,
|
|
67
|
-
|
|
90
|
+
appName,
|
|
91
|
+
keepBatchOpen,
|
|
92
|
+
batch,
|
|
93
|
+
branchName,
|
|
94
|
+
parentBranchName,
|
|
95
|
+
baselineBranchName,
|
|
96
|
+
compareWithParentBranch,
|
|
97
|
+
ignoreGitBranching: ignoreGitMergeBase,
|
|
98
|
+
baselineEnvName,
|
|
99
|
+
environmentName: envName,
|
|
100
|
+
ignoreBaseline,
|
|
101
|
+
...serverSettings,
|
|
68
102
|
};
|
|
69
|
-
|
|
70
103
|
const checkParams = {
|
|
71
104
|
url,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
scriptHooks,
|
|
105
|
+
ignoreRegions: ignoreRegionsBackCompat,
|
|
106
|
+
floatingRegions: mapFloatingRegions(floatingRegions),
|
|
107
|
+
layoutRegions,
|
|
108
|
+
strictRegions,
|
|
109
|
+
contentRegions,
|
|
110
|
+
accessibilityRegions: mapAccessibilityRegions(accessibilityRegions),
|
|
111
|
+
renderers,
|
|
112
|
+
hooks: scriptHooks,
|
|
80
113
|
sizeMode,
|
|
81
114
|
target,
|
|
82
115
|
fully,
|
|
@@ -84,14 +117,100 @@ function makeRenderStory({logger, testWindow, performance, timeItAsync}) {
|
|
|
84
117
|
region,
|
|
85
118
|
tag,
|
|
86
119
|
sendDom,
|
|
87
|
-
visualGridOptions,
|
|
120
|
+
ufgOptions: visualGridOptions,
|
|
88
121
|
useDom,
|
|
89
122
|
enablePatterns,
|
|
90
123
|
ignoreDisplacements,
|
|
124
|
+
fully,
|
|
125
|
+
ignoreCaret,
|
|
126
|
+
matchLevel,
|
|
127
|
+
accessibilitySettings: accessibilityValidation
|
|
128
|
+
? {
|
|
129
|
+
level: accessibilityValidation ? accessibilityValidation.level : undefined,
|
|
130
|
+
version: accessibilityValidation
|
|
131
|
+
? accessibilityValidation.guidelinesVersion
|
|
132
|
+
: undefined,
|
|
133
|
+
}
|
|
134
|
+
: undefined,
|
|
91
135
|
};
|
|
92
136
|
|
|
137
|
+
function mapAccessibilityRegions(accessabilityRegions) {
|
|
138
|
+
if (!accessabilityRegions) return;
|
|
139
|
+
if (!Array.isArray(accessabilityRegions)) accessabilityRegions = [accessabilityRegions];
|
|
140
|
+
return accessabilityRegions.map(region => {
|
|
141
|
+
const res = {
|
|
142
|
+
type: region.accessibilityType,
|
|
143
|
+
};
|
|
144
|
+
if (region.selector) {
|
|
145
|
+
res.region = region.selector;
|
|
146
|
+
} else if (region.region && isRegion(region.region)) {
|
|
147
|
+
res.region = {
|
|
148
|
+
y: region.region.top,
|
|
149
|
+
x: region.region.left,
|
|
150
|
+
width: region.region.width,
|
|
151
|
+
height: region.region.height,
|
|
152
|
+
};
|
|
153
|
+
} else {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
return res;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function mapFloatingRegions(floatingRegions) {
|
|
161
|
+
if (!floatingRegions) return;
|
|
162
|
+
if (!Array.isArray(floatingRegions)) floatingRegions = [floatingRegions];
|
|
163
|
+
return floatingRegions.map(region => {
|
|
164
|
+
let res = {
|
|
165
|
+
offset: {
|
|
166
|
+
bottom: region.maxDownOffset || 0,
|
|
167
|
+
left: region.maxLeftOffset || 0,
|
|
168
|
+
top: region.maxUpOffset || 0,
|
|
169
|
+
right: region.maxRightOffset || 0,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
if (region.selector) {
|
|
173
|
+
res.region = region.selector;
|
|
174
|
+
} else if (region.region && isRegion(region.region)) {
|
|
175
|
+
res.region = {
|
|
176
|
+
y: region.region.top,
|
|
177
|
+
x: region.region.left,
|
|
178
|
+
width: region.region.width,
|
|
179
|
+
height: region.region.height,
|
|
180
|
+
};
|
|
181
|
+
} else {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
return res;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function isRegion(region) {
|
|
189
|
+
if (
|
|
190
|
+
region.hasOwnProperty('top') &&
|
|
191
|
+
region.hasOwnProperty('left') &&
|
|
192
|
+
region.hasOwnProperty('width') &&
|
|
193
|
+
region.hasOwnProperty('height')
|
|
194
|
+
) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
93
199
|
return timeItAsync(baselineName, async () => {
|
|
94
|
-
|
|
200
|
+
const {checkAndClose} = await openEyes({settings: openParams});
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
throttle(async () => {
|
|
203
|
+
try {
|
|
204
|
+
const checkResults = await checkAndClose({
|
|
205
|
+
settings: {...checkParams, ...closeSettings, throwEx: false},
|
|
206
|
+
target: snapshots,
|
|
207
|
+
});
|
|
208
|
+
resolve(checkResults);
|
|
209
|
+
} catch (ex) {
|
|
210
|
+
reject(ex);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
95
214
|
}).then(onDoneStory);
|
|
96
215
|
|
|
97
216
|
function onDoneStory(results) {
|
package/src/shouldRenderIE.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
function splitConfigsByBrowser(config) {
|
|
2
|
-
const
|
|
3
|
-
if (
|
|
4
|
-
const result =
|
|
2
|
+
const renderers = validateBrowsers(config);
|
|
3
|
+
if (renderers.length) {
|
|
4
|
+
const result = renderers.reduce(
|
|
5
5
|
([nonIE, IE], browser) => {
|
|
6
6
|
if (isIE(browser)) {
|
|
7
7
|
IE.push(browser);
|
|
@@ -14,7 +14,7 @@ function splitConfigsByBrowser(config) {
|
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
return result.reduce(
|
|
17
|
-
(acc, browser) => (browser.length > 0 ? acc.concat({...config, browser}) : acc),
|
|
17
|
+
(acc, browser) => (browser.length > 0 ? acc.concat({...config, renderers: browser}) : acc),
|
|
18
18
|
[],
|
|
19
19
|
);
|
|
20
20
|
} else {
|
|
@@ -35,8 +35,8 @@ function isIE(browser) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function validateBrowsers(config) {
|
|
38
|
-
if (config.
|
|
39
|
-
return Array.isArray(config.
|
|
38
|
+
if (config.renderers) {
|
|
39
|
+
return Array.isArray(config.renderers) ? config.renderers : [config.renderers];
|
|
40
40
|
} else {
|
|
41
41
|
return [];
|
|
42
42
|
}
|
|
@@ -58,7 +58,7 @@ async function validateAndPopulateConfig({config, packagePath, logger}) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (config.fakeIE && !config.
|
|
61
|
+
if (config.fakeIE && !config.renderers.find(isIE)) {
|
|
62
62
|
console.log(
|
|
63
63
|
chalk.yellow(
|
|
64
64
|
`\u26A0 fakeIE flag was set, but no IE browsers were found in the configuration`,
|