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,316 @@
1
+ import path from 'path';
2
+ import { mkdirSync, writeFileSync } from 'fs';
3
+ import EventEmitter from 'events';
4
+ import {
5
+ ServerTest,
6
+ TestMeta,
7
+ TestResult,
8
+ TestStatus,
9
+ CreeveyUpdate,
10
+ ApprovePayload,
11
+ isDefined,
12
+ isFunction,
13
+ CreeveyStatus,
14
+ } from '../../types.js';
15
+ import { tryToLoadTestsData } from '../utils.js';
16
+ import { copyFile, mkdir, writeFile } from 'fs/promises';
17
+
18
+ /**
19
+ * TestsManager is responsible for all operations related to test data management
20
+ * including loading, saving, merging, and updating test data.
21
+ * It extends EventEmitter to emit update events that can be subscribed to.
22
+ */
23
+ export class TestsManager extends EventEmitter {
24
+ private tests: Partial<Record<string, ServerTest>> = {};
25
+ private screenDir: string;
26
+ private reportDir: string;
27
+
28
+ /**
29
+ * Creates a new TestsManager instance
30
+ * @param screenDir Directory for storing reference images
31
+ * @param reportDir Directory for storing reports and screenshots
32
+ */
33
+ constructor(screenDir: string, reportDir: string) {
34
+ super();
35
+ this.screenDir = screenDir;
36
+ this.reportDir = reportDir;
37
+ }
38
+
39
+ /**
40
+ * Get a copy of all tests
41
+ * @returns all tests
42
+ */
43
+ public getTests(): Partial<Record<string, ServerTest>> {
44
+ return this.tests;
45
+ }
46
+
47
+ /**
48
+ * Get a test by ID
49
+ * @param id Test ID
50
+ * @returns Test data
51
+ */
52
+ public getTest(id: string): ServerTest | undefined {
53
+ return this.tests[id];
54
+ }
55
+
56
+ /**
57
+ * Get test data in a format suitable for status reporting
58
+ * @returns Test data in the format needed for status
59
+ */
60
+ public getTestsData(): CreeveyStatus['tests'] {
61
+ const testsData: CreeveyStatus['tests'] = {};
62
+
63
+ Object.entries(this.tests).forEach(([id, test]) => {
64
+ if (!test) return;
65
+
66
+ const { story: _, fn: __, ...testData } = test;
67
+ testsData[id] = testData;
68
+ });
69
+
70
+ return testsData;
71
+ }
72
+
73
+ /**
74
+ * Load tests from a report file
75
+ */
76
+ public loadTestsFromReport(): Partial<Record<string, ServerTest>> {
77
+ // TODO: Move to utils
78
+ const reportDataPath = path.join(this.reportDir, 'data.js');
79
+ const testsFromReport = tryToLoadTestsData(reportDataPath) ?? {};
80
+ return testsFromReport;
81
+ }
82
+
83
+ /**
84
+ * Merge tests from report with tests from stories
85
+ */
86
+ private mergeTests(
87
+ testsWithReports: CreeveyStatus['tests'],
88
+ testsFromStories: Partial<Record<string, ServerTest>>,
89
+ ): Partial<Record<string, ServerTest>> {
90
+ Object.values(testsFromStories)
91
+ .filter(isDefined)
92
+ .forEach((test) => {
93
+ const testWithReport = testsWithReports[test.id];
94
+ if (!testWithReport) return;
95
+ test.retries = testWithReport.retries;
96
+ if (testWithReport.status === 'success' || testWithReport.status === 'failed') {
97
+ test.status = testWithReport.status;
98
+ }
99
+ test.results = testWithReport.results;
100
+ test.approved = testWithReport.approved;
101
+ });
102
+
103
+ return testsFromStories;
104
+ }
105
+
106
+ public loadAndMergeTests(testsFromStories: Partial<Record<string, ServerTest>>): Partial<Record<string, ServerTest>> {
107
+ const testsFromReport = this.loadTestsFromReport();
108
+
109
+ return this.mergeTests(testsFromReport, testsFromStories);
110
+ }
111
+
112
+ /**
113
+ * Update tests with incremental changes
114
+ * @param testsDiff Tests to update or remove
115
+ */
116
+ public updateTests(testsDiff: Partial<Record<string, ServerTest>>): CreeveyUpdate | null {
117
+ const tests: CreeveyUpdate['tests'] = {};
118
+ const removedTests: TestMeta[] = [];
119
+
120
+ Object.entries(testsDiff).forEach(([id, newTest]) => {
121
+ if (newTest) {
122
+ if (this.tests[id]) {
123
+ this.tests[id] = {
124
+ ...newTest,
125
+ retries: this.tests[id].retries,
126
+ results: this.tests[id].results,
127
+ approved: this.tests[id].approved,
128
+ };
129
+ } else {
130
+ this.tests[id] = newTest;
131
+ }
132
+
133
+ const { story: _, fn: __, ...restTest } = newTest;
134
+ tests[id] = { ...restTest, status: 'unknown' };
135
+ } else if (this.tests[id]) {
136
+ const { id: testId, browser, testName, storyPath, storyId } = this.tests[id];
137
+ removedTests.push({ id: testId, browser, testName, storyPath, storyId });
138
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
139
+ delete this.tests[id];
140
+ }
141
+ });
142
+
143
+ this.saveTestsToJson();
144
+
145
+ const update = { tests, removedTests };
146
+ this.emit('update', update);
147
+ return update;
148
+ }
149
+
150
+ /**
151
+ * Update test result
152
+ * @param id Test ID
153
+ * @param status New test status
154
+ * @param result Optional test result
155
+ */
156
+ public updateTestStatus(id: string, status: TestStatus, result?: TestResult): CreeveyUpdate | null {
157
+ // TODO Handle 'retrying' status
158
+ const test = this.tests[id];
159
+ if (!test) return null;
160
+
161
+ const { browser, testName, storyPath, storyId } = test;
162
+ test.status = status === 'retrying' ? 'failed' : status;
163
+
164
+ if (!result) {
165
+ // NOTE: Running status
166
+ const update = { tests: { [id]: { id, browser, testName, storyPath, status, storyId } } };
167
+ this.emit('update', update);
168
+ return update;
169
+ }
170
+
171
+ test.results ??= [];
172
+ test.results.push(result);
173
+
174
+ if (status === 'failed') {
175
+ test.approved = null;
176
+ }
177
+
178
+ const update = {
179
+ tests: {
180
+ [id]: {
181
+ id,
182
+ browser,
183
+ testName,
184
+ storyPath,
185
+ status,
186
+ approved: test.approved,
187
+ results: [result],
188
+ storyId,
189
+ },
190
+ },
191
+ };
192
+
193
+ this.emit('update', update);
194
+ return update;
195
+ }
196
+
197
+ /**
198
+ * Save tests to JSON file
199
+ * @param reportDir Directory to save the JSON file
200
+ */
201
+ public saveTestsToJson(): void {
202
+ mkdirSync(this.reportDir, { recursive: true });
203
+ writeFileSync(
204
+ path.join(this.reportDir, 'tests.json'),
205
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
206
+ JSON.stringify(this.tests, (_, value) => (isFunction(value) ? value.toString() : value), 2),
207
+ );
208
+ }
209
+
210
+ /**
211
+ * Save test data to a module
212
+ * @param data Test data to include in the module
213
+ */
214
+ public async saveTestData(data: CreeveyStatus['tests'] = this.getTestsData()): Promise<void> {
215
+ const dataModule = `
216
+ (function (root, factory) {
217
+ if (typeof module === 'object' && module.exports) {
218
+ module.exports = factory();
219
+ } else {
220
+ root.__CREEVEY_DATA__ = factory();
221
+ }
222
+ }(this, function () { return ${JSON.stringify(data)} }));
223
+ `;
224
+ await writeFile(path.join(this.reportDir, 'data.js'), dataModule);
225
+ }
226
+
227
+ /**
228
+ * Copy image for approval
229
+ * @param test Test data
230
+ * @param image Image name
231
+ * @param actual Actual image path
232
+ */
233
+ private async copyImage(test: ServerTest, image: string, actual: string): Promise<void> {
234
+ const { browser, testName, storyPath } = test;
235
+ const restPath = [...storyPath, testName].filter(isDefined);
236
+ const testPath = path.join(...restPath, image == browser ? '' : browser);
237
+ const srcImagePath = path.join(this.reportDir, testPath, actual);
238
+ const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
239
+ await mkdir(path.join(this.screenDir, testPath), { recursive: true });
240
+ await copyFile(srcImagePath, dstImagePath);
241
+ }
242
+
243
+ /**
244
+ * Approve a specific test
245
+ * @param payload Approval payload with test ID, retry index, and image name
246
+ */
247
+ public async approve({ id, retry, image }: ApprovePayload): Promise<CreeveyUpdate | null> {
248
+ const test = this.tests[id];
249
+ if (!test?.results) return null;
250
+ const result = test.results[retry];
251
+ if (!result.images) return null;
252
+ const images = result.images[image];
253
+ if (!images) return null;
254
+ test.approved ??= {};
255
+ const { browser, testName, storyPath, storyId } = test;
256
+
257
+ await this.copyImage(test, image, images.actual);
258
+
259
+ test.approved[image] = retry;
260
+
261
+ if (Object.keys(result.images).every((name) => typeof test.approved?.[name] == 'number')) {
262
+ test.status = 'approved';
263
+ }
264
+
265
+ const update = {
266
+ tests: {
267
+ [id]: {
268
+ id,
269
+ browser,
270
+ testName,
271
+ storyPath,
272
+ status: test.status,
273
+ approved: test.approved,
274
+ storyId,
275
+ },
276
+ },
277
+ };
278
+
279
+ this.emit('update', update);
280
+ return update;
281
+ }
282
+
283
+ /**
284
+ * Approve all failed tests
285
+ */
286
+ public async approveAll(): Promise<CreeveyUpdate> {
287
+ const updatedTests: NonNullable<CreeveyUpdate['tests']> = {};
288
+ for (const test of Object.values(this.tests)) {
289
+ if (!test?.results) continue;
290
+ const retry = test.results.length - 1;
291
+ const { images, status } = test.results.at(retry) ?? {};
292
+ if (!images || status != 'failed') continue;
293
+ for (const [name, image] of Object.entries(images)) {
294
+ if (!image) continue;
295
+ await this.copyImage(test, name, image.actual);
296
+
297
+ test.approved ??= {};
298
+ test.approved[name] = retry;
299
+ test.status = 'approved';
300
+
301
+ updatedTests[test.id] = {
302
+ id: test.id,
303
+ browser: test.browser,
304
+ storyPath: test.storyPath,
305
+ storyId: test.storyId,
306
+ status: test.status,
307
+ approved: { [name]: retry },
308
+ };
309
+ }
310
+ }
311
+
312
+ const result = { tests: updatedTests };
313
+ this.emit('update', result);
314
+ return result;
315
+ }
316
+ }
@@ -1,34 +1,46 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { pathToFileURL } from 'url';
1
3
  import semver from 'semver';
2
- import { exec } from 'shelljs';
4
+ import sh from 'shelljs';
5
+
6
+ const importMetaUrl = pathToFileURL(__filename).href;
3
7
 
4
8
  // TODO Support custom docker images
5
- export function playwrightDockerFile(browser: string, version: string): string {
9
+ export async function playwrightDockerFile(browser: string, version: string): Promise<string> {
6
10
  const sv = semver.coerce(version);
7
11
 
8
12
  let npmRegistry;
9
13
  try {
10
- npmRegistry = exec('npm config get registry', { silent: true }).stdout.trim();
14
+ npmRegistry = sh.exec('npm config get registry', { silent: true }).stdout.trim();
11
15
  } catch {
12
16
  /* noop */
13
17
  }
14
18
 
15
- return `
16
- FROM mcr.microsoft.com/playwright:v${sv?.format() ?? version}
19
+ const indexJs = await readFile(new URL('./index-source.mjs', importMetaUrl), 'utf-8');
20
+
21
+ const dockerfile = `
22
+ FROM node:lts
17
23
 
18
24
  WORKDIR /creevey
19
25
 
20
26
  RUN echo "{ \\"type\\": \\"module\\" }" > package.json && \\
21
- echo "import { ${browser} as browser } from 'playwright-core';" >> index.js && \\
22
- echo "const ws = await browser.launchServer({ port: 4444, wsPath: 'creevey' })" >> index.js && \\${
27
+ ${indexJs
28
+ .split('\n')
29
+ .map((line) => ` echo "${line.replace(/"/g, '\\"')}" >> index.js && \\`)
30
+ .join('\n')}
31
+ ${
23
32
  npmRegistry
24
33
  ? `
25
34
  echo "registry=${npmRegistry}" > .npmrc && \\`
26
35
  : ''
27
36
  }
28
- npm i playwright-core${sv ? `@${sv.format()}` : ''}
37
+ npm i playwright-core${sv ? `@${sv.format()}` : ''} && \\
38
+ npx -y playwright${sv ? `@${sv.format()}` : ''} install --with-deps ${browser}
29
39
 
30
40
  EXPOSE 4444
31
41
 
32
42
  ENTRYPOINT [ "node", "./index.js" ]
33
43
  `;
44
+
45
+ return dockerfile.replace(/\\\n\s*\\?\n/g, '\\\n');
34
46
  }
@@ -1,9 +1,17 @@
1
+ import assert from 'assert';
1
2
  import { runImage } from '../docker';
2
3
  import { emitWorkerMessage, subscribeOn } from '../messages';
3
- import { isInsideDocker } from '../utils';
4
+ import { getCreeveyCache, isInsideDocker, resolvePlaywrightBrowserType } from '../utils';
4
5
  import { LOCALHOST_REGEXP } from '../webdriver';
6
+ import type { BrowserConfigObject, Config } from '../../types';
5
7
 
6
- export async function startPlaywrightContainer(imageName: string, debug: boolean): Promise<string> {
8
+ export async function startPlaywrightContainer(
9
+ imageName: string,
10
+ browser: string,
11
+ config: Config,
12
+ debug: boolean,
13
+ ): Promise<string> {
14
+ const { browserName, playwrightOptions } = config.browsers[browser] as BrowserConfigObject;
7
15
  const port = await new Promise<number>((resolve) => {
8
16
  subscribeOn('worker', (message) => {
9
17
  if (message.type == 'port') {
@@ -13,13 +21,18 @@ export async function startPlaywrightContainer(imageName: string, debug: boolean
13
21
  emitWorkerMessage({ type: 'port', payload: { port: -1 } });
14
22
  });
15
23
 
24
+ const cacheDir = await getCreeveyCache();
25
+
26
+ assert(cacheDir, "Couldn't get cache directory");
27
+
16
28
  const host = await runImage(
17
29
  imageName,
18
- [],
30
+ [JSON.stringify({ ...playwrightOptions, browser: resolvePlaywrightBrowserType(browserName) })],
19
31
  {
20
32
  ExposedPorts: { [`${port}/tcp`]: {} },
21
33
  HostConfig: {
22
34
  PortBindings: { ['4444/tcp']: [{ HostPort: `${port}` }] },
35
+ Binds: [`${cacheDir}/${process.pid}:/creevey/traces`],
23
36
  },
24
37
  },
25
38
  debug,
@@ -0,0 +1,16 @@
1
+ import { chromium, firefox, webkit } from 'playwright-core';
2
+
3
+ /** @type import("playwright-core").LaunchOptions & { browser: 'chromium' | 'firefox' | 'webkit' } */
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
5
+ const config = JSON.parse(process.argv.slice(2)[0]);
6
+
7
+ const browsers = { chromium, firefox, webkit };
8
+
9
+ const ws = await browsers[config.browser].launchServer({
10
+ ...config,
11
+ port: 4444,
12
+ wsPath: 'creevey',
13
+ tracesDir: 'traces',
14
+ });
15
+
16
+ console.log(config.browser, 'browser server launched on:', ws.wsEndpoint());