creevey 0.10.0-beta.9 → 0.10.0-rc.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 (348) hide show
  1. package/AUTHORS +2 -0
  2. package/CHANGELOG.md +281 -0
  3. package/README.md +19 -41
  4. package/dist/client/addon/components/Addon.js +18 -8
  5. package/dist/client/addon/components/Addon.js.map +1 -1
  6. package/dist/client/addon/components/Panel.js +2 -2
  7. package/dist/client/addon/components/Panel.js.map +1 -1
  8. package/dist/client/addon/components/TestSelect.js +2 -2
  9. package/dist/client/addon/components/TestSelect.js.map +1 -1
  10. package/dist/client/addon/components/Tools.js +19 -9
  11. package/dist/client/addon/components/Tools.js.map +1 -1
  12. package/dist/client/addon/controller.d.ts +1 -1
  13. package/dist/client/addon/controller.js +3 -3
  14. package/dist/client/addon/controller.js.map +1 -1
  15. package/dist/client/addon/decorator.d.ts +1 -1
  16. package/dist/client/addon/makeDecorator.d.ts +9 -0
  17. package/dist/client/addon/makeDecorator.js +48 -0
  18. package/dist/client/addon/makeDecorator.js.map +1 -0
  19. package/dist/client/addon/manager.js +38 -39
  20. package/dist/client/addon/manager.js.map +1 -1
  21. package/dist/client/addon/preset.d.ts +0 -1
  22. package/dist/client/addon/preset.js +3 -2
  23. package/dist/client/addon/preset.js.map +1 -1
  24. package/dist/client/addon/preview.d.ts +1 -1
  25. package/dist/client/addon/withCreevey.d.ts +5 -3
  26. package/dist/client/addon/withCreevey.js +5 -20
  27. package/dist/client/addon/withCreevey.js.map +1 -1
  28. package/dist/client/shared/components/ImagesView/BlendView.d.ts +2 -2
  29. package/dist/client/shared/components/ImagesView/BlendView.js +18 -8
  30. package/dist/client/shared/components/ImagesView/BlendView.js.map +1 -1
  31. package/dist/client/shared/components/ImagesView/ImagesView.js +1 -1
  32. package/dist/client/shared/components/ImagesView/ImagesView.js.map +1 -1
  33. package/dist/client/shared/components/ImagesView/SideBySideView.d.ts +2 -2
  34. package/dist/client/shared/components/ImagesView/SideBySideView.js +19 -9
  35. package/dist/client/shared/components/ImagesView/SideBySideView.js.map +1 -1
  36. package/dist/client/shared/components/ImagesView/SlideView.d.ts +2 -2
  37. package/dist/client/shared/components/ImagesView/SlideView.js +19 -9
  38. package/dist/client/shared/components/ImagesView/SlideView.js.map +1 -1
  39. package/dist/client/shared/components/ImagesView/SwapView.d.ts +2 -2
  40. package/dist/client/shared/components/ImagesView/SwapView.js +19 -9
  41. package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
  42. package/dist/client/shared/components/ImagesView/common.d.ts +1 -1
  43. package/dist/client/shared/components/PageFooter/PageFooter.js +1 -1
  44. package/dist/client/shared/components/PageFooter/PageFooter.js.map +1 -1
  45. package/dist/client/shared/components/PageFooter/Paging.js +1 -1
  46. package/dist/client/shared/components/PageFooter/Paging.js.map +1 -1
  47. package/dist/client/shared/components/PageHeader/ImagePreview.d.ts +2 -2
  48. package/dist/client/shared/components/PageHeader/ImagePreview.js +1 -1
  49. package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
  50. package/dist/client/shared/components/PageHeader/PageHeader.js +34 -13
  51. package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
  52. package/dist/client/shared/components/ResultsPage.d.ts +2 -2
  53. package/dist/client/shared/components/ResultsPage.js +22 -10
  54. package/dist/client/shared/components/ResultsPage.js.map +1 -1
  55. package/dist/client/shared/creeveyClientApi.js +18 -1
  56. package/dist/client/shared/creeveyClientApi.js.map +1 -1
  57. package/dist/client/shared/helpers.d.ts +1 -3
  58. package/dist/client/shared/helpers.js +4 -19
  59. package/dist/client/shared/helpers.js.map +1 -1
  60. package/dist/client/web/CreeveyApp.d.ts +1 -0
  61. package/dist/client/web/CreeveyApp.js +22 -9
  62. package/dist/client/web/CreeveyApp.js.map +1 -1
  63. package/dist/client/web/CreeveyContext.d.ts +1 -0
  64. package/dist/client/web/CreeveyContext.js +18 -7
  65. package/dist/client/web/CreeveyContext.js.map +1 -1
  66. package/dist/client/web/CreeveyLoader.d.ts +1 -1
  67. package/dist/client/web/CreeveyLoader.js +3 -3
  68. package/dist/client/web/CreeveyLoader.js.map +1 -1
  69. package/dist/client/web/CreeveyView/SideBar/Checkbox.d.ts +4 -4
  70. package/dist/client/web/CreeveyView/SideBar/Checkbox.js +36 -6
  71. package/dist/client/web/CreeveyView/SideBar/Checkbox.js.map +1 -1
  72. package/dist/client/web/CreeveyView/SideBar/Search.js +18 -8
  73. package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
  74. package/dist/client/web/CreeveyView/SideBar/SideBar.js +26 -12
  75. package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
  76. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +28 -17
  77. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
  78. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +32 -12
  79. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
  80. package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +6 -6
  81. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +20 -11
  82. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
  83. package/dist/client/web/CreeveyView/SideBar/TestLink.js +20 -11
  84. package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
  85. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +2 -2
  86. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js +2 -2
  87. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js.map +1 -1
  88. package/dist/client/web/CreeveyView/SideBar/TestsStatus.d.ts +2 -2
  89. package/dist/client/web/CreeveyView/SideBar/TestsStatus.js +3 -2
  90. package/dist/client/web/CreeveyView/SideBar/TestsStatus.js.map +1 -1
  91. package/dist/client/web/CreeveyView/SideBar/Toggle.js +1 -1
  92. package/dist/client/web/CreeveyView/SideBar/Toggle.js.map +1 -1
  93. package/dist/client/web/KeyboardEventsContext.js +17 -7
  94. package/dist/client/web/KeyboardEventsContext.js.map +1 -1
  95. package/dist/client/web/assets/index-CtSq3IhG.js +518 -0
  96. package/dist/client/web/index.html +1 -1
  97. package/dist/client/web/index.js +26 -11
  98. package/dist/client/web/index.js.map +1 -1
  99. package/dist/client/web/themes.d.ts +2 -0
  100. package/dist/client/web/themes.js +22 -0
  101. package/dist/client/web/themes.js.map +1 -0
  102. package/dist/creevey.d.ts +1 -1
  103. package/dist/creevey.js +122 -41
  104. package/dist/creevey.js.map +1 -1
  105. package/dist/index.d.ts +1 -0
  106. package/dist/playwright/generator.d.ts +25 -0
  107. package/dist/playwright/generator.js +243 -0
  108. package/dist/playwright/generator.js.map +1 -0
  109. package/dist/playwright/helpers.d.ts +2 -0
  110. package/dist/playwright/helpers.js +29 -0
  111. package/dist/playwright/helpers.js.map +1 -0
  112. package/dist/playwright/reporter.d.ts +83 -0
  113. package/dist/playwright/reporter.js +334 -0
  114. package/dist/playwright/reporter.js.map +1 -0
  115. package/dist/playwright/setup.d.ts +3 -0
  116. package/dist/playwright/setup.js +72 -0
  117. package/dist/playwright/setup.js.map +1 -0
  118. package/dist/playwright.d.ts +1 -0
  119. package/dist/playwright.js +3 -1
  120. package/dist/playwright.js.map +1 -1
  121. package/dist/server/compare.d.ts +18 -0
  122. package/dist/server/compare.js +182 -0
  123. package/dist/server/compare.js.map +1 -0
  124. package/dist/server/config.d.ts +3 -3
  125. package/dist/server/config.js +75 -8
  126. package/dist/server/config.js.map +1 -1
  127. package/dist/server/connection.d.ts +3 -0
  128. package/dist/server/connection.js +28 -0
  129. package/dist/server/connection.js.map +1 -0
  130. package/dist/server/docker.d.ts +1 -1
  131. package/dist/server/docker.js +54 -32
  132. package/dist/server/docker.js.map +1 -1
  133. package/dist/server/index.d.ts +2 -2
  134. package/dist/server/index.js +161 -64
  135. package/dist/server/index.js.map +1 -1
  136. package/dist/server/master/api.d.ts +11 -6
  137. package/dist/server/master/api.js +88 -25
  138. package/dist/server/master/api.js.map +1 -1
  139. package/dist/server/master/handlers/capture-handler.d.ts +5 -0
  140. package/dist/server/master/handlers/capture-handler.js +25 -0
  141. package/dist/server/master/handlers/capture-handler.js.map +1 -0
  142. package/dist/server/master/handlers/index.d.ts +4 -0
  143. package/dist/server/master/handlers/index.js +21 -0
  144. package/dist/server/master/handlers/index.js.map +1 -0
  145. package/dist/server/master/handlers/ping-handler.d.ts +2 -0
  146. package/dist/server/master/handlers/ping-handler.js +8 -0
  147. package/dist/server/master/handlers/ping-handler.js.map +1 -0
  148. package/dist/server/master/handlers/static-handler.d.ts +1 -0
  149. package/dist/server/master/handlers/static-handler.js +20 -0
  150. package/dist/server/master/handlers/static-handler.js.map +1 -0
  151. package/dist/server/master/handlers/stories-handler.d.ts +4 -0
  152. package/dist/server/master/handlers/stories-handler.js +24 -0
  153. package/dist/server/master/handlers/stories-handler.js.map +1 -0
  154. package/dist/server/master/master.js +7 -24
  155. package/dist/server/master/master.js.map +1 -1
  156. package/dist/server/master/pool.d.ts +1 -0
  157. package/dist/server/master/pool.js +5 -3
  158. package/dist/server/master/pool.js.map +1 -1
  159. package/dist/server/master/queue.d.ts +1 -1
  160. package/dist/server/master/queue.js +14 -6
  161. package/dist/server/master/queue.js.map +1 -1
  162. package/dist/server/master/runner.d.ts +6 -6
  163. package/dist/server/master/runner.js +98 -130
  164. package/dist/server/master/runner.js.map +1 -1
  165. package/dist/server/master/server.d.ts +1 -1
  166. package/dist/server/master/server.js +193 -88
  167. package/dist/server/master/server.js.map +1 -1
  168. package/dist/server/master/start.d.ts +1 -2
  169. package/dist/server/master/start.js +13 -29
  170. package/dist/server/master/start.js.map +1 -1
  171. package/dist/server/master/testsManager.d.ts +81 -0
  172. package/dist/server/master/testsManager.js +282 -0
  173. package/dist/server/master/testsManager.js.map +1 -0
  174. package/dist/server/playwright/docker-file.d.ts +1 -1
  175. package/dist/server/playwright/docker-file.js +17 -8
  176. package/dist/server/playwright/docker-file.js.map +1 -1
  177. package/dist/server/playwright/docker.d.ts +2 -1
  178. package/dist/server/playwright/docker.js +10 -2
  179. package/dist/server/playwright/docker.js.map +1 -1
  180. package/dist/server/playwright/index-source.mjs +16 -0
  181. package/dist/server/playwright/internal.d.ts +7 -7
  182. package/dist/server/playwright/internal.js +137 -79
  183. package/dist/server/playwright/internal.js.map +1 -1
  184. package/dist/server/playwright/webdriver.d.ts +3 -3
  185. package/dist/server/playwright/webdriver.js +0 -6
  186. package/dist/server/playwright/webdriver.js.map +1 -1
  187. package/dist/server/providers/browser.js +4 -3
  188. package/dist/server/providers/browser.js.map +1 -1
  189. package/dist/server/providers/hybrid.js +2 -2
  190. package/dist/server/providers/hybrid.js.map +1 -1
  191. package/dist/server/report.d.ts +10 -0
  192. package/dist/server/report.js +45 -0
  193. package/dist/server/report.js.map +1 -0
  194. package/dist/server/reporters/creevey.d.ts +7 -0
  195. package/dist/server/reporters/creevey.js +63 -0
  196. package/dist/server/reporters/creevey.js.map +1 -0
  197. package/dist/server/reporters/index.d.ts +2 -0
  198. package/dist/server/reporters/index.js +16 -0
  199. package/dist/server/reporters/index.js.map +1 -0
  200. package/dist/server/reporters/junit.d.ts +16 -0
  201. package/dist/server/reporters/junit.js +167 -0
  202. package/dist/server/reporters/junit.js.map +1 -0
  203. package/dist/server/reporters/teamcity.d.ts +7 -0
  204. package/dist/server/reporters/teamcity.js +60 -0
  205. package/dist/server/reporters/teamcity.js.map +1 -0
  206. package/dist/server/selenium/internal.d.ts +3 -3
  207. package/dist/server/selenium/internal.js +48 -34
  208. package/dist/server/selenium/internal.js.map +1 -1
  209. package/dist/server/selenium/selenoid.js +12 -6
  210. package/dist/server/selenium/selenoid.js.map +1 -1
  211. package/dist/server/selenium/webdriver.d.ts +3 -3
  212. package/dist/server/selenium/webdriver.js +4 -8
  213. package/dist/server/selenium/webdriver.js.map +1 -1
  214. package/dist/server/shutdown.d.ts +1 -0
  215. package/dist/server/shutdown.js +23 -0
  216. package/dist/server/shutdown.js.map +1 -0
  217. package/dist/server/stories.d.ts +0 -1
  218. package/dist/server/stories.js +0 -12
  219. package/dist/server/stories.js.map +1 -1
  220. package/dist/server/telemetry.js +3 -3
  221. package/dist/server/telemetry.js.map +1 -1
  222. package/dist/server/testsFiles/parser.js +45 -5
  223. package/dist/server/testsFiles/parser.js.map +1 -1
  224. package/dist/server/utils.d.ts +23 -0
  225. package/dist/server/utils.js +113 -13
  226. package/dist/server/utils.js.map +1 -1
  227. package/dist/server/webdriver.d.ts +1 -1
  228. package/dist/server/worker/context.d.ts +3 -0
  229. package/dist/server/worker/context.js +15 -0
  230. package/dist/server/worker/context.js.map +1 -0
  231. package/dist/server/worker/match-image.d.ts +8 -12
  232. package/dist/server/worker/match-image.js +11 -178
  233. package/dist/server/worker/match-image.js.map +1 -1
  234. package/dist/server/worker/start.d.ts +2 -2
  235. package/dist/server/worker/start.js +27 -63
  236. package/dist/server/worker/start.js.map +1 -1
  237. package/dist/shared/index.d.ts +1 -1
  238. package/dist/shared/index.js +9 -7
  239. package/dist/shared/index.js.map +1 -1
  240. package/dist/types.d.ts +84 -43
  241. package/dist/types.js +65 -1
  242. package/dist/types.js.map +1 -1
  243. package/docs/cli.md +80 -0
  244. package/docs/config.md +179 -165
  245. package/docs/examples/playwright-reporer/playwright.config.ts +37 -0
  246. package/docs/migration-0.9-to-0.10.md +144 -0
  247. package/docs/playwright-reporter.md +357 -0
  248. package/docs/storybook.md +60 -0
  249. package/docs/tests.md +50 -45
  250. package/package.json +78 -83
  251. package/playwright.config.mts +46 -0
  252. package/src/client/addon/components/Addon.tsx +1 -1
  253. package/src/client/addon/components/Panel.tsx +2 -2
  254. package/src/client/addon/components/TestSelect.tsx +2 -2
  255. package/src/client/addon/components/Tools.tsx +2 -2
  256. package/src/client/addon/controller.ts +4 -4
  257. package/src/client/addon/makeDecorator.ts +69 -0
  258. package/src/client/addon/manager.ts +38 -37
  259. package/src/client/addon/preset.ts +2 -1
  260. package/src/client/addon/withCreevey.ts +10 -18
  261. package/src/client/shared/components/ImagesView/BlendView.tsx +1 -1
  262. package/src/client/shared/components/ImagesView/ImagesView.tsx +1 -1
  263. package/src/client/shared/components/ImagesView/SideBySideView.tsx +2 -2
  264. package/src/client/shared/components/ImagesView/SlideView.tsx +2 -2
  265. package/src/client/shared/components/ImagesView/SwapView.tsx +2 -2
  266. package/src/client/shared/components/ImagesView/common.ts +1 -1
  267. package/src/client/shared/components/PageFooter/PageFooter.tsx +1 -1
  268. package/src/client/shared/components/PageFooter/Paging.tsx +1 -1
  269. package/src/client/shared/components/PageHeader/ImagePreview.tsx +1 -1
  270. package/src/client/shared/components/PageHeader/PageHeader.tsx +23 -7
  271. package/src/client/shared/components/ResultsPage.tsx +6 -4
  272. package/src/client/shared/creeveyClientApi.ts +19 -1
  273. package/src/client/shared/helpers.ts +4 -24
  274. package/src/client/web/CreeveyApp.tsx +5 -2
  275. package/src/client/web/CreeveyContext.tsx +2 -0
  276. package/src/client/web/CreeveyLoader.tsx +2 -2
  277. package/src/client/web/CreeveyView/SideBar/Checkbox.tsx +3 -3
  278. package/src/client/web/CreeveyView/SideBar/Search.tsx +1 -1
  279. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +11 -6
  280. package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +21 -19
  281. package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +20 -5
  282. package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +10 -8
  283. package/src/client/web/CreeveyView/SideBar/TestLink.tsx +9 -7
  284. package/src/client/web/CreeveyView/SideBar/TestStatusIcon.tsx +2 -2
  285. package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +3 -2
  286. package/src/client/web/CreeveyView/SideBar/Toggle.tsx +1 -1
  287. package/src/client/web/index.tsx +10 -5
  288. package/src/client/web/themes.ts +24 -0
  289. package/src/creevey.ts +92 -38
  290. package/src/playwright/generator.ts +322 -0
  291. package/src/playwright/helpers.ts +31 -0
  292. package/src/playwright/reporter.ts +381 -0
  293. package/src/playwright/setup.ts +84 -0
  294. package/src/playwright.ts +1 -0
  295. package/src/server/compare.ts +260 -0
  296. package/src/server/config.ts +52 -9
  297. package/src/server/connection.ts +26 -0
  298. package/src/server/docker.ts +62 -34
  299. package/src/server/index.ts +161 -79
  300. package/src/server/master/api.ts +94 -28
  301. package/src/server/master/handlers/capture-handler.ts +20 -0
  302. package/src/server/master/handlers/index.ts +4 -0
  303. package/src/server/master/handlers/ping-handler.ts +6 -0
  304. package/src/server/master/handlers/static-handler.ts +16 -0
  305. package/src/server/master/handlers/stories-handler.ts +20 -0
  306. package/src/server/master/master.ts +10 -27
  307. package/src/server/master/pool.ts +7 -3
  308. package/src/server/master/queue.ts +21 -7
  309. package/src/server/master/runner.ts +123 -134
  310. package/src/server/master/server.ts +214 -101
  311. package/src/server/master/start.ts +19 -41
  312. package/src/server/master/testsManager.ts +316 -0
  313. package/src/server/playwright/docker-file.ts +20 -8
  314. package/src/server/playwright/docker.ts +16 -3
  315. package/src/server/playwright/index-source.mjs +16 -0
  316. package/src/server/playwright/internal.ts +169 -96
  317. package/src/server/playwright/webdriver.ts +4 -10
  318. package/src/server/providers/browser.ts +4 -3
  319. package/src/server/providers/hybrid.ts +2 -3
  320. package/src/server/report.ts +51 -0
  321. package/src/server/reporters/creevey.ts +71 -0
  322. package/src/server/reporters/index.ts +11 -0
  323. package/src/server/reporters/junit.ts +207 -0
  324. package/src/server/reporters/teamcity.ts +74 -0
  325. package/src/server/selenium/internal.ts +62 -45
  326. package/src/server/selenium/selenoid.ts +13 -6
  327. package/src/server/selenium/webdriver.ts +8 -12
  328. package/src/server/shutdown.ts +19 -0
  329. package/src/server/stories.ts +1 -12
  330. package/src/server/telemetry.ts +3 -3
  331. package/src/server/testsFiles/parser.ts +52 -4
  332. package/src/server/utils.ts +123 -14
  333. package/src/server/webdriver.ts +1 -1
  334. package/src/server/worker/context.ts +14 -0
  335. package/src/server/worker/match-image.ts +16 -248
  336. package/src/server/worker/start.ts +32 -75
  337. package/src/shared/index.ts +10 -8
  338. package/src/types.ts +91 -58
  339. package/types/global.d.ts +1 -0
  340. package/dist/client/web/assets/index-BE9CL5_G.js +0 -591
  341. package/dist/server/reporter.d.ts +0 -26
  342. package/dist/server/reporter.js +0 -108
  343. package/dist/server/reporter.js.map +0 -1
  344. package/dist/server/update.d.ts +0 -2
  345. package/dist/server/update.js +0 -53
  346. package/dist/server/update.js.map +0 -1
  347. package/src/server/reporter.ts +0 -139
  348. package/src/server/update.ts +0 -74
@@ -1,10 +1,11 @@
1
1
  /// <reference types="../../../types/selenium-context" />
2
- import { Args } from '@storybook/csf';
3
- import { Config, StorybookGlobals, StoryInput, StoriesRaw, Options, ServerTest } from '../../types.js';
2
+ import type { Args } from 'storybook/internal/types';
3
+ import { Config, StorybookGlobals, StoryInput, StoriesRaw, ServerTest, WorkerOptions } from '../../types.js';
4
4
  import { subscribeOn } from '../messages.js';
5
5
  import { CreeveyWebdriverBase } from '../webdriver.js';
6
6
  import type { InternalBrowser } from './internal.js';
7
7
  import { logger } from '../logger.js';
8
+ import { removeWorkerContainer } from '../worker/context.js';
8
9
 
9
10
  declare global {
10
11
  interface Window {
@@ -21,8 +22,8 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
21
22
  #browserName: string;
22
23
  #gridUrl: string;
23
24
  #config: Config;
24
- #options: Options;
25
- constructor(browser: string, gridUrl: string, config: Config, options: Options) {
25
+ #options: WorkerOptions;
26
+ constructor(browser: string, gridUrl: string, config: Config, options: WorkerOptions) {
26
27
  super();
27
28
 
28
29
  this.#browserName = browser;
@@ -31,7 +32,9 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
31
32
  this.#options = options;
32
33
 
33
34
  subscribeOn('shutdown', () => {
34
- void this.#browser?.closeBrowser().finally(() => process.exit());
35
+ void this.#browser?.closeBrowser().finally(() => {
36
+ void removeWorkerContainer().finally(() => process.exit());
37
+ });
35
38
  this.#browser = null;
36
39
  });
37
40
  }
@@ -42,7 +45,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
42
45
 
43
46
  getSessionId(): Promise<string> {
44
47
  if (!this.#browser) {
45
- // TODO Describe the error
46
48
  throw new Error('Browser is not initialized');
47
49
  }
48
50
 
@@ -89,7 +91,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
89
91
 
90
92
  async loadStoriesFromBrowser(): Promise<StoriesRaw> {
91
93
  if (!this.#browser) {
92
- // TODO Describe the error
93
94
  throw new Error('Browser is not initialized');
94
95
  }
95
96
 
@@ -98,7 +99,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
98
99
 
99
100
  afterTest(test: ServerTest): Promise<void> {
100
101
  if (!this.#browser) {
101
- // TODO Describe the error
102
102
  throw new Error('Browser is not initialized');
103
103
  }
104
104
 
@@ -110,7 +110,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
110
110
  ignoreElements?: string | string[] | null,
111
111
  ): Promise<Buffer> {
112
112
  if (!this.#browser) {
113
- // TODO Describe the error
114
113
  throw new Error('Browser is not initialized');
115
114
  }
116
115
 
@@ -119,7 +118,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
119
118
 
120
119
  protected waitForComplete(callback: (isCompleted: boolean) => void): void {
121
120
  if (!this.#browser) {
122
- // TODO Describe the error
123
121
  throw new Error('Browser is not initialized');
124
122
  }
125
123
 
@@ -128,7 +126,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
128
126
 
129
127
  protected async selectStory(id: string, waitForReady?: boolean): Promise<boolean> {
130
128
  if (!this.#browser) {
131
- // TODO Describe the error
132
129
  throw new Error('Browser is not initialized');
133
130
  }
134
131
 
@@ -137,7 +134,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
137
134
 
138
135
  protected async updateStoryArgs(story: StoryInput, updatedArgs: Args): Promise<void> {
139
136
  if (!this.#browser) {
140
- // TODO Describe the error
141
137
  throw new Error('Browser is not initialized');
142
138
  }
143
139
 
@@ -0,0 +1,19 @@
1
+ import cluster from 'cluster';
2
+ import { subscribeOn } from './messages.js';
3
+ import { shutdownOnException, isShuttingDown } from './utils.js';
4
+
5
+ if (cluster.isWorker) {
6
+ subscribeOn('shutdown', () => {
7
+ isShuttingDown.current = true;
8
+ });
9
+ }
10
+
11
+ process.on('uncaughtException', shutdownOnException);
12
+ process.on('unhandledRejection', shutdownOnException);
13
+ // TODO SIGINT Stuck with selenium
14
+ process.on('SIGINT', () => {
15
+ if (isShuttingDown.current) {
16
+ process.exit(-1);
17
+ }
18
+ isShuttingDown.current = true;
19
+ });
@@ -1,5 +1,3 @@
1
- import path from 'path';
2
- import { mkdirSync, writeFileSync } from 'fs';
3
1
  import { createHash } from 'crypto';
4
2
  import _ from 'lodash';
5
3
  import type {
@@ -12,7 +10,7 @@ import type {
12
10
  CreeveyTestFunction,
13
11
  CreeveyTestContext,
14
12
  } from '../types.js';
15
- import { isDefined, isFunction } from '../types.js';
13
+ import { isDefined } from '../types.js';
16
14
  import { shouldSkip } from './utils.js';
17
15
 
18
16
  function storyTestFabric(delay?: number, testFn?: CreeveyTestFunction) {
@@ -129,12 +127,3 @@ export async function loadTestsFromStories(
129
127
 
130
128
  return tests;
131
129
  }
132
-
133
- export function saveTestsJson(tests: Record<string, unknown>, dstPath: string = process.cwd()): void {
134
- mkdirSync(dstPath, { recursive: true });
135
- writeFileSync(
136
- path.join(dstPath, 'tests.json'),
137
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
138
- JSON.stringify(tests, (_, value) => (isFunction(value) ? value.toString() : value), 2),
139
- );
140
- }
@@ -128,7 +128,7 @@ export async function sendScreenshotsCount(
128
128
  repoUrl: repoUrl ?? 'unknown',
129
129
  creeveyVersion: creeveyVersion ?? 'unknown',
130
130
  storybookVersion: storybookVersion ?? 'unknown',
131
- options: options._,
131
+ options,
132
132
  gridUrl,
133
133
  screenDir: config.screenDir ? path.relative(gitRootPath ?? process.cwd(), config.screenDir) : undefined,
134
134
  useDocker: config.useDocker,
@@ -181,8 +181,8 @@ export async function sendScreenshotsCount(
181
181
  const testsMeta = { runId: uuid, tests };
182
182
 
183
183
  const fullPathname = buildPathname('tests', testsMeta);
184
- // NOTE: Keep request path shorter than 32k symbols
185
- const chunksCount = Math.ceil(fullPathname.length / 32_000);
184
+ // NOTE: Keep request path shorter than 24k symbols
185
+ const chunksCount = Math.ceil(fullPathname.length / 24_000);
186
186
  let chunks: string[] = [];
187
187
  if (chunksCount > 1) {
188
188
  const testsString = JSON.stringify(tests);
@@ -1,8 +1,58 @@
1
1
  import { pathToFileURL } from 'url';
2
- import { toId, storyNameFromExport } from '@storybook/csf';
3
2
  import { CreeveyStoryParams, CreeveyTestFunction } from '../../types.js';
4
3
  import { loadThroughTSX } from '../utils.js';
5
4
 
5
+ // NOTE: Copy-pasted from @storybook/csf
6
+ function toStartCaseStr(str: string) {
7
+ return str
8
+ .replace(/_/g, ' ')
9
+ .replace(/-/g, ' ')
10
+ .replace(/\./g, ' ')
11
+ .replace(/([^\n])([A-Z])([a-z])/g, (_, $1, $2, $3) => `${$1} ${$2}${$3}`)
12
+ .replace(/([a-z])([A-Z])/g, (_, $1, $2) => `${$1} ${$2}`)
13
+ .replace(/([a-z])([0-9])/gi, (_, $1, $2) => `${$1} ${$2}`)
14
+ .replace(/([0-9])([a-z])/gi, (_, $1, $2) => `${$1} ${$2}`)
15
+ .replace(/(\s|^)(\w)/g, (_, $1, $2: string) => `${$1}${$2.toUpperCase()}`)
16
+ .replace(/ +/g, ' ')
17
+ .trim();
18
+ }
19
+
20
+ /**
21
+ * Remove punctuation and illegal characters from a story ID.
22
+ *
23
+ * See https://gist.github.com/davidjrice/9d2af51100e41c6c4b4a
24
+ */
25
+ const sanitize = (string: string) => {
26
+ return (
27
+ string
28
+ .toLowerCase()
29
+ // eslint-disable-next-line no-useless-escape
30
+ .replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '-')
31
+ .replace(/-+/g, '-')
32
+ .replace(/^-+/, '')
33
+ .replace(/-+$/, '')
34
+ );
35
+ };
36
+
37
+ const sanitizeSafe = (string: string, part: string) => {
38
+ const sanitized = sanitize(string);
39
+ if (sanitized === '') {
40
+ throw new Error(`Invalid ${part} '${string}', must include alphanumeric characters`);
41
+ }
42
+ return sanitized;
43
+ };
44
+
45
+ /**
46
+ * Generate a storybook ID from a component/kind and story name.
47
+ */
48
+ const toId = (kind: string, name?: string) =>
49
+ `${sanitizeSafe(kind, 'kind')}${name ? `--${sanitizeSafe(name, 'name')}` : ''}`;
50
+
51
+ /**
52
+ * Transform a CSF named export into a readable story name
53
+ */
54
+ const storyNameFromExport = (key: string) => toStartCaseStr(key);
55
+
6
56
  export type CreeveyParamsByStoryId = Record<string, CreeveyStoryParams>;
7
57
 
8
58
  export default async function parse(files: string[]): Promise<CreeveyParamsByStoryId> {
@@ -55,8 +105,6 @@ export const story = (
55
105
 
56
106
  export const test = (title: string, testFn: CreeveyTestFunction): void => {
57
107
  const storyId = getStoryId(kindTitle, storyTitle);
58
- if (!result[storyId]) {
59
- result[storyId] = {};
60
- }
108
+ result[storyId] ??= {};
61
109
  result[storyId].tests = Object.assign({}, result[storyId].tests, { [title]: testFn });
62
110
  };
@@ -1,12 +1,17 @@
1
1
  import fs from 'fs';
2
- import { get } from 'https';
2
+ import path from 'path';
3
+ import http from 'http';
4
+ import https from 'https';
5
+ import assert from 'assert';
3
6
  import cluster from 'cluster';
4
- import { dirname } from 'path';
7
+ import pidtree from 'pidtree';
5
8
  import { fileURLToPath, pathToFileURL } from 'url';
6
9
  import { register as esmRegister } from 'tsx/esm/api';
7
10
  import { register as cjsRegister } from 'tsx/cjs/api';
8
11
  import { SkipOptions, SkipOption, isDefined, TestData, noop, ServerTest, Worker } from '../types.js';
9
- import { emitShutdownMessage, sendShutdownMessage } from './messages.js';
12
+ import { emitShutdownMessage, emitWorkerMessage, sendShutdownMessage } from './messages.js';
13
+ import { LOCALHOST_REGEXP } from './webdriver.js';
14
+ import { logger } from './logger.js';
10
15
 
11
16
  const importMetaUrl = pathToFileURL(__filename).href;
12
17
 
@@ -14,6 +19,19 @@ export const isShuttingDown = { current: false };
14
19
 
15
20
  export const configExt = ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts'];
16
21
 
22
+ const browserTypes = {
23
+ chromium: 'chromium',
24
+ 'chromium-headless-shell': 'chromium',
25
+ chrome: 'chromium',
26
+ 'chrome-beta': 'chromium',
27
+ msedge: 'chromium',
28
+ 'msedge-beta': 'chromium',
29
+ 'msedge-dev': 'chromium',
30
+ 'bidi-chromium': 'chromium',
31
+ firefox: 'firefox',
32
+ webkit: 'webkit',
33
+ } as const;
34
+
17
35
  export const skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
18
36
 
19
37
  function matchBy(pattern: string | string[] | RegExp | undefined, value: string): boolean {
@@ -72,6 +90,18 @@ export function shouldSkipByOption(
72
90
  return skipByBrowser && skipByKind && skipByStory && skipByTest && reason;
73
91
  }
74
92
 
93
+ export function shutdownOnException(reason: unknown): void {
94
+ if (isShuttingDown.current) return;
95
+
96
+ const error = reason instanceof Error ? (reason.stack ?? reason.message) : (reason as string);
97
+
98
+ logger().error(error);
99
+
100
+ process.exitCode = -1;
101
+ if (cluster.isWorker) emitWorkerMessage({ type: 'error', payload: { subtype: 'unknown', error } });
102
+ if (cluster.isPrimary) void shutdownWorkers();
103
+ }
104
+
75
105
  export async function shutdownWorkers(): Promise<void> {
76
106
  isShuttingDown.current = true;
77
107
  await Promise.all(
@@ -82,13 +112,14 @@ export async function shutdownWorkers(): Promise<void> {
82
112
  (worker) =>
83
113
  new Promise<void>((resolve) => {
84
114
  const timeout = setTimeout(() => {
85
- worker.kill();
86
- }, 10000);
115
+ if (worker.process.pid) void killTree(worker.process.pid);
116
+ }, 10_000);
87
117
  worker.on('exit', () => {
88
118
  clearTimeout(timeout);
89
119
  resolve();
90
120
  });
91
121
  sendShutdownMessage(worker);
122
+ worker.disconnect();
92
123
  }),
93
124
  ),
94
125
  );
@@ -98,7 +129,7 @@ export async function shutdownWorkers(): Promise<void> {
98
129
  export function gracefullyKill(worker: Worker): void {
99
130
  worker.isShuttingDown = true;
100
131
  const timeout = setTimeout(() => {
101
- worker.kill();
132
+ if (worker.process.pid) void killTree(worker.process.pid);
102
133
  }, 10000);
103
134
  worker.on('exit', () => {
104
135
  clearTimeout(timeout);
@@ -106,9 +137,34 @@ export function gracefullyKill(worker: Worker): void {
106
137
  sendShutdownMessage(worker);
107
138
  }
108
139
 
140
+ export async function killTree(rootPid: number): Promise<void> {
141
+ const pids = await pidtree(rootPid, { root: true });
142
+
143
+ pids.forEach((pid) => {
144
+ try {
145
+ process.kill(pid, 'SIGKILL');
146
+ } catch {
147
+ /* noop */
148
+ }
149
+ });
150
+ }
151
+
152
+ export function shutdownWithError(): void {
153
+ process.exit(1);
154
+ }
155
+
156
+ export function resolvePlaywrightBrowserType(browserName: string): (typeof browserTypes)[keyof typeof browserTypes] {
157
+ assert(
158
+ browserName in browserTypes,
159
+ new Error(`Failed to match browser name "${browserName}" to playwright browserType`),
160
+ );
161
+
162
+ return browserTypes[browserName as keyof typeof browserTypes];
163
+ }
164
+
109
165
  export async function getCreeveyCache(): Promise<string | undefined> {
110
166
  const { default: findCacheDir } = await import('find-cache-dir');
111
- return findCacheDir({ name: 'creevey', cwd: dirname(fileURLToPath(importMetaUrl)) });
167
+ return findCacheDir({ name: 'creevey', cwd: path.dirname(fileURLToPath(importMetaUrl)) });
112
168
  }
113
169
 
114
170
  export async function runSequence(seq: (() => unknown)[], predicate: () => boolean): Promise<boolean> {
@@ -141,11 +197,12 @@ export function testsToImages(tests: (TestData | undefined)[]): Set<string> {
141
197
 
142
198
  // https://tuhrig.de/how-to-know-you-are-inside-a-docker-container/
143
199
  export const isInsideDocker =
144
- fs.existsSync('/proc/1/cgroup') && fs.readFileSync('/proc/1/cgroup', 'utf-8').includes('docker');
200
+ (fs.existsSync('/proc/1/cgroup') && fs.readFileSync('/proc/1/cgroup', 'utf-8').includes('docker')) ||
201
+ process.env.DOCKER === 'true';
145
202
 
146
203
  export const downloadBinary = (downloadUrl: string, destination: string): Promise<void> =>
147
204
  new Promise((resolve, reject) =>
148
- get(downloadUrl, (response) => {
205
+ https.get(downloadUrl, (response) => {
149
206
  if (response.statusCode == 302) {
150
207
  const { location } = response.headers;
151
208
  if (!location) {
@@ -187,7 +244,7 @@ export function readDirRecursive(dirPath: string): string[] {
187
244
 
188
245
  export function tryToLoadTestsData(filename: string): Partial<Record<string, ServerTest>> | undefined {
189
246
  try {
190
- // eslint-disable-next-line @typescript-eslint/no-require-imports
247
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-dynamic-require
191
248
  return require(filename) as Partial<Record<string, ServerTest>>;
192
249
  } catch {
193
250
  /* noop */
@@ -198,19 +255,71 @@ const [nodeVersion] = process.versions.node.split('.').map(Number);
198
255
  export async function loadThroughTSX<T>(
199
256
  callback: (load: (modulePath: string) => Promise<T>) => Promise<T>,
200
257
  ): Promise<T> {
201
- // TODO Check if it work in node18 and type: 'module'
202
- const unregister = nodeVersion > 18 ? esmRegister() : cjsRegister();
258
+ const unregisterESM = nodeVersion > 18 ? esmRegister() : noop;
259
+ const unregisterCJS = cjsRegister();
203
260
 
204
261
  const result = await callback((modulePath) =>
205
262
  nodeVersion > 18
206
263
  ? import(modulePath)
207
- : // eslint-disable-next-line @typescript-eslint/no-require-imports
264
+ : // eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-dynamic-require
208
265
  Promise.resolve(require(modulePath) as T),
209
266
  );
210
267
 
211
268
  // NOTE: `unregister` type is `(() => Promise<void>) | (() => void)`
212
269
  // eslint-disable-next-line @typescript-eslint/await-thenable, @typescript-eslint/no-confusing-void-expression
213
- await unregister();
270
+ await unregisterCJS();
271
+ // eslint-disable-next-line @typescript-eslint/await-thenable, @typescript-eslint/no-confusing-void-expression
272
+ await unregisterESM();
214
273
 
215
274
  return result;
216
275
  }
276
+
277
+ export function waitOnUrl(waitUrl: string, timeout: number, delay: number) {
278
+ const urls = [waitUrl];
279
+ if (!LOCALHOST_REGEXP.test(waitUrl)) {
280
+ const parsedUrl = new URL(waitUrl);
281
+ parsedUrl.host = 'localhost';
282
+ urls.push(parsedUrl.toString());
283
+ }
284
+ const startTime = Date.now();
285
+ return Promise.race(
286
+ urls.map(
287
+ (url) =>
288
+ new Promise<void>((resolve, reject) => {
289
+ const interval = setInterval(() => {
290
+ http
291
+ .get(url, (response) => {
292
+ if (response.statusCode === 200) {
293
+ clearInterval(interval);
294
+ resolve();
295
+ }
296
+ })
297
+ .on('error', () => {
298
+ // Ignore HTTP errors
299
+ });
300
+
301
+ if (Date.now() - startTime > timeout) {
302
+ clearInterval(interval);
303
+ reject(new Error(`${url} didn't respond within ${timeout / 1000} seconds`));
304
+ }
305
+ }, delay);
306
+ }),
307
+ ),
308
+ );
309
+ }
310
+
311
+ /**
312
+ * Copies static assets to the report directory
313
+ * @param reportDir Directory where the report will be generated
314
+ */
315
+ export async function copyStatics(reportDir: string): Promise<void> {
316
+ const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '../../dist/client/web');
317
+ const assets = (await fs.promises.readdir(path.join(clientDir, 'assets'), { withFileTypes: true }))
318
+ .filter((dirent) => dirent.isFile())
319
+ .map((dirent) => dirent.name);
320
+ await fs.promises.mkdir(path.join(reportDir, 'assets'), { recursive: true });
321
+ await fs.promises.copyFile(path.join(clientDir, 'index.html'), path.join(reportDir, 'index.html'));
322
+ for (const asset of assets) {
323
+ await fs.promises.copyFile(path.join(clientDir, 'assets', asset), path.join(reportDir, 'assets', asset));
324
+ }
325
+ }
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { networkInterfaces } from 'os';
3
3
  import { logger } from './logger.js';
4
- import { Args } from '@storybook/csf';
4
+ import type { Args } from 'storybook/internal/types';
5
5
  import {
6
6
  isDefined,
7
7
  StoryInput,
@@ -0,0 +1,14 @@
1
+ import type { Container } from 'dockerode';
2
+
3
+ let workerContainer: Container | null = null;
4
+
5
+ export function setWorkerContainer(container: Container): void {
6
+ workerContainer = container;
7
+ }
8
+
9
+ export async function removeWorkerContainer(): Promise<void> {
10
+ if (workerContainer) {
11
+ await workerContainer.remove({ force: true });
12
+ workerContainer = null;
13
+ }
14
+ }