@applitools/eyes-storybook 3.26.0 → 3.27.2

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,31 @@
3
3
  ## Unreleased
4
4
 
5
5
 
6
+ ## 3.27.2 - 2021/12/23
7
+
8
+ - updated to @applitools/driver@1.4.7 (from 1.4.5)
9
+ - updated to @applitools/eyes-sdk-core@12.24.9 (from 12.24.7)
10
+ - updated to @applitools/logger@1.0.8 (from 1.0.7)
11
+ - updated to @applitools/visual-grid-client@15.8.55 (from 15.8.53)
12
+
13
+ ## 3.27.1 - 2021/12/21
14
+
15
+ - add support for storybook api 6.4
16
+ - updated to @applitools/driver@1.4.5 (from 1.3.5)
17
+ - updated to @applitools/eyes-sdk-core@12.24.7 (from 12.24.5)
18
+ - updated to @applitools/logger@1.0.7 (from 1.0.6)
19
+ - updated to @applitools/test-server@1.0.8 (from 1.0.7)
20
+ - updated to @applitools/visual-grid-client@15.8.53 (from 15.8.49)
21
+
22
+ ## 3.27.0 - 2021/12/6
23
+
24
+ - support custom properties and query params
25
+ - remove `queryParams` api from story and global config
26
+
27
+ ## 3.26.1 - 2021/11/28
28
+
29
+ - add custom test properties to stories with query params
30
+
6
31
  ## 3.26.0 - 2021/11/26
7
32
 
8
33
  - add support for `queryParams` config property
package/README.md CHANGED
@@ -28,7 +28,6 @@ Applitools Eyes SDK for [Storybook](http://storybook.js.org).
28
28
  - [global](#global)
29
29
  - [component](#component)
30
30
  - [`variations`](#variations)
31
- - [`queryParams`](#queryparams)
32
31
  - [`waitBeforeCapture`](#waitbeforecapture)
33
32
  - [`properties`](#properties)
34
33
  - [`ignoreRegions`](#ignoreregions)
@@ -181,7 +180,6 @@ In addition to command-line arguments, it's possible to define the following con
181
180
  | `waitBeforeCapture` | undefined | Selector, function or timeout.<br/>If ```number``` then the argument is treated as time in milliseconds to wait before all screenshots.<br/>If ```string``` then the argument is treated as a selector for elements to wait for before all screenshots.<br/>If ```function```, then the argument is treated as a predicate to wait for before all screenshots.<br/><hr/>For per component configuration see [waitBeforeCapture.](#waitBeforeCapture)<br/>Note that we use Puppeteer's [page.waitForTimeout()](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitfortimeoutmilliseconds), [page.waitForSelector()](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforselectorselector-options), [page.waitForXPath()](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforxpathxpath-options) and [page.waitForFunction()](https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforfunctionpagefunction-options-args), checkout it's API for more details. |
182
181
  | `include` | true | A predicate function, a string or a regular expression specifying which stories should be visually tested.<br/>Visual baselines will be created only for the components specified.<br/>The function receives an object with ```name```, ```kind```, ```storyTitle``` and ```parameters``` properties.<br/>For example (exclude all stories with a name that start with [SKIP]):<br/>```({name, kind, storyTitle, parameters}) => !/^\[SKIP\]/.test(name)```<br/>For more information, see [per component configuration - include](#include). |
183
182
  | `variations` | undefined | Specifies additional variations for all or some of the stories. For example, RTL. For more information, see [per component configuration - variations](#variations).|
184
- | `queryParam` | undefined | Specifies additional query parameters for all or some of the stories. For more information, see [per component configuration - queryParams](#queryParams).|
185
183
  | `notifyOnCompletion` | false | If `true` batch completion notifications are sent. |
186
184
  | `dontCloseBatches` | false | If true, batches are not closed for notifyOnCompletion.|
187
185
  | `testConcurrency` | 5 | The maximum number of tests that can run concurrently. The default value is the allowed amount for free accounts. For paid accounts, set this number to the quota set for your account. |
@@ -425,10 +423,9 @@ storiesOf('Some kind', module)
425
423
 
426
424
  ### `variations`
427
425
 
428
- An array of string values, which specifies which variations to add for this story. For each value, an additional visual test will be executed for the component. It will have the same name only with a `[<variation name>]` suffix, and when the component is loaded, the URL will have an additional param: `eyes-variation=<variation name>`.
426
+ An array of object values, which specifies which variations to add for this story. For each value, an additional visual test will be executed for the component. Each variation could contain `queryParams` and `properties` fields to specifies custom query parameters and eyes properties respectfully. Variation tests will have the same name.
429
427
 
430
- This can accommodate many use cases, for example RTL (right to left).
431
- It's now possible for the component to render its variation version when the relevant URL param is present. For Example, here's a storybook that handles an RTL variation:
428
+ This can accommodate many use cases, for example `@storybook/addon-contexts`. With addons like this it is possible to render components in a different way depends on query parameters in URL. For Example, here's a storybook that handles an RTL variation:
432
429
 
433
430
  ```js
434
431
  const isRTL = new URL(window.location).searchParams.get('eyes-variation') === 'RTL';
@@ -445,17 +442,10 @@ storiesOf('Components that support RTL', module)
445
442
  <span>I am visually perfect!</span>
446
443
  <span>{isRTL ? ' and rendered right to left as well :)' : ''}</span>
447
444
  </div>,
448
- {eyes: {variations: ['RTL']}}
445
+ {eyes: {variations: [{queryParams: {'eyes-variation': 'RTL'}, properties: {name: 'isRTL', value: 'true'}, {properties: {name: 'isRTL', value: 'false'}}]}}
449
446
  )
450
447
  ```
451
448
 
452
- ### `queryParams`
453
-
454
- An array of object values, which specifies `name` and `value` of query parameter which will be added to the story. For each value, an additional visual test will be executed for the component. It will have the same name display name, but still generate a different baseline.
455
-
456
- This can accommodate many use cases, for example `@storybook/addon-contexts`.
457
- With addons like this it is possible to render components in a different way depends on query parameters in URL.
458
-
459
449
  ### `waitBeforeCapture`
460
450
 
461
451
  Selector or timeout, see [advanced configuration](#advanced-configuration) for more details.
@@ -7,6 +7,7 @@ function __getClientAPI(...args) {
7
7
  v4: 'v4',
8
8
  v5: 'v5',
9
9
  v5_2: 'v5_2',
10
+ v6_4: 'v6_4',
10
11
  };
11
12
 
12
13
  function getClientAPI() {
@@ -19,7 +20,9 @@ function __getClientAPI(...args) {
19
20
  function getStorybookVersion() {
20
21
  const addons = frameWindow.__STORYBOOK_ADDONS;
21
22
 
22
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
24
+ return API_VERSIONS.v6_4;
25
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
26
  return API_VERSIONS.v5_2;
24
27
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
25
28
  return API_VERSIONS.v5;
@@ -81,6 +84,21 @@ function __getClientAPI(...args) {
81
84
  };
82
85
  break;
83
86
  }
87
+
88
+ case API_VERSIONS.v6_4: {
89
+ api = {
90
+ getStories: () => {
91
+ return clientAPI.raw();
92
+ },
93
+ selectStory: async i => {
94
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
95
+ storyId: clientAPI.raw()[i].id,
96
+ });
97
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
98
+ },
99
+ };
100
+ break;
101
+ }
84
102
  }
85
103
 
86
104
  return {version, ...api};
@@ -7,6 +7,7 @@ function __getStories(...args) {
7
7
  v4: 'v4',
8
8
  v5: 'v5',
9
9
  v5_2: 'v5_2',
10
+ v6_4: 'v6_4',
10
11
  };
11
12
 
12
13
  function getClientAPI() {
@@ -19,7 +20,9 @@ function __getStories(...args) {
19
20
  function getStorybookVersion() {
20
21
  const addons = frameWindow.__STORYBOOK_ADDONS;
21
22
 
22
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
24
+ return API_VERSIONS.v6_4;
25
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
26
  return API_VERSIONS.v5_2;
24
27
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
25
28
  return API_VERSIONS.v5;
@@ -81,6 +84,21 @@ function __getStories(...args) {
81
84
  };
82
85
  break;
83
86
  }
87
+
88
+ case API_VERSIONS.v6_4: {
89
+ api = {
90
+ getStories: () => {
91
+ return clientAPI.raw();
92
+ },
93
+ selectStory: async i => {
94
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
95
+ storyId: clientAPI.raw()[i].id,
96
+ });
97
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
98
+ },
99
+ };
100
+ break;
101
+ }
84
102
  }
85
103
 
86
104
  return {version, ...api};
@@ -7,6 +7,7 @@ function __renderStoryWithClientAPI(...args) {
7
7
  v4: 'v4',
8
8
  v5: 'v5',
9
9
  v5_2: 'v5_2',
10
+ v6_4: 'v6_4',
10
11
  };
11
12
 
12
13
  function getClientAPI() {
@@ -19,7 +20,9 @@ function __renderStoryWithClientAPI(...args) {
19
20
  function getStorybookVersion() {
20
21
  const addons = frameWindow.__STORYBOOK_ADDONS;
21
22
 
22
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
24
+ return API_VERSIONS.v6_4;
25
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
26
  return API_VERSIONS.v5_2;
24
27
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
25
28
  return API_VERSIONS.v5;
@@ -81,6 +84,21 @@ function __renderStoryWithClientAPI(...args) {
81
84
  };
82
85
  break;
83
86
  }
87
+
88
+ case API_VERSIONS.v6_4: {
89
+ api = {
90
+ getStories: () => {
91
+ return clientAPI.raw();
92
+ },
93
+ selectStory: async i => {
94
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
95
+ storyId: clientAPI.raw()[i].id,
96
+ });
97
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
98
+ },
99
+ };
100
+ break;
101
+ }
84
102
  }
85
103
 
86
104
  return {version, ...api};
@@ -112,11 +130,11 @@ function __renderStoryWithClientAPI(...args) {
112
130
 
113
131
  var getClientAPI_1 = getClientAPI;
114
132
 
115
- function renderStoryWithClientAPI(index) {
133
+ async function renderStoryWithClientAPI(index) {
116
134
  let api;
117
135
  try {
118
136
  api = getClientAPI_1();
119
- api.selectStory(index);
137
+ await api.selectStory(index);
120
138
  } catch (ex) {
121
139
  return {message: ex.message, version: api ? api.version : undefined};
122
140
  }
@@ -7,6 +7,7 @@ function __runRunAfterScript(...args) {
7
7
  v4: 'v4',
8
8
  v5: 'v5',
9
9
  v5_2: 'v5_2',
10
+ v6_4: 'v6_4',
10
11
  };
11
12
 
12
13
  function getClientAPI() {
@@ -19,7 +20,9 @@ function __runRunAfterScript(...args) {
19
20
  function getStorybookVersion() {
20
21
  const addons = frameWindow.__STORYBOOK_ADDONS;
21
22
 
22
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
24
+ return API_VERSIONS.v6_4;
25
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
26
  return API_VERSIONS.v5_2;
24
27
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
25
28
  return API_VERSIONS.v5;
@@ -81,6 +84,21 @@ function __runRunAfterScript(...args) {
81
84
  };
82
85
  break;
83
86
  }
87
+
88
+ case API_VERSIONS.v6_4: {
89
+ api = {
90
+ getStories: () => {
91
+ return clientAPI.raw();
92
+ },
93
+ selectStory: async i => {
94
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
95
+ storyId: clientAPI.raw()[i].id,
96
+ });
97
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
98
+ },
99
+ };
100
+ break;
101
+ }
84
102
  }
85
103
 
86
104
  return {version, ...api};
@@ -7,6 +7,7 @@ function __runRunBeforeScript(...args) {
7
7
  v4: 'v4',
8
8
  v5: 'v5',
9
9
  v5_2: 'v5_2',
10
+ v6_4: 'v6_4',
10
11
  };
11
12
 
12
13
  function getClientAPI() {
@@ -19,7 +20,9 @@ function __runRunBeforeScript(...args) {
19
20
  function getStorybookVersion() {
20
21
  const addons = frameWindow.__STORYBOOK_ADDONS;
21
22
 
22
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
24
+ return API_VERSIONS.v6_4;
25
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
23
26
  return API_VERSIONS.v5_2;
24
27
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
25
28
  return API_VERSIONS.v5;
@@ -81,6 +84,21 @@ function __runRunBeforeScript(...args) {
81
84
  };
82
85
  break;
83
86
  }
87
+
88
+ case API_VERSIONS.v6_4: {
89
+ api = {
90
+ getStories: () => {
91
+ return clientAPI.raw();
92
+ },
93
+ selectStory: async i => {
94
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
95
+ storyId: clientAPI.raw()[i].id,
96
+ });
97
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
98
+ },
99
+ };
100
+ break;
101
+ }
84
102
  }
85
103
 
86
104
  return {version, ...api};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-storybook",
3
- "version": "3.26.0",
3
+ "version": "3.27.2",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=8.6.0"
@@ -58,14 +58,14 @@
58
58
  "directory": "packages/eyes-storybook"
59
59
  },
60
60
  "dependencies": {
61
- "@applitools/driver": "1.3.5",
62
- "@applitools/eyes-sdk-core": "12.24.5",
61
+ "@applitools/driver": "1.4.7",
62
+ "@applitools/eyes-sdk-core": "12.24.9",
63
63
  "@applitools/functional-commons": "1.6.0",
64
- "@applitools/logger": "1.0.6",
64
+ "@applitools/logger": "1.0.8",
65
65
  "@applitools/monitoring-commons": "1.0.19",
66
66
  "@applitools/spec-driver-puppeteer": "1.1.0",
67
- "@applitools/test-server": "1.0.7",
68
- "@applitools/visual-grid-client": "15.8.49",
67
+ "@applitools/test-server": "1.0.8",
68
+ "@applitools/visual-grid-client": "15.8.55",
69
69
  "boxen": "4.2.0",
70
70
  "chalk": "3.0.0",
71
71
  "detect-port": "1.3.0",
@@ -79,11 +79,10 @@
79
79
  "devDependencies": {
80
80
  "@applitools/scripts": "^1.0.1",
81
81
  "@applitools/sdk-release-kit": "0.13.4",
82
- "@applitools/sdk-shared": "0.9.9",
82
+ "@applitools/sdk-shared": "0.9.11",
83
83
  "@applitools/snaptdout": "^1.0.1",
84
- "@applitools/utils": "1.2.4",
85
- "@storybook/addon-options": "^5.2.8",
86
- "@storybook/react": "^5.2.8",
84
+ "@applitools/utils": "1.2.5",
85
+ "@storybook/react": "^6.4.0",
87
86
  "@testing-library/dom": "^5.6.1",
88
87
  "babel-core": "^6.26.3",
89
88
  "babel-loader": "^8.0.6",
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ function addVariationStories({stories, config}) {
4
+ const defaultStories = [];
5
+ const variationStories = {};
6
+ for (const story of stories) {
7
+ const variations = getStoryVariations(story, config);
8
+ if (variations) {
9
+ for (const variation of variations) {
10
+ const variationKey = stringifyVariation(variation);
11
+ const variationStoriesArray =
12
+ variationStories[variationKey] || (variationStories[variationKey] = []);
13
+ const variationStory = {...story};
14
+ if (variation.queryParams || variation.properties) {
15
+ variationStory.parameters = addVariation(story.parameters, variation);
16
+ }
17
+ variationStoriesArray.push(variationStory);
18
+ }
19
+ } else {
20
+ defaultStories.push(story);
21
+ }
22
+ }
23
+
24
+ return Object.values(variationStories).reduce((allStories, variationStories) => {
25
+ return allStories.concat(variationStories);
26
+ }, defaultStories);
27
+ }
28
+
29
+ function getStoryVariations(story, config) {
30
+ if (story.parameters && story.parameters.eyes && story.parameters.eyes.variations) {
31
+ if (!Array.isArray(story.parameters.eyes.variations)) {
32
+ throw new Error('variations should be an array');
33
+ }
34
+ return normalizeVariations(story.parameters.eyes.variations);
35
+ }
36
+
37
+ if (config.variations) {
38
+ if (Array.isArray(config.variations)) {
39
+ return normalizeVariations(config.variations);
40
+ } else if (typeof config.variations === 'function') {
41
+ const variations = config.variations(story);
42
+ if (variations) {
43
+ if (!Array.isArray(variations)) {
44
+ throw new Error('global variations should be a function that returns array');
45
+ }
46
+ return normalizeVariations(variations);
47
+ }
48
+ } else {
49
+ throw new Error('global variations should be an array or a function that returns array');
50
+ }
51
+ }
52
+ }
53
+
54
+ function normalizeVariations(variations) {
55
+ let shouldHasDefault = false; // default variation is one without query params
56
+ const normalizedVariations = variations.map(variation => {
57
+ if (typeof variation === 'string') {
58
+ shouldHasDefault = true;
59
+ return {
60
+ queryParams: {'eyes-variation': variation},
61
+ properties: [{name: 'eyes-variation', value: variation}],
62
+ };
63
+ }
64
+ if (variation.queryParams && (!variation.properties || variation.properties.length === 0)) {
65
+ return {
66
+ ...variation,
67
+ properties: Object.entries(variation.queryParams).map(([name, value]) => ({name, value})),
68
+ };
69
+ }
70
+ return variation;
71
+ });
72
+
73
+ // if it should has default variation and it is not already there
74
+ if (shouldHasDefault && !normalizedVariations.some(variation => !variation.queryParams)) {
75
+ normalizedVariations.unshift({});
76
+ }
77
+
78
+ return normalizedVariations;
79
+ }
80
+
81
+ function stringifyVariation(variation) {
82
+ if (!variation.queryParams) return '';
83
+ return Object.keys(variation.queryParams)
84
+ .sort()
85
+ .map(name => `${name}=${variation.queryParams[name]}`)
86
+ .join('&');
87
+ }
88
+
89
+ function addVariation(parameters, variation) {
90
+ parameters = {...parameters};
91
+ parameters.eyes = {...parameters.eyes};
92
+ if (variation.queryParams) {
93
+ parameters.eyes.queryParams = variation.queryParams;
94
+ }
95
+ if (variation.properties) {
96
+ parameters.eyes.properties = [
97
+ ...(parameters.eyes.properties || []),
98
+ ...(variation.properties || []),
99
+ ];
100
+ }
101
+ return parameters;
102
+ }
103
+
104
+ module.exports = addVariationStories;
@@ -4,6 +4,7 @@ const API_VERSIONS = {
4
4
  v4: 'v4',
5
5
  v5: 'v5',
6
6
  v5_2: 'v5_2',
7
+ v6_4: 'v6_4',
7
8
  };
8
9
 
9
10
  function getClientAPI() {
@@ -16,7 +17,9 @@ function getClientAPI() {
16
17
  function getStorybookVersion() {
17
18
  const addons = frameWindow.__STORYBOOK_ADDONS;
18
19
 
19
- if (frameWindow.__STORYBOOK_STORY_STORE__) {
20
+ if (frameWindow.__STORYBOOK_PREVIEW__) {
21
+ return API_VERSIONS.v6_4;
22
+ } else if (frameWindow.__STORYBOOK_STORY_STORE__) {
20
23
  return API_VERSIONS.v5_2;
21
24
  } else if (frameWindow.__STORYBOOK_CLIENT_API__ && frameWindow.__STORYBOOK_CLIENT_API__.raw) {
22
25
  return API_VERSIONS.v5;
@@ -78,6 +81,21 @@ function getClientAPI() {
78
81
  };
79
82
  break;
80
83
  }
84
+
85
+ case API_VERSIONS.v6_4: {
86
+ api = {
87
+ getStories: () => {
88
+ return clientAPI.raw();
89
+ },
90
+ selectStory: async i => {
91
+ frameWindow.__STORYBOOK_PREVIEW__.urlStore.setSelection({
92
+ storyId: clientAPI.raw()[i].id,
93
+ });
94
+ await frameWindow.__STORYBOOK_PREVIEW__.renderSelection();
95
+ },
96
+ };
97
+ break;
98
+ }
81
99
  }
82
100
 
83
101
  return {version, ...api};
@@ -1,10 +1,10 @@
1
1
  const getClientAPI = require('./getClientAPI');
2
2
 
3
- function renderStoryWithClientAPI(index) {
3
+ async function renderStoryWithClientAPI(index) {
4
4
  let api;
5
5
  try {
6
6
  api = getClientAPI();
7
- api.selectStory(index);
7
+ await api.selectStory(index);
8
8
  } catch (ex) {
9
9
  return {message: ex.message, version: api ? api.version : undefined};
10
10
  }
@@ -10,7 +10,7 @@ const makeRenderStories = require('./renderStories');
10
10
  const makeGetStoryData = require('./getStoryData');
11
11
  const ora = require('ora');
12
12
  const filterStories = require('./filterStories');
13
- const addParametrizedStories = require('./addParametrizedStories');
13
+ const addVariationStories = require('./addVariationStories');
14
14
  const browserLog = require('./browserLog');
15
15
  const memoryLog = require('./memoryLog');
16
16
  const getIframeUrl = require('./getIframeUrl');
@@ -116,12 +116,12 @@ async function eyesStorybook({
116
116
  );
117
117
 
118
118
  const filteredStories = filterStories({stories, config});
119
- const storiesIncludingParametrizedVariations = addParametrizedStories({
119
+ const storiesIncludingVariations = addVariationStories({
120
120
  stories: filteredStories,
121
121
  config,
122
122
  });
123
123
 
124
- logger.log(`starting to run ${storiesIncludingParametrizedVariations.length} stories`);
124
+ logger.log(`starting to run ${storiesIncludingVariations.length} stories`);
125
125
 
126
126
  const getStoryData = makeGetStoryData({
127
127
  logger,
@@ -158,7 +158,7 @@ async function eyesStorybook({
158
158
  setRenderIE,
159
159
  setTransitioningIntoIE,
160
160
  configs,
161
- stories: storiesIncludingParametrizedVariations,
161
+ stories: storiesIncludingVariations,
162
162
  pagePool,
163
163
  logger,
164
164
  timeItAsync,
@@ -3,11 +3,17 @@ const getStoryTitle = require('./getStoryTitle');
3
3
 
4
4
  function getStoryBaselineName({name, kind, parameters}) {
5
5
  const storyTitle = getStoryTitle({name, kind, parameters});
6
- const queryParam = parameters && parameters.eyes && parameters.eyes.queryParam;
6
+ const queryParams = parameters && parameters.eyes && parameters.eyes.queryParams;
7
+ if (!queryParams) return storyTitle;
8
+ const customQueryParams = {...queryParams};
9
+ delete customQueryParams['eyes-variation'];
10
+ if (Object.keys(customQueryParams).length === 0) return storyTitle;
7
11
 
8
- if (!queryParam || queryParam.name === 'eyes-variation') return storyTitle;
12
+ const queryParamsString = Object.entries(customQueryParams)
13
+ .map(([name, value]) => `${name}=${value}`)
14
+ .join('&');
9
15
 
10
- return `${storyTitle} [${queryParam.name}=${queryParam.value}]`;
16
+ return `${storyTitle} [${queryParamsString}]`;
11
17
  }
12
18
 
13
19
  module.exports = getStoryBaselineName;
@@ -15,19 +15,9 @@ function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPa
15
15
 
16
16
  const eyesParameters = story.parameters && story.parameters.eyes;
17
17
  if (story.isApi && !reloadPagePerStory) {
18
- const expectedQueryParam = eyesParameters ? eyesParameters.queryParam : undefined;
19
- const actualQueryParam = await getQueryParam(
20
- eyesParameters && eyesParameters.queryParams
21
- ? eyesParameters.queryParams.map(queryParam => queryParam.name)
22
- : undefined,
23
- );
24
- if (
25
- (!actualQueryParam && !expectedQueryParam) ||
26
- (actualQueryParam &&
27
- expectedQueryParam &&
28
- actualQueryParam.value === expectedQueryParam.name &&
29
- actualQueryParam.value === expectedQueryParam.value)
30
- ) {
18
+ const currentUrl = page.url();
19
+ const expectedQueryParams = eyesParameters ? eyesParameters.queryParams : undefined;
20
+ if (urlQueryParamsEquals(currentUrl, expectedQueryParams)) {
31
21
  const err = await page.evaluate(renderStoryWithClientAPI, story.index);
32
22
  err && handleRenderStoryError(err);
33
23
  } else {
@@ -84,19 +74,28 @@ function makeGetStoryData({logger, takeDomSnapshots, waitBeforeCapture, reloadPa
84
74
  }
85
75
  }
86
76
 
87
- async function getQueryParam(queryParamNames = []) {
77
+ function urlQueryParamsEquals(url, expectedQueryParams) {
88
78
  try {
89
- const url = new URL(await page.url());
90
- queryParamNames = [...queryParamNames, 'eyes-variation'];
91
- const queryParamName = queryParamNames.find(queryParamName =>
92
- url.searchParams.has(queryParamName),
93
- );
94
- if (queryParamName) {
95
- return {name: queryParamName, value: url.searchParams.get(queryParamName)};
79
+ url = new URL(url);
80
+ } catch (err) {
81
+ logger.error('Error during parsing page url', err);
82
+ return false;
83
+ }
84
+
85
+ expectedQueryParams = expectedQueryParams || {};
86
+ const expectedQueryParamNames = Object.keys(expectedQueryParams);
87
+ const actualQueryParamNames = [];
88
+ for (const [name, value] of url.searchParams) {
89
+ if (['eyes-storybook', 'selectedKind', 'selectedStory'].includes(name)) continue;
90
+ if (!expectedQueryParams.hasOwnProperty(name) || !expectedQueryParams[name] === value) {
91
+ return false;
96
92
  }
97
- } catch (ex) {
98
- logger.log('failed to get url from page (in need of eyes-variation param)');
93
+ actualQueryParamNames.push(name);
99
94
  }
95
+
96
+ if (actualQueryParamNames.length !== expectedQueryParamNames.length) return false;
97
+
98
+ return true;
100
99
  }
101
100
 
102
101
  // TODO (amit): handle this error in the caller (probably renderStories)
@@ -1,11 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  function getStoryTitle({name, kind, parameters}) {
4
- const queryParam = parameters && parameters.eyes && parameters.eyes.queryParam;
5
- const variation =
6
- queryParam && queryParam.name === 'eyes-variation' ? queryParam.value : undefined;
4
+ const queryParams = (parameters && parameters.eyes && parameters.eyes.queryParams) || {};
5
+ const eyesVariation = queryParams['eyes-variation'];
7
6
 
8
- return `${kind}: ${name}${variation ? ` [${variation}]` : ''}`;
7
+ return `${kind}: ${name}${eyesVariation ? ` [${eyesVariation}]` : ''}`;
9
8
  }
10
9
 
11
10
  module.exports = getStoryTitle;
@@ -2,12 +2,15 @@
2
2
  const getIframeUrl = require('./getIframeUrl');
3
3
 
4
4
  function getStoryUrl({name, kind, parameters}, baseUrl) {
5
- const queryParam = parameters && parameters.eyes && parameters.eyes.queryParam;
6
- const queryParamString = queryParam ? `&${queryParam.name}=${queryParam.value}` : '';
5
+ const queryParams = (parameters && parameters.eyes && parameters.eyes.queryParams) || {};
6
+ const queryString = Object.entries(queryParams).reduce(
7
+ (queryString, [name, value]) => queryString + `&${name}=${value}`,
8
+ '',
9
+ );
7
10
 
8
11
  return `${getIframeUrl(baseUrl)}&selectedKind=${encodeURIComponent(
9
12
  kind,
10
- )}&selectedStory=${encodeURIComponent(name)}${queryParamString}`;
13
+ )}&selectedStory=${encodeURIComponent(name)}${queryString}`;
11
14
  }
12
15
 
13
16
  module.exports = getStoryUrl;
@@ -8,7 +8,12 @@ function makeRenderStory({logger, testWindow, performance, timeItAsync}) {
8
8
  const {name, kind, parameters} = story;
9
9
  const baselineName = getStoryBaselineName({name, kind, parameters});
10
10
  const title = getStoryTitle({name, kind, parameters});
11
- const eyesOptions = Object.assign({}, config, (parameters && parameters.eyes) || {});
11
+ const eyesParameters = (parameters && parameters.eyes) || {};
12
+ const eyesOptions = {
13
+ ...config,
14
+ ...eyesParameters,
15
+ properties: [...(config.properties || []), ...(eyesParameters.properties || [])],
16
+ };
12
17
  const {
13
18
  ignoreDisplacements,
14
19
  ignoreRegions,
@@ -45,15 +50,17 @@ function makeRenderStory({logger, testWindow, performance, timeItAsync}) {
45
50
 
46
51
  logger.log(`running story ${title} with baseline ${baselineName}`);
47
52
 
53
+ const storyProperties = [
54
+ {name: 'Component name', value: kind},
55
+ {name: 'State', value: name},
56
+ ...(properties || []),
57
+ ];
58
+
48
59
  const openParams = {
49
60
  testName: baselineName,
50
61
  displayName: title,
51
62
  browser: config.browser,
52
- properties: [
53
- {name: 'Component name', value: kind},
54
- {name: 'State', value: name},
55
- ...(properties || []),
56
- ],
63
+ properties: storyProperties,
57
64
  accessibilitySettings: accessibilityValidation,
58
65
  };
59
66
 
@@ -72,7 +72,7 @@ class StorybookConnector extends EventEmitter {
72
72
 
73
73
  const successMessageListener = str => {
74
74
  const isReady = stripAnsi(str).match(
75
- /Storybook \d{1,2}\.\d{1,2}\.\d{1,2}(-.+)? started|Storybook started on =>/,
75
+ /Storybook \d{1,2}\.\d{1,2}\.\d{1,2}(.+)? started|Storybook started on =>/,
76
76
  );
77
77
 
78
78
  if (isReady) {
@@ -1,81 +0,0 @@
1
- 'use strict';
2
-
3
- function addParametrizedStories({stories, config}) {
4
- const parametrizedStories = {};
5
- for (const story of stories) {
6
- const queryParams = getStoryQueryParams(story, config);
7
- if (!queryParams) continue;
8
- for (const queryParam of queryParams) {
9
- const queryParamString = `${queryParam.name}=${queryParam.value}`;
10
- const parametrizeStoriesArray =
11
- parametrizedStories[queryParamString] || (parametrizedStories[queryParamString] = []);
12
- parametrizeStoriesArray.push({
13
- ...story,
14
- parameters: addQueryParam(story.parameters, queryParam),
15
- });
16
- }
17
- }
18
-
19
- return Object.values(parametrizedStories).reduce((allStories, parametrizedStories) => {
20
- return allStories.concat(parametrizedStories);
21
- }, stories);
22
- }
23
-
24
- function getStoryQueryParams(story, config) {
25
- let queryParams;
26
- if (story.parameters && story.parameters.eyes && story.parameters.eyes.queryParams) {
27
- if (!Array.isArray(story.parameters.eyes.queryParams)) {
28
- throw new Error('queryParams should be an array');
29
- }
30
- queryParams = [...story.parameters.eyes.queryParams];
31
- }
32
- if (story.parameters && story.parameters.eyes && story.parameters.eyes.variations) {
33
- if (!Array.isArray(story.parameters.eyes.variations)) {
34
- throw new Error('variations should be an array');
35
- }
36
- queryParams = [
37
- ...(queryParams || []),
38
- ...variationsToQueryParams(story.parameters.eyes.variations),
39
- ];
40
- }
41
-
42
- if (queryParams) return queryParams;
43
-
44
- if (config.queryParams) {
45
- if (!Array.isArray(config.queryParams)) {
46
- throw new Error('global queryParams should be an array');
47
- }
48
- queryParams = [...config.queryParams];
49
- }
50
-
51
- if (config.variations) {
52
- if (Array.isArray(config.variations)) {
53
- queryParams = [...(queryParams || []), ...variationsToQueryParams(config.variations)];
54
- } else if (typeof config.variations === 'function') {
55
- const variations = config.variations(story);
56
- if (variations) {
57
- if (!Array.isArray(variations)) {
58
- throw new Error('global variations should be a function that returns array');
59
- }
60
- queryParams = [...(queryParams || []), ...variationsToQueryParams(variations)];
61
- }
62
- } else {
63
- throw new Error('global variations should be an array or a function that returns array');
64
- }
65
- }
66
-
67
- if (queryParams) return queryParams;
68
- }
69
-
70
- function variationsToQueryParams(variations) {
71
- return variations.map(variation => ({name: 'eyes-variation', value: variation}));
72
- }
73
-
74
- function addQueryParam(parameters, queryParam) {
75
- parameters = {...parameters};
76
- parameters.eyes = {...parameters.eyes};
77
- parameters.eyes.queryParam = queryParam;
78
- return parameters;
79
- }
80
-
81
- module.exports = addParametrizedStories;