creevey 0.10.0-beta.8 → 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 (350) 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 +4 -4
  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 +14 -21
  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 +31 -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 +2 -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 +45 -15
  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 +44 -15
  62. package/dist/client/web/CreeveyApp.js.map +1 -1
  63. package/dist/client/web/CreeveyContext.d.ts +6 -0
  64. package/dist/client/web/CreeveyContext.js +21 -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 +20 -10
  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 +67 -13
  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 -13
  82. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
  83. package/dist/client/web/CreeveyView/SideBar/TestLink.js +20 -13
  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.d.ts +1 -8
  94. package/dist/client/web/KeyboardEventsContext.js +79 -64
  95. package/dist/client/web/KeyboardEventsContext.js.map +1 -1
  96. package/dist/client/web/assets/index-CtSq3IhG.js +518 -0
  97. package/dist/client/web/index.html +1 -1
  98. package/dist/client/web/index.js +26 -11
  99. package/dist/client/web/index.js.map +1 -1
  100. package/dist/client/web/themes.d.ts +2 -0
  101. package/dist/client/web/themes.js +22 -0
  102. package/dist/client/web/themes.js.map +1 -0
  103. package/dist/creevey.d.ts +1 -1
  104. package/dist/creevey.js +122 -41
  105. package/dist/creevey.js.map +1 -1
  106. package/dist/index.d.ts +1 -0
  107. package/dist/playwright/generator.d.ts +25 -0
  108. package/dist/playwright/generator.js +243 -0
  109. package/dist/playwright/generator.js.map +1 -0
  110. package/dist/playwright/helpers.d.ts +2 -0
  111. package/dist/playwright/helpers.js +29 -0
  112. package/dist/playwright/helpers.js.map +1 -0
  113. package/dist/playwright/reporter.d.ts +83 -0
  114. package/dist/playwright/reporter.js +334 -0
  115. package/dist/playwright/reporter.js.map +1 -0
  116. package/dist/playwright/setup.d.ts +3 -0
  117. package/dist/playwright/setup.js +72 -0
  118. package/dist/playwright/setup.js.map +1 -0
  119. package/dist/playwright.d.ts +1 -0
  120. package/dist/playwright.js +3 -1
  121. package/dist/playwright.js.map +1 -1
  122. package/dist/server/compare.d.ts +18 -0
  123. package/dist/server/compare.js +182 -0
  124. package/dist/server/compare.js.map +1 -0
  125. package/dist/server/config.d.ts +3 -3
  126. package/dist/server/config.js +75 -8
  127. package/dist/server/config.js.map +1 -1
  128. package/dist/server/connection.d.ts +3 -0
  129. package/dist/server/connection.js +28 -0
  130. package/dist/server/connection.js.map +1 -0
  131. package/dist/server/docker.d.ts +1 -1
  132. package/dist/server/docker.js +54 -32
  133. package/dist/server/docker.js.map +1 -1
  134. package/dist/server/index.d.ts +2 -2
  135. package/dist/server/index.js +165 -64
  136. package/dist/server/index.js.map +1 -1
  137. package/dist/server/master/api.d.ts +11 -6
  138. package/dist/server/master/api.js +88 -25
  139. package/dist/server/master/api.js.map +1 -1
  140. package/dist/server/master/handlers/capture-handler.d.ts +5 -0
  141. package/dist/server/master/handlers/capture-handler.js +25 -0
  142. package/dist/server/master/handlers/capture-handler.js.map +1 -0
  143. package/dist/server/master/handlers/index.d.ts +4 -0
  144. package/dist/server/master/handlers/index.js +21 -0
  145. package/dist/server/master/handlers/index.js.map +1 -0
  146. package/dist/server/master/handlers/ping-handler.d.ts +2 -0
  147. package/dist/server/master/handlers/ping-handler.js +8 -0
  148. package/dist/server/master/handlers/ping-handler.js.map +1 -0
  149. package/dist/server/master/handlers/static-handler.d.ts +1 -0
  150. package/dist/server/master/handlers/static-handler.js +20 -0
  151. package/dist/server/master/handlers/static-handler.js.map +1 -0
  152. package/dist/server/master/handlers/stories-handler.d.ts +4 -0
  153. package/dist/server/master/handlers/stories-handler.js +24 -0
  154. package/dist/server/master/handlers/stories-handler.js.map +1 -0
  155. package/dist/server/master/master.js +7 -24
  156. package/dist/server/master/master.js.map +1 -1
  157. package/dist/server/master/pool.d.ts +1 -0
  158. package/dist/server/master/pool.js +5 -3
  159. package/dist/server/master/pool.js.map +1 -1
  160. package/dist/server/master/queue.d.ts +1 -1
  161. package/dist/server/master/queue.js +14 -6
  162. package/dist/server/master/queue.js.map +1 -1
  163. package/dist/server/master/runner.d.ts +6 -6
  164. package/dist/server/master/runner.js +98 -130
  165. package/dist/server/master/runner.js.map +1 -1
  166. package/dist/server/master/server.d.ts +1 -1
  167. package/dist/server/master/server.js +193 -88
  168. package/dist/server/master/server.js.map +1 -1
  169. package/dist/server/master/start.d.ts +1 -2
  170. package/dist/server/master/start.js +13 -29
  171. package/dist/server/master/start.js.map +1 -1
  172. package/dist/server/master/testsManager.d.ts +81 -0
  173. package/dist/server/master/testsManager.js +282 -0
  174. package/dist/server/master/testsManager.js.map +1 -0
  175. package/dist/server/playwright/docker-file.d.ts +1 -1
  176. package/dist/server/playwright/docker-file.js +17 -8
  177. package/dist/server/playwright/docker-file.js.map +1 -1
  178. package/dist/server/playwright/docker.d.ts +2 -1
  179. package/dist/server/playwright/docker.js +10 -2
  180. package/dist/server/playwright/docker.js.map +1 -1
  181. package/dist/server/playwright/index-source.mjs +16 -0
  182. package/dist/server/playwright/internal.d.ts +7 -7
  183. package/dist/server/playwright/internal.js +144 -84
  184. package/dist/server/playwright/internal.js.map +1 -1
  185. package/dist/server/playwright/webdriver.d.ts +3 -3
  186. package/dist/server/playwright/webdriver.js +0 -6
  187. package/dist/server/playwright/webdriver.js.map +1 -1
  188. package/dist/server/providers/browser.js +4 -3
  189. package/dist/server/providers/browser.js.map +1 -1
  190. package/dist/server/providers/hybrid.js +2 -2
  191. package/dist/server/providers/hybrid.js.map +1 -1
  192. package/dist/server/report.d.ts +10 -0
  193. package/dist/server/report.js +45 -0
  194. package/dist/server/report.js.map +1 -0
  195. package/dist/server/reporters/creevey.d.ts +7 -0
  196. package/dist/server/reporters/creevey.js +63 -0
  197. package/dist/server/reporters/creevey.js.map +1 -0
  198. package/dist/server/reporters/index.d.ts +2 -0
  199. package/dist/server/reporters/index.js +16 -0
  200. package/dist/server/reporters/index.js.map +1 -0
  201. package/dist/server/reporters/junit.d.ts +16 -0
  202. package/dist/server/reporters/junit.js +167 -0
  203. package/dist/server/reporters/junit.js.map +1 -0
  204. package/dist/server/reporters/teamcity.d.ts +7 -0
  205. package/dist/server/reporters/teamcity.js +60 -0
  206. package/dist/server/reporters/teamcity.js.map +1 -0
  207. package/dist/server/selenium/internal.d.ts +4 -4
  208. package/dist/server/selenium/internal.js +56 -40
  209. package/dist/server/selenium/internal.js.map +1 -1
  210. package/dist/server/selenium/selenoid.js +12 -6
  211. package/dist/server/selenium/selenoid.js.map +1 -1
  212. package/dist/server/selenium/webdriver.d.ts +3 -3
  213. package/dist/server/selenium/webdriver.js +4 -8
  214. package/dist/server/selenium/webdriver.js.map +1 -1
  215. package/dist/server/shutdown.d.ts +1 -0
  216. package/dist/server/shutdown.js +23 -0
  217. package/dist/server/shutdown.js.map +1 -0
  218. package/dist/server/stories.d.ts +0 -1
  219. package/dist/server/stories.js +0 -12
  220. package/dist/server/stories.js.map +1 -1
  221. package/dist/server/telemetry.js +3 -3
  222. package/dist/server/telemetry.js.map +1 -1
  223. package/dist/server/testsFiles/parser.js +45 -5
  224. package/dist/server/testsFiles/parser.js.map +1 -1
  225. package/dist/server/utils.d.ts +23 -0
  226. package/dist/server/utils.js +114 -15
  227. package/dist/server/utils.js.map +1 -1
  228. package/dist/server/webdriver.d.ts +1 -1
  229. package/dist/server/worker/context.d.ts +3 -0
  230. package/dist/server/worker/context.js +15 -0
  231. package/dist/server/worker/context.js.map +1 -0
  232. package/dist/server/worker/match-image.d.ts +8 -12
  233. package/dist/server/worker/match-image.js +11 -178
  234. package/dist/server/worker/match-image.js.map +1 -1
  235. package/dist/server/worker/start.d.ts +2 -2
  236. package/dist/server/worker/start.js +41 -64
  237. package/dist/server/worker/start.js.map +1 -1
  238. package/dist/shared/index.d.ts +1 -1
  239. package/dist/shared/index.js +9 -7
  240. package/dist/shared/index.js.map +1 -1
  241. package/dist/types.d.ts +84 -43
  242. package/dist/types.js +65 -1
  243. package/dist/types.js.map +1 -1
  244. package/docs/cli.md +80 -0
  245. package/docs/config.md +179 -165
  246. package/docs/examples/playwright-reporer/playwright.config.ts +37 -0
  247. package/docs/migration-0.9-to-0.10.md +144 -0
  248. package/docs/playwright-reporter.md +357 -0
  249. package/docs/storybook.md +60 -0
  250. package/docs/tests.md +50 -45
  251. package/package.json +78 -83
  252. package/playwright.config.mts +46 -0
  253. package/src/client/addon/components/Addon.tsx +1 -1
  254. package/src/client/addon/components/Panel.tsx +4 -4
  255. package/src/client/addon/components/TestSelect.tsx +2 -2
  256. package/src/client/addon/components/Tools.tsx +2 -2
  257. package/src/client/addon/controller.ts +4 -4
  258. package/src/client/addon/makeDecorator.ts +69 -0
  259. package/src/client/addon/manager.ts +38 -37
  260. package/src/client/addon/preset.ts +2 -1
  261. package/src/client/addon/withCreevey.ts +16 -19
  262. package/src/client/shared/components/ImagesView/BlendView.tsx +1 -1
  263. package/src/client/shared/components/ImagesView/ImagesView.tsx +1 -1
  264. package/src/client/shared/components/ImagesView/SideBySideView.tsx +2 -2
  265. package/src/client/shared/components/ImagesView/SlideView.tsx +2 -2
  266. package/src/client/shared/components/ImagesView/SwapView.tsx +20 -2
  267. package/src/client/shared/components/ImagesView/common.ts +1 -1
  268. package/src/client/shared/components/PageFooter/PageFooter.tsx +1 -1
  269. package/src/client/shared/components/PageFooter/Paging.tsx +1 -1
  270. package/src/client/shared/components/PageHeader/ImagePreview.tsx +2 -1
  271. package/src/client/shared/components/PageHeader/PageHeader.tsx +23 -7
  272. package/src/client/shared/components/ResultsPage.tsx +33 -10
  273. package/src/client/shared/creeveyClientApi.ts +19 -1
  274. package/src/client/shared/helpers.ts +4 -24
  275. package/src/client/web/CreeveyApp.tsx +30 -9
  276. package/src/client/web/CreeveyContext.tsx +11 -0
  277. package/src/client/web/CreeveyLoader.tsx +2 -2
  278. package/src/client/web/CreeveyView/SideBar/Checkbox.tsx +3 -3
  279. package/src/client/web/CreeveyView/SideBar/Search.tsx +4 -4
  280. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +11 -6
  281. package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +48 -15
  282. package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +20 -5
  283. package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +12 -12
  284. package/src/client/web/CreeveyView/SideBar/TestLink.tsx +10 -10
  285. package/src/client/web/CreeveyView/SideBar/TestStatusIcon.tsx +2 -2
  286. package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +3 -2
  287. package/src/client/web/CreeveyView/SideBar/Toggle.tsx +1 -1
  288. package/src/client/web/KeyboardEventsContext.tsx +61 -73
  289. package/src/client/web/index.tsx +10 -5
  290. package/src/client/web/themes.ts +24 -0
  291. package/src/creevey.ts +92 -38
  292. package/src/playwright/generator.ts +322 -0
  293. package/src/playwright/helpers.ts +31 -0
  294. package/src/playwright/reporter.ts +381 -0
  295. package/src/playwright/setup.ts +84 -0
  296. package/src/playwright.ts +1 -0
  297. package/src/server/compare.ts +260 -0
  298. package/src/server/config.ts +52 -9
  299. package/src/server/connection.ts +26 -0
  300. package/src/server/docker.ts +62 -34
  301. package/src/server/index.ts +166 -79
  302. package/src/server/master/api.ts +94 -28
  303. package/src/server/master/handlers/capture-handler.ts +20 -0
  304. package/src/server/master/handlers/index.ts +4 -0
  305. package/src/server/master/handlers/ping-handler.ts +6 -0
  306. package/src/server/master/handlers/static-handler.ts +16 -0
  307. package/src/server/master/handlers/stories-handler.ts +20 -0
  308. package/src/server/master/master.ts +10 -27
  309. package/src/server/master/pool.ts +7 -3
  310. package/src/server/master/queue.ts +21 -7
  311. package/src/server/master/runner.ts +123 -134
  312. package/src/server/master/server.ts +214 -101
  313. package/src/server/master/start.ts +19 -41
  314. package/src/server/master/testsManager.ts +316 -0
  315. package/src/server/playwright/docker-file.ts +20 -8
  316. package/src/server/playwright/docker.ts +16 -3
  317. package/src/server/playwright/index-source.mjs +16 -0
  318. package/src/server/playwright/internal.ts +176 -103
  319. package/src/server/playwright/webdriver.ts +4 -10
  320. package/src/server/providers/browser.ts +4 -3
  321. package/src/server/providers/hybrid.ts +2 -3
  322. package/src/server/report.ts +51 -0
  323. package/src/server/reporters/creevey.ts +71 -0
  324. package/src/server/reporters/index.ts +11 -0
  325. package/src/server/reporters/junit.ts +207 -0
  326. package/src/server/reporters/teamcity.ts +74 -0
  327. package/src/server/selenium/internal.ts +70 -53
  328. package/src/server/selenium/selenoid.ts +13 -6
  329. package/src/server/selenium/webdriver.ts +8 -12
  330. package/src/server/shutdown.ts +19 -0
  331. package/src/server/stories.ts +1 -12
  332. package/src/server/telemetry.ts +3 -3
  333. package/src/server/testsFiles/parser.ts +52 -4
  334. package/src/server/utils.ts +124 -16
  335. package/src/server/webdriver.ts +1 -1
  336. package/src/server/worker/context.ts +14 -0
  337. package/src/server/worker/match-image.ts +16 -248
  338. package/src/server/worker/start.ts +49 -79
  339. package/src/shared/index.ts +10 -8
  340. package/src/types.ts +91 -58
  341. package/types/global.d.ts +1 -0
  342. package/dist/client/web/assets/index-DB8lHlJw.js +0 -591
  343. package/dist/server/reporter.d.ts +0 -26
  344. package/dist/server/reporter.js +0 -108
  345. package/dist/server/reporter.js.map +0 -1
  346. package/dist/server/update.d.ts +0 -2
  347. package/dist/server/update.js +0 -53
  348. package/dist/server/update.js.map +0 -1
  349. package/src/server/reporter.ts +0 -139
  350. package/src/server/update.ts +0 -74
@@ -0,0 +1,71 @@
1
+ import chalk from 'chalk';
2
+ import Logger from 'loglevel';
3
+ import prefix from 'loglevel-plugin-prefix';
4
+ import { FakeTest, isImageError, TEST_EVENTS } from '../../types.js';
5
+ import EventEmitter from 'events';
6
+
7
+ const testLevels: Record<string, string> = {
8
+ INFO: chalk.green('PASS'),
9
+ WARN: chalk.yellow('START'),
10
+ ERROR: chalk.red('FAIL'),
11
+ };
12
+
13
+ export class CreeveyReporter {
14
+ private logger: Logger.Logger | null = null;
15
+ // TODO Output in better way, like vitest, maybe
16
+ constructor(runner: EventEmitter) {
17
+ runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
18
+ this.getLogger(test.creevey).warn(chalk.cyan(test.fullTitle()));
19
+ });
20
+ runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
21
+ this.getLogger(test.creevey).info(chalk.cyan(test.fullTitle()), chalk.gray(`(${test.duration} ms)`));
22
+ });
23
+ runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error) => {
24
+ this.getLogger(test.creevey).error(
25
+ chalk.cyan(test.fullTitle()),
26
+ chalk.gray(`(${test.duration} ms)`),
27
+ '\n ',
28
+ this.getErrors(
29
+ error,
30
+ (error, imageName) => `${chalk.bold(imageName ?? test.creevey.browserName)}:${error}`,
31
+ (error) => error.stack ?? error.message,
32
+ ).join('\n '),
33
+ );
34
+ });
35
+ }
36
+
37
+ private getLogger(options: { sessionId: string; browserName: string }) {
38
+ if (this.logger) return this.logger;
39
+ const { sessionId, browserName } = options;
40
+ const testLogger = Logger.getLogger(sessionId);
41
+
42
+ this.logger = prefix.apply(testLogger, {
43
+ format(level) {
44
+ return `[${browserName}:${chalk.gray(process.pid)}] ${testLevels[level]} => ${chalk.gray(sessionId)}`;
45
+ },
46
+ });
47
+
48
+ return this.logger;
49
+ }
50
+
51
+ private getErrors(
52
+ error: unknown,
53
+ imageErrorToString: (error: string, imageName?: string) => string,
54
+ errorToString: (error: Error) => string,
55
+ ): string[] {
56
+ const errors = [];
57
+ if (!(error instanceof Error)) {
58
+ errors.push(error as string);
59
+ } else if (!isImageError(error)) {
60
+ errors.push(errorToString(error));
61
+ } else if (typeof error.images == 'string') {
62
+ errors.push(imageErrorToString(error.images));
63
+ } else {
64
+ const imageErrors = error.images ?? {};
65
+ Object.keys(imageErrors).forEach((imageName) => {
66
+ errors.push(imageErrorToString(imageErrors[imageName] ?? '', imageName));
67
+ });
68
+ }
69
+ return errors;
70
+ }
71
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseReporter } from '../../types.js';
2
+ import { CreeveyReporter } from './creevey.js';
3
+ import { JUnitReporter } from './junit.js';
4
+ import { TeamcityReporter } from './teamcity.js';
5
+
6
+ export function getReporter(reporter: BaseReporter | 'creevey' | 'teamcity' | 'junit'): BaseReporter {
7
+ if (reporter === 'creevey') return CreeveyReporter;
8
+ if (reporter === 'teamcity') return TeamcityReporter;
9
+ if (reporter === 'junit') return JUnitReporter;
10
+ return reporter;
11
+ }
@@ -0,0 +1,207 @@
1
+ import EventEmitter from 'events';
2
+ import { dirname, resolve } from 'path';
3
+ import { closeSync, existsSync, mkdirSync, openSync, writeFileSync } from 'fs';
4
+ import { TEST_EVENTS, FakeTest } from '../../types.js';
5
+ import { logger } from '../logger.js';
6
+
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ class IndentedLogger<T = any> {
9
+ private currentIndent = '';
10
+
11
+ constructor(private baseLog: (text: string) => T) {}
12
+
13
+ indent(): void {
14
+ this.currentIndent += ' ';
15
+ }
16
+
17
+ unindent(): void {
18
+ this.currentIndent = this.currentIndent.substring(0, this.currentIndent.length - 4);
19
+ }
20
+
21
+ log(text: string): T {
22
+ return this.baseLog(this.currentIndent + text);
23
+ }
24
+ }
25
+
26
+ // NOTE: This is a reworked copy of the JUnitReporter class from Vitest.
27
+ export class JUnitReporter {
28
+ private reportFile: string;
29
+ private fileFd?: number;
30
+ private logger: IndentedLogger<void>;
31
+ private suites: Record<string, FakeTest[]> = {};
32
+ // TODO classnameTemplate
33
+ // TODO Output console logs
34
+ // TODO Output attachments
35
+ constructor(runner: EventEmitter, options: { reportDir: string; reporterOptions: { outputFile?: string } }) {
36
+ const { reportDir, reporterOptions } = options;
37
+
38
+ this.reportFile = reporterOptions.outputFile ?? resolve(reportDir, 'junit.xml');
39
+
40
+ this.logger = new IndentedLogger((text) => {
41
+ this.fileFd ??= openSync(this.reportFile, 'w+');
42
+
43
+ writeFileSync(this.fileFd, `${text}\n`);
44
+ });
45
+
46
+ runner.on(TEST_EVENTS.RUN_BEGIN, () => {
47
+ this.suites = {};
48
+
49
+ const outputDirectory = dirname(this.reportFile);
50
+ if (!existsSync(outputDirectory)) {
51
+ mkdirSync(outputDirectory, { recursive: true });
52
+ }
53
+
54
+ this.fileFd = openSync(this.reportFile, 'w+');
55
+ });
56
+ runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
57
+ const suite = (this.suites[test.parent.title] ??= []);
58
+ suite.push(test);
59
+ });
60
+ runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest) => {
61
+ const suite = (this.suites[test.parent.title] ??= []);
62
+ suite.push(test);
63
+ });
64
+ runner.on(TEST_EVENTS.RUN_END, () => {
65
+ this.onFinished();
66
+ });
67
+ }
68
+
69
+ private writeElement(name: string, attrs: Record<string, string | number | undefined>, children?: () => void): void {
70
+ const pairs: string[] = [];
71
+ for (const key in attrs) {
72
+ const attr = attrs[key];
73
+ if (attr === undefined) {
74
+ continue;
75
+ }
76
+
77
+ pairs.push(`${key}="${escapeXML(attr)}"`);
78
+ }
79
+
80
+ this.logger.log(`<${name}${pairs.length ? ` ${pairs.join(' ')}` : ''}>`);
81
+ this.logger.indent();
82
+ children?.call(this);
83
+ this.logger.unindent();
84
+
85
+ this.logger.log(`</${name}>`);
86
+ }
87
+
88
+ private writeTasks(tests: FakeTest[]): void {
89
+ for (const test of tests) {
90
+ const classname = test.parent.title;
91
+
92
+ this.writeElement(
93
+ 'testcase',
94
+ {
95
+ classname,
96
+ name: test.title,
97
+ time: getDuration(test),
98
+ },
99
+ () => {
100
+ if (test.state === 'failed') {
101
+ const error = test.err;
102
+ this.writeElement('failure', { message: error });
103
+ }
104
+ },
105
+ );
106
+ }
107
+ }
108
+
109
+ private onFinished(): void {
110
+ this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
111
+
112
+ const suites = Object.entries(this.suites).map(([name, tests]) => {
113
+ return {
114
+ name,
115
+ tests,
116
+ failures: tests.filter((test) => test.state === 'failed').length,
117
+ time: tests.reduce((acc, test) => acc + (test.duration ?? 0), 0),
118
+ };
119
+ });
120
+ const stats = suites.reduce(
121
+ (s, { tests, failures, time }) => {
122
+ s.tests += tests.length;
123
+ s.failures += failures;
124
+ s.time += time;
125
+ return s;
126
+ },
127
+ { name: 'creevey tests', tests: 0, failures: 0, time: 0 },
128
+ );
129
+
130
+ this.writeElement('testsuites', { ...stats, time: executionTime(stats.time) }, () => {
131
+ suites.forEach(({ name, tests, failures, time }) => {
132
+ this.writeElement(
133
+ 'testsuite',
134
+ {
135
+ name,
136
+ tests: tests.length,
137
+ failures,
138
+ time: executionTime(time),
139
+ },
140
+ () => {
141
+ this.writeTasks(tests);
142
+ },
143
+ );
144
+ });
145
+ });
146
+
147
+ if (this.reportFile) {
148
+ logger().info(`JUNIT report written to ${this.reportFile}`);
149
+ }
150
+
151
+ if (this.fileFd) {
152
+ closeSync(this.fileFd);
153
+ this.fileFd = undefined;
154
+ }
155
+ }
156
+ }
157
+
158
+ // https://gist.github.com/john-doherty/b9195065884cdbfd2017a4756e6409cc
159
+ function removeInvalidXMLCharacters(value: string, removeDiscouragedChars: boolean): string {
160
+ let regex =
161
+ // eslint-disable-next-line no-control-regex
162
+ /([\0-\x08\v\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
163
+ value = String(value).replace(regex, '');
164
+
165
+ if (removeDiscouragedChars) {
166
+ // remove everything discouraged by XML 1.0 specifications
167
+ regex = new RegExp(
168
+ '([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|\\uD83F[\\uDFFE\\uDFFF]|(?:\\uD87F[\\uDF' +
169
+ 'FE\\uDFFF])|\\uD8BF[\\uDFFE\\uDFFF]|\\uD8FF[\\uDFFE\\uDFFF]|(?:\\uD93F[\\uDFFE\\uD' +
170
+ 'FFF])|\\uD97F[\\uDFFE\\uDFFF]|\\uD9BF[\\uDFFE\\uDFFF]|\\uD9FF[\\uDFFE\\uDFFF]' +
171
+ '|\\uDA3F[\\uDFFE\\uDFFF]|\\uDA7F[\\uDFFE\\uDFFF]|\\uDABF[\\uDFFE\\uDFFF]|(?:\\' +
172
+ 'uDAFF[\\uDFFE\\uDFFF])|\\uDB3F[\\uDFFE\\uDFFF]|\\uDB7F[\\uDFFE\\uDFFF]|(?:\\uDBBF' +
173
+ '[\\uDFFE\\uDFFF])|\\uDBFF[\\uDFFE\\uDFFF](?:[\\0-\\t\\v\\f\\x0E-\\u2027\\u202A-\\uD7FF\\' +
174
+ 'uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|' +
175
+ '(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))',
176
+ 'g',
177
+ );
178
+
179
+ value = value.replace(regex, '');
180
+ }
181
+
182
+ return value;
183
+ }
184
+
185
+ function escapeXML(value: string | number): string {
186
+ return removeInvalidXMLCharacters(
187
+ String(value)
188
+ .replace(/&/g, '&amp;')
189
+ .replace(/"/g, '&quot;')
190
+ .replace(/'/g, '&apos;')
191
+ .replace(/</g, '&lt;')
192
+ .replace(/>/g, '&gt;'),
193
+ true,
194
+ );
195
+ }
196
+
197
+ function executionTime(durationMS: number) {
198
+ return (durationMS / 1000).toLocaleString('en-US', {
199
+ useGrouping: false,
200
+ maximumFractionDigits: 10,
201
+ });
202
+ }
203
+
204
+ function getDuration(task: FakeTest): string | undefined {
205
+ const duration = task.duration ?? 0;
206
+ return executionTime(duration);
207
+ }
@@ -0,0 +1,74 @@
1
+ import { FakeTest, Images, isDefined, TEST_EVENTS } from '../../types.js';
2
+ import EventEmitter from 'events';
3
+
4
+ export class TeamcityReporter {
5
+ constructor(runner: EventEmitter, options: { reportDir: string }) {
6
+ const { reportDir } = options;
7
+
8
+ runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
9
+ console.log(`##teamcity[testStarted name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`);
10
+ });
11
+
12
+ runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
13
+ console.log(`##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`);
14
+ });
15
+
16
+ runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error: Error) => {
17
+ const browserName = this.escape(test.creevey.browserName);
18
+ Object.entries(test.creevey.images).forEach(([name, image]) => {
19
+ if (!image) return;
20
+ const filePath = test
21
+ .titlePath()
22
+ .slice(0, -1)
23
+ .concat(name == browserName ? [] : [browserName])
24
+ .map(this.escape)
25
+ .join('/');
26
+
27
+ const { error: _, ...rest } = image;
28
+ Object.values(rest as Partial<Images>)
29
+ .filter(isDefined)
30
+ .forEach((fileName) => {
31
+ console.log(`##teamcity[publishArtifacts '${reportDir}/${filePath}/${fileName} => report/${filePath}']`);
32
+ console.log(
33
+ `##teamcity[testMetadata testName='${this.escape(
34
+ test.fullTitle(),
35
+ )}' type='image' value='report/${filePath}/${fileName}' flowId='${test.creevey.workerId}']`,
36
+ );
37
+ });
38
+ });
39
+
40
+ // Output failed test as passed due TC don't support retry mechanic
41
+ // 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
42
+
43
+ if (test.creevey.willRetry)
44
+ console.log(
45
+ `##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`,
46
+ );
47
+ else
48
+ console.log(
49
+ `##teamcity[testFailed name='${this.escape(test.fullTitle())}' message='${this.escape(
50
+ error.message,
51
+ )}' details='${this.escape(error.stack ?? '')}' flowId='${test.creevey.workerId}']`,
52
+ );
53
+ });
54
+ }
55
+
56
+ private escape = (str: string): string => {
57
+ if (!str) return '';
58
+ return (
59
+ str
60
+ .toString()
61
+ // eslint-disable-next-line no-control-regex
62
+ .replace(/\x1B.*?m/g, '')
63
+ .replace(/\|/g, '||')
64
+ .replace(/\n/g, '|n')
65
+ .replace(/\r/g, '|r')
66
+ .replace(/\[/g, '|[')
67
+ .replace(/\]/g, '|]')
68
+ .replace(/\u0085/g, '|x')
69
+ .replace(/\u2028/g, '|l')
70
+ .replace(/\u2029/g, '|p')
71
+ .replace(/'/g, "|'")
72
+ );
73
+ };
74
+ }
@@ -1,4 +1,4 @@
1
- import { Args } from '@storybook/csf';
1
+ import type { Args } from 'storybook/internal/types';
2
2
  import chalk from 'chalk';
3
3
  import http from 'http';
4
4
  import https from 'https';
@@ -19,12 +19,12 @@ import {
19
19
  StorybookGlobals,
20
20
  StoryInput,
21
21
  StoriesRaw,
22
- Options,
22
+ WorkerOptions,
23
23
  ServerTest,
24
24
  StorybookEvents,
25
25
  } from '../../types.js';
26
26
  import { colors, logger } from '../logger.js';
27
- import { subscribeOn } from '../messages.js';
27
+ import { emitWorkerMessage, subscribeOn } from '../messages.js';
28
28
  import { getTestPath, isShuttingDown, runSequence } from '../utils.js';
29
29
  import {
30
30
  appendIframePath,
@@ -97,7 +97,7 @@ async function buildWebdriver(
97
97
  browser: string,
98
98
  gridUrl: string,
99
99
  config: Config,
100
- options: Options,
100
+ options: WorkerOptions,
101
101
  ): Promise<WebDriver | null> {
102
102
  const browserConfig = config.browsers[browser] as BrowserConfigObject;
103
103
  const { /*customizeBuilder,*/ seleniumCapabilities, browserName } = browserConfig;
@@ -191,11 +191,13 @@ export class InternalBrowser {
191
191
  #browser: WebDriver;
192
192
  #serverHost: string | null = null;
193
193
  #serverPort: number;
194
+ #storybookGlobals?: StorybookGlobals;
194
195
  #unsubscribe: () => void = noop;
195
196
  #keepAliveInterval: NodeJS.Timeout | null = null;
196
- constructor(browser: WebDriver, port: number) {
197
+ constructor(browser: WebDriver, port: number, storybookGlobals?: StorybookGlobals) {
197
198
  this.#browser = browser;
198
199
  this.#serverPort = port;
200
+ this.#storybookGlobals = storybookGlobals;
199
201
  this.#unsubscribe = subscribeOn('shutdown', () => {
200
202
  void this.closeBrowser();
201
203
  });
@@ -247,7 +249,7 @@ export class InternalBrowser {
247
249
  const rects = await this.#browser.executeScript<
248
250
  { elementRect: ElementRect; windowRect: ElementRect } | undefined
249
251
  >(function (selector: string): { elementRect: ElementRect; windowRect: ElementRect } | undefined {
250
- window.scrollTo(0, 0); // TODO Maybe we should remove same code from `resetMousePosition`
252
+ window.scrollTo(0, 0);
251
253
  // eslint-disable-next-line no-var
252
254
  var element = document.querySelector(selector);
253
255
  if (!element) return;
@@ -264,9 +266,7 @@ export class InternalBrowser {
264
266
  },
265
267
  // NOTE page_Offset is used only for IE9-11
266
268
  windowRect: {
267
- // eslint-disable-next-line @typescript-eslint/no-deprecated
268
269
  top: Math.round(window.scrollY || window.pageYOffset),
269
- // eslint-disable-next-line @typescript-eslint/no-deprecated
270
270
  left: Math.round(window.scrollX || window.pageXOffset),
271
271
  width: window.innerWidth,
272
272
  height: window.innerHeight,
@@ -295,12 +295,10 @@ export class InternalBrowser {
295
295
  // ? context
296
296
  // ? await context.captureElementScreenshot(await element.getId())
297
297
  // : await browser.findElement(By.css(captureElement)).takeScreenshot()
298
- // : // TODO pointer-events: none, need to research
299
- // await takeCompositeScreenshot(browser, windowRect, elementRect);
298
+ // : await takeCompositeScreenshot(browser, windowRect, elementRect);
300
299
  screenshot = isFitIntoViewport
301
300
  ? await this.#browser.findElement(By.css(captureElement)).takeScreenshot()
302
- : // TODO pointer-events: none, need to research
303
- await this.takeCompositeScreenshot(windowRect, elementRect);
301
+ : await this.takeCompositeScreenshot(windowRect, elementRect);
304
302
 
305
303
  logger().debug(`${chalk.cyan(captureElement)} is captured`);
306
304
  }
@@ -321,6 +319,7 @@ export class InternalBrowser {
321
319
 
322
320
  async selectStory(id: string, waitForReady = false): Promise<boolean> {
323
321
  // NOTE: Global variables might be reset after hot reload. I think it's workaround, maybe we need better solution
322
+ await this.updateStorybookGlobals();
324
323
  await this.updateBrowserGlobalVariables();
325
324
  await this.resetMousePosition();
326
325
 
@@ -374,12 +373,32 @@ export class InternalBrowser {
374
373
  }
375
374
 
376
375
  async loadStoriesFromBrowser(): Promise<StoriesRaw> {
377
- const stories = await this.#browser.executeAsyncScript<StoriesRaw | undefined>(function (
378
- callback: (stories: StoriesRaw | undefined) => void,
376
+ const result = await this.#browser.executeAsyncScript<
377
+ [error?: { message: string; stack?: string } | null, stories?: StoriesRaw]
378
+ >(function (
379
+ callback: (response: [error?: { message: string; stack?: string } | null, stories?: StoriesRaw]) => void,
379
380
  ) {
380
- void window.__CREEVEY_GET_STORIES__().then(callback);
381
+ window
382
+ .__CREEVEY_GET_STORIES__()
383
+ .then((stories) => {
384
+ callback([null, stories]);
385
+ })
386
+ .catch((error: unknown) => {
387
+ const errorInfo = {
388
+ message: error instanceof Error ? error.message : String(error),
389
+ stack: error instanceof Error ? error.stack : undefined,
390
+ };
391
+ callback([errorInfo]);
392
+ });
381
393
  });
382
394
 
395
+ const [error, stories] = result;
396
+
397
+ if (error) {
398
+ const errorObj = new Error(error.message);
399
+ if (error.stack) errorObj.stack = error.stack;
400
+ throw errorObj;
401
+ }
383
402
  if (!stories) throw new Error("Can't get stories, it seems creevey or storybook API isn't available");
384
403
 
385
404
  return stories;
@@ -407,17 +426,24 @@ export class InternalBrowser {
407
426
  browserName: string,
408
427
  gridUrl: string,
409
428
  config: Config,
410
- options: Options,
429
+ options: WorkerOptions,
411
430
  ): Promise<InternalBrowser | null> {
412
431
  const browserConfig = config.browsers[browserName] as BrowserConfigObject;
413
- const { storybookUrl: address = config.storybookUrl, limit, viewport, _storybookGlobals } = browserConfig;
432
+ const {
433
+ storybookUrl: address = config.storybookUrl,
434
+ limit,
435
+ viewport,
436
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
437
+ _storybookGlobals,
438
+ storybookGlobals = _storybookGlobals,
439
+ } = browserConfig;
414
440
  void limit;
415
441
 
416
442
  const browser = await buildWebdriver(browserName, gridUrl, config, options);
417
443
 
418
444
  if (!browser) return null;
419
445
 
420
- const internalBrowser = new InternalBrowser(browser, options.port);
446
+ const internalBrowser = new InternalBrowser(browser, options.port, storybookGlobals);
421
447
 
422
448
  try {
423
449
  if (isShuttingDown.current) return null;
@@ -427,8 +453,6 @@ export class InternalBrowser {
427
453
  gridUrl,
428
454
  viewport,
429
455
  storybookUrl: address,
430
- storybookGlobals: _storybookGlobals,
431
- resolveStorybookUrl: config.resolveStorybookUrl,
432
456
  });
433
457
 
434
458
  return done ? internalBrowser : null;
@@ -451,15 +475,11 @@ export class InternalBrowser {
451
475
  gridUrl,
452
476
  viewport,
453
477
  storybookUrl,
454
- storybookGlobals,
455
- resolveStorybookUrl,
456
478
  }: {
457
479
  browserName: string;
458
480
  gridUrl: string;
459
481
  viewport?: { width: number; height: number };
460
482
  storybookUrl: string;
461
- storybookGlobals?: StorybookGlobals;
462
- resolveStorybookUrl?: () => Promise<string>;
463
483
  }): Promise<boolean> {
464
484
  const sessionId = (await this.#browser.getSession()).getId();
465
485
  let browserHost = '';
@@ -483,9 +503,9 @@ export class InternalBrowser {
483
503
  return await runSequence(
484
504
  [
485
505
  () => this.#browser.manage().setTimeouts({ pageLoad: 60000, script: 60000 }),
486
- () => this.openStorybookPage(storybookUrl, resolveStorybookUrl),
506
+ () => this.openStorybookPage(storybookUrl),
487
507
  () => this.waitForStorybook(),
488
- () => this.updateStorybookGlobals(storybookGlobals),
508
+ () => this.updateStorybookGlobals(),
489
509
  () => this.resolveCreeveyHost(),
490
510
  () => this.updateBrowserGlobalVariables(),
491
511
  // NOTE: Selenium draws automation toolbar with some delay after webdriver initialization
@@ -500,25 +520,14 @@ export class InternalBrowser {
500
520
  );
501
521
  }
502
522
 
503
- private async openStorybookPage(storybookUrl: string, resolver?: () => Promise<string>): Promise<void> {
523
+ private async openStorybookPage(storybookUrl: string): Promise<void> {
504
524
  if (!LOCALHOST_REGEXP.test(storybookUrl)) {
505
525
  return this.#browser.get(appendIframePath(storybookUrl));
506
526
  }
507
527
 
508
528
  try {
509
- if (resolver) {
510
- logger().debug('Resolving storybook url with custom resolver');
511
-
512
- const resolvedUrl = await resolver();
513
-
514
- logger().debug(`Resolver storybook url ${resolvedUrl}`);
515
-
516
- await this.#browser.get(appendIframePath(resolvedUrl));
517
- } else {
518
- // TODO Pageload timeout 10s
519
- // NOTE: getUrlChecker already calls `browser.get` so we don't need another one
520
- await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
521
- }
529
+ // NOTE: getUrlChecker already calls `browser.get` so we don't need another one
530
+ await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
522
531
  } catch (error) {
523
532
  logger().error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
524
533
  throw error;
@@ -554,7 +563,7 @@ export class InternalBrowser {
554
563
  }
555
564
 
556
565
  private async waitForStorybook(): Promise<void> {
557
- logger().debug('Waiting for `setStories` event to make sure that storybook is initiated');
566
+ logger().debug('Waiting for Storybook to initiate');
558
567
 
559
568
  const isTimeout = await Promise.race([
560
569
  new Promise<boolean>((resolve) => {
@@ -567,9 +576,6 @@ export class InternalBrowser {
567
576
  do {
568
577
  // TODO Research a different way to ensure storybook is initiated
569
578
  wait = await this.#browser.executeScript<boolean>(function (SET_GLOBALS: string): boolean {
570
- // TODO Maybe use
571
- // import { global } from '@storybook/global';
572
- // global.IS_STORYBOOK
573
579
  if (typeof window.__STORYBOOK_ADDONS_CHANNEL__ == 'undefined') return true;
574
580
  if (window.__STORYBOOK_ADDONS_CHANNEL__.last(SET_GLOBALS) == undefined) return true;
575
581
  return false;
@@ -579,21 +585,22 @@ export class InternalBrowser {
579
585
  })(),
580
586
  ]);
581
587
 
582
- // TODO Change the message to describe a reason why it might happen
583
- if (isTimeout) throw new Error('Failed to wait `setStories` event');
588
+ if (isTimeout) throw new Error('Failed to wait Storybook init');
584
589
  }
585
590
 
586
- private async updateStorybookGlobals(globals?: StorybookGlobals): Promise<void> {
587
- if (!globals) return;
591
+ private async updateStorybookGlobals(): Promise<void> {
592
+ if (!this.#storybookGlobals) return;
588
593
 
589
594
  logger().debug('Applying storybook globals');
590
595
  await this.#browser.executeScript(function (globals: StorybookGlobals) {
591
596
  window.__CREEVEY_UPDATE_GLOBALS__(globals);
592
- }, globals);
597
+ }, this.#storybookGlobals);
593
598
  }
594
599
 
595
600
  private async resolveCreeveyHost(): Promise<void> {
596
- const addresses = getAddresses();
601
+ const storybookUrl = await this.#browser.getCurrentUrl();
602
+ const storybookHost = new URL(storybookUrl).hostname;
603
+ const addresses = [storybookHost, ...getAddresses()];
597
604
 
598
605
  this.#serverHost = await this.#browser.executeAsyncScript(
599
606
  function (hosts: string[], port: number, callback: (host?: string | null) => void) {
@@ -633,6 +640,7 @@ export class InternalBrowser {
633
640
  private async updateBrowserGlobalVariables() {
634
641
  await this.#browser.executeScript(
635
642
  function (workerId: number, creeveyHost: string, creeveyPort: number) {
643
+ window.__CREEVEY_ENV__ = true;
636
644
  window.__CREEVEY_WORKER_ID__ = workerId;
637
645
  window.__CREEVEY_SERVER_HOST__ = creeveyHost;
638
646
  window.__CREEVEY_SERVER_PORT__ = creeveyPort;
@@ -831,9 +839,18 @@ export class InternalBrowser {
831
839
  private keepAlive(): void {
832
840
  this.#keepAliveInterval = setInterval(() => {
833
841
  // NOTE Simple way to keep session alive
834
- void this.#browser.getCurrentUrl().then((url) => {
835
- logger().debug('current url', chalk.magenta(url));
836
- });
842
+ void this.#browser
843
+ .getCurrentUrl()
844
+ .then((url) => {
845
+ logger().debug('current url', chalk.magenta(url));
846
+ })
847
+ .catch((error: unknown) => {
848
+ logger().error(error);
849
+ emitWorkerMessage({
850
+ type: 'error',
851
+ payload: { subtype: 'browser', error: 'Failed to ping browser' },
852
+ });
853
+ });
837
854
  }, 10 * 1000);
838
855
  }
839
856
  }