creevey 0.7.39 → 0.8.0-beta.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.
Files changed (239) hide show
  1. package/CHANGELOG.md +33 -2
  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 +37 -5
  6. package/docs/grid.md +2 -1
  7. package/jest.config.js +6 -0
  8. package/lib/cjs/client/addon/Manager.js +124 -271
  9. package/lib/cjs/client/addon/components/Addon.js +17 -38
  10. package/lib/cjs/client/addon/components/Icons.js +11 -7
  11. package/lib/cjs/client/addon/components/Panel.js +17 -13
  12. package/lib/cjs/client/addon/components/TestSelect.js +11 -9
  13. package/lib/cjs/client/addon/components/Tools.js +21 -40
  14. package/lib/cjs/client/addon/decorator.js +1 -1
  15. package/lib/cjs/client/addon/index.js +31 -0
  16. package/lib/cjs/client/addon/preset.ie11.js +74 -0
  17. package/lib/cjs/client/addon/preset.js +13 -31
  18. package/lib/cjs/client/addon/readyForCapture.js +12 -0
  19. package/lib/cjs/client/addon/register.js +46 -70
  20. package/lib/cjs/client/addon/utils.js +5 -41
  21. package/lib/cjs/client/addon/withCreevey.js +221 -155
  22. package/lib/cjs/client/shared/components/ImagesView/BlendView.js +26 -24
  23. package/lib/cjs/client/shared/components/ImagesView/ImagesView.js +22 -18
  24. package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +44 -66
  25. package/lib/cjs/client/shared/components/ImagesView/SlideView.js +38 -50
  26. package/lib/cjs/client/shared/components/ImagesView/SwapView.js +26 -45
  27. package/lib/cjs/client/shared/components/ImagesView/index.js +9 -9
  28. package/lib/cjs/client/shared/components/PageFooter/PageFooter.js +12 -8
  29. package/lib/cjs/client/shared/components/PageFooter/Paging.js +14 -18
  30. package/lib/cjs/client/shared/components/PageHeader/ImagePreview.js +22 -18
  31. package/lib/cjs/client/shared/components/PageHeader/PageHeader.js +42 -67
  32. package/lib/cjs/client/shared/components/ResultsPage.js +39 -69
  33. package/lib/cjs/client/shared/creeveyClientApi.js +55 -82
  34. package/lib/cjs/client/shared/helpers.js +140 -211
  35. package/lib/cjs/client/shared/viewMode.js +5 -5
  36. package/lib/cjs/client/web/142.js +2 -0
  37. package/lib/cjs/client/web/142.js.LICENSE.txt +12 -0
  38. package/lib/cjs/client/web/32.js +1 -0
  39. package/lib/cjs/client/web/551.js +1 -0
  40. package/lib/cjs/client/web/566.js +2 -0
  41. package/lib/cjs/client/web/566.js.LICENSE.txt +31 -0
  42. package/lib/cjs/client/web/691.js +2 -0
  43. package/lib/cjs/client/web/691.js.LICENSE.txt +8 -0
  44. package/lib/cjs/client/web/725.js +1 -0
  45. package/lib/cjs/client/web/main.js +2 -38
  46. package/lib/cjs/client/web/main.js.LICENSE.txt +49 -0
  47. package/lib/cjs/creevey.js +3 -5
  48. package/lib/cjs/index.js +10 -15
  49. package/lib/cjs/server/config.js +5 -4
  50. package/lib/cjs/server/docker.js +3 -7
  51. package/lib/cjs/server/extract.js +7 -4
  52. package/lib/cjs/server/index.js +3 -5
  53. package/lib/cjs/server/loaders/babel/creevey-plugin.js +1 -3
  54. package/lib/cjs/server/loaders/babel/helpers.js +13 -23
  55. package/lib/cjs/server/loaders/babel/register.js +3 -4
  56. package/lib/cjs/server/loaders/webpack/compile.js +33 -50
  57. package/lib/cjs/server/loaders/webpack/creevey-loader.js +20 -22
  58. package/lib/cjs/server/loaders/webpack/dummy-hmr.js +2 -7
  59. package/lib/cjs/server/loaders/webpack/mdx-loader.js +2 -2
  60. package/lib/cjs/server/loaders/webpack/start.js +1 -1
  61. package/lib/cjs/server/logger.js +2 -1
  62. package/lib/cjs/server/master/index.js +4 -4
  63. package/lib/cjs/server/master/master.js +1 -0
  64. package/lib/cjs/server/master/pool.js +38 -47
  65. package/lib/cjs/server/master/runner.js +53 -66
  66. package/lib/cjs/server/master/server.js +78 -4
  67. package/lib/cjs/server/messages.js +128 -18
  68. package/lib/cjs/server/selenium/browser.js +129 -55
  69. package/lib/cjs/server/selenium/selenoid.js +6 -8
  70. package/lib/cjs/server/stories.js +58 -84
  71. package/lib/cjs/server/storybook/entry.js +8 -22
  72. package/lib/cjs/server/storybook/helpers.js +22 -21
  73. package/lib/cjs/server/storybook/providers/browser.js +74 -0
  74. package/lib/cjs/server/storybook/{nodejs-provider.js → providers/nodejs.js} +44 -22
  75. package/lib/cjs/server/update.js +1 -5
  76. package/lib/cjs/server/utils.js +36 -15
  77. package/lib/cjs/server/worker/helpers.js +2 -6
  78. package/lib/cjs/server/worker/reporter.js +8 -20
  79. package/lib/cjs/server/worker/worker.js +21 -19
  80. package/lib/cjs/shared/index.js +101 -0
  81. package/lib/cjs/shared/serializeRegExp.js +42 -0
  82. package/lib/cjs/types.js +11 -6
  83. package/lib/esm/client/addon/Manager.js +124 -272
  84. package/lib/esm/client/addon/components/Addon.js +15 -34
  85. package/lib/esm/client/addon/components/Icons.js +10 -6
  86. package/lib/esm/client/addon/components/Panel.js +17 -13
  87. package/lib/esm/client/addon/components/TestSelect.js +11 -9
  88. package/lib/esm/client/addon/components/Tools.js +19 -36
  89. package/lib/esm/client/addon/decorator.js +1 -1
  90. package/lib/esm/client/addon/index.js +2 -0
  91. package/lib/esm/client/addon/preset.ie11.js +59 -0
  92. package/lib/esm/client/addon/preset.js +12 -26
  93. package/lib/esm/client/addon/readyForCapture.js +5 -0
  94. package/lib/esm/client/addon/register.js +42 -66
  95. package/lib/esm/client/addon/utils.js +3 -34
  96. package/lib/esm/client/addon/withCreevey.js +209 -156
  97. package/lib/esm/client/shared/components/ImagesView/BlendView.js +23 -20
  98. package/lib/esm/client/shared/components/ImagesView/ImagesView.js +21 -17
  99. package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +42 -63
  100. package/lib/esm/client/shared/components/ImagesView/SlideView.js +36 -47
  101. package/lib/esm/client/shared/components/ImagesView/SwapView.js +24 -42
  102. package/lib/esm/client/shared/components/PageFooter/PageFooter.js +12 -8
  103. package/lib/esm/client/shared/components/PageFooter/Paging.js +14 -18
  104. package/lib/esm/client/shared/components/PageHeader/ImagePreview.js +22 -18
  105. package/lib/esm/client/shared/components/PageHeader/PageHeader.js +37 -60
  106. package/lib/esm/client/shared/components/ResultsPage.js +36 -64
  107. package/lib/esm/client/shared/creeveyClientApi.js +57 -84
  108. package/lib/esm/client/shared/helpers.js +124 -195
  109. package/lib/esm/client/shared/viewMode.js +4 -4
  110. package/lib/esm/creevey.js +3 -5
  111. package/lib/esm/index.js +2 -3
  112. package/lib/esm/server/config.js +4 -5
  113. package/lib/esm/server/docker.js +2 -2
  114. package/lib/esm/server/extract.js +6 -4
  115. package/lib/esm/server/index.js +3 -4
  116. package/lib/esm/server/loaders/babel/creevey-plugin.js +1 -3
  117. package/lib/esm/server/loaders/babel/helpers.js +12 -22
  118. package/lib/esm/server/loaders/babel/register.js +3 -4
  119. package/lib/esm/server/loaders/webpack/compile.js +34 -51
  120. package/lib/esm/server/loaders/webpack/creevey-loader.js +9 -10
  121. package/lib/esm/server/loaders/webpack/dummy-hmr.js +2 -6
  122. package/lib/esm/server/loaders/webpack/mdx-loader.js +2 -2
  123. package/lib/esm/server/loaders/webpack/start.js +1 -1
  124. package/lib/esm/server/master/index.js +4 -4
  125. package/lib/esm/server/master/master.js +1 -0
  126. package/lib/esm/server/master/pool.js +38 -49
  127. package/lib/esm/server/master/runner.js +53 -66
  128. package/lib/esm/server/master/server.js +76 -6
  129. package/lib/esm/server/messages.js +118 -14
  130. package/lib/esm/server/selenium/browser.js +126 -57
  131. package/lib/esm/server/selenium/selenoid.js +5 -7
  132. package/lib/esm/server/stories.js +60 -83
  133. package/lib/esm/server/storybook/entry.js +7 -24
  134. package/lib/esm/server/storybook/helpers.js +13 -16
  135. package/lib/esm/server/storybook/providers/browser.js +60 -0
  136. package/lib/esm/server/storybook/{nodejs-provider.js → providers/nodejs.js} +42 -21
  137. package/lib/esm/server/update.js +1 -5
  138. package/lib/esm/server/utils.js +28 -10
  139. package/lib/esm/server/worker/helpers.js +2 -6
  140. package/lib/esm/server/worker/reporter.js +8 -20
  141. package/lib/esm/server/worker/worker.js +22 -20
  142. package/lib/esm/shared/index.js +78 -0
  143. package/lib/esm/shared/serializeRegExp.js +24 -0
  144. package/lib/esm/types.js +3 -0
  145. package/lib/types/cli.d.ts +1 -1
  146. package/lib/types/client/addon/Manager.d.ts +37 -37
  147. package/lib/types/client/addon/components/Addon.d.ts +8 -8
  148. package/lib/types/client/addon/components/Icons.d.ts +7 -7
  149. package/lib/types/client/addon/components/Panel.d.ts +9 -9
  150. package/lib/types/client/addon/components/TestSelect.d.ts +8 -9
  151. package/lib/types/client/addon/components/Tools.d.ts +6 -6
  152. package/lib/types/client/addon/decorator.d.ts +1 -1
  153. package/lib/types/client/addon/index.d.ts +2 -0
  154. package/lib/types/client/addon/preset.d.ts +23 -22
  155. package/lib/types/client/addon/preset.ie11.d.ts +10 -0
  156. package/lib/types/client/addon/readyForCapture.d.ts +6 -0
  157. package/lib/types/client/addon/register.d.ts +3 -3
  158. package/lib/types/client/addon/utils.d.ts +3 -6
  159. package/lib/types/client/addon/withCreevey.d.ts +24 -13
  160. package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +3 -3
  161. package/lib/types/client/shared/components/ImagesView/ImagesView.d.ts +24 -25
  162. package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +3 -3
  163. package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +3 -3
  164. package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +3 -3
  165. package/lib/types/client/shared/components/ImagesView/index.d.ts +5 -5
  166. package/lib/types/client/shared/components/PageFooter/PageFooter.d.ts +8 -9
  167. package/lib/types/client/shared/components/PageFooter/Paging.d.ts +7 -8
  168. package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +12 -12
  169. package/lib/types/client/shared/components/PageHeader/PageHeader.d.ts +16 -17
  170. package/lib/types/client/shared/components/ResultsPage.d.ts +18 -18
  171. package/lib/types/client/shared/creeveyClientApi.d.ts +9 -9
  172. package/lib/types/client/shared/helpers.d.ts +46 -46
  173. package/lib/types/client/shared/viewMode.d.ts +4 -4
  174. package/lib/types/client/web/CreeveyApp.d.ts +11 -12
  175. package/lib/types/client/web/CreeveyContext.d.ts +11 -11
  176. package/lib/types/client/web/CreeveyLoader.d.ts +2 -3
  177. package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +19 -19
  178. package/lib/types/client/web/CreeveyView/SideBar/Search.d.ts +6 -6
  179. package/lib/types/client/web/CreeveyView/SideBar/SideBar.d.ts +14 -14
  180. package/lib/types/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +12 -13
  181. package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +33 -33
  182. package/lib/types/client/web/CreeveyView/SideBar/TestLink.d.ts +7 -8
  183. package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +10 -10
  184. package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +9 -9
  185. package/lib/types/client/web/CreeveyView/SideBar/Toggle.d.ts +6 -6
  186. package/lib/types/client/web/CreeveyView/SideBar/index.d.ts +1 -1
  187. package/lib/types/client/web/KeyboardEventsContext.d.ts +13 -13
  188. package/lib/types/client/web/index.d.ts +4 -4
  189. package/lib/types/creevey.d.ts +1 -1
  190. package/lib/types/index.d.ts +0 -1
  191. package/lib/types/server/config.d.ts +4 -4
  192. package/lib/types/server/docker.d.ts +7 -7
  193. package/lib/types/server/extract.d.ts +2 -2
  194. package/lib/types/server/index.d.ts +2 -2
  195. package/lib/types/server/loaders/babel/creevey-plugin.d.ts +1 -1
  196. package/lib/types/server/loaders/babel/helpers.d.ts +19 -19
  197. package/lib/types/server/loaders/babel/register.d.ts +5 -5
  198. package/lib/types/server/loaders/hooks/mdx.d.ts +1 -1
  199. package/lib/types/server/loaders/hooks/svelte.d.ts +1 -1
  200. package/lib/types/server/loaders/webpack/compile.d.ts +2 -2
  201. package/lib/types/server/loaders/webpack/creevey-loader.d.ts +4 -2
  202. package/lib/types/server/loaders/webpack/dummy-hmr.d.ts +10 -10
  203. package/lib/types/server/loaders/webpack/mdx-loader.d.ts +6 -6
  204. package/lib/types/server/loaders/webpack/start.d.ts +1 -1
  205. package/lib/types/server/logger.d.ts +10 -6
  206. package/lib/types/server/master/api.d.ts +7 -7
  207. package/lib/types/server/master/index.d.ts +3 -3
  208. package/lib/types/server/master/master.d.ts +7 -6
  209. package/lib/types/server/master/pool.d.ts +31 -30
  210. package/lib/types/server/master/runner.d.ts +26 -26
  211. package/lib/types/server/master/server.d.ts +2 -2
  212. package/lib/types/server/messages.d.ts +29 -18
  213. package/lib/types/server/selenium/browser.d.ts +17 -14
  214. package/lib/types/server/selenium/index.d.ts +2 -2
  215. package/lib/types/server/selenium/selenoid.d.ts +3 -3
  216. package/lib/types/server/stories.d.ts +8 -9
  217. package/lib/types/server/storybook/entry.d.ts +17 -14
  218. package/lib/types/server/storybook/helpers.d.ts +24 -23
  219. package/lib/types/server/storybook/providers/browser.d.ts +4 -0
  220. package/lib/types/server/storybook/providers/nodejs.d.ts +9 -0
  221. package/lib/types/server/update.d.ts +2 -2
  222. package/lib/types/server/utils.d.ts +19 -18
  223. package/lib/types/server/worker/chai-image.d.ts +6 -6
  224. package/lib/types/server/worker/helpers.d.ts +8 -7
  225. package/lib/types/server/worker/index.d.ts +1 -1
  226. package/lib/types/server/worker/reporter.d.ts +8 -8
  227. package/lib/types/server/worker/worker.d.ts +4 -4
  228. package/lib/types/shared/index.d.ts +7 -0
  229. package/lib/types/shared/serializeRegExp.d.ts +9 -0
  230. package/lib/types/types.d.ts +487 -459
  231. package/package.json +121 -99
  232. package/preset/ie11.js +5 -0
  233. package/{preset.js → preset/index.js} +2 -2
  234. package/types/mdx.d.ts +3 -2
  235. package/types/mocha.d.ts +1 -0
  236. package/lib/cjs/client/web/1.js +0 -13
  237. package/lib/cjs/client/web/2.js +0 -1
  238. package/lib/types/server/storybook/nodejs-provider.d.ts +0 -5
  239. package/storybook-static/stories.json +0 -530
@@ -40,21 +40,19 @@ export function getStorybookVersion() {
40
40
  return version;
41
41
  }
42
42
  export function isStorybookVersionLessThan(major, minor) {
43
- var _process$env$__CREEVE;
44
-
45
- const [sbMajor, sbMinor] = ((_process$env$__CREEVE = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE !== void 0 ? _process$env$__CREEVE : getStorybookVersion()).split('.');
43
+ const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
46
44
  return Number(sbMajor) < major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) < minor;
47
45
  }
46
+ export function isStorybookVersionGreaterThan(major, minor) {
47
+ const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
48
+ return Number(sbMajor) > major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) > minor;
49
+ }
48
50
  export function isStorybookVersion(major, minor) {
49
- var _process$env$__CREEVE2;
50
-
51
- const [sbMajor, sbMinor] = ((_process$env$__CREEVE2 = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE2 !== void 0 ? _process$env$__CREEVE2 : getStorybookVersion()).split('.');
51
+ const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
52
52
  return Number(sbMajor) == major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) == minor;
53
53
  }
54
54
  export function getStorybookFramework() {
55
- var _process$env$__CREEVE3;
56
-
57
- const framework = (_process$env$__CREEVE3 = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__) !== null && _process$env$__CREEVE3 !== void 0 ? _process$env$__CREEVE3 : supportedFrameworks.find(framework => {
55
+ const framework = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__ ?? supportedFrameworks.find(framework => {
58
56
  try {
59
57
  return require.resolve(resolveFromStorybook(`@storybook/${framework}`));
60
58
  } catch (_) {
@@ -75,8 +73,8 @@ export async function importStorybookConfig() {
75
73
  try {
76
74
  return storybookConfigRef.current = (await import(require.resolve(configPath))).default;
77
75
  } catch (_) {
78
- const storybookUtilsPath = isStorybookVersionLessThan(6, 2) ? '@storybook/core/dist/server/utils' : '@storybook/core-common/dist/cjs/utils';
79
- const serverRequireModule = isStorybookVersionLessThan(6, 2) ? 'server-require' : 'interpret-require'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
76
+ const storybookUtilsPath = '@storybook/core-common/dist/cjs/utils';
77
+ const serverRequireModule = 'interpret-require'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
80
78
 
81
79
  const {
82
80
  getInterpretedFile
@@ -85,16 +83,15 @@ export async function importStorybookConfig() {
85
83
  const {
86
84
  default: serverRequireFallback,
87
85
  serverRequire = serverRequireFallback
88
- } = await import(resolveFromStorybook(`${storybookUtilsPath}/${serverRequireModule}`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
86
+ } = await import(resolveFromStorybook(`${storybookUtilsPath}/${serverRequireModule}`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
89
87
 
90
- const mainConfigFile = isStorybookVersionLessThan(6, 1) ? configPath : // eslint-disable-next-line @typescript-eslint/no-unsafe-call
91
- getInterpretedFile(configPath); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
88
+ const mainConfigFile = getInterpretedFile(configPath); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
92
89
 
93
90
  return storybookConfigRef.current = serverRequire(mainConfigFile);
94
91
  }
95
92
  }
96
93
  export async function isCSFv3Enabled() {
97
- var _await$importStoryboo, _await$importStoryboo2, _await$importStoryboo3;
94
+ var _await$importStoryboo, _await$importStoryboo2;
98
95
 
99
- return (_await$importStoryboo = (_await$importStoryboo2 = await importStorybookConfig()) === null || _await$importStoryboo2 === void 0 ? void 0 : (_await$importStoryboo3 = _await$importStoryboo2.features) === null || _await$importStoryboo3 === void 0 ? void 0 : _await$importStoryboo3.previewCsfV3) !== null && _await$importStoryboo !== void 0 ? _await$importStoryboo : false;
96
+ return ((_await$importStoryboo = await importStorybookConfig()) === null || _await$importStoryboo === void 0 ? void 0 : (_await$importStoryboo2 = _await$importStoryboo.features) === null || _await$importStoryboo2 === void 0 ? void 0 : _await$importStoryboo2.previewCsfV3) ?? false;
100
97
  }
@@ -0,0 +1,60 @@
1
+ import cluster from 'cluster';
2
+ import { loadStoriesFromBrowser } from '../../selenium';
3
+ import { emitStoriesMessage, sendStoriesMessage, subscribeOn, subscribeOnWorker } from '../../messages';
4
+ import { isDefined } from '../../../types';
5
+ import { logger } from '../../logger';
6
+ export async function loadStories(_config, {
7
+ port
8
+ }, storiesListener) {
9
+ if (cluster.isPrimary) {
10
+ return new Promise(resolve => {
11
+ const worker = Object.values(cluster.workers ?? {}).filter(isDefined).find(worker => worker.isConnected());
12
+
13
+ if (worker) {
14
+ const unsubscribe = subscribeOnWorker(worker, 'stories', message => {
15
+ if (message.type == 'set') {
16
+ const {
17
+ stories,
18
+ oldTests
19
+ } = message.payload;
20
+ if (oldTests.length > 0) logger.warn(`If you use browser stories provider of CSFv3 Storybook feature\n` + `Creevey will not load tests defined in story parameters from following stories:\n` + oldTests.join('\n'));
21
+ unsubscribe();
22
+ resolve(stories);
23
+ }
24
+ });
25
+ sendStoriesMessage(worker, {
26
+ type: 'get'
27
+ });
28
+ }
29
+
30
+ subscribeOn('stories', message => {
31
+ // TODO updates only one browser :(
32
+ if (message.type == 'update') storiesListener(new Map(message.payload));
33
+ });
34
+ });
35
+ } else {
36
+ subscribeOn('stories', message => {
37
+ if (message.type == 'get') emitStoriesMessage({
38
+ type: 'set',
39
+ payload: {
40
+ stories,
41
+ oldTests: storiesWithOldTests
42
+ }
43
+ });
44
+ if (message.type == 'update') storiesListener(new Map(message.payload));
45
+ });
46
+ const stories = await loadStoriesFromBrowser(port);
47
+ const storiesWithOldTests = [];
48
+ Object.values(stories).forEach(story => {
49
+ var _parameters, _parameters$creevey;
50
+
51
+ if ((_parameters = story.parameters) !== null && _parameters !== void 0 && (_parameters$creevey = _parameters.creevey) !== null && _parameters$creevey !== void 0 && _parameters$creevey.tests) {
52
+ var _parameters2, _parameters2$creevey;
53
+
54
+ (_parameters2 = story.parameters) === null || _parameters2 === void 0 ? true : (_parameters2$creevey = _parameters2.creevey) === null || _parameters2$creevey === void 0 ? true : delete _parameters2$creevey.tests;
55
+ storiesWithOldTests.push(`${story.kind}/${story.name}`);
56
+ }
57
+ });
58
+ return stories;
59
+ }
60
+ }
@@ -1,16 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/ban-ts-comment */
2
2
  import path from 'path';
3
- import { isWorker, isMaster } from 'cluster';
3
+ import cluster from 'cluster';
4
4
  import chokidar from 'chokidar';
5
- import { noop } from '../../types';
6
- import { getCreeveyCache } from '../utils';
7
- import { subscribeOn } from '../messages';
8
- import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents, isStorybookVersionLessThan } from './helpers';
9
- import { logger } from '../logger';
10
- import { flatStories } from '../stories';
5
+ import { noop } from '../../../types';
6
+ import { getCreeveyCache } from '../../utils';
7
+ import { subscribeOn } from '../../messages';
8
+ import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents } from '../helpers';
9
+ import { logger } from '../../logger';
11
10
 
12
11
  async function initStorybookEnvironment() {
13
- // @ts-ignore
12
+ // @ts-expect-error There is no @types/global-jsdom package
14
13
  (await import('global-jsdom')).default(undefined, {
15
14
  url: 'http://localhost'
16
15
  }); // NOTE Cutoff `jsdom` part from userAgent, because storybook check enviroment and create events channel if runs in browser
@@ -25,10 +24,10 @@ async function initStorybookEnvironment() {
25
24
  logger
26
25
  } = await importStorybookClientLogger(); // NOTE: Disable duplication warnings for >=6.2 storybook
27
26
 
28
- if (isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
27
+ if (cluster.isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
29
28
 
30
29
  logger.debug = noop;
31
- return import('./entry');
30
+ return import('../entry');
32
31
  }
33
32
 
34
33
  function watchStories(channel, watcher, initialFiles) {
@@ -39,7 +38,7 @@ function watchStories(channel, watcher, initialFiles) {
39
38
  watcher.on('change', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
40
39
  watcher.on('unlink', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
41
40
  return data => {
42
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
41
+ const stories = data.stories;
43
42
  const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
44
43
  const addedFiles = Array.from(files).filter(filePath => !watchingFiles.has(filePath));
45
44
  const removedFiles = Array.from(watchingFiles).filter(filePath => !files.has(filePath));
@@ -84,13 +83,14 @@ async function loadStoriesDirectly(config, {
84
83
  debug
85
84
  }) {
86
85
  const {
87
- toRequireContext
86
+ toRequireContext,
87
+ normalizeStoriesEntry
88
88
  } = await importStorybookCoreCommon();
89
89
  const {
90
90
  addParameters,
91
91
  configure
92
- } = await import('./entry');
93
- const requireContext = await (await import('../loaders/babel/register')).default(config, debug);
92
+ } = await import('../entry');
93
+ const requireContext = await (await import('../../loaders/babel/register')).default(config, debug);
94
94
 
95
95
  const preview = (() => {
96
96
  try {
@@ -103,12 +103,16 @@ async function loadStoriesDirectly(config, {
103
103
  const {
104
104
  stories
105
105
  } = await importStorybookConfig();
106
- const contexts = stories.map(input => {
106
+ const contexts = stories.map(entry => {
107
+ const normalizedEntry = normalizeStoriesEntry(entry, {
108
+ configDir: config.storybookDir,
109
+ workingDir: process.cwd()
110
+ });
107
111
  const {
108
112
  path: storiesPath,
109
113
  recursive,
110
114
  match
111
- } = toRequireContext(input);
115
+ } = toRequireContext(normalizedEntry);
112
116
  watcher === null || watcher === void 0 ? void 0 : watcher.add(path.resolve(config.storybookDir, storiesPath));
113
117
  return () => requireContext(storiesPath, recursive, new RegExp(match));
114
118
  });
@@ -149,7 +153,7 @@ async function loadStoriesDirectly(config, {
149
153
  try {
150
154
  configure(contexts.map(ctx => ctx()), module, false);
151
155
  } catch (error) {
152
- if (isMaster) logger.error(error);
156
+ if (cluster.isPrimary) logger.error(error);
153
157
  }
154
158
  }
155
159
 
@@ -162,7 +166,8 @@ async function loadStoriesDirectly(config, {
162
166
  void startStorybook();
163
167
  });
164
168
  void startStorybook();
165
- }
169
+ } // TODO Do we need to support multiple storybooks here?
170
+
166
171
 
167
172
  export async function loadStories(config, {
168
173
  watch,
@@ -175,16 +180,16 @@ export async function loadStories(config, {
175
180
  } = storybookApi;
176
181
  channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
177
182
  channel.on('storiesUpdated', storiesListener);
178
- let watcher = null;
183
+ let watcher;
179
184
  if (watch) watcher = chokidar.watch([], {
180
185
  ignoreInitial: true
181
186
  });
182
187
  const loadPromise = new Promise(resolve => {
183
188
  channel.once(Events.SET_STORIES, data => {
184
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
189
+ const stories = data.stories;
185
190
  const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
186
191
  if (watcher) channel.on(Events.SET_STORIES, watchStories(channel, watcher, files));
187
- resolve(data);
192
+ resolve(stories);
188
193
  });
189
194
  });
190
195
  if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
@@ -192,4 +197,20 @@ export async function loadStories(config, {
192
197
  debug
193
198
  });
194
199
  return loadPromise;
200
+ }
201
+ export async function extractStoriesData(config, {
202
+ watch,
203
+ debug
204
+ }) {
205
+ const storybookApi = await initStorybookEnvironment();
206
+ const Events = await importStorybookCoreEvents();
207
+ const {
208
+ channel
209
+ } = storybookApi;
210
+ channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
211
+ const loadPromise = new Promise(resolve => channel.once(Events.SET_STORIES, resolve));
212
+ if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
213
+ debug
214
+ });
215
+ return loadPromise;
195
216
  }
@@ -15,11 +15,7 @@ function tryToLoadTestsData(filename) {
15
15
  const actualRegex = /^(.*)-actual-(\d+)\.png$/i;
16
16
 
17
17
  function approve(dirents, srcPath, dstPath, testPaths, isMatch) {
18
- dirents.filter(dirent => dirent.isFile()).map(dirent => actualRegex.exec(dirent.name)).filter(isDefined).filter(([fileName, imageName]) => !testPaths || testPaths.find(([token]) => token == imageName) && isMatch(path.join(srcPath, fileName))).reduce((images, [, imageName, retry]) => {
19
- var _images$get;
20
-
21
- return Number(retry) > ((_images$get = images.get(imageName)) !== null && _images$get !== void 0 ? _images$get : -1) ? images.set(imageName, Number(retry)) : images;
22
- }, new Map()).forEach((retry, imageName) => {
18
+ dirents.filter(dirent => dirent.isFile()).map(dirent => actualRegex.exec(dirent.name)).filter(isDefined).filter(([fileName, imageName]) => !testPaths || testPaths.find(([token]) => token == imageName) && isMatch(path.join(srcPath, fileName))).reduce((images, [, imageName, retry]) => Number(retry) > (images.get(imageName) ?? -1) ? images.set(imageName, Number(retry)) : images, new Map()).forEach((retry, imageName) => {
23
19
  mkdirSync(dstPath, {
24
20
  recursive: true
25
21
  });
@@ -9,6 +9,7 @@ export const isShuttingDown = {
9
9
  };
10
10
  export const LOCALHOST_REGEXP = /(localhost|127\.0\.0\.1)/i;
11
11
  export const extensions = ['.js', '.jsx', '.ts', '.tsx'];
12
+ export const skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
12
13
 
13
14
  function matchBy(pattern, value) {
14
15
  return typeof pattern == 'string' && pattern == value || Array.isArray(pattern) && pattern.includes(value) || pattern instanceof RegExp && pattern.test(value) || !isDefined(pattern);
@@ -20,9 +21,30 @@ export function shouldSkip(browser, meta, skipOptions, test) {
20
21
  }
21
22
 
22
23
  if (Array.isArray(skipOptions)) {
23
- return skipOptions.map(skipOption => shouldSkip(browser, meta, skipOption, test)).find(Boolean) || false;
24
+ for (const skip of skipOptions) {
25
+ const reason = shouldSkip(browser, meta, skip, test);
26
+ if (reason) return reason;
27
+ }
28
+
29
+ return false;
24
30
  }
25
31
 
32
+ let hasSkipOptionKeys = false;
33
+
34
+ for (const skipKey in skipOptions) {
35
+ if (skipOptionKeys.includes(skipKey)) {
36
+ hasSkipOptionKeys = true;
37
+ continue;
38
+ }
39
+
40
+ const reason = shouldSkip(browser, meta, {
41
+ reason: skipKey,
42
+ ...skipOptions[skipKey]
43
+ }, test);
44
+ if (reason) return reason;
45
+ }
46
+
47
+ if (!hasSkipOptionKeys) return false;
26
48
  const {
27
49
  in: browsers,
28
50
  kinds,
@@ -42,7 +64,7 @@ export function shouldSkip(browser, meta, skipOptions, test) {
42
64
  }
43
65
  export async function shutdownWorkers() {
44
66
  isShuttingDown.current = true;
45
- await Promise.all(Object.values(cluster.workers).filter(isDefined).filter(worker => worker.isConnected()).map(worker => new Promise(resolve => {
67
+ await Promise.all(Object.values(cluster.workers ?? {}).filter(isDefined).filter(worker => worker.isConnected()).map(worker => new Promise(resolve => {
46
68
  const timeout = setTimeout(() => worker.kill(), 10000);
47
69
  worker.on('exit', () => {
48
70
  clearTimeout(timeout);
@@ -74,27 +96,23 @@ export function testsToImages(tests) {
74
96
  storyPath,
75
97
  results
76
98
  }) => {
77
- var _results$slice$0$imag, _results$slice$;
99
+ var _results$slice$;
78
100
 
79
- return Object.keys((_results$slice$0$imag = results === null || results === void 0 ? void 0 : (_results$slice$ = results.slice(-1)[0]) === null || _results$slice$ === void 0 ? void 0 : _results$slice$.images) !== null && _results$slice$0$imag !== void 0 ? _results$slice$0$imag : {}).map(image => `${[...storyPath, testName, browser, browser == image ? undefined : image].filter(isDefined).join('/')}.png`);
101
+ return Object.keys((results === null || results === void 0 ? void 0 : (_results$slice$ = results.slice(-1)[0]) === null || _results$slice$ === void 0 ? void 0 : _results$slice$.images) ?? {}).map(image => `${[...storyPath, testName, browser, browser == image ? undefined : image].filter(isDefined).join('/')}.png`);
80
102
  })));
81
103
  } // https://tuhrig.de/how-to-know-you-are-inside-a-docker-container/
82
104
 
83
105
  export const isInsideDocker = existsSync('/proc/1/cgroup') && /docker/.test(readFileSync('/proc/1/cgroup', 'utf8'));
84
106
  export const downloadBinary = (downloadUrl, destination) => new Promise((resolve, reject) => get(downloadUrl, response => {
85
- var _response$statusCode2;
86
-
87
107
  if (response.statusCode == 302) {
88
- var _response$statusCode;
89
-
90
108
  const {
91
109
  location
92
110
  } = response.headers;
93
- if (!location) return reject(new Error(`Couldn't download selenoid. Status code: ${(_response$statusCode = response.statusCode) !== null && _response$statusCode !== void 0 ? _response$statusCode : 'UNKNOWN'}`));
111
+ if (!location) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
94
112
  return resolve(downloadBinary(location, destination));
95
113
  }
96
114
 
97
- if (response.statusCode != 200) return reject(new Error(`Couldn't download selenoid. Status code: ${(_response$statusCode2 = response.statusCode) !== null && _response$statusCode2 !== void 0 ? _response$statusCode2 : 'UNKNOWN'}`));
115
+ if (response.statusCode != 200) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
98
116
  const fileStream = createWriteStream(destination);
99
117
  response.pipe(fileStream);
100
118
  fileStream.on('finish', () => {
@@ -47,14 +47,10 @@ function removeTestOrSuite(testOrSuite) {
47
47
 
48
48
  export async function addTestsFromStories(rootSuite, config, {
49
49
  browser,
50
- watch,
51
- debug
50
+ ...options
52
51
  }) {
53
52
  const mochaTestsById = new Map();
54
- const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, {
55
- watch,
56
- debug
57
- }, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
53
+ const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, options, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
58
54
  const oldTest = mochaTestsById.get(id);
59
55
  mochaTestsById.delete(id);
60
56
  if (oldTest) removeTestOrSuite(oldTest);
@@ -1,5 +1,3 @@
1
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
-
3
1
  import chalk from 'chalk';
4
2
  import { reporters } from 'mocha';
5
3
  import prefix from 'loglevel-plugin-prefix';
@@ -26,31 +24,18 @@ export class CreeveyReporter extends reporters.Base {
26
24
  });
27
25
  runner.on('test', test => testLogger.warn(chalk.cyan(test.titlePath().join('/'))));
28
26
  runner.on('pass', test => testLogger.info(chalk.cyan(test.titlePath().join('/'))));
29
- runner.on('fail', (test, error) => testLogger.error(chalk.cyan(test.titlePath().join('/')), '\n ', getErrors(error, (error, imageName) => `${chalk.bold(imageName !== null && imageName !== void 0 ? imageName : topLevelSuite)}:${error}`, error => {
30
- var _error$stack;
31
-
32
- return `${(_error$stack = error.stack) !== null && _error$stack !== void 0 ? _error$stack : error.message}`;
33
- }).join('\n ')));
27
+ runner.on('fail', (test, error) => testLogger.error(chalk.cyan(test.titlePath().join('/')), '\n ', getErrors(error, (error, imageName) => `${chalk.bold(imageName ?? topLevelSuite)}:${error}`, error => `${error.stack ?? error.message}`).join('\n ')));
34
28
  }
35
29
 
36
30
  }
37
31
  export class TeamcityReporter extends reporters.Base {
38
32
  constructor(runner, options) {
39
33
  super(runner);
40
-
41
- _defineProperty(this, "escape", str => {
42
- if (!str) return '';
43
- return str.toString() // eslint-disable-next-line no-control-regex
44
- .replace(/\x1B.*?m/g, '').replace(/\|/g, '||').replace(/\n/g, '|n').replace(/\r/g, '|r').replace(/\[/g, '|[').replace(/\]/g, '|]').replace(/\u0085/g, '|x').replace(/\u2028/g, '|l').replace(/\u2029/g, '|p').replace(/'/g, "|'");
45
- });
46
-
47
34
  const topLevelSuite = this.escape(options.reporterOptions.topLevelSuite);
48
35
  const reporterOptions = options.reporterOptions;
49
36
  runner.on('suite', suite => suite.root ? console.log(`##teamcity[testSuiteStarted name='${topLevelSuite}' flowId='${process.pid}']`) : console.log(`##teamcity[testSuiteStarted name='${this.escape(suite.title)}' flowId='${process.pid}']`));
50
37
  runner.on('test', test => console.log(`##teamcity[testStarted name='${this.escape(test.title)}' flowId='${process.pid}']`));
51
38
  runner.on('fail', (test, error) => {
52
- var _error$stack2;
53
-
54
39
  Object.entries(reporterOptions.images).forEach(([name, image]) => {
55
40
  if (!image) return;
56
41
  const filePath = test.titlePath().concat(name == topLevelSuite ? [] : [topLevelSuite]).map(this.escape).join('/'); // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -66,7 +51,7 @@ export class TeamcityReporter extends reporters.Base {
66
51
  }); // Output failed test as passed due TC don't support retry mechanic
67
52
  // https://teamcity-support.jetbrains.com/hc/en-us/community/posts/207216829-Count-test-as-successful-if-at-least-one-try-is-successful?page=1#community_comment_207394125
68
53
 
69
- reporterOptions.willRetry ? console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`) : console.log(`##teamcity[testFailed name='${this.escape(test.title)}' message='${this.escape(error.message)}' details='${this.escape((_error$stack2 = error.stack) !== null && _error$stack2 !== void 0 ? _error$stack2 : '')}' flowId='${process.pid}']`);
54
+ reporterOptions.willRetry ? console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`) : console.log(`##teamcity[testFailed name='${this.escape(test.title)}' message='${this.escape(error.message)}' details='${this.escape(error.stack ?? '')}' flowId='${process.pid}']`);
70
55
  });
71
56
  runner.on('pending', test => console.log(`##teamcity[testIgnored name='${this.escape(test.title)}' message='${this.escape(typeof test.skipReason == 'boolean' ? test.title : test.skipReason)}' flowId='${process.pid}']`));
72
57
  runner.on('test end', test => console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`));
@@ -74,6 +59,11 @@ export class TeamcityReporter extends reporters.Base {
74
59
  runner.on('end', () => console.log(`##teamcity[testSuiteFinished name='${topLevelSuite}' flowId='${process.pid}']`));
75
60
  }
76
61
 
62
+ escape = str => {
63
+ if (!str) return '';
64
+ return str.toString() // eslint-disable-next-line no-control-regex
65
+ .replace(/\x1B.*?m/g, '').replace(/\|/g, '||').replace(/\n/g, '|n').replace(/\r/g, '|r').replace(/\[/g, '|[').replace(/\]/g, '|]').replace(/\u0085/g, '|x').replace(/\u2028/g, '|l').replace(/\u2029/g, '|p').replace(/'/g, "|'");
66
+ };
77
67
  }
78
68
 
79
69
  function getErrors(error, imageErrorToString, errorToString) {
@@ -88,9 +78,7 @@ function getErrors(error, imageErrorToString, errorToString) {
88
78
  } else {
89
79
  const imageErrors = error.images;
90
80
  Object.keys(imageErrors).forEach(imageName => {
91
- var _imageErrors$imageNam;
92
-
93
- errors.push(imageErrorToString((_imageErrors$imageNam = imageErrors[imageName]) !== null && _imageErrors$imageNam !== void 0 ? _imageErrors$imageNam : '', imageName));
81
+ errors.push(imageErrorToString(imageErrors[imageName] ?? '', imageName));
94
82
  });
95
83
  }
96
84
 
@@ -8,7 +8,7 @@ import { Key, until } from 'selenium-webdriver';
8
8
  import { isImageError } from '../../types';
9
9
  import { subscribeOn, emitTestMessage, emitWorkerMessage } from '../messages';
10
10
  import chaiImage from './chai-image';
11
- import { getBrowser, switchStory } from '../selenium';
11
+ import { closeBrowser, getBrowser, switchStory } from '../selenium';
12
12
  import { CreeveyReporter, TeamcityReporter } from './reporter';
13
13
  import { addTestsFromStories } from './helpers';
14
14
  import { logger } from '../logger';
@@ -34,9 +34,7 @@ async function getLastImageNumber(imageDir, imageName) {
34
34
  const actualImagesRegexp = new RegExp(`${imageName}-actual-(\\d+)\\.png`);
35
35
 
36
36
  try {
37
- var _await$readdirAsync$m;
38
-
39
- return (_await$readdirAsync$m = (await readdirAsync(imageDir)).map(filename => filename.replace(actualImagesRegexp, '$1')).map(Number).filter(x => !isNaN(x)).sort((a, b) => b - a)[0]) !== null && _await$readdirAsync$m !== void 0 ? _await$readdirAsync$m : 0;
37
+ return (await readdirAsync(imageDir)).map(filename => filename.replace(actualImagesRegexp, '$1')).map(Number).filter(x => !isNaN(x)).sort((a, b) => b - a)[0] ?? 0;
40
38
  } catch (_error) {
41
39
  return 0;
42
40
  }
@@ -49,12 +47,11 @@ export default async function worker(config, options) {
49
47
  let retries = 0;
50
48
  let images = {};
51
49
  let error = undefined;
50
+ const screenshots = [];
52
51
  const testScope = [];
53
52
 
54
53
  function runHandler(failures) {
55
54
  if (failures > 0 && (error || Object.values(images).some(image => (image === null || image === void 0 ? void 0 : image.error) != null))) {
56
- var _error2;
57
-
58
55
  const isTimeout = hasTimeout(error) || Object.values(images).some(image => hasTimeout(image === null || image === void 0 ? void 0 : image.error));
59
56
  const payload = {
60
57
  status: 'failed',
@@ -64,7 +61,7 @@ export default async function worker(config, options) {
64
61
  isTimeout ? emitWorkerMessage({
65
62
  type: 'error',
66
63
  payload: {
67
- error: (_error2 = error) !== null && _error2 !== void 0 ? _error2 : 'Unknown error'
64
+ error: error ?? 'Unknown error'
68
65
  }
69
66
  }) : emitTestMessage({
70
67
  type: 'end',
@@ -95,18 +92,16 @@ export default async function worker(config, options) {
95
92
  }
96
93
 
97
94
  async function getExpected(assertImageName) {
98
- var _images$imageName;
99
-
100
95
  // context => [kind, story, test, browser]
101
96
  // rootSuite -> kindSuite -> storyTest -> [browsers.png]
102
97
  // rootSuite -> kindSuite -> storySuite -> test -> [browsers.png]
103
98
  const testPath = [...testScope];
104
- const imageName = assertImageName !== null && assertImageName !== void 0 ? assertImageName : testPath.pop();
99
+ const imageName = assertImageName ?? testPath.pop();
105
100
  const imagesMeta = [];
106
101
  const reportImageDir = path.join(config.reportDir, ...testPath);
107
102
  const imageNumber = (await getLastImageNumber(reportImageDir, imageName)) + 1;
108
103
  const actualImageName = `${imageName}-actual-${imageNumber}.png`;
109
- const image = images[imageName] = (_images$imageName = images[imageName]) !== null && _images$imageName !== void 0 ? _images$imageName : {
104
+ const image = images[imageName] = images[imageName] ?? {
110
105
  actual: actualImageName
111
106
  };
112
107
 
@@ -168,18 +163,26 @@ export default async function worker(config, options) {
168
163
 
169
164
  }
170
165
  };
171
- const mocha = new Mocha(mochaOptions); // @ts-expect-error: @types/mocha has out-dated types
172
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
173
-
166
+ const mocha = new Mocha(mochaOptions);
174
167
  mocha.cleanReferencesAfterRun(false);
175
168
  chai.use(chaiImage(getExpected, config.diffOptions));
169
+ if ((await getBrowser(config, options.browser)) == null) return;
176
170
  await addTestsFromStories(mocha.suite, config, {
177
171
  browser: options.browser,
178
172
  watch: options.ui,
179
- debug: options.debug
173
+ debug: options.debug,
174
+ port: options.port
180
175
  });
181
- const browserConfig = config.browsers[options.browser];
182
- const browser = await getBrowser(config, browserConfig);
176
+
177
+ try {
178
+ var _await$getBrowser;
179
+
180
+ await ((_await$getBrowser = await getBrowser(config, options.browser)) === null || _await$getBrowser === void 0 ? void 0 : _await$getBrowser.getCurrentUrl());
181
+ } catch (_) {
182
+ await closeBrowser();
183
+ }
184
+
185
+ const browser = await getBrowser(config, options.browser);
183
186
  const sessionId = (_await$browser$getSes = await (browser === null || browser === void 0 ? void 0 : browser.getSession())) === null || _await$browser$getSes === void 0 ? void 0 : _await$browser$getSes.getId();
184
187
  if (browser == null) return;
185
188
  const interval = setInterval(() => void browser.getCurrentUrl().then(url => {
@@ -194,6 +197,7 @@ export default async function worker(config, options) {
194
197
  this.expect = chai.expect;
195
198
  this.browserName = options.browser;
196
199
  this.testScope = testScope;
200
+ this.screenshots = screenshots;
197
201
  });
198
202
  mocha.suite.beforeEach(switchStory);
199
203
  subscribeOn('test', message => {
@@ -210,9 +214,7 @@ export default async function worker(config, options) {
210
214
  if (!(reason instanceof Error)) {
211
215
  error = reason;
212
216
  } else if (!isImageError(reason)) {
213
- var _reason$stack;
214
-
215
- error = (_reason$stack = reason.stack) !== null && _reason$stack !== void 0 ? _reason$stack : reason.message;
217
+ error = reason.stack ?? reason.message;
216
218
  } else if (typeof reason.images == 'string') {
217
219
  const image = images[testScope.slice(-1)[0]];
218
220
  if (image) image.error = reason.images;
@@ -0,0 +1,78 @@
1
+ import { mapValues, mergeWith, cloneDeepWith } from 'lodash';
2
+ import { deserializeRegExp, isSerializedRegExp, isRegExp, serializeRegExp } from './serializeRegExp'; // NOTE: Copy-paste from storybook/api
3
+
4
+ export const combineParameters = function () {
5
+ for (var _len = arguments.length, parameterSets = new Array(_len), _key = 0; _key < _len; _key++) {
6
+ parameterSets[_key] = arguments[_key];
7
+ }
8
+
9
+ return (// eslint-disable-next-line @typescript-eslint/no-unsafe-return
10
+ mergeWith({}, ...parameterSets, (_, srcValue) => {
11
+ // Treat arrays as scalars:
12
+ if (Array.isArray(srcValue)) return srcValue;
13
+ return undefined;
14
+ })
15
+ );
16
+ }; // NOTE: Copy-paste from storybook/api
17
+
18
+ export const denormalizeStoryParameters = _ref => {
19
+ let {
20
+ globalParameters,
21
+ kindParameters,
22
+ stories
23
+ } = _ref;
24
+ return mapValues(stories, storyData => {
25
+ var _kindParameters$story;
26
+
27
+ return { ...storyData,
28
+ parameters: combineParameters(globalParameters, (_kindParameters$story = kindParameters[storyData.kind]) !== null && _kindParameters$story !== void 0 ? _kindParameters$story : {}, storyData.parameters)
29
+ };
30
+ });
31
+ };
32
+ export const serializeRawStories = stories => {
33
+ return mapValues(stories, storyData => {
34
+ const creevey = storyData.parameters.creevey;
35
+
36
+ if (creevey !== null && creevey !== void 0 && creevey.skip) {
37
+ return { ...storyData,
38
+ parameters: { ...storyData.parameters,
39
+ creevey: { ...creevey,
40
+ skip: cloneDeepWith(creevey.skip, value => {
41
+ if (isRegExp(value)) {
42
+ return serializeRegExp(value);
43
+ }
44
+
45
+ return undefined;
46
+ })
47
+ }
48
+ }
49
+ };
50
+ }
51
+
52
+ return storyData;
53
+ });
54
+ };
55
+ export const deserializeRawStories = stories => {
56
+ return mapValues(stories, deserializeStory);
57
+ };
58
+ export const deserializeStory = story => {
59
+ const creevey = story.parameters.creevey;
60
+
61
+ if (creevey !== null && creevey !== void 0 && creevey.skip) {
62
+ return { ...story,
63
+ parameters: { ...story.parameters,
64
+ creevey: { ...creevey,
65
+ skip: cloneDeepWith(creevey.skip, value => {
66
+ if (isSerializedRegExp(value)) {
67
+ return deserializeRegExp(value);
68
+ }
69
+
70
+ return undefined;
71
+ })
72
+ }
73
+ }
74
+ };
75
+ }
76
+
77
+ return story;
78
+ };