plum-e2e 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +142 -70
  2. package/backend/Dockerfile +4 -2
  3. package/backend/_scaffold/utils/browser.ts +1 -0
  4. package/backend/app.js +4 -2
  5. package/backend/config/scripts/generate-report.js +38 -30
  6. package/{.prettierignore → backend/entrypoint.sh} +7 -6
  7. package/backend/package-lock.json +453 -10
  8. package/backend/package.json +5 -2
  9. package/backend/prisma/migrations/20260614000000_init/migration.sql +35 -0
  10. package/backend/prisma/migrations/20260614000001_add_project/migration.sql +8 -0
  11. package/backend/prisma/migrations/migration_lock.toml +3 -0
  12. package/backend/prisma/schema.prisma +53 -0
  13. package/backend/routes/backup.routes.js +50 -0
  14. package/backend/routes/cron.routes.js +9 -60
  15. package/backend/routes/reports.routes.js +39 -6
  16. package/backend/routes/settings.routes.js +43 -0
  17. package/backend/server.js +52 -1
  18. package/backend/services/backupService.js +88 -0
  19. package/backend/services/cronService.js +68 -78
  20. package/backend/{routes/schedules.routes.js → services/prisma.js} +3 -13
  21. package/backend/services/reportService.js +48 -20
  22. package/backend/services/settingsService.js +36 -0
  23. package/bin/plum.js +216 -34
  24. package/docker-compose.yml +24 -0
  25. package/frontend/.svelte-kit/adapter-node/.vite/manifest.json +190 -0
  26. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
  27. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/Button.cBruH0aD.css +17 -0
  28. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
  29. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.BVnUajEa.css +17 -0
  30. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
  31. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
  32. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
  33. package/frontend/.svelte-kit/adapter-node/chunks/Badge.js +30 -0
  34. package/frontend/.svelte-kit/adapter-node/chunks/Button.js +32 -0
  35. package/frontend/.svelte-kit/adapter-node/chunks/attributes.js +34 -0
  36. package/frontend/.svelte-kit/adapter-node/chunks/client.js +59 -0
  37. package/{backend/services/scheduleService.js → frontend/.svelte-kit/adapter-node/chunks/equality.js} +13 -16
  38. package/frontend/.svelte-kit/adapter-node/chunks/escaping.js +36 -0
  39. package/frontend/.svelte-kit/adapter-node/chunks/exports.js +247 -0
  40. package/frontend/.svelte-kit/adapter-node/chunks/index.js +1135 -0
  41. package/frontend/.svelte-kit/adapter-node/chunks/internal.js +695 -0
  42. package/frontend/.svelte-kit/adapter-node/chunks/reports.js +57 -0
  43. package/frontend/.svelte-kit/adapter-node/entries/fallbacks/error.svelte.js +44 -0
  44. package/frontend/.svelte-kit/adapter-node/entries/pages/_layout.svelte.js +181 -0
  45. package/frontend/.svelte-kit/adapter-node/entries/pages/_page.svelte.js +164 -0
  46. package/frontend/.svelte-kit/adapter-node/entries/pages/reports/_page.svelte.js +141 -0
  47. package/frontend/.svelte-kit/adapter-node/entries/pages/reports/_slug_/_page.svelte.js +42 -0
  48. package/frontend/.svelte-kit/adapter-node/entries/pages/scheduled-tests/_page.svelte.js +179 -0
  49. package/frontend/.svelte-kit/adapter-node/index.js +3144 -0
  50. package/frontend/.svelte-kit/adapter-node/internal.js +30 -0
  51. package/frontend/.svelte-kit/adapter-node/manifest-full.js +77 -0
  52. package/frontend/.svelte-kit/adapter-node/manifest.js +81 -0
  53. package/frontend/.svelte-kit/adapter-node/nodes/0.js +25 -0
  54. package/frontend/.svelte-kit/adapter-node/nodes/1.js +25 -0
  55. package/frontend/.svelte-kit/adapter-node/nodes/2.js +25 -0
  56. package/frontend/.svelte-kit/adapter-node/nodes/3.js +25 -0
  57. package/frontend/.svelte-kit/adapter-node/nodes/4.js +25 -0
  58. package/frontend/.svelte-kit/adapter-node/nodes/5.js +25 -0
  59. package/frontend/.svelte-kit/ambient.d.ts +240 -0
  60. package/frontend/.svelte-kit/generated/client/app.js +51 -0
  61. package/frontend/.svelte-kit/generated/client/matchers.js +18 -0
  62. package/frontend/.svelte-kit/generated/client/nodes/0.js +18 -0
  63. package/frontend/.svelte-kit/generated/client/nodes/1.js +18 -0
  64. package/frontend/.svelte-kit/generated/client/nodes/2.js +18 -0
  65. package/frontend/.svelte-kit/generated/client/nodes/3.js +18 -0
  66. package/frontend/.svelte-kit/generated/client/nodes/4.js +18 -0
  67. package/frontend/.svelte-kit/generated/client/nodes/5.js +18 -0
  68. package/frontend/.svelte-kit/generated/client-optimized/app.js +51 -0
  69. package/frontend/.svelte-kit/generated/client-optimized/matchers.js +18 -0
  70. package/frontend/.svelte-kit/generated/client-optimized/nodes/0.js +18 -0
  71. package/frontend/.svelte-kit/generated/client-optimized/nodes/1.js +18 -0
  72. package/frontend/.svelte-kit/generated/client-optimized/nodes/2.js +18 -0
  73. package/frontend/.svelte-kit/generated/client-optimized/nodes/3.js +18 -0
  74. package/frontend/.svelte-kit/generated/client-optimized/nodes/4.js +18 -0
  75. package/frontend/.svelte-kit/generated/client-optimized/nodes/5.js +18 -0
  76. package/frontend/.svelte-kit/generated/root.js +20 -0
  77. package/frontend/.svelte-kit/generated/root.svelte +83 -0
  78. package/frontend/.svelte-kit/generated/server/internal.js +65 -0
  79. package/frontend/.svelte-kit/non-ambient.d.ts +42 -0
  80. package/frontend/.svelte-kit/output/client/.vite/manifest.json +289 -0
  81. package/frontend/.svelte-kit/output/client/_app/immutable/assets/0.CnXRuPt4.css +17 -0
  82. package/frontend/.svelte-kit/output/client/_app/immutable/assets/2.CGnCsn5q.css +17 -0
  83. package/frontend/.svelte-kit/output/client/_app/immutable/assets/3.BVnUajEa.css +17 -0
  84. package/frontend/.svelte-kit/output/client/_app/immutable/assets/4.DBhBrHFz.css +17 -0
  85. package/frontend/.svelte-kit/output/client/_app/immutable/assets/5.D93VAB-w.css +17 -0
  86. package/frontend/.svelte-kit/output/client/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
  87. package/frontend/.svelte-kit/output/client/_app/immutable/assets/Button.cBruH0aD.css +17 -0
  88. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
  89. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.BVnUajEa.css +17 -0
  90. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
  91. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
  92. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
  93. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/B0bn91RF.js +18 -0
  94. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/B1kE5jmt.js +23 -0
  95. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BKz6FZdB.js +18 -0
  96. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Be4iUAB0.js +18 -0
  97. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BpaMqo9O.js +18 -0
  98. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Bt3-Z7H1.js +18 -0
  99. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CHV2KnPr.js +18 -0
  100. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CJ8q7g9Y.js +18 -0
  101. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Cit9MuSg.js +20 -0
  102. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CwBTqcbj.js +18 -0
  103. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DBk3zeq4.js +18 -0
  104. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DFJLQFic.js +18 -0
  105. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DTUE7kkY.js +18 -0
  106. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/IYPwzKs_.js +20 -0
  107. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/oc0we5Us.js +18 -0
  108. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/rVEKg0Ak.js +18 -0
  109. package/frontend/.svelte-kit/output/client/_app/immutable/entry/app.C2MbX06K.js +19 -0
  110. package/frontend/.svelte-kit/output/client/_app/immutable/entry/start.GiBry-lw.js +18 -0
  111. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/0.BsCYK-Tn.js +21 -0
  112. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/1.N4gjrCnX.js +18 -0
  113. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/2.D9yQNzK8.js +18 -0
  114. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/3.CBC5WvNb.js +18 -0
  115. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/4.BU6UZHSE.js +19 -0
  116. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/5.Dzzfrntl.js +18 -0
  117. package/frontend/.svelte-kit/output/client/_app/version.json +1 -0
  118. package/frontend/.svelte-kit/output/client/favicon.png +0 -0
  119. package/frontend/.svelte-kit/output/server/.vite/manifest.json +190 -0
  120. package/frontend/.svelte-kit/output/server/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
  121. package/frontend/.svelte-kit/output/server/_app/immutable/assets/Button.cBruH0aD.css +17 -0
  122. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
  123. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.BVnUajEa.css +17 -0
  124. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
  125. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
  126. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
  127. package/frontend/.svelte-kit/output/server/chunks/Badge.js +30 -0
  128. package/frontend/.svelte-kit/output/server/chunks/Button.js +32 -0
  129. package/frontend/.svelte-kit/output/server/chunks/attributes.js +34 -0
  130. package/frontend/.svelte-kit/output/server/chunks/client.js +59 -0
  131. package/frontend/.svelte-kit/output/server/chunks/equality.js +31 -0
  132. package/frontend/.svelte-kit/output/server/chunks/escaping.js +36 -0
  133. package/frontend/.svelte-kit/output/server/chunks/exports.js +247 -0
  134. package/frontend/.svelte-kit/output/server/chunks/index.js +1135 -0
  135. package/frontend/.svelte-kit/output/server/chunks/internal.js +695 -0
  136. package/frontend/.svelte-kit/output/server/chunks/reports.js +57 -0
  137. package/frontend/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +44 -0
  138. package/frontend/.svelte-kit/output/server/entries/pages/_layout.svelte.js +181 -0
  139. package/frontend/.svelte-kit/output/server/entries/pages/_page.svelte.js +164 -0
  140. package/frontend/.svelte-kit/output/server/entries/pages/reports/_page.svelte.js +141 -0
  141. package/frontend/.svelte-kit/output/server/entries/pages/reports/_slug_/_page.svelte.js +42 -0
  142. package/frontend/.svelte-kit/output/server/entries/pages/scheduled-tests/_page.svelte.js +179 -0
  143. package/frontend/.svelte-kit/output/server/index.js +3144 -0
  144. package/frontend/.svelte-kit/output/server/internal.js +30 -0
  145. package/frontend/.svelte-kit/output/server/manifest-full.js +77 -0
  146. package/frontend/.svelte-kit/output/server/manifest.js +77 -0
  147. package/frontend/.svelte-kit/output/server/nodes/0.js +25 -0
  148. package/frontend/.svelte-kit/output/server/nodes/1.js +25 -0
  149. package/frontend/.svelte-kit/output/server/nodes/2.js +25 -0
  150. package/frontend/.svelte-kit/output/server/nodes/3.js +25 -0
  151. package/frontend/.svelte-kit/output/server/nodes/4.js +25 -0
  152. package/frontend/.svelte-kit/output/server/nodes/5.js +25 -0
  153. package/frontend/.svelte-kit/tsconfig.json +49 -0
  154. package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css +17 -0
  155. package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css.br +0 -0
  156. package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css.gz +0 -0
  157. package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css +17 -0
  158. package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css.br +0 -0
  159. package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css.gz +0 -0
  160. package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css +17 -0
  161. package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css.br +0 -0
  162. package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css.gz +0 -0
  163. package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css +17 -0
  164. package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css.br +0 -0
  165. package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css.gz +0 -0
  166. package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css +17 -0
  167. package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css.br +0 -0
  168. package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css.gz +0 -0
  169. package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
  170. package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css.br +0 -0
  171. package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css.gz +0 -0
  172. package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css +17 -0
  173. package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css.br +0 -0
  174. package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css.gz +0 -0
  175. package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
  176. package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css.br +0 -0
  177. package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css.gz +0 -0
  178. package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css +17 -0
  179. package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css.br +0 -0
  180. package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css.gz +0 -0
  181. package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
  182. package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css.br +0 -0
  183. package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css.gz +0 -0
  184. package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
  185. package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css.br +0 -0
  186. package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css.gz +0 -0
  187. package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
  188. package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css.br +0 -0
  189. package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css.gz +0 -0
  190. package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js +18 -0
  191. package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js.br +0 -0
  192. package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js.gz +0 -0
  193. package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js +23 -0
  194. package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js.br +0 -0
  195. package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js.gz +0 -0
  196. package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js +18 -0
  197. package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js.br +0 -0
  198. package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js.gz +0 -0
  199. package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js +18 -0
  200. package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js.br +0 -0
  201. package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js.gz +0 -0
  202. package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js +18 -0
  203. package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js.br +0 -0
  204. package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js.gz +0 -0
  205. package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js +18 -0
  206. package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js.br +0 -0
  207. package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js.gz +0 -0
  208. package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js +18 -0
  209. package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js.br +18 -0
  210. package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js.gz +0 -0
  211. package/frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js +18 -0
  212. package/{resources/comments-format.text → frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js.br} +0 -0
  213. package/frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js.gz +0 -0
  214. package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js +20 -0
  215. package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js.br +0 -0
  216. package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js.gz +0 -0
  217. package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js +18 -0
  218. package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js.br +0 -0
  219. package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js.gz +0 -0
  220. package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js +18 -0
  221. package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js.br +0 -0
  222. package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js.gz +0 -0
  223. package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js +18 -0
  224. package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js.br +0 -0
  225. package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js.gz +0 -0
  226. package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js +18 -0
  227. package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js.br +0 -0
  228. package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js.gz +0 -0
  229. package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js +20 -0
  230. package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js.br +0 -0
  231. package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js.gz +0 -0
  232. package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js +18 -0
  233. package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js.br +0 -0
  234. package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js.gz +0 -0
  235. package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js +18 -0
  236. package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js.br +0 -0
  237. package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js.gz +0 -0
  238. package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js +19 -0
  239. package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js.br +0 -0
  240. package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js.gz +0 -0
  241. package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js +18 -0
  242. package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js.br +18 -0
  243. package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js.gz +0 -0
  244. package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js +21 -0
  245. package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js.br +0 -0
  246. package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js.gz +0 -0
  247. package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js +18 -0
  248. package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js.br +0 -0
  249. package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js.gz +0 -0
  250. package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js +18 -0
  251. package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js.br +0 -0
  252. package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js.gz +0 -0
  253. package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js +18 -0
  254. package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js.br +0 -0
  255. package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js.gz +0 -0
  256. package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js +19 -0
  257. package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js.br +0 -0
  258. package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js.gz +0 -0
  259. package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js +18 -0
  260. package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js.br +0 -0
  261. package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js.gz +0 -0
  262. package/frontend/build/client/_app/version.json +1 -0
  263. package/frontend/build/client/_app/version.json.br +0 -0
  264. package/frontend/build/client/_app/version.json.gz +0 -0
  265. package/frontend/build/client/favicon.png +0 -0
  266. package/frontend/build/env.js +111 -0
  267. package/frontend/build/handler.js +1511 -0
  268. package/frontend/build/index.js +362 -0
  269. package/frontend/build/server/chunks/0-BFfqmlsS.js +26 -0
  270. package/frontend/build/server/chunks/0-BFfqmlsS.js.map +17 -0
  271. package/frontend/build/server/chunks/1-hso3H4Ax.js +26 -0
  272. package/frontend/build/server/chunks/1-hso3H4Ax.js.map +17 -0
  273. package/frontend/build/server/chunks/2-BSZWXCWp.js +26 -0
  274. package/frontend/build/server/chunks/2-BSZWXCWp.js.map +17 -0
  275. package/frontend/build/server/chunks/3-BYumY9dv.js +26 -0
  276. package/frontend/build/server/chunks/3-BYumY9dv.js.map +17 -0
  277. package/frontend/build/server/chunks/4-2UUrCVtM.js +26 -0
  278. package/frontend/build/server/chunks/4-2UUrCVtM.js.map +17 -0
  279. package/frontend/build/server/chunks/5-C2_y_fwT.js +26 -0
  280. package/frontend/build/server/chunks/5-C2_y_fwT.js.map +17 -0
  281. package/frontend/build/server/chunks/Badge-CC4U7C0c.js +30 -0
  282. package/frontend/build/server/chunks/Badge-CC4U7C0c.js.map +17 -0
  283. package/frontend/build/server/chunks/Button-BLkPicwS.js +33 -0
  284. package/frontend/build/server/chunks/Button-BLkPicwS.js.map +17 -0
  285. package/frontend/build/server/chunks/_layout.svelte-Bfxcj9C6.js +183 -0
  286. package/frontend/build/server/chunks/_layout.svelte-Bfxcj9C6.js.map +17 -0
  287. package/frontend/build/server/chunks/_page.svelte-DEK6UvaI.js +45 -0
  288. package/frontend/build/server/chunks/_page.svelte-DEK6UvaI.js.map +17 -0
  289. package/frontend/build/server/chunks/_page.svelte-DScVdHOq.js +142 -0
  290. package/frontend/build/server/chunks/_page.svelte-DScVdHOq.js.map +17 -0
  291. package/frontend/build/server/chunks/_page.svelte-Ns7w2sZt.js +180 -0
  292. package/frontend/build/server/chunks/_page.svelte-Ns7w2sZt.js.map +17 -0
  293. package/frontend/build/server/chunks/_page.svelte-s6ZIOitT.js +165 -0
  294. package/frontend/build/server/chunks/_page.svelte-s6ZIOitT.js.map +17 -0
  295. package/frontend/build/server/chunks/attributes-BeaNKpgU.js +34 -0
  296. package/frontend/build/server/chunks/attributes-BeaNKpgU.js.map +17 -0
  297. package/frontend/build/server/chunks/client-C9IaEwNo.js +52 -0
  298. package/frontend/build/server/chunks/client-C9IaEwNo.js.map +17 -0
  299. package/frontend/build/server/chunks/error.svelte-HKBv5sQT.js +45 -0
  300. package/frontend/build/server/chunks/error.svelte-HKBv5sQT.js.map +17 -0
  301. package/frontend/build/server/chunks/escaping-CqgfEcN3.js +36 -0
  302. package/frontend/build/server/chunks/escaping-CqgfEcN3.js.map +17 -0
  303. package/frontend/build/server/chunks/exports-OxlCJ8yE.js +192 -0
  304. package/frontend/build/server/chunks/exports-OxlCJ8yE.js.map +17 -0
  305. package/frontend/build/server/chunks/index-CjHlq1kt.js +1076 -0
  306. package/frontend/build/server/chunks/index-CjHlq1kt.js.map +17 -0
  307. package/frontend/build/server/chunks/reports-D3ZeYSmi.js +56 -0
  308. package/frontend/build/server/chunks/reports-D3ZeYSmi.js.map +17 -0
  309. package/frontend/build/server/index.js +5015 -0
  310. package/frontend/build/server/index.js.map +17 -0
  311. package/frontend/build/server/manifest.js +84 -0
  312. package/frontend/build/server/manifest.js.map +17 -0
  313. package/frontend/build/shims.js +49 -0
  314. package/frontend/package-lock.json +2 -2
  315. package/frontend/package.json +1 -1
  316. package/frontend/src/lib/api/reports.js +38 -27
  317. package/frontend/src/lib/api/schedules.js +9 -25
  318. package/frontend/src/lib/api/settings.js +48 -0
  319. package/frontend/src/lib/components/layout/Nav.svelte +2 -1
  320. package/frontend/src/lib/components/layout/RunnerPanel.svelte +160 -21
  321. package/frontend/src/lib/components/ui/Terminal.svelte +2 -2
  322. package/frontend/src/lib/stores/runner.js +9 -0
  323. package/frontend/src/routes/+page.svelte +10 -3
  324. package/frontend/src/routes/reports/+page.svelte +342 -51
  325. package/frontend/src/routes/reports/[slug]/+page.svelte +2 -0
  326. package/frontend/src/routes/scheduled-tests/+page.svelte +247 -11
  327. package/frontend/src/routes/settings/+page.svelte +410 -0
  328. package/package.json +6 -2
  329. package/.claude/settings.local.json +0 -27
  330. package/.husky/pre-commit +0 -2
  331. package/.prettierrc +0 -15
  332. package/.vscode/settings.json +0 -10
  333. package/backend/config/scripts/create-settings.js +0 -53
  334. package/license-config.json +0 -37
package/README.md CHANGED
@@ -1,26 +1,26 @@
1
- ![alt-text="social-preview"](https://repository-images.githubusercontent.com/936477779/e928fce3-6d4c-4609-92a0-0a1091c99752)
1
+ ![Plum social preview](https://repository-images.githubusercontent.com/936477779/e928fce3-6d4c-4609-92a0-0a1091c99752)
2
2
 
3
3
  <p align="center">
4
- 📖 <a href="https://github.com/silverlunah/plum/wiki">Wiki</a> |
5
- 📦 <a href="https://www.npmjs.com/package/plum-e2e">npm</a>
4
+ <a href="https://www.npmjs.com/package/plum-e2e"><img src="https://img.shields.io/npm/v/plum-e2e?color=7c3aed&label=plum-e2e" alt="npm version" /></a>
5
+ <a href="https://github.com/silverlunah/plum/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-GPL--3.0-blue" alt="license" /></a>
6
+ <a href="https://github.com/silverlunah/plum/wiki"><img src="https://img.shields.io/badge/docs-wiki-informational" alt="docs" /></a>
6
7
  </p>
7
8
 
8
- ## Welcome to Plum!
9
-
10
- Plum is a ready-to-use E2E test automation environment that combines [Playwright](https://playwright.dev) and [Cucumber](https://cucumber.io). Write tests in [Gherkin](https://cucumber.io/docs/gherkin/) format, run them from the CLI or through a UI, and view reports — all in one place.
9
+ <p align="center">
10
+ A ready-to-use E2E test automation environment built on <a href="https://playwright.dev">Playwright</a> + <a href="https://cucumber.io">Cucumber</a>.<br/>
11
+ Write tests in Gherkin, run them from the CLI or UI, and view reports — all in one place.
12
+ </p>
11
13
 
12
14
  ---
13
15
 
14
- ## For Users
16
+ ## Requirements
15
17
 
16
- > People who want to use Plum as a test environment for their website.
18
+ - [Node.js](https://nodejs.org) (v18+)
19
+ - [Docker](https://www.docker.com) — only needed for `plum start`
17
20
 
18
- ### Prerequisites
19
-
20
- - [Node.js](https://nodejs.org)
21
- - [Docker](https://www.docker.com) (required for `plum start`)
21
+ ---
22
22
 
23
- ### Setup
23
+ ## Quick Start
24
24
 
25
25
  ```bash
26
26
  npm install -g plum-e2e
@@ -28,38 +28,117 @@ mkdir my-tests && cd my-tests
28
28
  plum init
29
29
  ```
30
30
 
31
- `plum init` creates the following in your project directory and installs the [Cucumber VS Code extension](https://marketplace.visualstudio.com/items?itemName=cucumberopen.cucumber-official) for step definition linking:
31
+ ---
32
+
33
+ ## Setup & Configuration
34
+
35
+ ### `plum init`
36
+
37
+ Scaffolds a new project in the current directory. Run this once after creating your project folder.
38
+
39
+ ```bash
40
+ plum init
41
+ ```
42
+
43
+ Creates the following structure:
32
44
 
33
45
  <pre>
34
- ╠═ tests
35
- ║ ╠═ features : Gherkin feature files your test cases
36
- ║ ╠═ step_definitions : TypeScript step implementations
37
- ║ ╠═ pages : Page Object Models
38
- ║ ╚═ utils : Shared utilities (browser setup, constants, etc.)
39
- ╠═ .vscode
40
- ║ ╚═ settings.json : Cucumber extension config (step definition linking)
41
- ╚═ .env : Environment config (BASE_URL, IS_HEADLESS)
46
+ ╠═ tests/
47
+ ║ ╠═ features/ — Gherkin .feature files (your test cases)
48
+ ║ ╠═ step_definitions/ — TypeScript step implementations
49
+ ║ ╠═ pages/ — Page Object Models
50
+ ║ ╚═ utils/ — Browser setup, hooks, shared helpers
51
+ ╠═ .vscode/
52
+ ║ ╚═ settings.json Cucumber extension config (step linking)
53
+ ╠═ .env Environment config (BASE_URL, IS_HEADLESS)
54
+ ╠═ .gitignore — Pre-configured to ignore .plum/ and reports/
55
+ ╚═ plum.plugins.json — Add extra npm packages for your tests here
42
56
  </pre>
43
57
 
44
- ### Commands
58
+ Also installs all Plum dependencies and the [Cucumber VS Code extension](https://marketplace.visualstudio.com/items?itemName=cucumberopen.cucumber-official) for step definition linking.
59
+
60
+ ---
61
+
62
+ ### `.env` — Environment Config
45
63
 
46
- | Command | Description |
47
- | ----------------------------- | -------------------------------------------------------------------------- |
48
- | `plum init` | Scaffold the `tests/` folder and `.env` file in your project directory |
49
- | `plum dev [tag]` | Run tests locally without Docker. Pass a tag to filter (e.g. `@test-1`) |
50
- | `plum dev --parallel N [tag]` | Run tests in parallel with N workers (e.g. `plum dev --parallel 4`) |
51
- | `plum start` | Start the full stack via Docker and open the UI at `http://localhost:5173` |
52
- | `plum create-step` | Interactive prompt to generate a step definition and page object |
64
+ Plum creates a `.env` in your project root. Edit it to point at your app:
65
+
66
+ ```env
67
+ BASE_URL=https://your-app.com
68
+ IS_HEADLESS=false
69
+ ```
70
+
71
+ | Variable | Description |
72
+ | ------------- | -------------------------------------------------------- |
73
+ | `BASE_URL` | The base URL Playwright navigates to during tests |
74
+ | `IS_HEADLESS` | Run the browser headlessly (`true`) or visibly (`false`) |
53
75
 
54
76
  ---
55
77
 
56
- ### Writing a Test
78
+ ### `plum.plugins.json` Adding Packages
57
79
 
58
- Tests follow a three-layer structure: **Feature Step Definition Page Object**.
80
+ If your tests need extra npm packages (e.g. a faker library, an assertion helper), add them to `plum.plugins.json`:
81
+
82
+ ```json
83
+ {
84
+ "dependencies": {
85
+ "@faker-js/faker": "^9.0.0",
86
+ "dayjs": "^1.11.0"
87
+ }
88
+ }
89
+ ```
90
+
91
+ Plum installs these automatically before running tests. Commit this file so your whole team shares the same dependencies.
92
+
93
+ ---
94
+
95
+ ## Development Commands
96
+
97
+ ### `plum dev` — Run Tests Locally
98
+
99
+ Runs tests directly on your machine without Docker. This is the fastest way to write and debug tests.
100
+
101
+ ```bash
102
+ plum dev # run all tests
103
+ plum dev @test-login-1 # run a single scenario by tag
104
+ plum dev @suite-login # run a whole suite by tag
105
+ plum dev --parallel 4 # run all tests across 4 workers
106
+ plum dev --parallel 4 @suite-x # run a suite in parallel
107
+ ```
108
+
109
+ > Syncs your `tests/` folder into Plum, installs dependencies, and runs Cucumber.
59
110
 
60
- #### 1. Feature File
111
+ ---
61
112
 
62
- Create a `.feature` file in `tests/features/`. Tags are used to filter which tests to run.
113
+ ### `plum start` Run via Docker
114
+
115
+ Starts the full Plum stack (backend + UI) in Docker. Use this when you want the web interface at `http://localhost:5173` to trigger, monitor, and schedule tests.
116
+
117
+ ```bash
118
+ plum start
119
+ ```
120
+
121
+ > Requires Docker to be running. Automatically rebuilds if you've changed plugins or config.
122
+
123
+ ---
124
+
125
+ ### `plum create-step` — Generate a Step
126
+
127
+ Interactive prompt that generates a new step definition and its Page Object method.
128
+
129
+ ```bash
130
+ plum create-step
131
+ ```
132
+
133
+ Follow the prompts to describe the action — Plum writes the boilerplate so you just fill in the implementation.
134
+
135
+ ---
136
+
137
+ ## Writing a Test
138
+
139
+ Tests follow a three-layer structure: **Feature → Step Definition → Page Object**.
140
+
141
+ ### 1. Feature File
63
142
 
64
143
  ```gherkin
65
144
  # tests/features/Login.feature
@@ -74,9 +153,9 @@ Feature: Login
74
153
  Then I should see the dashboard
75
154
  ```
76
155
 
77
- #### 2. Page Object Model
156
+ Use tags (`@suite-login`, `@test-login-1`) to filter which tests to run.
78
157
 
79
- Create a `.ts` file in `tests/pages/`. Methods are **static** — they use `page()` internally so you never need to pass a page instance around.
158
+ ### 2. Page Object
80
159
 
81
160
  ```typescript
82
161
  // tests/pages/LoginPage.ts
@@ -100,9 +179,9 @@ export class LoginPage {
100
179
  }
101
180
  ```
102
181
 
103
- #### 3. Step Definition
182
+ Methods are **static** — they use `page()` internally so you never pass a page instance around.
104
183
 
105
- Create a `.ts` file in `tests/step_definitions/`. Just import the page and call its static methods directly.
184
+ ### 3. Step Definition
106
185
 
107
186
  ```typescript
108
187
  // tests/step_definitions/LoginSteps.ts
@@ -123,59 +202,52 @@ Then('I should see the dashboard', async () => {
123
202
  });
124
203
  ```
125
204
 
126
- #### Running your test
205
+ ---
127
206
 
128
- ```bash
129
- plum dev @test-login-1 # run a single scenario
130
- plum dev @suite-login # run the whole suite
131
- plum dev # run all tests
132
- ```
207
+ ## Command Reference
133
208
 
134
- ---
209
+ | Command | When to use |
210
+ | ----------------------- | -------------------------------------------- |
211
+ | `plum init` | First-time setup in a new project folder |
212
+ | `plum dev` | Run all tests locally |
213
+ | `plum dev @tag` | Run tests matching a tag locally |
214
+ | `plum dev --parallel N` | Run tests across N parallel workers locally |
215
+ | `plum start` | Start the full UI stack via Docker |
216
+ | `plum create-step` | Interactively scaffold a new step definition |
135
217
 
136
- ## For Developers
218
+ ---
137
219
 
138
- > People who want to contribute to or develop Plum itself.
220
+ ## For Contributors
139
221
 
140
- ### Setup
222
+ > Only relevant if you're developing Plum itself.
141
223
 
142
224
  ```bash
143
225
  git clone https://github.com/silverlunah/plum.git
144
226
  cd plum
145
- npm run init
227
+ npm run init # installs root + backend + frontend dependencies
146
228
  ```
147
229
 
148
- `npm run init` installs all dependencies across the root, backend, and frontend.
149
-
150
- ### Backend Local Commands
151
-
152
- Run these from the `backend/` directory:
153
-
154
- | Command | Description |
155
- | -------------------------- | ---------------------------------------------------------------- |
156
- | `npm run init` | Create `.env` and copy scaffold into `backend/tests/` |
157
- | `npm test [-- tag]` | Run tests from `backend/tests/` directly |
158
- | `npm test -- --parallel N` | Run tests in parallel with N workers |
159
- | `npm run create-step` | Interactive prompt to generate a step definition and page object |
230
+ ### Backend
160
231
 
161
232
  ```bash
162
233
  cd backend
163
- npm run init # sets up .env and tests/ for local development
164
- npm test # run all tests
165
- npm test -- @test-1 # run a specific test by tag
166
- npm test -- --parallel 4 # run tests in parallel
167
- npm run create-step # generate a new step and page interactively
234
+ npm run init # set up .env and local test scaffold
235
+ npm test # run all tests
236
+ npm test -- @test-1 # run a specific test by tag
237
+ npm test -- --parallel 4 # run tests in parallel
238
+ npm run create-step # generate a step definition interactively
168
239
  ```
169
240
 
170
241
  ### Docker
171
242
 
172
243
  ```bash
173
- npm run docker:up # build and start all services
244
+ npm run docker:up # build and start all services in detached mode
174
245
  npm run docker:down # stop all services
175
246
  ```
176
247
 
177
248
  ---
178
249
 
179
- ## Other
180
-
181
- Plum is completely free to use! But if you want to share some love, here's my [PayPal](https://www.paypal.me/silverlunah) or [Wise](https://wise.com/pay/me/janneserjosee)
250
+ <p align="center">
251
+ Plum is free to use. If you'd like to show some love:<br/>
252
+ <a href="https://www.paypal.me/silverlunah">PayPal</a> · <a href="https://wise.com/pay/me/janneserjosee">Wise</a>
253
+ </p>
@@ -15,7 +15,7 @@
15
15
  # along with Plum. If not, see https://www.gnu.org/licenses/.
16
16
  #
17
17
 
18
- FROM mcr.microsoft.com/playwright:v1.41.1
18
+ FROM mcr.microsoft.com/playwright:v1.50.0
19
19
  WORKDIR /app
20
20
 
21
21
  COPY package.json package-lock.json ./
@@ -24,7 +24,9 @@ RUN npx playwright install --with-deps
24
24
 
25
25
  COPY . .
26
26
 
27
+ RUN npx prisma generate
27
28
  RUN npm run create-env && sed -i 's/^IS_HEADLESS=false/IS_HEADLESS=true/' .env
28
29
 
29
30
  EXPOSE 3001
30
- CMD ["node", "server.js"]
31
+ RUN chmod +x /app/entrypoint.sh
32
+ ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"]
@@ -28,6 +28,7 @@ export async function teardown(
28
28
  await _page.screenshot({ path: screenshotPath });
29
29
  const screenshotData = fs.readFileSync(screenshotPath);
30
30
  await attach(screenshotData, 'image/png');
31
+ fs.unlinkSync(screenshotPath);
31
32
  }
32
33
  await _browser?.close();
33
34
  }
package/backend/app.js CHANGED
@@ -26,12 +26,14 @@ app.use(express.json());
26
26
  const testRoutes = require('./routes/tests.routes');
27
27
  const reportRoutes = require('./routes/reports.routes');
28
28
  const cronRoutes = require('./routes/cron.routes');
29
- const scheduleRoutes = require('./routes/schedules.routes');
29
+ const settingsRoutes = require('./routes/settings.routes');
30
+ const backupRoutes = require('./routes/backup.routes');
30
31
 
31
32
  app.use('/tests', testRoutes);
32
33
  app.use('/reports', reportRoutes);
33
34
  app.use('/cron-jobs', cronRoutes);
34
35
  app.use('/reports', express.static('reports'));
35
- app.use('/schedules', scheduleRoutes);
36
+ app.use('/settings', settingsRoutes);
37
+ app.use('/backup', backupRoutes);
36
38
 
37
39
  module.exports = app;
@@ -17,42 +17,12 @@
17
17
 
18
18
  const fs = require('fs');
19
19
  const path = require('path');
20
- const { reportsHistory } = require('../settings.json');
21
-
22
20
  const reportsDir = 'reports';
23
21
  const screenshotsDir = path.join(reportsDir, 'screenshots');
24
- const maxReports = reportsHistory;
25
22
 
26
23
  if (!fs.existsSync(reportsDir)) fs.mkdirSync(reportsDir, { recursive: true });
27
24
  if (!fs.existsSync(screenshotsDir)) fs.mkdirSync(screenshotsDir, { recursive: true });
28
25
 
29
- // Clean up old timestamped report JSON files
30
- const existingReports = fs
31
- .readdirSync(reportsDir)
32
- .filter((f) => f.endsWith('.json') && (f.startsWith('PASS_') || f.startsWith('FAIL_')))
33
- .sort(
34
- (a, b) =>
35
- fs.statSync(path.join(reportsDir, b)).mtime - fs.statSync(path.join(reportsDir, a)).mtime
36
- );
37
-
38
- while (existingReports.length >= maxReports) {
39
- fs.unlinkSync(path.join(reportsDir, existingReports.pop()));
40
- }
41
-
42
- // Clean up old screenshots
43
- const existingScreenshots = fs
44
- .readdirSync(screenshotsDir)
45
- .filter((f) => f.endsWith('.png') || f.endsWith('.jpg'))
46
- .sort(
47
- (a, b) =>
48
- fs.statSync(path.join(screenshotsDir, b)).mtime -
49
- fs.statSync(path.join(screenshotsDir, a)).mtime
50
- );
51
-
52
- while (existingScreenshots.length >= maxReports) {
53
- fs.unlinkSync(path.join(screenshotsDir, existingScreenshots.pop()));
54
- }
55
-
56
26
  // Determine PASS/FAIL from cucumber JSON output
57
27
  const jsonReportFile = path.join(reportsDir, 'cucumber_report.json');
58
28
  let status = 'PASS';
@@ -86,6 +56,44 @@ const reportFileName = `${status}_cucumber_report_${process.env.TRIGGER}_${tag}_
86
56
  if (fs.existsSync(jsonReportFile)) {
87
57
  fs.copyFileSync(jsonReportFile, path.join(reportsDir, reportFileName));
88
58
  console.log(`Report saved: ${reportFileName}`);
59
+
60
+ // Persist metadata to database
61
+ (async () => {
62
+ try {
63
+ const { PrismaClient } = require('@prisma/client');
64
+ const prisma = new PrismaClient();
65
+
66
+ const triggerType = process.env.TRIGGER || 'command-line-trigger';
67
+ const builtInTriggers = ['manual-trigger', 'command-line-trigger', 'undefined'];
68
+ let cronJobId = null;
69
+
70
+ if (!builtInTriggers.includes(triggerType)) {
71
+ const job = await prisma.cronJob.findUnique({ where: { taskName: triggerType } });
72
+ if (job) cronJobId = job.id;
73
+ }
74
+
75
+ const rawTag = process.env.TAG || '@all-tests';
76
+ const tags = rawTag.replace(/^\(|\)$/g, '');
77
+
78
+ await prisma.report.upsert({
79
+ where: { fileName: reportFileName },
80
+ create: {
81
+ fileName: reportFileName,
82
+ status,
83
+ tags,
84
+ triggerType,
85
+ runners: runnerCount,
86
+ cronJobId
87
+ },
88
+ update: {}
89
+ });
90
+
91
+ await prisma.$disconnect();
92
+ console.log('Report metadata saved to database.');
93
+ } catch (e) {
94
+ console.error('Could not save report metadata to DB:', e.message);
95
+ }
96
+ })();
89
97
  } else {
90
98
  console.log('Skipping report save — no cucumber_report.json.');
91
99
  }
@@ -1,4 +1,4 @@
1
- #
1
+ #!/bin/sh
2
2
  # This file is part of Plum.
3
3
  #
4
4
  # Plum is free software: you can redistribute it and/or modify
@@ -13,9 +13,10 @@
13
13
  #
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with Plum. If not, see https://www.gnu.org/licenses/.
16
- #
16
+ set -e
17
+
18
+ echo "Running database migrations..."
19
+ npx prisma migrate deploy
17
20
 
18
- # Package Managers
19
- package-lock.json
20
- pnpm-lock.yaml
21
- yarn.lock
21
+ echo "Starting server..."
22
+ exec node server.js