@applitools/eyes-storybook 3.31.5 → 3.32.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
@@ -3,6 +3,19 @@
3
3
  ## Unreleased
4
4
 
5
5
 
6
+ ## 3.32.1 - 2023/4/16
7
+
8
+ ### Features
9
+ ### Bug fixes
10
+ - result output throw error
11
+
12
+ ## 3.32.0 - 2023/3/30
13
+
14
+ ### Features
15
+ - Add support for configuration per subsets of stories
16
+ ### Bug fixes
17
+ - Improve performance in DOM snapshot
18
+
6
19
  ## 3.31.5 - 2023/3/28
7
20
 
8
21
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-storybook",
3
- "version": "3.31.5",
3
+ "version": "3.32.1",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "applitools",
@@ -73,14 +73,14 @@
73
73
  }
74
74
  },
75
75
  "dependencies": {
76
- "@applitools/core": "2.4.3",
77
- "@applitools/driver": "1.11.37",
76
+ "@applitools/core": "2.4.13",
77
+ "@applitools/driver": "1.11.41",
78
78
  "@applitools/functional-commons": "1.6.0",
79
79
  "@applitools/logger": "1.1.48",
80
80
  "@applitools/monitoring-commons": "1.0.19",
81
- "@applitools/spec-driver-puppeteer": "1.1.49",
81
+ "@applitools/spec-driver-puppeteer": "1.1.54",
82
82
  "@applitools/test-server": "1.1.28",
83
- "@applitools/ufg-client": "1.2.4",
83
+ "@applitools/ufg-client": "1.2.8",
84
84
  "@applitools/utils": "1.3.32",
85
85
  "boxen": "4.2.0",
86
86
  "chalk": "3.0.0",
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ const checkSettingsParams = [
4
+ 'browser',
5
+ 'ignoreCaret',
6
+ 'matchLevel',
7
+ 'waitBeforeCapture',
8
+ 'ignoreDisplacements',
9
+ 'ignoreRegions',
10
+ 'floatingRegions',
11
+ 'layoutRegions',
12
+ 'strictRegions',
13
+ 'contentRegions',
14
+ 'accessibilityRegions',
15
+ 'accessibilityValidation',
16
+ 'layoutBreakpoints',
17
+ 'sendDom',
18
+ 'useDom',
19
+ 'enablePatterns',
20
+ 'visualGridOptions',
21
+ 'scriptHooks',
22
+ 'target',
23
+ 'region',
24
+ 'selector',
25
+ 'fully',
26
+ 'fakeIE',
27
+ 'disableBrowserFetching',
28
+ ];
29
+
30
+ module.exports = {checkSettingsParams};
package/src/cli.js CHANGED
@@ -7,7 +7,7 @@ const eyesStorybook = require('./eyesStorybook');
7
7
  const processResults = require('./processResults');
8
8
  const validateAndPopulateConfig = require('./validateAndPopulateConfig');
9
9
  const yargsOptions = require('./yargsOptions');
10
- const generateConfig = require('./generateConfig');
10
+ const {generateConfig} = require('./generateConfig');
11
11
  const defaultConfig = require('./defaultConfig');
12
12
  const configDigest = require('./configDigest');
13
13
  const {makeTiming} = require('@applitools/monitoring-commons');
@@ -1,30 +1,32 @@
1
- const {shouldRenderIE} = require('./shouldRenderIE');
2
-
3
1
  async function executeRenders({
4
2
  timeItAsync,
5
3
  setTransitioningIntoIE,
6
4
  renderStories,
7
- configs,
8
5
  pagePool,
9
- stories,
6
+ storiesByBrowserWithConfig,
10
7
  logger,
11
8
  setRenderIE,
12
9
  }) {
13
10
  const results = [];
14
- for (const config of configs) {
15
- logger.verbose(`executing render story with ${JSON.stringify(config)}`);
16
- if (shouldRenderIE(config)) {
17
- setRenderIE(true);
18
- setTransitioningIntoIE(true);
19
- await pagePool.drain();
20
- setTransitioningIntoIE(false);
21
- }
22
-
23
- const result = await timeItAsync('renderStories', () => renderStories(stories, config));
24
-
11
+ if (storiesByBrowserWithConfig.stories.length) {
12
+ logger.verbose(`executing render stories for non fakeIE browsers`);
13
+ const result = await timeItAsync('renderStories', () =>
14
+ renderStories(storiesByBrowserWithConfig.stories, false),
15
+ );
25
16
  results.push(...result);
26
17
  }
18
+ if (storiesByBrowserWithConfig.storiesWithIE.length) {
19
+ logger.verbose(`executing render stories for fakeIE`);
20
+ setRenderIE(true);
21
+ setTransitioningIntoIE(true);
22
+ await pagePool.drain();
23
+ setTransitioningIntoIE(false);
27
24
 
25
+ const result = await timeItAsync('renderStories', () =>
26
+ renderStories(storiesByBrowserWithConfig.storiesWithIE, true),
27
+ );
28
+ results.push(...result);
29
+ }
28
30
  return results;
29
31
  }
30
32
 
@@ -19,10 +19,10 @@ const {takeDomSnapshots} = require('@applitools/core');
19
19
  const {Driver} = require('@applitools/driver');
20
20
  const spec = require('@applitools/spec-driver-puppeteer');
21
21
  const {refineErrorMessage} = require('./errMessages');
22
- const {splitConfigsByBrowser} = require('./shouldRenderIE');
23
22
  const executeRenders = require('./executeRenders');
24
23
  const {makeCore} = require('@applitools/core');
25
24
  const {makeUFGClient} = require('@applitools/ufg-client');
25
+ const makeGetStoriesWithConfig = require('./getStoriesWithConfig');
26
26
 
27
27
  const CONCURRENT_PAGES = 3;
28
28
  const MAX_RETRIES = 10;
@@ -65,19 +65,13 @@ async function eyesStorybook({
65
65
  if (config.puppeteerExtraHTTPHeaders) {
66
66
  await page.setExtraHTTPHeaders(config.puppeteerExtraHTTPHeaders);
67
67
  }
68
- const core = await makeCore({
69
- spec,
70
- concurrency: testConcurrency,
71
- logger,
72
- agentId,
73
- });
68
+ const core = await makeCore({spec, agentId, logger});
74
69
  const manager = await core.makeManager({
75
- spec,
76
- concurrency: testConcurrency,
77
- agentId,
78
- logger,
79
- core,
80
70
  type: 'ufg',
71
+ settings: {
72
+ concurrency: testConcurrency,
73
+ },
74
+ logger,
81
75
  });
82
76
 
83
77
  const settings = {
@@ -88,6 +82,8 @@ async function eyesStorybook({
88
82
  };
89
83
  const [error, account] = await presult(core.getAccountInfo({settings, logger}));
90
84
 
85
+ const getStoriesWithConfig = makeGetStoriesWithConfig({config});
86
+
91
87
  if (error && error.message && error.message.includes('Unauthorized(401)')) {
92
88
  const failMsg = 'Incorrect API Key';
93
89
  logger.log(failMsg);
@@ -116,7 +112,7 @@ async function eyesStorybook({
116
112
  const pagePool = createPagePool({initPage, logger});
117
113
 
118
114
  const doTakeDomSnapshots = async ({page, renderers, layoutBreakpoints, waitBeforeCapture}) => {
119
- const driver = await new Driver({spec, driver: page, logger}).init();
115
+ const driver = await new Driver({spec, driver: page, logger});
120
116
  const skipResources = client.getCachedResourceUrls();
121
117
  const result = await takeDomSnapshots({
122
118
  logger,
@@ -161,7 +157,18 @@ async function eyesStorybook({
161
157
  config,
162
158
  });
163
159
 
164
- logger.log(`starting to run ${storiesIncludingVariations.length} stories`);
160
+ logger.log(
161
+ `there are ${storiesIncludingVariations.length} stories after filtering and adding variations `,
162
+ );
163
+
164
+ const storiesByBrowserWithConfig = getStoriesWithConfig({
165
+ stories: storiesIncludingVariations,
166
+ logger,
167
+ });
168
+
169
+ logger.log(
170
+ `starting to run ${storiesByBrowserWithConfig.stories.length} normal stories ("non fake IE") and ${storiesByBrowserWithConfig.storiesWithIE.length} "fake IE stories"`,
171
+ );
165
172
 
166
173
  const getStoryData = makeGetStoryData({
167
174
  logger,
@@ -197,14 +204,13 @@ async function eyesStorybook({
197
204
  });
198
205
 
199
206
  logger.log('finished creating functions');
200
- const configs = config.fakeIE ? splitConfigsByBrowser(config) : [config];
207
+
201
208
  const [error, results] = await presult(
202
209
  executeRenders({
203
210
  renderStories,
204
211
  setRenderIE,
205
212
  setTransitioningIntoIE,
206
- configs,
207
- stories: storiesIncludingVariations,
213
+ storiesByBrowserWithConfig,
208
214
  pagePool,
209
215
  logger,
210
216
  timeItAsync,
@@ -40,7 +40,7 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
40
40
  result.waitBeforeCapture = Number(result.waitBeforeCapture);
41
41
  }
42
42
 
43
- if (result.showLogs === '1') {
43
+ if (result.showLogs === '1' || process.env.APPLITOOLS_SHOW_LOGS === 'true') {
44
44
  result.showLogs = true;
45
45
  }
46
46
 
@@ -77,18 +77,31 @@ function generateConfig({argv = {}, defaultConfig = {}, externalConfigParams = [
77
77
  );
78
78
  }
79
79
 
80
- if (!result.browser) {
80
+ transformBrowser(result);
81
+ if (!result.renderers) {
81
82
  result.renderers = [{name: 'chrome', width: 1024, height: 768}];
82
- } else {
83
+ }
84
+
85
+ return result;
86
+ }
87
+
88
+ function transformBrowser(result) {
89
+ if (result.browser) {
83
90
  result.renderers = [];
84
91
  if (!Array.isArray(result.browser)) {
85
92
  result.browser = [result.browser];
86
93
  }
87
94
  result.renderers = result.browser.map(browser => {
88
- return browser.deviceName ? {chromeEmulationInfo: browser} : browser;
95
+ if (browser.deviceName) {
96
+ return {chromeEmulationInfo: browser};
97
+ } else if (!browser.name) {
98
+ return {...browser, name: 'chrome'};
99
+ } else {
100
+ return browser;
101
+ }
89
102
  });
90
103
  }
91
104
  delete result.browser;
92
105
  return result;
93
106
  }
94
- module.exports = generateConfig;
107
+ module.exports = {generateConfig, transformBrowser};
@@ -0,0 +1,102 @@
1
+ const {splitConfigsByBrowser, shouldRenderIE} = require('./shouldRenderIE');
2
+ const getStoryTitle = require('./getStoryTitle');
3
+ const {transformBrowser} = require('./generateConfig');
4
+ const {checkSettingsParams} = require('./checkSettingsParams');
5
+ const getStoryBaselineName = require('./getStoryBaselineName');
6
+
7
+ function makeGetStoriesWithConfig({config}) {
8
+ const storiesWithConfig = new Map();
9
+ const storiesWithConfigIE = new Map();
10
+ const basicConfig = {...config};
11
+ delete basicConfig.storyConfiguration;
12
+
13
+ return function getStoriesWithConfig({stories, logger = console}) {
14
+ const storiesWithTitle = addStoryTitleAndBaselineName(stories);
15
+ if (!config.storyConfiguration) {
16
+ addConfigToStories({config, stories: storiesWithTitle});
17
+ } else {
18
+ const storyConfigurations = Array.isArray(config.storyConfiguration)
19
+ ? config.storyConfiguration
20
+ : [config.storyConfiguration];
21
+ let remainingStories = [...storiesWithTitle];
22
+ for (const storyConfig of storyConfigurations) {
23
+ const filterStories = storyConfig.stories;
24
+ delete storyConfig.stories;
25
+
26
+ if (filterStories) {
27
+ const storiesSubset = storiesWithTitle
28
+ .filter(story => {
29
+ try {
30
+ return filterStories(story);
31
+ } catch (err) {
32
+ logger.log(`An error was thrown from substory function: ${err}`);
33
+ return;
34
+ }
35
+ })
36
+ .filter(Boolean);
37
+ addConfigToStories({
38
+ config: transformBrowser(allowedProps(storyConfig)),
39
+ stories: storiesSubset,
40
+ });
41
+
42
+ remainingStories = remainingStories.filter(story => !storiesSubset.includes(story));
43
+ }
44
+ }
45
+
46
+ if (remainingStories.length) {
47
+ addConfigToStories({config: basicConfig, stories: remainingStories});
48
+ }
49
+ }
50
+ return {
51
+ stories: Array.from(storiesWithConfig.values()),
52
+ storiesWithIE: Array.from(storiesWithConfigIE.values()),
53
+ };
54
+ };
55
+
56
+ function addConfigToStories({config, stories}) {
57
+ const configs = config.fakeIE ? splitConfigsByBrowser(config) : [config];
58
+ for (const config of configs) {
59
+ for (const story of stories) {
60
+ addConfigToStoy({
61
+ story,
62
+ config,
63
+ isIE: shouldRenderIE(config),
64
+ });
65
+ }
66
+ }
67
+ }
68
+
69
+ function addConfigToStoy({story, config, isIE}) {
70
+ const storiesToUpdate = isIE ? storiesWithConfigIE : storiesWithConfig;
71
+ storiesToUpdate.set(story.baselineName, {
72
+ ...story,
73
+ config: {
74
+ ...basicConfig,
75
+ ...storiesToUpdate.get(story.baselineName)?.config,
76
+ ...config,
77
+ },
78
+ });
79
+ }
80
+
81
+ function addStoryTitleAndBaselineName(stories) {
82
+ return stories.map(story => {
83
+ return {
84
+ ...story,
85
+ storyTitle: getStoryTitle(story),
86
+ baselineName: getStoryBaselineName(story),
87
+ };
88
+ });
89
+ }
90
+
91
+ function allowedProps(config) {
92
+ const configKeys = Object.keys(config);
93
+ for (const key of configKeys) {
94
+ if (!checkSettingsParams.includes(key)) {
95
+ delete config[key];
96
+ }
97
+ }
98
+ return config;
99
+ }
100
+ }
101
+
102
+ module.exports = makeGetStoriesWithConfig;
@@ -6,7 +6,7 @@ const {formatters} = require('@applitools/core');
6
6
 
7
7
  function handleJsonFile(jsonFilePath, summary) {
8
8
  const path = resolve(jsonFilePath, 'eyes.json');
9
- fs.writeFileSync(path, formatters.toJsonOutput(summary));
9
+ fs.writeFileSync(path, formatters.toJsonOutput(summary.results.map(({result}) => result)));
10
10
  return path;
11
11
  }
12
12
 
@@ -8,10 +8,13 @@ function handleTapFile(tapFilePath, summary) {
8
8
  const path = resolve(tapFilePath, 'eyes.tap');
9
9
  fs.writeFileSync(
10
10
  path,
11
- formatters.toHierarchicTAPString(summary.results, {
12
- includeSubTests: false,
13
- markNewAsPassed: true,
14
- }),
11
+ formatters.toHierarchicTAPString(
12
+ summary.results.map(({result}) => result),
13
+ {
14
+ includeSubTests: false,
15
+ markNewAsPassed: true,
16
+ },
17
+ ),
15
18
  );
16
19
  return path;
17
20
  }
@@ -6,7 +6,13 @@ const {formatters} = require('@applitools/core');
6
6
 
7
7
  function handleXmlFile(xmlFilePath, summary, {suiteName = 'Eyes Storybook', totalTime} = {}) {
8
8
  const path = resolve(xmlFilePath, 'eyes.xml');
9
- fs.writeFileSync(path, formatters.toXmlOutput(summary.results, {suiteName, totalTime}));
9
+ fs.writeFileSync(
10
+ path,
11
+ formatters.toXmlOutput(
12
+ summary.results.map(({result}) => result),
13
+ {suiteName, totalTime},
14
+ ),
15
+ );
10
16
  return path;
11
17
  }
12
18
 
@@ -3,7 +3,6 @@ const getStoryUrl = require('./getStoryUrl');
3
3
  const getStoryBaselineName = require('./getStoryBaselineName');
4
4
  const ora = require('ora');
5
5
  const {presult} = require('@applitools/functional-commons');
6
- const {shouldRenderIE} = require('./shouldRenderIE');
7
6
 
8
7
  function makeRenderStories({
9
8
  getStoryData,
@@ -17,7 +16,7 @@ function makeRenderStories({
17
16
  }) {
18
17
  let newPageIdToAdd;
19
18
 
20
- return async function renderStories(stories, config) {
19
+ return async function renderStories(stories, isIE) {
21
20
  let doneStories = 0;
22
21
  const allTestResults = [];
23
22
  let allStoriesPromise = Promise.resolve();
@@ -66,7 +65,7 @@ function makeRenderStories({
66
65
  getStoryData({
67
66
  story,
68
67
  storyUrl,
69
- renderers: config.renderers,
68
+ renderers: story.config.renderers,
70
69
  page,
71
70
  waitBeforeStory: waitBeforeCapture,
72
71
  }),
@@ -92,7 +91,7 @@ function makeRenderStories({
92
91
  getStoryData({
93
92
  story,
94
93
  storyUrl,
95
- renderers: config.renderers,
94
+ renderers: story.config.renderers,
96
95
  page: newPageObj.page,
97
96
  waitBeforeStory: waitBeforeCapture,
98
97
  }),
@@ -113,7 +112,6 @@ function makeRenderStories({
113
112
  snapshots: storyData,
114
113
  url: storyUrl,
115
114
  story,
116
- config,
117
115
  });
118
116
  return onDoneStory(testResults, story);
119
117
  } catch (ex) {
@@ -134,11 +132,11 @@ function makeRenderStories({
134
132
  }
135
133
 
136
134
  function updateSpinnerText(number, length) {
137
- return `Done ${number} stories out of ${length} ${shouldRenderIE(config) ? '(IE)' : ''}`;
135
+ return `Done ${number} stories out of ${length} ${isIE ? '(IE)' : ''}`;
138
136
  }
139
137
 
140
138
  function onDoneStory(resultsOrErr, story) {
141
- spinner.text = updateSpinnerText(++doneStories, stories.length);
139
+ spinner.text = updateSpinnerText(++doneStories, stories.length, story.config);
142
140
  const title = getStoryBaselineName(story);
143
141
  allTestResults.push({title, resultsOrErr});
144
142
  return {title, resultsOrErr};
@@ -1,6 +1,4 @@
1
1
  'use strict';
2
- const getStoryTitle = require('./getStoryTitle');
3
- const getStoryBaselineName = require('./getStoryBaselineName');
4
2
  const {deprecationWarning} = require('./errMessages');
5
3
  const throat = require('throat');
6
4
 
@@ -15,10 +13,11 @@ function makeRenderStory({
15
13
  serverSettings,
16
14
  }) {
17
15
  const throttle = throat(storyDataGap);
18
- return function renderStory({config, story, snapshots, url}) {
16
+ return function renderStory({story, snapshots, url}) {
17
+ const config = story.config;
19
18
  const {name, kind, parameters, hasPlayFunction} = story;
20
- const baselineName = getStoryBaselineName({name, kind, parameters});
21
- const title = getStoryTitle({name, kind, parameters});
19
+ const baselineName = story.baselineName;
20
+ const title = story.storyTitle;
22
21
  const eyesParameters = (parameters && parameters.eyes) || {};
23
22
  const eyesOptions = {
24
23
  ...config,
@@ -38,7 +37,6 @@ function makeRenderStory({
38
37
  target,
39
38
  fully,
40
39
  selector,
41
- region,
42
40
  tag,
43
41
  properties,
44
42
  ignore,
@@ -111,10 +109,8 @@ function makeRenderStory({
111
109
  renderers,
112
110
  hooks: scriptHooks,
113
111
  sizeMode,
114
- target,
112
+ region: target === 'region' ? selector : undefined,
115
113
  fully,
116
- selector,
117
- region,
118
114
  tag,
119
115
  sendDom,
120
116
  ufgOptions: visualGridOptions,
@@ -134,6 +130,23 @@ function makeRenderStory({
134
130
  : undefined,
135
131
  };
136
132
 
133
+ return timeItAsync(baselineName, async () => {
134
+ const {checkAndClose} = await openEyes({settings: openParams});
135
+ return new Promise((resolve, reject) => {
136
+ throttle(async () => {
137
+ try {
138
+ const checkResults = await checkAndClose({
139
+ settings: {...checkParams, ...closeSettings, throwEx: false},
140
+ target: snapshots,
141
+ });
142
+ resolve(checkResults);
143
+ } catch (ex) {
144
+ reject(ex);
145
+ }
146
+ });
147
+ });
148
+ }).then(onDoneStory);
149
+
137
150
  function mapAccessibilityRegions(accessabilityRegions) {
138
151
  if (!accessabilityRegions) return;
139
152
  if (!Array.isArray(accessabilityRegions)) accessabilityRegions = [accessabilityRegions];
@@ -196,23 +209,6 @@ function makeRenderStory({
196
209
  }
197
210
  }
198
211
 
199
- return timeItAsync(baselineName, async () => {
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
- });
214
- }).then(onDoneStory);
215
-
216
212
  function onDoneStory(results) {
217
213
  logger.log('finished story', baselineName, 'in', performance[baselineName]);
218
214
  return results;