creevey 0.8.0-beta.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +30 -7
  2. package/README.md +9 -1
  3. package/addon/README.md +3 -0
  4. package/addon/package.json +4 -0
  5. package/docs/config.md +29 -26
  6. package/jest.config.js +6 -0
  7. package/lib/cjs/client/addon/Manager.js +122 -271
  8. package/lib/cjs/client/addon/components/Addon.js +17 -38
  9. package/lib/cjs/client/addon/components/Icons.js +11 -7
  10. package/lib/cjs/client/addon/components/Panel.js +17 -13
  11. package/lib/cjs/client/addon/components/TestSelect.js +11 -9
  12. package/lib/cjs/client/addon/components/Tools.js +21 -40
  13. package/lib/cjs/client/addon/decorator.js +1 -1
  14. package/lib/cjs/client/addon/index.js +31 -0
  15. package/lib/cjs/client/addon/preset.ie11.js +74 -0
  16. package/lib/cjs/client/addon/preset.js +13 -31
  17. package/lib/cjs/client/addon/readyForCapture.js +12 -0
  18. package/lib/cjs/client/addon/register.js +46 -70
  19. package/lib/cjs/client/addon/utils.js +6 -2
  20. package/lib/cjs/client/addon/withCreevey.js +221 -155
  21. package/lib/cjs/client/shared/components/ImagesView/BlendView.js +26 -24
  22. package/lib/cjs/client/shared/components/ImagesView/ImagesView.js +22 -18
  23. package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +44 -66
  24. package/lib/cjs/client/shared/components/ImagesView/SlideView.js +38 -50
  25. package/lib/cjs/client/shared/components/ImagesView/SwapView.js +26 -45
  26. package/lib/cjs/client/shared/components/ImagesView/index.js +9 -9
  27. package/lib/cjs/client/shared/components/PageFooter/PageFooter.js +12 -8
  28. package/lib/cjs/client/shared/components/PageFooter/Paging.js +14 -18
  29. package/lib/cjs/client/shared/components/PageHeader/ImagePreview.js +22 -18
  30. package/lib/cjs/client/shared/components/PageHeader/PageHeader.js +42 -67
  31. package/lib/cjs/client/shared/components/ResultsPage.js +39 -69
  32. package/lib/cjs/client/shared/creeveyClientApi.js +55 -82
  33. package/lib/cjs/client/shared/helpers.js +140 -211
  34. package/lib/cjs/client/shared/viewMode.js +5 -5
  35. package/lib/cjs/client/web/142.js +2 -0
  36. package/lib/cjs/client/web/142.js.LICENSE.txt +12 -0
  37. package/lib/cjs/client/web/32.js +1 -0
  38. package/lib/cjs/client/web/551.js +1 -0
  39. package/lib/cjs/client/web/566.js +2 -0
  40. package/lib/cjs/client/web/566.js.LICENSE.txt +31 -0
  41. package/lib/cjs/client/web/691.js +2 -0
  42. package/lib/cjs/client/web/691.js.LICENSE.txt +8 -0
  43. package/lib/cjs/client/web/725.js +1 -0
  44. package/lib/cjs/client/web/main.js +2 -38
  45. package/lib/cjs/client/web/main.js.LICENSE.txt +49 -0
  46. package/lib/cjs/creevey.js +3 -5
  47. package/lib/cjs/index.js +10 -15
  48. package/lib/cjs/server/config.js +5 -4
  49. package/lib/cjs/server/docker.js +3 -7
  50. package/lib/cjs/server/extract.js +7 -4
  51. package/lib/cjs/server/index.js +3 -5
  52. package/lib/cjs/server/loaders/babel/creevey-plugin.js +1 -3
  53. package/lib/cjs/server/loaders/babel/helpers.js +13 -23
  54. package/lib/cjs/server/loaders/babel/register.js +2 -4
  55. package/lib/cjs/server/loaders/webpack/compile.js +34 -51
  56. package/lib/cjs/server/loaders/webpack/creevey-loader.js +20 -22
  57. package/lib/cjs/server/loaders/webpack/dummy-hmr.js +2 -7
  58. package/lib/cjs/server/loaders/webpack/mdx-loader.js +2 -2
  59. package/lib/cjs/server/loaders/webpack/start.js +1 -1
  60. package/lib/cjs/server/logger.js +2 -1
  61. package/lib/cjs/server/master/index.js +4 -4
  62. package/lib/cjs/server/master/master.js +1 -0
  63. package/lib/cjs/server/master/pool.js +38 -47
  64. package/lib/cjs/server/master/runner.js +53 -66
  65. package/lib/cjs/server/master/server.js +78 -4
  66. package/lib/cjs/server/messages.js +128 -18
  67. package/lib/cjs/server/selenium/browser.js +129 -55
  68. package/lib/cjs/server/selenium/selenoid.js +5 -7
  69. package/lib/cjs/server/stories.js +58 -72
  70. package/lib/cjs/server/storybook/entry.js +7 -22
  71. package/lib/cjs/server/storybook/helpers.js +20 -27
  72. package/lib/cjs/server/storybook/providers/browser.js +74 -0
  73. package/lib/cjs/server/storybook/{nodejs-provider.js → providers/nodejs.js} +37 -20
  74. package/lib/cjs/server/update.js +1 -5
  75. package/lib/cjs/server/utils.js +26 -35
  76. package/lib/cjs/server/worker/helpers.js +2 -6
  77. package/lib/cjs/server/worker/reporter.js +8 -20
  78. package/lib/cjs/server/worker/worker.js +21 -19
  79. package/lib/cjs/shared/index.js +101 -0
  80. package/lib/cjs/shared/serializeRegExp.js +42 -0
  81. package/lib/cjs/types.js +11 -6
  82. package/lib/esm/client/addon/Manager.js +122 -271
  83. package/lib/esm/client/addon/components/Addon.js +15 -34
  84. package/lib/esm/client/addon/components/Icons.js +10 -6
  85. package/lib/esm/client/addon/components/Panel.js +17 -13
  86. package/lib/esm/client/addon/components/TestSelect.js +11 -9
  87. package/lib/esm/client/addon/components/Tools.js +19 -36
  88. package/lib/esm/client/addon/decorator.js +1 -1
  89. package/lib/esm/client/addon/index.js +2 -0
  90. package/lib/esm/client/addon/preset.ie11.js +59 -0
  91. package/lib/esm/client/addon/preset.js +12 -26
  92. package/lib/esm/client/addon/readyForCapture.js +5 -0
  93. package/lib/esm/client/addon/register.js +42 -66
  94. package/lib/esm/client/addon/utils.js +3 -2
  95. package/lib/esm/client/addon/withCreevey.js +209 -156
  96. package/lib/esm/client/shared/components/ImagesView/BlendView.js +23 -20
  97. package/lib/esm/client/shared/components/ImagesView/ImagesView.js +21 -17
  98. package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +42 -63
  99. package/lib/esm/client/shared/components/ImagesView/SlideView.js +36 -47
  100. package/lib/esm/client/shared/components/ImagesView/SwapView.js +24 -42
  101. package/lib/esm/client/shared/components/PageFooter/PageFooter.js +12 -8
  102. package/lib/esm/client/shared/components/PageFooter/Paging.js +14 -18
  103. package/lib/esm/client/shared/components/PageHeader/ImagePreview.js +22 -18
  104. package/lib/esm/client/shared/components/PageHeader/PageHeader.js +37 -60
  105. package/lib/esm/client/shared/components/ResultsPage.js +36 -64
  106. package/lib/esm/client/shared/creeveyClientApi.js +57 -84
  107. package/lib/esm/client/shared/helpers.js +124 -195
  108. package/lib/esm/client/shared/viewMode.js +4 -4
  109. package/lib/esm/creevey.js +3 -5
  110. package/lib/esm/index.js +2 -3
  111. package/lib/esm/server/config.js +4 -5
  112. package/lib/esm/server/docker.js +2 -2
  113. package/lib/esm/server/extract.js +6 -4
  114. package/lib/esm/server/index.js +3 -4
  115. package/lib/esm/server/loaders/babel/creevey-plugin.js +1 -3
  116. package/lib/esm/server/loaders/babel/helpers.js +12 -22
  117. package/lib/esm/server/loaders/babel/register.js +3 -5
  118. package/lib/esm/server/loaders/webpack/compile.js +35 -52
  119. package/lib/esm/server/loaders/webpack/creevey-loader.js +9 -10
  120. package/lib/esm/server/loaders/webpack/dummy-hmr.js +2 -6
  121. package/lib/esm/server/loaders/webpack/mdx-loader.js +2 -2
  122. package/lib/esm/server/loaders/webpack/start.js +1 -1
  123. package/lib/esm/server/master/index.js +4 -4
  124. package/lib/esm/server/master/master.js +1 -0
  125. package/lib/esm/server/master/pool.js +38 -49
  126. package/lib/esm/server/master/runner.js +53 -66
  127. package/lib/esm/server/master/server.js +76 -6
  128. package/lib/esm/server/messages.js +118 -14
  129. package/lib/esm/server/selenium/browser.js +126 -57
  130. package/lib/esm/server/selenium/selenoid.js +4 -6
  131. package/lib/esm/server/stories.js +58 -70
  132. package/lib/esm/server/storybook/entry.js +5 -22
  133. package/lib/esm/server/storybook/helpers.js +11 -20
  134. package/lib/esm/server/storybook/providers/browser.js +60 -0
  135. package/lib/esm/server/storybook/{nodejs-provider.js → providers/nodejs.js} +35 -19
  136. package/lib/esm/server/update.js +1 -5
  137. package/lib/esm/server/utils.js +18 -31
  138. package/lib/esm/server/worker/helpers.js +2 -6
  139. package/lib/esm/server/worker/reporter.js +8 -20
  140. package/lib/esm/server/worker/worker.js +22 -20
  141. package/lib/esm/shared/index.js +78 -0
  142. package/lib/esm/shared/serializeRegExp.js +24 -0
  143. package/lib/esm/types.js +3 -0
  144. package/lib/types/client/addon/Manager.d.ts +2 -2
  145. package/lib/types/client/addon/components/TestSelect.d.ts +0 -1
  146. package/lib/types/client/addon/index.d.ts +2 -0
  147. package/lib/types/client/addon/preset.d.ts +2 -1
  148. package/lib/types/client/addon/preset.ie11.d.ts +10 -0
  149. package/lib/types/client/addon/readyForCapture.d.ts +6 -0
  150. package/lib/types/client/addon/utils.d.ts +1 -0
  151. package/lib/types/client/addon/withCreevey.d.ts +13 -2
  152. package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +1 -1
  153. package/lib/types/client/shared/components/ImagesView/ImagesView.d.ts +0 -1
  154. package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +1 -1
  155. package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +1 -1
  156. package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +1 -1
  157. package/lib/types/client/shared/components/PageFooter/PageFooter.d.ts +0 -1
  158. package/lib/types/client/shared/components/PageFooter/Paging.d.ts +0 -1
  159. package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +1 -1
  160. package/lib/types/client/shared/components/PageHeader/PageHeader.d.ts +0 -1
  161. package/lib/types/client/shared/components/ResultsPage.d.ts +1 -1
  162. package/lib/types/client/web/CreeveyApp.d.ts +0 -1
  163. package/lib/types/client/web/CreeveyLoader.d.ts +1 -2
  164. package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +1 -1
  165. package/lib/types/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +0 -1
  166. package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +6 -6
  167. package/lib/types/client/web/CreeveyView/SideBar/TestLink.d.ts +0 -1
  168. package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +1 -1
  169. package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +1 -1
  170. package/lib/types/index.d.ts +0 -1
  171. package/lib/types/server/loaders/babel/register.d.ts +1 -1
  172. package/lib/types/server/loaders/webpack/creevey-loader.d.ts +4 -2
  173. package/lib/types/server/logger.d.ts +6 -2
  174. package/lib/types/server/master/master.d.ts +1 -0
  175. package/lib/types/server/master/pool.d.ts +1 -0
  176. package/lib/types/server/master/server.d.ts +1 -1
  177. package/lib/types/server/messages.d.ts +17 -6
  178. package/lib/types/server/selenium/browser.d.ts +5 -2
  179. package/lib/types/server/stories.d.ts +2 -2
  180. package/lib/types/server/storybook/entry.d.ts +2 -3
  181. package/lib/types/server/storybook/helpers.d.ts +1 -1
  182. package/lib/types/server/storybook/providers/browser.d.ts +4 -0
  183. package/lib/types/server/storybook/providers/nodejs.d.ts +9 -0
  184. package/lib/types/server/utils.d.ts +5 -1
  185. package/lib/types/server/worker/helpers.d.ts +2 -1
  186. package/lib/types/shared/index.d.ts +7 -0
  187. package/lib/types/shared/serializeRegExp.d.ts +9 -0
  188. package/lib/types/types.d.ts +32 -5
  189. package/package.json +120 -103
  190. package/preset/ie11.js +5 -0
  191. package/{preset.js → preset/index.js} +2 -2
  192. package/types/mdx.d.ts +3 -2
  193. package/types/mocha.d.ts +1 -0
  194. package/lib/cjs/client/web/1.js +0 -13
  195. package/lib/cjs/client/web/2.js +0 -1
  196. package/lib/cjs/shared.js +0 -35
  197. package/lib/esm/shared.js +0 -22
  198. package/lib/types/server/storybook/nodejs-provider.d.ts +0 -5
  199. package/lib/types/shared.d.ts +0 -4
@@ -3,25 +3,28 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.emitWorkerMessage = emitWorkerMessage;
7
- exports.emitTestMessage = emitTestMessage;
8
- exports.emitWebpackMessage = emitWebpackMessage;
9
6
  exports.emitDockerMessage = emitDockerMessage;
10
7
  exports.emitShutdownMessage = emitShutdownMessage;
11
- exports.sendTestMessage = sendTestMessage;
8
+ exports.emitStoriesMessage = emitStoriesMessage;
9
+ exports.emitTestMessage = emitTestMessage;
10
+ exports.emitWebpackMessage = emitWebpackMessage;
11
+ exports.emitWorkerMessage = emitWorkerMessage;
12
12
  exports.sendDockerMessage = sendDockerMessage;
13
13
  exports.sendShutdownMessage = sendShutdownMessage;
14
+ exports.sendStoriesMessage = sendStoriesMessage;
15
+ exports.sendTestMessage = sendTestMessage;
14
16
  exports.subscribeOn = subscribeOn;
17
+ exports.subscribeOnWorker = subscribeOnWorker;
15
18
 
16
19
  var _cluster = _interopRequireDefault(require("cluster"));
17
20
 
18
21
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
22
 
20
23
  function emitMessage(message) {
21
- var _process$send, _process$send2, _process;
24
+ var _process$send, _process;
22
25
 
23
26
  if (_cluster.default.isWorker && !process.connected) return false;
24
- return (_process$send = (_process$send2 = (_process = process).send) === null || _process$send2 === void 0 ? void 0 : _process$send2.call(_process, message)) !== null && _process$send !== void 0 ? _process$send : // @ts-expect-error: wrong typings `process.emit` return boolean
27
+ return ((_process$send = (_process = process).send) === null || _process$send === void 0 ? void 0 : _process$send.call(_process, message)) ?? // @ts-expect-error: wrong typings `process.emit` return boolean
25
28
  process.emit('message', message);
26
29
  }
27
30
 
@@ -32,6 +35,13 @@ function emitWorkerMessage(message) {
32
35
  });
33
36
  }
34
37
 
38
+ function emitStoriesMessage(message) {
39
+ return emitMessage({
40
+ scope: 'stories',
41
+ ...message
42
+ });
43
+ }
44
+
35
45
  function emitTestMessage(message) {
36
46
  return emitMessage({
37
47
  scope: 'test',
@@ -59,19 +69,27 @@ function emitShutdownMessage() {
59
69
  });
60
70
  }
61
71
 
62
- const handlers = Object.assign(Object.create(null), {
63
- worker: new Set(),
64
- test: new Set(),
65
- webpack: new Set(),
66
- docker: new Set(),
67
- shutdown: new Set()
68
- });
72
+ function createHandlers() {
73
+ return Object.assign(Object.create(null), {
74
+ worker: new Set(),
75
+ stories: new Set(),
76
+ test: new Set(),
77
+ webpack: new Set(),
78
+ docker: new Set(),
79
+ shutdown: new Set()
80
+ });
81
+ }
82
+
83
+ const handlers = createHandlers();
69
84
 
70
85
  const handler = message => {
71
86
  switch (message.scope) {
72
87
  case 'worker':
73
88
  return handlers.worker.forEach(h => h(message));
74
89
 
90
+ case 'stories':
91
+ return handlers.stories.forEach(h => h(message));
92
+
75
93
  case 'test':
76
94
  return handlers.test.forEach(h => h(message));
77
95
 
@@ -88,28 +106,37 @@ const handler = message => {
88
106
 
89
107
  process.on('message', handler);
90
108
 
91
- function sendTestMessage(target, message) {
109
+ function sendStoriesMessage(target, message) {
92
110
  var _target$send;
93
111
 
94
112
  (_target$send = target.send) === null || _target$send === void 0 ? void 0 : _target$send.call(target, {
95
- scope: 'test',
113
+ scope: 'stories',
96
114
  ...message
97
115
  });
98
116
  }
99
117
 
100
- function sendDockerMessage(target, message) {
118
+ function sendTestMessage(target, message) {
101
119
  var _target$send2;
102
120
 
103
121
  (_target$send2 = target.send) === null || _target$send2 === void 0 ? void 0 : _target$send2.call(target, {
104
- scope: 'docker',
122
+ scope: 'test',
105
123
  ...message
106
124
  });
107
125
  }
108
126
 
109
- function sendShutdownMessage(target) {
127
+ function sendDockerMessage(target, message) {
110
128
  var _target$send3;
111
129
 
112
130
  (_target$send3 = target.send) === null || _target$send3 === void 0 ? void 0 : _target$send3.call(target, {
131
+ scope: 'docker',
132
+ ...message
133
+ });
134
+ }
135
+
136
+ function sendShutdownMessage(target) {
137
+ var _target$send4;
138
+
139
+ (_target$send4 = target.send) === null || _target$send4 === void 0 ? void 0 : _target$send4.call(target, {
113
140
  scope: 'shutdown'
114
141
  });
115
142
  }
@@ -123,6 +150,13 @@ function subscribeOn(scope, handler) {
123
150
  return () => handlers.worker.delete(workerHandler);
124
151
  }
125
152
 
153
+ case 'stories':
154
+ {
155
+ const storiesHandler = handler;
156
+ handlers.stories.add(storiesHandler);
157
+ return () => handlers.stories.delete(storiesHandler);
158
+ }
159
+
126
160
  case 'test':
127
161
  {
128
162
  const testHandler = handler;
@@ -151,4 +185,80 @@ function subscribeOn(scope, handler) {
151
185
  return () => handlers.shutdown.delete(shutdownHandler);
152
186
  }
153
187
  }
188
+ }
189
+
190
+ const workers = new Map();
191
+
192
+ function subscribeOnWorker(worker, scope, handler) {
193
+ const workerHandlers = workers.get(worker) ?? createHandlers();
194
+
195
+ if (!workers.has(worker)) {
196
+ workers.set(worker, workerHandlers);
197
+ worker.once('exit', () => workers.delete(worker));
198
+ worker.on('message', message => {
199
+ switch (message.scope) {
200
+ case 'worker':
201
+ return workerHandlers.worker.forEach(h => h(message));
202
+
203
+ case 'stories':
204
+ return workerHandlers.stories.forEach(h => h(message));
205
+
206
+ case 'test':
207
+ return workerHandlers.test.forEach(h => h(message));
208
+
209
+ case 'webpack':
210
+ return workerHandlers.webpack.forEach(h => h(message));
211
+
212
+ case 'docker':
213
+ return workerHandlers.docker.forEach(h => h(message));
214
+
215
+ case 'shutdown':
216
+ return workerHandlers.shutdown.forEach(h => h(message));
217
+ }
218
+ });
219
+ }
220
+
221
+ switch (scope) {
222
+ case 'worker':
223
+ {
224
+ const workerHandler = handler;
225
+ workerHandlers.worker.add(workerHandler);
226
+ return () => workerHandlers.worker.delete(workerHandler);
227
+ }
228
+
229
+ case 'stories':
230
+ {
231
+ const storiesHandler = handler;
232
+ workerHandlers.stories.add(storiesHandler);
233
+ return () => workerHandlers.stories.delete(storiesHandler);
234
+ }
235
+
236
+ case 'test':
237
+ {
238
+ const testHandler = handler;
239
+ workerHandlers.test.add(testHandler);
240
+ return () => workerHandlers.test.delete(testHandler);
241
+ }
242
+
243
+ case 'webpack':
244
+ {
245
+ const webpackHandler = handler;
246
+ workerHandlers.webpack.add(webpackHandler);
247
+ return () => workerHandlers.webpack.delete(webpackHandler);
248
+ }
249
+
250
+ case 'docker':
251
+ {
252
+ const dockerHandler = handler;
253
+ workerHandlers.docker.add(dockerHandler);
254
+ return () => workerHandlers.docker.delete(dockerHandler);
255
+ }
256
+
257
+ case 'shutdown':
258
+ {
259
+ const shutdownHandler = handler;
260
+ workerHandlers.shutdown.add(shutdownHandler);
261
+ return () => workerHandlers.shutdown.delete(shutdownHandler);
262
+ }
263
+ }
154
264
  }
@@ -3,9 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.updateStorybookGlobals = updateStorybookGlobals;
6
+ exports.closeBrowser = closeBrowser;
7
7
  exports.getBrowser = getBrowser;
8
+ exports.loadStoriesFromBrowser = loadStoriesFromBrowser;
8
9
  exports.switchStory = switchStory;
10
+ exports.takeScreenshot = takeScreenshot;
11
+ exports.updateStorybookGlobals = updateStorybookGlobals;
9
12
 
10
13
  var _chalk = _interopRequireDefault(require("chalk"));
11
14
 
@@ -39,15 +42,16 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
39
42
 
40
43
  const DOCKER_INTERNAL = 'host.docker.internal';
41
44
  let browserLogger = _logger.logger;
45
+ let browserName = '';
46
+ let browser = null;
47
+ let creeveyServerHost = null;
42
48
 
43
49
  function getSessionData(grid, sessionId = '') {
44
50
  const gridUrl = new URL(grid);
45
51
  gridUrl.pathname = `/host/${sessionId}`;
46
52
  return new Promise((resolve, reject) => (gridUrl.protocol == 'https:' ? _https.default : _http.default).get(gridUrl.toString(), res => {
47
53
  if (res.statusCode !== 200) {
48
- var _res$statusCode;
49
-
50
- return reject(new Error(`Couldn't get session data for ${sessionId}. Status code: ${(_res$statusCode = res.statusCode) !== null && _res$statusCode !== void 0 ? _res$statusCode : 'Unknown'}`));
54
+ return reject(new Error(`Couldn't get session data for ${sessionId}. Status code: ${res.statusCode ?? 'Unknown'}`));
51
55
  }
52
56
 
53
57
  let data = '';
@@ -57,17 +61,19 @@ function getSessionData(grid, sessionId = '') {
57
61
  try {
58
62
  resolve(JSON.parse(data));
59
63
  } catch (error) {
60
- var _error$stack;
61
-
62
- reject(new Error(`Couldn't get session data for ${sessionId}. ${error instanceof Error ? (_error$stack = error.stack) !== null && _error$stack !== void 0 ? _error$stack : error.message : error}`));
64
+ reject(new Error(`Couldn't get session data for ${sessionId}. ${error instanceof Error ? error.stack ?? error.message : error}`));
63
65
  }
64
66
  });
65
67
  }));
66
68
  }
67
69
 
70
+ function getAddresses() {
71
+ return [DOCKER_INTERNAL].concat(...Object.values((0, _os.networkInterfaces)()).filter(_types.isDefined).map(network => network.filter(info => info.family == 'IPv4').map(info => info.address)));
72
+ }
73
+
68
74
  async function resolveStorybookUrl(storybookUrl, checkUrl) {
69
75
  browserLogger.debug('Resolving storybook url');
70
- const addresses = [DOCKER_INTERNAL].concat(...Object.values((0, _os.networkInterfaces)()).filter(_types.isDefined).map(network => network.filter(info => info.family == 'IPv4').map(info => info.address)));
76
+ const addresses = getAddresses();
71
77
 
72
78
  for (const ip of addresses) {
73
79
  const resolvedUrl = storybookUrl.replace(_utils.LOCALHOST_REGEXP, ip);
@@ -121,17 +127,6 @@ function getUrlChecker(browser) {
121
127
  }
122
128
 
123
129
  async function waitForStorybook(browser) {
124
- // NOTE: Storybook 5.x doesn't have the `last` method
125
- if ((0, _helpers.isStorybookVersionLessThan)(6)) {
126
- browserLogger.debug('Waiting for `load` event to make sure that storybook is initiated');
127
- return browser.executeAsyncScript(function (callback) {
128
- if (document.readyState == 'complete') return callback();
129
- window.addEventListener('load', function () {
130
- callback();
131
- });
132
- });
133
- }
134
-
135
130
  browserLogger.debug('Waiting for `setStories` event to make sure that storybook is initiated');
136
131
  let wait = true;
137
132
  let isTimeout = false;
@@ -154,11 +149,11 @@ async function waitForStorybook(browser) {
154
149
  }
155
150
 
156
151
  async function resetMousePosition(browser) {
157
- var _ref, _await$browser$getCap, _await$browser$getCap2, _await$browser$getCap3;
152
+ var _await$browser$getCap, _await$browser$getCap2;
158
153
 
159
154
  browserLogger.debug('Resetting mouse position to the top-left corner');
160
155
  const browserName = (await browser.getCapabilities()).getBrowserName();
161
- const [browserVersion] = (_ref = (_await$browser$getCap = (_await$browser$getCap2 = (await browser.getCapabilities()).getBrowserVersion()) === null || _await$browser$getCap2 === void 0 ? void 0 : _await$browser$getCap2.split('.')) !== null && _await$browser$getCap !== void 0 ? _await$browser$getCap : (_await$browser$getCap3 = (await browser.getCapabilities()).get('version')) === null || _await$browser$getCap3 === void 0 ? void 0 : _await$browser$getCap3.split('.')) !== null && _ref !== void 0 ? _ref : []; // NOTE Reset mouse position to support keweb selenium grid browser versions
156
+ const [browserVersion] = ((_await$browser$getCap = (await browser.getCapabilities()).getBrowserVersion()) === null || _await$browser$getCap === void 0 ? void 0 : _await$browser$getCap.split('.')) ?? ((_await$browser$getCap2 = (await browser.getCapabilities()).get('version')) === null || _await$browser$getCap2 === void 0 ? void 0 : _await$browser$getCap2.split('.')) ?? []; // NOTE Reset mouse position to support keweb selenium grid browser versions
162
157
 
163
158
  if (browserName == 'chrome' && browserVersion == '70') {
164
159
  const {
@@ -242,10 +237,10 @@ const getScrollBarWidth = (() => {
242
237
 
243
238
 
244
239
  async function hasScrollBar(browser) {
245
- var _await$browser$getCap4, _await$browser$getCap5;
240
+ var _await$browser$getCap3;
246
241
 
247
242
  const browserName = (await browser.getCapabilities()).getBrowserName();
248
- const [browserVersion] = (_await$browser$getCap4 = (_await$browser$getCap5 = (await browser.getCapabilities()).getBrowserVersion()) === null || _await$browser$getCap5 === void 0 ? void 0 : _await$browser$getCap5.split('.')) !== null && _await$browser$getCap4 !== void 0 ? _await$browser$getCap4 : [];
243
+ const [browserVersion] = ((_await$browser$getCap3 = (await browser.getCapabilities()).getBrowserVersion()) === null || _await$browser$getCap3 === void 0 ? void 0 : _await$browser$getCap3.split('.')) ?? [];
249
244
  return browserName != 'Safari' && // NOTE This need to work with keweb selenium grid
250
245
  !(browserName == 'firefox' && browserVersion == '61');
251
246
  }
@@ -296,7 +291,8 @@ async function takeCompositeScreenshot(browser, windowRect, elementRect) {
296
291
  const scrollOffset = isFitVertically || isScreenshotWithoutScrollBar ? 0 : scrollBarWidth;
297
292
  const i = (y * compositeImage.width + x) * 4;
298
293
  const j = // NOTE compositeImage(x, y) => image(x, y)
299
- (y % viewportHeight * (viewportWidth + scrollOffset) + x % viewportWidth) * 4 + (isLastRow ? yOffset * (viewportWidth + scrollOffset) * 4 : 0) + (isLastCol ? xOffset * 4 : 0);
294
+ (y % viewportHeight * (viewportWidth + scrollOffset) + x % viewportWidth) * 4 + ( // NOTE Offset for last row/col image
295
+ isLastRow ? yOffset * (viewportWidth + scrollOffset) * 4 : 0) + (isLastCol ? xOffset * 4 : 0);
300
296
  const image = images[row * cols + col];
301
297
  compositeImage.data[i + 0] = image.data[j + 0];
302
298
  compositeImage.data[i + 1] = image.data[j + 1];
@@ -345,7 +341,7 @@ async function takeScreenshot(browser, captureElement, ignoreElements) {
345
341
  const {
346
342
  elementRect,
347
343
  windowRect
348
- } = rects !== null && rects !== void 0 ? rects : {};
344
+ } = rects ?? {};
349
345
  if (!elementRect || !windowRect) throw new Error(`Couldn't find element with selector: '${captureElement}'`);
350
346
  const isFitIntoViewport = elementRect.width + elementRect.left <= windowRect.width && elementRect.height + elementRect.top <= windowRect.height;
351
347
  if (isFitIntoViewport) browserLogger.debug(`Capturing ${_chalk.default.cyan(captureElement)}`);else browserLogger.debug(`Capturing composite screenshot image of ${_chalk.default.cyan(captureElement)}`);
@@ -366,22 +362,19 @@ async function selectStory(browser, {
366
362
  name
367
363
  }, waitForReady = false) {
368
364
  browserLogger.debug(`Triggering 'SetCurrentStory' event with storyId ${_chalk.default.magenta(id)}`);
369
- const errorMessage = await browser.executeAsyncScript(function (id, kind, name, shouldWaitForReady, callback) {
365
+ const result = await browser.executeAsyncScript(function (id, kind, name, shouldWaitForReady, callback) {
370
366
  if (typeof window.__CREEVEY_SELECT_STORY__ == 'undefined') {
371
- return callback("Creevey can't switch story. This may happened if forget to add `creevey` addon to your storybook config, or storybook not loaded in browser due syntax error.");
367
+ return callback(["Creevey can't switch story. This may happened if forget to add `creevey` addon to your storybook config, or storybook not loaded in browser due syntax error."]);
372
368
  }
373
369
 
374
- window.__CREEVEY_SELECT_STORY__(id, kind, name, shouldWaitForReady, callback);
370
+ void window.__CREEVEY_SELECT_STORY__(id, kind, name, shouldWaitForReady, callback);
375
371
  }, id, kind, name, waitForReady);
372
+ const [errorMessage, isCaptureCalled = false] = result ?? [];
376
373
  if (errorMessage) throw new Error(errorMessage);
374
+ return isCaptureCalled;
377
375
  }
378
376
 
379
377
  async function updateStorybookGlobals(browser, globals) {
380
- if ((0, _helpers.isStorybookVersionLessThan)(6)) {
381
- browserLogger.warn('Globals are not supported by Storybook versions less than 6');
382
- return;
383
- }
384
-
385
378
  browserLogger.debug('Applying storybook globals');
386
379
  await browser.executeScript(function (globals) {
387
380
  window.__CREEVEY_UPDATE_GLOBALS__(globals);
@@ -413,7 +406,45 @@ async function openStorybookPage(browser, storybookUrl, resolver) {
413
406
  }
414
407
  }
415
408
 
416
- async function getBrowser(config, browserConfig) {
409
+ async function resolveCreeveyHost(browser, port) {
410
+ if (creeveyServerHost != null) return creeveyServerHost;
411
+ const addresses = getAddresses();
412
+ creeveyServerHost = await browser.executeAsyncScript(function (hosts, port, callback) {
413
+ void Promise.all(hosts.map(function (host) {
414
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
415
+ return fetch('http://' + host + ':' + port + '/ping').then(function (response) {
416
+ return response.text();
417
+ }).then(function (pong) {
418
+ return pong == 'pong' ? host : null;
419
+ }).catch(function () {
420
+ return null;
421
+ });
422
+ })).then(function (hosts) {
423
+ callback(hosts.find(function (host) {
424
+ return host != null;
425
+ }));
426
+ });
427
+ }, addresses, port);
428
+ if (creeveyServerHost == null) throw new Error("Can't reach creevey server from a browser");
429
+ return creeveyServerHost;
430
+ }
431
+
432
+ async function loadStoriesFromBrowser(port) {
433
+ if (!browser) throw new Error("Can't get stories from browser if webdriver isn't connected");
434
+ const host = await resolveCreeveyHost(browser, port);
435
+ const stories = await browser.executeAsyncScript(function (creeveyHost, creeveyPort, callback) {
436
+ window.__CREEVEY_SERVER_HOST__ = creeveyHost;
437
+ window.__CREEVEY_SERVER_PORT__ = creeveyPort;
438
+ void window.__CREEVEY_GET_STORIES__().then(callback);
439
+ }, host, port);
440
+ if (!stories) throw new Error("Can't get stories, it seems creevey or storybook API isn't available");
441
+ return stories;
442
+ }
443
+
444
+ async function getBrowser(config, name) {
445
+ if (browser) return browser;
446
+ browserName = name;
447
+ const browserConfig = config.browsers[browserName];
417
448
  const {
418
449
  gridUrl = config.gridUrl,
419
450
  storybookUrl: address = config.storybookUrl,
@@ -423,14 +454,11 @@ async function getBrowser(config, browserConfig) {
423
454
  ...userCapabilities
424
455
  } = browserConfig;
425
456
  void limit;
426
- const {
427
- browserName
428
- } = userCapabilities;
429
- const realAddress = address;
430
- let browser = null; // TODO Define some capabilities explicitly and define typings
457
+ const realAddress = address; // TODO Define some capabilities explicitly and define typings
431
458
 
432
- const capabilities = new _seleniumWebdriver.Capabilities(userCapabilities);
433
- capabilities.setPageLoadStrategy(_capabilities.PageLoadStrategy.NONE);
459
+ const capabilities = new _seleniumWebdriver.Capabilities({ ...userCapabilities,
460
+ pageLoadStrategy: _capabilities.PageLoadStrategy.NONE
461
+ });
434
462
  (0, _messages.subscribeOn)('shutdown', () => {
435
463
  var _browser;
436
464
 
@@ -445,7 +473,7 @@ async function getBrowser(config, browserConfig) {
445
473
  const url = new URL(gridUrl);
446
474
  url.username = url.username ? '********' : '';
447
475
  url.password = url.password ? '********' : '';
448
- browserLogger.debug(`(${browserName}) Connecting to Selenium ${_chalk.default.magenta(url.toString())}`);
476
+ browserLogger.debug(`(${name}) Connecting to Selenium ${_chalk.default.magenta(url.toString())}`);
449
477
  browser = await new _seleniumWebdriver.Builder().usingServer(gridUrl).withCapabilities(capabilities).build();
450
478
  const sessionId = (_await$browser$getSes = await browser.getSession()) === null || _await$browser$getSes === void 0 ? void 0 : _await$browser$getSes.getId();
451
479
  let browserHost = '';
@@ -459,14 +487,14 @@ async function getBrowser(config, browserConfig) {
459
487
  /* noop */
460
488
  }
461
489
 
462
- browserLogger.debug(`(${browserName}) Connected successful with ${[_chalk.default.green(browserHost), _chalk.default.magenta(sessionId)].filter(Boolean).join(':')}`);
490
+ browserLogger.debug(`(${name}) Connected successful with ${[_chalk.default.green(browserHost), _chalk.default.magenta(sessionId)].filter(Boolean).join(':')}`);
463
491
  browserLogger = (0, _loglevel.getLogger)(sessionId);
464
492
 
465
493
  _loglevelPluginPrefix.default.apply(browserLogger, {
466
494
  format(level) {
467
495
  const levelColor = _logger.colors[level.toUpperCase()];
468
496
 
469
- return `[${browserName}:${_chalk.default.gray(sessionId)}] ${levelColor(level)} =>`;
497
+ return `[${name}:${_chalk.default.gray(sessionId)}] ${levelColor(level)} =>`;
470
498
  }
471
499
 
472
500
  });
@@ -480,17 +508,18 @@ async function getBrowser(config, browserConfig) {
480
508
  });
481
509
  }, () => viewport && browser && resizeViewport(browser, viewport), () => browser && openStorybookPage(browser, realAddress, config.resolveStorybookUrl), () => browser && waitForStorybook(browser)], () => !_utils.isShuttingDown.current);
482
510
  } catch (originalError) {
483
- var _await$browser$getCur, _browser4;
511
+ var _browser4;
484
512
 
485
513
  if (_utils.isShuttingDown.current) {
486
514
  var _browser3;
487
515
 
488
516
  (_browser3 = browser) === null || _browser3 === void 0 ? void 0 : _browser3.quit().catch(_types.noop);
517
+ browser = null;
489
518
  return null;
490
519
  }
491
520
 
492
521
  if (originalError instanceof Error && originalError.name == 'ResolveUrlError') throw originalError;
493
- const error = new Error(`Can't load storybook root page by URL ${(_await$browser$getCur = await ((_browser4 = browser) === null || _browser4 === void 0 ? void 0 : _browser4.getCurrentUrl())) !== null && _await$browser$getCur !== void 0 ? _await$browser$getCur : realAddress}`);
522
+ const error = new Error(`Can't load storybook root page by URL ${(await ((_browser4 = browser) === null || _browser4 === void 0 ? void 0 : _browser4.getCurrentUrl())) ?? realAddress}`);
494
523
  if (originalError instanceof Error) error.stack = originalError.stack;
495
524
  throw error;
496
525
  }
@@ -499,6 +528,9 @@ async function getBrowser(config, browserConfig) {
499
528
  await updateStorybookGlobals(browser, _storybookGlobals);
500
529
  }
501
530
 
531
+ await browser.executeScript(function (workerId) {
532
+ window.__CREEVEY_WORKER_ID__ = workerId;
533
+ }, process.pid);
502
534
  return browser;
503
535
  }
504
536
 
@@ -514,12 +546,23 @@ async function updateStoryArgs(browser, story, updatedArgs) {
514
546
  }, story.id, updatedArgs, Events.UPDATE_STORY_ARGS, Events.STORY_RENDERED);
515
547
  }
516
548
 
549
+ async function closeBrowser() {
550
+ if (!browser) return;
551
+
552
+ try {
553
+ await browser.quit();
554
+ } finally {
555
+ browser = null;
556
+ }
557
+ }
558
+
517
559
  async function switchStory() {
518
- var _this$currentTest, _this$currentTest$ctx, _parameters$creevey;
560
+ var _this$currentTest, _this$currentTest$ctx;
519
561
 
520
562
  let testOrSuite = this.currentTest;
521
563
  if (!testOrSuite) throw new Error("Can't switch story, because test context doesn't have 'currentTest' field");
522
564
  this.testScope.length = 0;
565
+ this.screenshots.length = 0;
523
566
  this.testScope.push(this.browserName);
524
567
 
525
568
  while ((_testOrSuite = testOrSuite) !== null && _testOrSuite !== void 0 && _testOrSuite.title) {
@@ -541,15 +584,8 @@ async function switchStory() {
541
584
  captureElement = '#root',
542
585
  waitForReady,
543
586
  ignoreElements
544
- } = (_parameters$creevey = parameters.creevey) !== null && _parameters$creevey !== void 0 ? _parameters$creevey : {};
587
+ } = parameters.creevey ?? {};
545
588
  browserLogger.debug(`Switching to story ${_chalk.default.cyan(kind)}/${_chalk.default.cyan(name)} by id ${_chalk.default.magenta(id)}`);
546
- await resetMousePosition(this.browser);
547
- await selectStory(this.browser, {
548
- id,
549
- kind,
550
- name
551
- }, waitForReady);
552
- browserLogger.debug(`Story ${_chalk.default.magenta(id)} ready for capturing`);
553
589
  if (captureElement) Object.defineProperty(this, 'captureElement', {
554
590
  enumerable: true,
555
591
  configurable: true,
@@ -561,6 +597,44 @@ async function switchStory() {
561
597
  this.updateStoryArgs = updatedArgs => updateStoryArgs(this.browser, story, updatedArgs);
562
598
 
563
599
  this.testScope.reverse();
600
+ let storyPlayResolver;
601
+ let waitForComplete = new Promise(resolve => storyPlayResolver = resolve);
602
+ const unsubscribe = (0, _messages.subscribeOn)('stories', message => {
603
+ if (message.type != 'capture') return;
604
+ const {
605
+ payload = {},
606
+ payload: {
607
+ imageName
608
+ } = {}
609
+ } = message;
610
+ void takeScreenshot(this.browser, payload.captureElement ?? captureElement, payload.ignoreElements ?? ignoreElements).then(screenshot => {
611
+ this.screenshots.push({
612
+ imageName,
613
+ screenshot
614
+ });
615
+ void this.browser.executeAsyncScript(function (callback) {
616
+ window.__CREEVEY_HAS_PLAY_COMPLETED_YET__(callback);
617
+ }).then(isCompleted => storyPlayResolver(isCompleted));
618
+ (0, _messages.emitStoriesMessage)({
619
+ type: 'capture'
620
+ });
621
+ });
622
+ });
623
+ await resetMousePosition(this.browser);
624
+ const isCaptureCalled = await selectStory(this.browser, {
625
+ id,
626
+ kind,
627
+ name
628
+ }, waitForReady);
629
+
630
+ if (isCaptureCalled) {
631
+ while (!(await waitForComplete)) {
632
+ waitForComplete = new Promise(resolve => storyPlayResolver = resolve);
633
+ }
634
+ }
635
+
636
+ unsubscribe();
637
+ browserLogger.debug(`Story ${_chalk.default.magenta(id)} ready for capturing`);
564
638
  }
565
639
 
566
640
  async function insertIgnoreStyles(browser, ignoreElements) {
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.startSelenoidStandalone = startSelenoidStandalone;
7
6
  exports.startSelenoidContainer = startSelenoidContainer;
7
+ exports.startSelenoidStandalone = startSelenoidStandalone;
8
8
 
9
9
  var _path = _interopRequireDefault(require("path"));
10
10
 
@@ -20,7 +20,7 @@ var _core = require("@octokit/core");
20
20
 
21
21
  var _messages = require("../messages");
22
22
 
23
- var _cluster = require("cluster");
23
+ var _cluster = _interopRequireDefault(require("cluster"));
24
24
 
25
25
  var _shelljs = require("shelljs");
26
26
 
@@ -62,8 +62,6 @@ async function createSelenoidConfig(browsers, {
62
62
  }
63
63
 
64
64
  async function downloadSelenoidBinary(destination) {
65
- var _assets$find;
66
-
67
65
  const platformNameMapping = {
68
66
  darwin: 'selenoid_darwin_amd64',
69
67
  linux: 'selenoid_linux_amd64',
@@ -80,9 +78,9 @@ async function downloadSelenoidBinary(destination) {
80
78
  const {
81
79
  browser_download_url: downloadUrl,
82
80
  size: binarySize
83
- } = (_assets$find = assets.find(({
81
+ } = assets.find(({
84
82
  name
85
- }) => platformNameMapping[process.platform] == name)) !== null && _assets$find !== void 0 ? _assets$find : {};
83
+ }) => platformNameMapping[process.platform] == name) ?? {};
86
84
  if ((0, _fs.existsSync)(destination) && (0, _fs.lstatSync)(destination).size == binarySize) return;
87
85
 
88
86
  if (!downloadUrl) {
@@ -94,7 +92,7 @@ async function downloadSelenoidBinary(destination) {
94
92
 
95
93
  async function startSelenoidStandalone(config, debug) {
96
94
  config.gridUrl = 'http://localhost:4444/wd/hub';
97
- if (_cluster.isWorker) return;
95
+ if (_cluster.default.isWorker) return;
98
96
  const browsers = Object.values(config.browsers).filter(browser => !browser.gridUrl);
99
97
  const selenoidConfigDir = await createSelenoidConfig(browsers, {
100
98
  useDocker: false